Skip to content

Commit 9e27e33

Browse files
Fix FrameWaitForFunctionTests.ShouldPollOnMutation (#2225)
* Fix FrameWaitForFunctionTests.ShouldPollOnMutation and ShouldPollOnMutationAsync. * Fix CodeFactor * Fixed FrameWaitForFunctionTests by awaiting for the call to `poller.start()`. The previous attempt still did not guarantee the correct execution, but this should. * PR review * Moved ConnectionTransportInterceptor into its own file.
1 parent e0df7f7 commit 9e27e33

File tree

3 files changed

+93
-9
lines changed

3 files changed

+93
-9
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using PuppeteerSharp.Transport;
4+
5+
namespace PuppeteerSharp.Tests
6+
{
7+
public sealed class ConnectionTransportInterceptor : IConnectionTransport
8+
{
9+
private readonly IConnectionTransport _connectionTransport;
10+
11+
public ConnectionTransportInterceptor(IConnectionTransport connectionTransport)
12+
{
13+
_connectionTransport = connectionTransport;
14+
}
15+
16+
public event EventHandler<string> MessageSent;
17+
18+
public Task SendAsync(string message)
19+
{
20+
var task = _connectionTransport.SendAsync(message);
21+
MessageSent?.Invoke(_connectionTransport, message);
22+
return task;
23+
}
24+
25+
public bool IsClosed => _connectionTransport.IsClosed;
26+
27+
public event EventHandler<TransportClosedEventArgs> Closed
28+
{
29+
add { _connectionTransport.Closed += value; }
30+
remove { _connectionTransport.Closed -= value; }
31+
}
32+
33+
public event EventHandler<MessageReceivedEventArgs> MessageReceived
34+
{
35+
add { _connectionTransport.MessageReceived += value; }
36+
remove { _connectionTransport.MessageReceived -= value; }
37+
}
38+
39+
public void Dispose() => _connectionTransport.Dispose();
40+
41+
public void StopReading() => _connectionTransport.StopReading();
42+
}
43+
}

lib/PuppeteerSharp.Tests/WaitTaskTests/FrameWaitForFunctionTests.cs

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,38 @@
11
using System;
22
using System.Threading.Tasks;
33
using PuppeteerSharp.Tests.Attributes;
4+
using PuppeteerSharp.Transport;
45
using PuppeteerSharp.Xunit;
56
using Xunit;
67
using Xunit.Abstractions;
78

89
namespace PuppeteerSharp.Tests.WaitTaskTests
910
{
1011
[Collection(TestConstants.TestFixtureCollectionName)]
11-
public class FrameWaitForFunctionTests : PuppeteerPageBaseTest
12+
public sealed class FrameWaitForFunctionTests : PuppeteerPageBaseTest, IDisposable
1213
{
14+
private ConnectionTransportInterceptor _connectionTransportInterceptor;
15+
1316
public FrameWaitForFunctionTests(ITestOutputHelper output) : base(output)
1417
{
18+
DefaultOptions = TestConstants.DefaultBrowserOptions();
19+
20+
// Set up a custom TransportFactory to intercept sent messages
21+
// Some of the tests require making assertions after a WaitForFunction has
22+
// started, but before it has resolved. We detect that reliably by
23+
// listening to the message that is sent to start polling.
24+
// This might not be an issue in upstream puppeteer.js, or may be highly unlikely,
25+
// due to differences between node.js's task scheduler and .net's.
26+
DefaultOptions.TransportFactory = async (url, options, cancellationToken) =>
27+
{
28+
_connectionTransportInterceptor = new ConnectionTransportInterceptor(await WebSocketTransport.DefaultTransportFactory(url, options, cancellationToken));
29+
return _connectionTransportInterceptor;
30+
};
31+
}
32+
33+
public void Dispose()
34+
{
35+
_connectionTransportInterceptor.Dispose();
1536
}
1637

1738
[PuppeteerTest("waittask.spec.ts", "Frame.waitForFunction", "should work when resolved right before execution context disposal")]
@@ -33,26 +54,24 @@ public async Task ShouldPollOnInterval()
3354
{
3455
var startTime = DateTime.UtcNow;
3556
var polling = 100;
57+
var startedPolling = WaitForStartPollingAsync();
3658
var watchdog = Page.WaitForFunctionAsync("() => window.__FOO === 'hit'", new WaitForFunctionOptions { PollingInterval = polling });
37-
// Wait for function will release the execution faster than in node.
38-
// We add some CDP action to wait for the task to start the polling
39-
await Page.EvaluateExpressionAsync("document.body.appendChild(document.createElement('div'))");
59+
await startedPolling;
4060
await Page.EvaluateFunctionAsync("() => setTimeout(window.__FOO = 'hit', 50)");
4161
await watchdog;
4262

4363
Assert.True((DateTime.UtcNow - startTime).TotalMilliseconds > polling / 2);
4464
}
45-
65+
4666
[PuppeteerTest("waittask.spec.ts", "Frame.waitForFunction", "should poll on interval async")]
4767
[PuppeteerFact]
4868
public async Task ShouldPollOnIntervalAsync()
4969
{
5070
var startTime = DateTime.UtcNow;
5171
var polling = 1000;
72+
var startedPolling = WaitForStartPollingAsync();
5273
var watchdog = Page.WaitForFunctionAsync("async () => window.__FOO === 'hit'", new WaitForFunctionOptions { PollingInterval = polling });
53-
// Wait for function will release the execution faster than in node.
54-
// We add some CDP action to wait for the task to start the polling
55-
await Page.EvaluateExpressionAsync("document.body.appendChild(document.createElement('div'))");
74+
await startedPolling;
5675
await Page.EvaluateFunctionAsync("async () => setTimeout(window.__FOO = 'hit', 50)");
5776
await watchdog;
5877
Assert.True((DateTime.UtcNow - startTime).TotalMilliseconds > polling / 2);
@@ -63,9 +82,11 @@ public async Task ShouldPollOnIntervalAsync()
6382
public async Task ShouldPollOnMutation()
6483
{
6584
var success = false;
85+
var startedPolling = WaitForStartPollingAsync();
6686
var watchdog = Page.WaitForFunctionAsync("() => window.__FOO === 'hit'",
6787
new WaitForFunctionOptions { Polling = WaitForFunctionPollingOption.Mutation })
6888
.ContinueWith(_ => success = true);
89+
await startedPolling;
6990
await Page.EvaluateExpressionAsync("window.__FOO = 'hit'");
7091
Assert.False(success);
7192
await Page.EvaluateExpressionAsync("document.body.appendChild(document.createElement('div'))");
@@ -77,9 +98,11 @@ public async Task ShouldPollOnMutation()
7798
public async Task ShouldPollOnMutationAsync()
7899
{
79100
var success = false;
101+
var startedPolling = WaitForStartPollingAsync();
80102
var watchdog = Page.WaitForFunctionAsync("async () => window.__FOO === 'hit'",
81103
new WaitForFunctionOptions { Polling = WaitForFunctionPollingOption.Mutation })
82104
.ContinueWith(_ => success = true);
105+
await startedPolling;
83106
await Page.EvaluateFunctionAsync("async () => window.__FOO = 'hit'");
84107
Assert.False(success);
85108
await Page.EvaluateExpressionAsync("document.body.appendChild(document.createElement('div'))");
@@ -216,5 +239,22 @@ public async Task ShouldSurviveNavigations()
216239
await Page.EvaluateFunctionAsync("() => window.__done = true");
217240
await watchdog;
218241
}
242+
243+
private Task<bool> WaitForStartPollingAsync()
244+
{
245+
TaskCompletionSource<bool> startedPolling = new TaskCompletionSource<bool>();
246+
247+
// Wait for function will release the execution faster than in node.
248+
// We intercept the poller.start() call to prevent tests from continuing before the polling has started.
249+
_connectionTransportInterceptor.MessageSent += (_, message) =>
250+
{
251+
if (message.Contains("poller => poller.start()"))
252+
{
253+
startedPolling.SetResult(true);
254+
}
255+
};
256+
257+
return startedPolling.Task;
258+
}
219259
}
220-
}
260+
}

lib/PuppeteerSharp/WaitTask.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ await _isolatedWorld.GetPuppeteerUtilAsync().ConfigureAwait(false),
144144
}.Concat(_args).ToArray()).ConfigureAwait(false);
145145
}
146146

147+
// Note that FrameWaitForFunctionTests listen for this particular message to orchestrate the test execution
147148
await _poller.EvaluateFunctionAsync("poller => poller.start()").ConfigureAwait(false);
148149

149150
var success = await _poller.EvaluateFunctionHandleAsync("poller => poller.result()").ConfigureAwait(false);

0 commit comments

Comments
 (0)