Skip to content

Commit

Permalink
Improve FrameWaitForXPathTests tests (hardkoded#2235)
Browse files Browse the repository at this point in the history
  • Loading branch information
kblok committed Jun 13, 2023
1 parent 6ecce37 commit a5ae465
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

namespace PuppeteerSharp.Tests
{
public sealed class ConnectionTransportInterceptor : IConnectionTransport
public sealed class PollerInterceptor : IConnectionTransport
{
private readonly IConnectionTransport _connectionTransport;

public ConnectionTransportInterceptor(IConnectionTransport connectionTransport)
public PollerInterceptor(IConnectionTransport connectionTransport)
{
_connectionTransport = connectionTransport;
}
Expand Down Expand Up @@ -39,5 +39,22 @@ public Task SendAsync(string message)
public void Dispose() => _connectionTransport.Dispose();

public void StopReading() => _connectionTransport.StopReading();

public Task<bool> WaitForStartPollingAsync()
{
var startedPolling = new TaskCompletionSource<bool>();

// Wait for function will release the execution faster than in node.
// We intercept the poller.start() call to prevent tests from continuing before the polling has started.
MessageSent += (_, message) =>
{
if (message.Contains("poller => poller.start()"))
{
startedPolling.SetResult(true);
}
};

return startedPolling.Task;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace PuppeteerSharp.Tests.WaitTaskTests
[Collection(TestConstants.TestFixtureCollectionName)]
public sealed class FrameWaitForFunctionTests : PuppeteerPageBaseTest, IDisposable
{
private ConnectionTransportInterceptor _connectionTransportInterceptor;
private PollerInterceptor _pollerInterceptor;

public FrameWaitForFunctionTests(ITestOutputHelper output) : base(output)
{
Expand All @@ -25,14 +25,14 @@ public FrameWaitForFunctionTests(ITestOutputHelper output) : base(output)
// due to differences between node.js's task scheduler and .net's.
DefaultOptions.TransportFactory = async (url, options, cancellationToken) =>
{
_connectionTransportInterceptor = new ConnectionTransportInterceptor(await WebSocketTransport.DefaultTransportFactory(url, options, cancellationToken));
return _connectionTransportInterceptor;
_pollerInterceptor = new PollerInterceptor(await WebSocketTransport.DefaultTransportFactory(url, options, cancellationToken));
return _pollerInterceptor;
};
}

public void Dispose()
{
_connectionTransportInterceptor.Dispose();
_pollerInterceptor.Dispose();
}

[PuppeteerTest("waittask.spec.ts", "Frame.waitForFunction", "should work when resolved right before execution context disposal")]
Expand All @@ -54,7 +54,7 @@ public async Task ShouldPollOnInterval()
{
var startTime = DateTime.UtcNow;
var polling = 100;
var startedPolling = WaitForStartPollingAsync();
var startedPolling = _pollerInterceptor.WaitForStartPollingAsync();
var watchdog = Page.WaitForFunctionAsync("() => window.__FOO === 'hit'", new WaitForFunctionOptions { PollingInterval = polling });
await startedPolling;
await Page.EvaluateFunctionAsync("() => setTimeout(window.__FOO = 'hit', 50)");
Expand All @@ -69,7 +69,7 @@ public async Task ShouldPollOnIntervalAsync()
{
var startTime = DateTime.UtcNow;
var polling = 1000;
var startedPolling = WaitForStartPollingAsync();
var startedPolling = _pollerInterceptor.WaitForStartPollingAsync();
var watchdog = Page.WaitForFunctionAsync("async () => window.__FOO === 'hit'", new WaitForFunctionOptions { PollingInterval = polling });
await startedPolling;
await Page.EvaluateFunctionAsync("async () => setTimeout(window.__FOO = 'hit', 50)");
Expand All @@ -82,7 +82,7 @@ public async Task ShouldPollOnIntervalAsync()
public async Task ShouldPollOnMutation()
{
var success = false;
var startedPolling = WaitForStartPollingAsync();
var startedPolling = _pollerInterceptor.WaitForStartPollingAsync();
var watchdog = Page.WaitForFunctionAsync("() => window.__FOO === 'hit'",
new WaitForFunctionOptions { Polling = WaitForFunctionPollingOption.Mutation })
.ContinueWith(_ => success = true);
Expand All @@ -98,7 +98,7 @@ public async Task ShouldPollOnMutation()
public async Task ShouldPollOnMutationAsync()
{
var success = false;
var startedPolling = WaitForStartPollingAsync();
var startedPolling = _pollerInterceptor.WaitForStartPollingAsync();
var watchdog = Page.WaitForFunctionAsync("async () => window.__FOO === 'hit'",
new WaitForFunctionOptions { Polling = WaitForFunctionPollingOption.Mutation })
.ContinueWith(_ => success = true);
Expand Down Expand Up @@ -239,22 +239,5 @@ public async Task ShouldSurviveNavigations()
await Page.EvaluateFunctionAsync("() => window.__done = true");
await watchdog;
}

private Task<bool> WaitForStartPollingAsync()
{
TaskCompletionSource<bool> startedPolling = new TaskCompletionSource<bool>();

// Wait for function will release the execution faster than in node.
// We intercept the poller.start() call to prevent tests from continuing before the polling has started.
_connectionTransportInterceptor.MessageSent += (_, message) =>
{
if (message.Contains("poller => poller.start()"))
{
startedPolling.SetResult(true);
}
};

return startedPolling.Task;
}
}
}
31 changes: 26 additions & 5 deletions lib/PuppeteerSharp.Tests/WaitTaskTests/FrameWaitForXPathTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,36 @@
using PuppeteerSharp.Helpers;
using PuppeteerSharp.Xunit;
using PuppeteerSharp.Tests.Attributes;
using PuppeteerSharp.Transport;

namespace PuppeteerSharp.Tests.WaitTaskTests
{
[Collection(TestConstants.TestFixtureCollectionName)]
public class FrameWaitForXPathTests : PuppeteerPageBaseTest
public sealed class FrameWaitForXPathTests : PuppeteerPageBaseTest, IDisposable
{
const string addElement = "tag => document.body.appendChild(document.createElement(tag))";
const string AddElement = "tag => document.body.appendChild(document.createElement(tag))";
private PollerInterceptor _pollerInterceptor;

public FrameWaitForXPathTests(ITestOutputHelper output) : base(output)
{
DefaultOptions = TestConstants.DefaultBrowserOptions();

// Set up a custom TransportFactory to intercept sent messages
// Some of the tests require making assertions after a WaitForFunction has
// started, but before it has resolved. We detect that reliably by
// listening to the message that is sent to start polling.
// This might not be an issue in upstream puppeteer.js, or may be highly unlikely,
// due to differences between node.js's task scheduler and .net's.
DefaultOptions.TransportFactory = async (url, options, cancellationToken) =>
{
_pollerInterceptor = new PollerInterceptor(await WebSocketTransport.DefaultTransportFactory(url, options, cancellationToken));
return _pollerInterceptor;
};
}

public void Dispose()
{
_pollerInterceptor.Dispose();
}

[PuppeteerTest("waittask.spec.ts", "Frame.waitForXPath", "should support some fancy xpath")]
Expand All @@ -37,8 +57,8 @@ public async Task ShouldRunInSpecifiedFrame()
var frame1 = Page.Frames.First(f => f.Name == "frame1");
var frame2 = Page.Frames.First(f => f.Name == "frame2");
var waitForXPathPromise = frame2.WaitForXPathAsync("//div");
await frame1.EvaluateFunctionAsync(addElement, "div");
await frame2.EvaluateFunctionAsync(addElement, "div");
await frame1.EvaluateFunctionAsync(AddElement, "div");
await frame2.EvaluateFunctionAsync(AddElement, "div");
var eHandle = await waitForXPathPromise;
Assert.Equal(frame2, eHandle.ExecutionContext.Frame);
}
Expand All @@ -60,10 +80,11 @@ public async Task ShouldThrowWhenFrameIsDetached()
public async Task HiddenShouldWaitForDisplayNone()
{
var divHidden = false;
var startedPolling = _pollerInterceptor.WaitForStartPollingAsync();
await Page.SetContentAsync("<div style='display: block;'></div>");
var waitForXPath = Page.WaitForXPathAsync("//div", new WaitForSelectorOptions { Hidden = true })
.ContinueWith(_ => divHidden = true);
await Page.WaitForXPathAsync("//div"); // do a round trip
await startedPolling;
Assert.False(divHidden);
await Page.EvaluateExpressionAsync("document.querySelector('div').style.setProperty('display', 'none')");
Assert.True(await waitForXPath.WithTimeout());
Expand Down

0 comments on commit a5ae465

Please sign in to comment.