Skip to content

Commit 8057843

Browse files
Meir017kblok
authored andcommitted
Support waitUntil option for Page.SetContentAsync (#788)
1 parent 7f07b4e commit 8057843

File tree

12 files changed

+176
-136
lines changed

12 files changed

+176
-136
lines changed

lib/PuppeteerSharp.Tests/PageTests/SetContentTests.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,21 @@ public async Task ShouldWorkWithHtml4Doctype()
4444

4545
Assert.Equal($"{doctype}{ExpectedOutput}", result);
4646
}
47+
48+
[Fact]
49+
public async Task ShouldAwaitResourceToLoad()
50+
{
51+
var imgPath = "/img.png";
52+
var imgResponse = new TaskCompletionSource<bool>();
53+
Server.SetRoute(imgPath, context => imgResponse.Task);
54+
var loaded = false;
55+
var waitTask = Server.WaitForRequest(imgPath);
56+
var contentTask = Page.SetContentAsync($"<img src=\"{TestConstants.ServerUrl + imgPath}\"></img>")
57+
.ContinueWith(_ => loaded = true);
58+
await waitTask;
59+
Assert.False(loaded);
60+
imgResponse.SetResult(true);
61+
await contentTask;
62+
}
4763
}
4864
}

lib/PuppeteerSharp/Browser.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ public Browser(
152152
/// <summary>
153153
/// Dafault wait time in milliseconds. Defaults to 30 seconds.
154154
/// </summary>
155-
public int DefaultWaitForTimeout { get; set; } = 30000;
155+
public int DefaultWaitForTimeout { get; set; } = Puppeteer.DefaultTimeout;
156156

157157
#endregion
158158

lib/PuppeteerSharp/CookieParam.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace PuppeteerSharp
55
/// <summary>
66
/// Cookie data.
77
/// </summary>
8-
/// <seealso cref="Page.SetContentAsync(string)"/>
8+
/// <seealso cref="Page.SetContentAsync(string, NavigationOptions)"/>
99
/// <seealso cref="Page.DeleteCookieAsync(CookieParam[])"/>
1010
/// <seealso cref="Page.GetCookiesAsync(string[])"/>
1111
public class CookieParam

lib/PuppeteerSharp/Frame.cs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -544,21 +544,37 @@ public Task<string> GetContentAsync()
544544
if (document.documentElement)
545545
retVal += document.documentElement.outerHTML;
546546
return retVal;
547-
}");
548-
547+
}");
548+
549549
/// <summary>
550550
/// Sets the HTML markup to the page
551551
/// </summary>
552-
/// <param name="html">HTML markup to assign to the page.</param>
552+
/// <param name="html">HTML markup to assign to the page.</param>
553+
/// <param name="options">The options</param>
553554
/// <returns>Task.</returns>
554-
/// <seealso cref="Page.SetContentAsync(string)"/>
555-
public Task SetContentAsync(string html)
556-
=> EvaluateFunctionAsync(@"html => {
555+
/// <seealso cref="Page.SetContentAsync(string, NavigationOptions)"/>
556+
public async Task SetContentAsync(string html, NavigationOptions options = null)
557+
{
558+
var waitUntil = options?.WaitUntil ?? new[] { WaitUntilNavigation.Load };
559+
var timeout = options?.Timeout ?? Puppeteer.DefaultTimeout;
560+
561+
// We rely upon the fact that document.open() will reset frame lifecycle with "init"
562+
// lifecycle event. @see https://crrev.com/608658
563+
await EvaluateFunctionAsync(@"html => {
557564
document.open();
558565
document.write(html);
559566
document.close();
560-
}", html);
567+
}", html);
568+
569+
var watcher = new LifecycleWatcher(FrameManager, this, timeout, options);
570+
571+
var watcherTask = await Task.WhenAny(
572+
watcher.TimeoutOrTerminationTask,
573+
watcher.LifecycleTask).ConfigureAwait(false);
561574

575+
await watcherTask;
576+
}
577+
562578
/// <summary>
563579
/// Returns page's title
564580
/// </summary>

