Skip to content

Commit d6a2106

Browse files
authored
Merge pull request #2314 from hardkoded/page-target-class
Introduce an internal PageTarget subclass
2 parents 962993c + 8d53b11 commit d6a2106

File tree

8 files changed

+250
-206
lines changed

8 files changed

+250
-206
lines changed

lib/PuppeteerSharp.Tests/BrowserContextTests/BrowserContextTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ public async Task ShouldWaitForTarget()
184184

185185
[PuppeteerTest("browsercontext.spec.ts", "BrowserContext", "should timeout waiting for a non-existent target")]
186186
[PuppeteerTimeout]
187-
public async Task ShouldTimeoutWaitingForNonExistantTarget()
187+
public async Task ShouldTimeoutWaitingForNonExistentTarget()
188188
{
189189
var context = await Browser.CreateIncognitoBrowserContextAsync();
190190
Assert.ThrowsAsync<TimeoutException>(()

lib/PuppeteerSharp.Tests/DefaultBrowserContextTests/BrowserTargetEventsTests.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
namespace PuppeteerSharp.Tests.DefaultBrowserContextTests
1111
{
12-
public class BrowserTargetEventsTests : PuppeteerBrowserBaseTest
12+
public class BrowserTargetEventsTests : PuppeteerBaseTest
1313
{
1414
public BrowserTargetEventsTests(): base()
1515
{
@@ -19,13 +19,16 @@ public BrowserTargetEventsTests(): base()
1919
[Skip(SkipAttribute.Targets.Firefox)]
2020
public async Task ShouldWork()
2121
{
22+
using var browser = await Puppeteer.LaunchAsync(TestConstants.DefaultBrowserOptions());
23+
2224
var events = new List<string>();
23-
Browser.TargetCreated += (_, _) => events.Add("CREATED");
24-
Browser.TargetChanged += (_, _) => events.Add("CHANGED");
25-
Browser.TargetDestroyed += (_, _) => events.Add("DESTROYED");
26-
var page = await Browser.NewPageAsync();
25+
browser.TargetCreated += (_, _) => events.Add("CREATED");
26+
browser.TargetChanged += (_, _) => events.Add("CHANGED");
27+
browser.TargetDestroyed += (_, _) => events.Add("DESTROYED");
28+
var page = await browser.NewPageAsync();
2729
await page.GoToAsync(TestConstants.EmptyPage);
2830
await page.CloseAsync();
31+
2932
Assert.AreEqual(new[] { "CREATED", "CHANGED", "DESTROYED" }, events);
3033
}
3134
}

lib/PuppeteerSharp.Tests/LauncherTests/DefaultBrowserContextTests.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ public BrowserTargetEventsTests(): base()
1919
[Skip(SkipAttribute.Targets.Firefox)]
2020
public async Task ShouldWork()
2121
{
22+
using var browser = await Puppeteer.LaunchAsync(TestConstants.DefaultBrowserOptions());
2223
var events = new List<string>();
24+
2325
Browser.TargetCreated += (_, _) => events.Add("CREATED");
2426
Browser.TargetChanged += (_, _) => events.Add("CHANGED");
2527
Browser.TargetDestroyed += (_, _) => events.Add("DESTROYED");

lib/PuppeteerSharp/Browser.cs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ public class Browser : IBrowser
2222
private readonly ConcurrentDictionary<string, BrowserContext> _contexts;
2323
private readonly ILogger<Browser> _logger;
2424
private readonly Func<TargetInfo, bool> _targetFilterCallback;
25-
private readonly Func<TargetInfo, bool> _isPageTargetFunc;
2625
private readonly BrowserContext _defaultContext;
2726
private readonly CustomQueriesManager _customQueriesManager = new();
2827
private Task _closeTask;
@@ -43,7 +42,7 @@ internal Browser(
4342
Connection = connection;
4443
_targetFilterCallback = targetFilter ?? ((TargetInfo _) => true);
4544
_logger = Connection.LoggerFactory.CreateLogger<Browser>();
46-
_isPageTargetFunc =
45+
IsPageTargetFunc =
4746
isPageTargetFunc ??
4847
new Func<TargetInfo, bool>((TargetInfo target) =>
4948
{
@@ -140,6 +139,8 @@ public bool IsClosed
140139

141140
internal ITargetManager TargetManager { get; }
142141

142+
internal Func<TargetInfo, bool> IsPageTargetFunc { get; set; }
143+
143144
/// <inheritdoc/>
144145
public Task<IPage> NewPageAsync() => _defaultContext.NewPageAsync();
145146

@@ -478,16 +479,25 @@ private Target CreateTarget(TargetInfo targetInfo, CDPSession session)
478479
context = _defaultContext;
479480
}
480481

482+
if (IsPageTargetFunc(targetInfo))
483+
{
484+
return new PageTarget(
485+
targetInfo,
486+
session,
487+
context,
488+
TargetManager,
489+
(bool isAutoAttachEmulated) => Connection.CreateSessionAsync(targetInfo, isAutoAttachEmulated),
490+
IgnoreHTTPSErrors,
491+
DefaultViewport,
492+
ScreenshotTaskQueue);
493+
}
494+
481495
return new Target(
482496
targetInfo,
483497
session,
484498
context,
485499
TargetManager,
486-
(bool isAutoAttachEmulated) => Connection.CreateSessionAsync(targetInfo, isAutoAttachEmulated),
487-
IgnoreHTTPSErrors,
488-
DefaultViewport,
489-
ScreenshotTaskQueue,
490-
_isPageTargetFunc);
500+
(bool isAutoAttachEmulated) => Connection.CreateSessionAsync(targetInfo, isAutoAttachEmulated));
491501
}
492502
}
493503
}

lib/PuppeteerSharp/BrowserContext.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ public Task<ITarget> WaitForTargetAsync(Func<ITarget, bool> predicate, WaitForOp
4949
/// <inheritdoc/>
5050
public async Task<IPage[]> PagesAsync()
5151
=> (await Task.WhenAll(
52-
Targets().Where(t => t.Type == TargetType.Page).Select(t => t.PageAsync())).ConfigureAwait(false))
52+
Targets()
53+
.Where(t =>
54+
t.Type == TargetType.Page ||
55+
(t.Type == TargetType.Other && Browser.IsPageTargetFunc((t as Target).TargetInfo)))
56+
.Select(t => t.PageAsync())).ConfigureAwait(false))
5357
.Where(p => p != null).ToArray();
5458

5559
/// <inheritdoc/>

lib/PuppeteerSharp/ITarget.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public interface ITarget
5151
Task<ICDPSession> CreateCDPSessionAsync();
5252

5353
/// <summary>
54-
/// Returns the <see cref="IPage"/> associated with the target. If the target is not <c>"page"</c> or <c>"background_page"</c> returns <c>null</c>.
54+
/// Returns the <see cref="IPage"/> associated with the target. If the target is not <c>"page"</c>, <c>"webview"</c> or <c>"background_page"</c> returns <c>null</c>.
5555
/// </summary>
5656
/// <returns>a task that returns a <see cref="IPage"/>.</returns>
5757
Task<IPage> PageAsync();

lib/PuppeteerSharp/PageTarget.cs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using PuppeteerSharp.Helpers;
4+
5+
namespace PuppeteerSharp
6+
{
7+
internal class PageTarget : Target
8+
{
9+
private readonly bool _ignoreHTTPSErrors;
10+
private readonly ViewPortOptions _defaultViewport;
11+
private readonly TaskQueue _screenshotTaskQueue;
12+
13+
public PageTarget(TargetInfo targetInfo, CDPSession session, BrowserContext context, ITargetManager targetManager, Func<bool, Task<CDPSession>> sessionFactory, bool ignoreHTTPSErrors, ViewPortOptions defaultViewport, TaskQueue screenshotTaskQueue)
14+
: base(targetInfo, session, context, targetManager, sessionFactory)
15+
{
16+
_ignoreHTTPSErrors = ignoreHTTPSErrors;
17+
_defaultViewport = defaultViewport;
18+
_screenshotTaskQueue = screenshotTaskQueue;
19+
PageTask = null;
20+
}
21+
22+
internal Task<Page> PageTask { get; set; }
23+
24+
/// <inheritdoc/>
25+
public override async Task<IPage> PageAsync()
26+
{
27+
if (PageTask == null)
28+
{
29+
var session = Session ?? await SessionFactory(true).ConfigureAwait(false);
30+
31+
PageTask = Page.CreateAsync(
32+
session,
33+
this,
34+
_ignoreHTTPSErrors,
35+
_defaultViewport,
36+
_screenshotTaskQueue);
37+
}
38+
39+
return await PageTask.ConfigureAwait(false);
40+
}
41+
42+
protected override void Initialize()
43+
{
44+
_ = InitializedTaskWrapper.Task.ContinueWith(
45+
async initializedTask =>
46+
{
47+
var success = initializedTask.Result;
48+
if (!success)
49+
{
50+
return;
51+
}
52+
53+
var opener = Opener as PageTarget;
54+
55+
var openerPageTask = opener?.PageTask;
56+
if (openerPageTask == null || Type != TargetType.Page)
57+
{
58+
return;
59+
}
60+
61+
var openerPage = (Page)await openerPageTask.ConfigureAwait(false);
62+
if (!openerPage.HasPopupEventListeners)
63+
{
64+
return;
65+
}
66+
67+
var popupPage = await PageAsync().ConfigureAwait(false);
68+
openerPage.OnPopup(popupPage);
69+
},
70+
TaskScheduler.Default);
71+
CheckIfInitialized();
72+
}
73+
74+
protected override void CheckIfInitialized()
75+
{
76+
if (IsInitialized)
77+
{
78+
return;
79+
}
80+
81+
IsInitialized = !string.IsNullOrEmpty(TargetInfo.Url);
82+
if (IsInitialized)
83+
{
84+
InitializedTaskWrapper.TrySetResult(true);
85+
}
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)