Skip to content

Commit 61b68a2

Browse files
authored
Emit events from the frame (#2416)
* Emit events from the frame * fix tests * fix old typo * Code factor * Some refactors * some fixes * more fixes
1 parent 9fa281b commit 61b68a2

File tree

9 files changed

+157
-160
lines changed

9 files changed

+157
-160
lines changed

lib/PuppeteerSharp.Tests/CoverageTests/JSCoverageTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public async Task ShouldIgnoreEvalScriptsByDefault()
6767

6868
[PuppeteerTest("coverage.spec.ts", "JSCoverage", "shouldn't ignore eval() scripts if reportAnonymousScripts is true")]
6969
[Skip(SkipAttribute.Targets.Firefox)]
70-
public async Task ShouldntIgnoreEvalScriptsIfReportAnonymousScriptsIsTrue()
70+
public async Task ShouldNotIgnoreEvalScriptsIfReportAnonymousScriptsIsTrue()
7171
{
7272
await Page.Coverage.StartJSCoverageAsync(new CoverageStartOptions
7373
{

lib/PuppeteerSharp.Tests/LauncherTests/BrowserDisconnectTests.cs

Lines changed: 26 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,31 @@ namespace PuppeteerSharp.Tests.LauncherTests
88
{
99
public class BrowserDisconnectTests : PuppeteerBrowserBaseTest
1010
{
11-
public BrowserDisconnectTests() : base()
12-
{
13-
}
14-
1511
[PuppeteerTest("launcher.spec.ts", "Browser.disconnect", "should reject navigation when browser closes")]
1612
[PuppeteerTimeout]
1713
public async Task ShouldRejectNavigationWhenBrowserCloses()
1814
{
1915
Server.SetRoute("/one-style.css", _ => Task.Delay(10000));
2016

21-
await using (var browser = await Puppeteer.LaunchAsync(TestConstants.DefaultBrowserOptions()))
17+
await using var browser = await Puppeteer.LaunchAsync(TestConstants.DefaultBrowserOptions());
18+
var remote = await Puppeteer.ConnectAsync(new ConnectOptions
2219
{
23-
var remote = await Puppeteer.ConnectAsync(new ConnectOptions
24-
{
25-
BrowserWSEndpoint = browser.WebSocketEndpoint
26-
});
27-
var page = await remote.NewPageAsync();
28-
var navigationTask = page.GoToAsync(TestConstants.ServerUrl + "/one-style.html", new NavigationOptions
20+
BrowserWSEndpoint = browser.WebSocketEndpoint
21+
});
22+
var page = await remote.NewPageAsync();
23+
var navigationTask = page.GoToAsync(TestConstants.ServerUrl + "/one-style.html", new NavigationOptions
24+
{
25+
Timeout = 60000
26+
});
27+
await Server.WaitForRequest("/one-style.css");
28+
remote.Disconnect();
29+
var exception = Assert.ThrowsAsync<NavigationException>(() => navigationTask);
30+
Assert.True(
31+
new[]
2932
{
30-
Timeout = 60000
31-
});
32-
await Server.WaitForRequest("/one-style.css");
33-
remote.Disconnect();
34-
var exception = Assert.ThrowsAsync<NavigationException>(() => navigationTask);
35-
Assert.True(
36-
new[]
37-
{
38-
"Navigation failed because browser has disconnected! (Connection disposed)",
39-
"Protocol error(Page.navigate): Target closed. (Connection disposed)",
40-
}.Any(value => value == exception.Message));
41-
}
33+
"Navigating frame was detached",
34+
"Protocol error(Page.navigate): Target closed. (Connection disposed)",
35+
}.Any(value => exception.Message.Contains(value)));
4236
}
4337

4438
[PuppeteerTest("launcher.spec.ts", "Browser.disconnect", "should reject waitForSelector when browser closes")]
@@ -47,18 +41,16 @@ public async Task ShouldRejectWaitForSelectorWhenBrowserCloses()
4741
{
4842
Server.SetRoute("/empty.html", _ => Task.Delay(10000));
4943

50-
await using (var browser = await Puppeteer.LaunchAsync(TestConstants.DefaultBrowserOptions()))
44+
await using var browser = await Puppeteer.LaunchAsync(TestConstants.DefaultBrowserOptions());
45+
var remote = await Puppeteer.ConnectAsync(new ConnectOptions
5146
{
52-
var remote = await Puppeteer.ConnectAsync(new ConnectOptions
53-
{
54-
BrowserWSEndpoint = browser.WebSocketEndpoint
55-
});
56-
var page = await remote.NewPageAsync();
57-
var watchdog = page.WaitForSelectorAsync("div", new WaitForSelectorOptions { Timeout = 60000 });
58-
remote.Disconnect();
59-
var exception = Assert.ThrowsAsync<WaitTaskTimeoutException>(() => watchdog);
60-
Assert.AreEqual("Connection disposed", (exception.InnerException as TargetClosedException).CloseReason);
61-
}
47+
BrowserWSEndpoint = browser.WebSocketEndpoint
48+
});
49+
var page = await remote.NewPageAsync();
50+
var watchdog = page.WaitForSelectorAsync("div", new WaitForSelectorOptions { Timeout = 60000 });
51+
remote.Disconnect();
52+
var exception = Assert.ThrowsAsync<WaitTaskTimeoutException>(() => watchdog);
53+
Assert.True(exception.Message.Contains("frame got detached"));
6254
}
6355
}
6456
}

lib/PuppeteerSharp.Tests/LauncherTests/PuppeteerConnectTests.cs

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -89,34 +89,33 @@ await Task.WhenAll(
8989
[Skip(SkipAttribute.Targets.Firefox)]
9090
public async Task ShouldSupportTargetFilter()
9191
{
92-
await using (var originalBrowser = await Puppeteer.LaunchAsync(TestConstants.DefaultBrowserOptions(), TestConstants.LoggerFactory))
93-
{
94-
var page1 = await originalBrowser.NewPageAsync();
95-
await page1.GoToAsync(TestConstants.EmptyPage);
96-
97-
var page2 = await originalBrowser.NewPageAsync();
98-
await page2.GoToAsync(TestConstants.EmptyPage + "?should-be-ignored");
92+
await using var browser = await Puppeteer.LaunchAsync(TestConstants.DefaultBrowserOptions(), TestConstants.LoggerFactory);
93+
var page1 = await browser.NewPageAsync();
94+
await page1.GoToAsync(TestConstants.EmptyPage);
9995

100-
var browser = await Puppeteer.ConnectAsync(new ConnectOptions
101-
{
102-
BrowserWSEndpoint = originalBrowser.WebSocketEndpoint,
103-
TargetFilter = (Target target) => !target.Url.Contains("should-be-ignored"),
104-
}, TestConstants.LoggerFactory);
96+
var page2 = await browser.NewPageAsync();
97+
await page2.GoToAsync(TestConstants.EmptyPage + "?should-be-ignored");
10598

106-
var pages = await browser.PagesAsync();
99+
var remoteBrowser = await Puppeteer.ConnectAsync(new ConnectOptions
100+
{
101+
BrowserWSEndpoint = browser.WebSocketEndpoint,
102+
TargetFilter = (Target target) => !target.Url.Contains("should-be-ignored"),
103+
}, TestConstants.LoggerFactory);
107104

108-
await page2.CloseAsync();
109-
await page1.CloseAsync();
110-
await browser.CloseAsync();
105+
var pages = await remoteBrowser.PagesAsync();
111106

112-
Assert.AreEqual(
113-
new string[]
114-
{
115-
"about:blank",
116-
TestConstants.EmptyPage
117-
},
118-
pages.Select((IPage p) => p.Url).OrderBy(t => t));
119-
}
107+
Assert.AreEqual(
108+
new string[]
109+
{
110+
"about:blank",
111+
TestConstants.EmptyPage
112+
},
113+
pages.Select((IPage p) => p.Url).OrderBy(t => t));
114+
115+
await page2.CloseAsync();
116+
await page1.CloseAsync();
117+
remoteBrowser.Disconnect();
118+
await browser.CloseAsync();
120119
}
121120

122121
[PuppeteerTimeout]
@@ -153,16 +152,14 @@ public async Task ShouldBeAbleToReconnectToADisconnectedBrowser()
153152

154153
Browser.Disconnect();
155154

156-
await using (var browser = await Puppeteer.ConnectAsync(options, TestConstants.LoggerFactory))
157-
{
158-
var pages = (await browser.PagesAsync()).ToList();
159-
var restoredPage = pages.FirstOrDefault(x => x.Url == url);
160-
Assert.NotNull(restoredPage);
161-
var frameDump = FrameUtils.DumpFrames(restoredPage.MainFrame);
162-
Assert.AreEqual(TestConstants.NestedFramesDumpResult, frameDump);
163-
var response = await restoredPage.EvaluateExpressionAsync<int>("7 * 8");
164-
Assert.AreEqual(56, response);
165-
}
155+
await using var browser = await Puppeteer.ConnectAsync(options, TestConstants.LoggerFactory);
156+
var pages = (await browser.PagesAsync()).ToList();
157+
var restoredPage = pages.FirstOrDefault(x => x.Url == url);
158+
Assert.NotNull(restoredPage);
159+
var frameDump = FrameUtils.DumpFrames(restoredPage.MainFrame);
160+
Assert.AreEqual(TestConstants.NestedFramesDumpResult, frameDump);
161+
var response = await restoredPage.EvaluateExpressionAsync<int>("7 * 8");
162+
Assert.AreEqual(56, response);
166163
}
167164

168165
[PuppeteerTest("launcher.spec.ts", "Puppeteer.connect", "should be able to connect to the same page simultaneously")]

lib/PuppeteerSharp.Tests/NavigationTests/PageGotoTests.cs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ namespace PuppeteerSharp.Tests.NavigationTests
1313
{
1414
public class PageGotoTests : PuppeteerPageBaseTest
1515
{
16-
public PageGotoTests() : base()
17-
{
18-
}
19-
2016
[PuppeteerTest("navigation.spec.ts", "Page.goto", "should work")]
2117
[PuppeteerTimeout]
2218
public async Task ShouldWork()
@@ -127,7 +123,25 @@ await Page.EvaluateFunctionAsync(@"() =>
127123
[Skip(SkipAttribute.Targets.Firefox)]
128124
public async Task ShouldNavigateToEmptyPageWithNetworkidle0()
129125
{
130-
var response = await Page.GoToAsync(TestConstants.EmptyPage, new NavigationOptions { WaitUntil = new[] { WaitUntilNavigation.Networkidle0 } });
126+
var response = await Page.GoToAsync(TestConstants.EmptyPage, new NavigationOptions
127+
{
128+
WaitUntil =
129+
[WaitUntilNavigation.Networkidle0]
130+
});
131+
Assert.AreEqual(HttpStatusCode.OK, response.Status);
132+
}
133+
134+
135+
[PuppeteerTest("navigation.spec.ts", "Page.goto", "should navigate to page with iframe and networkidle0")]
136+
[Skip(SkipAttribute.Targets.Firefox)]
137+
public async Task ShouldNavigateToPageWithIframeAndNetworkidle0()
138+
139+
{
140+
var response = await Page.GoToAsync(TestConstants.ServerUrl + "/frames/one-frame.html", new NavigationOptions
141+
{
142+
WaitUntil =
143+
[WaitUntilNavigation.Networkidle0]
144+
});
131145
Assert.AreEqual(HttpStatusCode.OK, response.Status);
132146
}
133147

lib/PuppeteerSharp/ChromeTargetManager.cs

Lines changed: 27 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ internal class ChromeTargetManager : ITargetManager
1919
private readonly AsyncDictionaryHelper<string, Target> _attachedTargetsByTargetId = new("Target {0} not found");
2020
private readonly ConcurrentDictionary<string, Target> _attachedTargetsBySessionId = new();
2121
private readonly ConcurrentDictionary<string, TargetInfo> _discoveredTargetsByTargetId = new();
22-
private readonly List<string> _targetsIdsForInit = [];
22+
private readonly ConcurrentSet<string> _targetsIdsForInit = [];
2323
private readonly TaskCompletionSource<bool> _initializeCompletionSource = new();
2424

2525
// Needed for .NET only to prevent race conditions between StoreExistingTargetsForInit and OnAttachedToTarget
@@ -39,39 +39,6 @@ public ChromeTargetManager(
3939
_connection.MessageReceived += OnMessageReceived;
4040
_connection.SessionDetached += Connection_SessionDetached;
4141
_targetDiscoveryTimeout = targetDiscoveryTimeout;
42-
43-
_ = _connection.SendAsync("Target.setDiscoverTargets", new TargetSetDiscoverTargetsRequest
44-
{
45-
Discover = true,
46-
Filter = new[]
47-
{
48-
new TargetSetDiscoverTargetsRequest.DiscoverFilter()
49-
{
50-
Type = "tab",
51-
Exclude = true,
52-
},
53-
new TargetSetDiscoverTargetsRequest.DiscoverFilter(),
54-
},
55-
}).ContinueWith(
56-
t =>
57-
{
58-
try
59-
{
60-
if (t.IsFaulted)
61-
{
62-
_logger.LogError(t.Exception, "Target.setDiscoverTargets failed");
63-
}
64-
else
65-
{
66-
StoreExistingTargetsForInit();
67-
}
68-
}
69-
finally
70-
{
71-
_targetDiscoveryCompletionSource.SetResult(true);
72-
}
73-
},
74-
TaskScheduler.Default);
7542
}
7643

7744
public event EventHandler<TargetChangedArgs> TargetAvailable;
@@ -86,14 +53,34 @@ public ChromeTargetManager(
8653

8754
public async Task InitializeAsync()
8855
{
89-
await _connection.SendAsync("Target.setAutoAttach", new TargetSetAutoAttachRequest()
56+
try
57+
{
58+
await _connection.SendAsync("Target.setDiscoverTargets", new TargetSetDiscoverTargetsRequest
59+
{
60+
Discover = true,
61+
Filter =
62+
[
63+
new TargetSetDiscoverTargetsRequest.DiscoverFilter() { Type = "tab", Exclude = true, },
64+
new TargetSetDiscoverTargetsRequest.DiscoverFilter()
65+
],
66+
}).ConfigureAwait(false);
67+
}
68+
finally
9069
{
91-
WaitForDebuggerOnStart = true,
92-
Flatten = true,
93-
AutoAttach = true,
94-
}).ConfigureAwait(false);
70+
_targetDiscoveryCompletionSource.SetResult(true);
71+
}
72+
73+
StoreExistingTargetsForInit();
74+
75+
await _connection.SendAsync(
76+
"Target.setAutoAttach",
77+
new TargetSetAutoAttachRequest()
78+
{
79+
WaitForDebuggerOnStart = true,
80+
Flatten = true,
81+
AutoAttach = true,
82+
}).ConfigureAwait(false);
9583

96-
await _targetDiscoveryCompletionSource.Task.ConfigureAwait(false);
9784
FinishInitializationIfReady();
9885

9986
await _initializeCompletionSource.Task.ConfigureAwait(false);

lib/PuppeteerSharp/ElementHandle.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -179,18 +179,17 @@ await handle.EvaluateFunctionAsync(@"(element) => {
179179
return handle;
180180
}
181181

182-
var objectId = RemoteObject.ObjectId;
183182
var node = await handle.Client.SendAsync<DomDescribeNodeResponse>("DOM.describeNode", new DomDescribeNodeRequest
184183
{
185-
ObjectId = RemoteObject.ObjectId,
184+
ObjectId = Id,
186185
}).ConfigureAwait(false);
187186
var backendNodeId = node.Node.BackendNodeId;
188187

189188
var files = resolveFilePaths ? filePaths.Select(Path.GetFullPath).ToArray() : filePaths;
190189
CheckForFileAccess(files);
191190
await handle.Client.SendAsync("DOM.setFileInputFiles", new DomSetFileInputFilesRequest
192191
{
193-
ObjectId = objectId,
192+
ObjectId = Id,
194193
Files = files,
195194
BackendNodeId = backendNodeId,
196195
}).ConfigureAwait(false);
@@ -350,7 +349,7 @@ public async Task<IFrame> ContentFrameAsync()
350349
{
351350
var nodeInfo = await Client.SendAsync<DomDescribeNodeResponse>("DOM.describeNode", new DomDescribeNodeRequest
352351
{
353-
ObjectId = RemoteObject.ObjectId,
352+
ObjectId = Id,
354353
}).ConfigureAwait(false);
355354

356355
return string.IsNullOrEmpty(nodeInfo.Node.FrameId) ? null : await FrameManager.FrameTree.GetFrameAsync(nodeInfo.Node.FrameId).ConfigureAwait(false);
@@ -537,7 +536,7 @@ public Task<BoxModelPoint> ClickablePointAsync(Offset? offset = null)
537536

538537
var contentQuadsTask = handle.Client.SendAsync<GetContentQuadsResponse>("DOM.getContentQuads", new DomGetContentQuadsRequest
539538
{
540-
ObjectId = handle.RemoteObject.ObjectId,
539+
ObjectId = handle.Id,
541540
});
542541
var layoutTask = Page.Client.SendAsync<PageGetLayoutMetricsResponse>("Page.getLayoutMetrics");
543542

@@ -776,7 +775,7 @@ private async Task<DomGetBoxModelResponse> GetBoxModelAsync()
776775
{
777776
return await Client.SendAsync<DomGetBoxModelResponse>("DOM.getBoxModel", new DomGetBoxModelRequest
778777
{
779-
ObjectId = RemoteObject.ObjectId,
778+
ObjectId = Id,
780779
}).ConfigureAwait(false);
781780
}
782781
catch (PuppeteerException ex)

0 commit comments

Comments
 (0)