lib/PuppeteerSharp/FrameManager.cs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,25 @@
1111
namespace PuppeteerSharp
1212
{
1313
internal class FrameManager
14-
{
15-
private readonly CDPSession _client;
14+
{
1615
private Dictionary<int, ExecutionContext> _contextIdToContext;
1716
private bool _ensureNewDocumentNavigation;
18-
private readonly ILogger _logger;
19-
private readonly NetworkManager _networkManager;
17+
private readonly ILogger _logger;
2018
private readonly ConcurrentDictionary<string, Frame> _frames;
2119
private readonly MultiMap<string, TaskCompletionSource<Frame>> _pendingFrameRequests;
2220
private const int WaitForRequestDelay = 1000;
2321

2422
private FrameManager(CDPSession client, Page page, NetworkManager networkManager)
2523
{
26-
_client = client;
24+
Client = client;
2725
Page = page;
2826
_frames = new ConcurrentDictionary<string, Frame>();
2927
_contextIdToContext = new Dictionary<int, ExecutionContext>();
30-
_logger = _client.Connection.LoggerFactory.CreateLogger<FrameManager>();
31-
_networkManager = networkManager;
28+
_logger = Client.Connection.LoggerFactory.CreateLogger<FrameManager>();
29+
NetworkManager = networkManager;
3230
_pendingFrameRequests = new MultiMap<string, TaskCompletionSource<Frame>>();
3331

34-
_client.MessageReceived += Client_MessageReceived;
32+
Client.MessageReceived += Client_MessageReceived;
3533
}
3634

3735
#region Properties
@@ -42,6 +40,8 @@ private FrameManager(CDPSession client, Page page, NetworkManager networkManager
4240
internal event EventHandler<FrameEventArgs> FrameNavigatedWithinDocument;
4341
internal event EventHandler<FrameEventArgs> LifecycleEvent;
4442

43+
internal CDPSession Client { get; }
44+
internal NetworkManager NetworkManager { get; }
4545
internal Frame MainFrame { get; set; }
4646
internal Page Page { get; }
4747
internal int DefaultNavigationTimeout { get; set; } = 30000;
@@ -70,13 +70,13 @@ internal ExecutionContext ExecutionContextById(int contextId)
7070
public async Task<Response> NavigateFrameAsync(Frame frame, string url, NavigationOptions options)
7171
{
7272
var referrer = string.IsNullOrEmpty(options.Referer)
73-
? _networkManager.ExtraHTTPHeaders?.GetValueOrDefault(MessageKeys.Referer)
73+
? NetworkManager.ExtraHTTPHeaders?.GetValueOrDefault(MessageKeys.Referer)
7474
: options.Referer;
7575
var requests = new Dictionary<string, Request>();
7676
var timeout = options?.Timeout ?? DefaultNavigationTimeout;
77-
using (var watcher = new NavigatorWatcher(_client, this, frame, _networkManager, timeout, options))
77+
using (var watcher = new LifecycleWatcher(this, frame, timeout, options))
7878
{
79-
var navigateTask = NavigateAsync(_client, url, referrer, frame.Id);
79+
var navigateTask = NavigateAsync(Client, url, referrer, frame.Id);
8080
await Task.WhenAny(
8181
watcher.TimeoutOrTerminationTask,
8282
navigateTask).ConfigureAwait(false);
@@ -128,7 +128,7 @@ private async Task NavigateAsync(CDPSession client, string url, string referrer,
128128
public async Task<Response> WaitForFrameNavigationAsync(Frame frame, NavigationOptions options = null)
129129
{
130130
var timeout = options?.Timeout ?? DefaultNavigationTimeout;
131-
using (var watcher = new NavigatorWatcher(_client, this, frame, _networkManager, timeout, options))
131+
using (var watcher = new LifecycleWatcher(this, frame, timeout, options))
132132
{
133133
var raceTask = await Task.WhenAny(
134134
watcher.NewDocumentNavigationTask,
@@ -205,7 +205,7 @@ private async void Client_MessageReceived(object sender, MessageEventArgs e)
205205
{
206206
var message = $"Connection failed to process {e.MessageID}. {ex.Message}. {ex.StackTrace}";
207207
_logger.LogError(ex, message);
208-
_client.Close(message);
208+
Client.Close(message);
209209
}
210210
}
211211

@@ -254,7 +254,7 @@ private async Task OnExecutionContextCreatedAsync(ContextPayload contextPayload)
254254
var frame = !string.IsNullOrEmpty(frameId) ? await GetFrameAsync(frameId) : null;
255255

256256
var context = new ExecutionContext(
257-
_client,
257+
Client,
258258
contextPayload,
259259
frame);
260260

@@ -305,7 +305,7 @@ private async Task OnFrameNavigatedAsync(FramePayload framePayload)
305305
else
306306
{
307307
// Initial main frame navigation.
308-
frame = new Frame(this, _client, null, framePayload.Id);
308+
frame = new Frame(this, Client, null, framePayload.Id);
309309
}
310310
AddFrame(framePayload.Id, frame);
311311
MainFrame = frame;
@@ -364,7 +364,7 @@ private void OnFrameAttached(string frameId, string parentFrameId)
364364
if (!_frames.ContainsKey(frameId) && _frames.ContainsKey(parentFrameId))
365365
{
366366
var parentFrame = _frames[parentFrameId];
367-
var frame = new Frame(this, _client, parentFrame, frameId);
367+
var frame = new Frame(this, Client, parentFrame, frameId);
368368
_frames[frame.Id] = frame;
369369
FrameAttached?.Invoke(this, new FrameEventArgs(frame));
370370
}

lib/PuppeteerSharp/LaunchOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public class LaunchOptions : IBrowserOptions, IConnectionOptions
4242
/// <summary>
4343
/// Maximum time in milliseconds to wait for the browser instance to start. Defaults to 30000 (30 seconds). Pass 0 to disable timeout.
4444
/// </summary>
45-
public int Timeout { get; set; } = 30_000;
45+
public int Timeout { get; set; } = Puppeteer.DefaultTimeout;
4646

4747
/// <summary>
4848
/// Whether to pipe browser process stdout and stderr into process.stdout and process.stderr. Defaults to false.

0 commit comments

Comments
 (0)