Skip to content

Commit 2e59b1e

Browse files
authored
Introduce Page.SetDefaultTimeout (#938)
* Some progress * Feature complete * Tests fixes * CodeFactor
1 parent ae2233f commit 2e59b1e

File tree

13 files changed

+201
-36
lines changed

13 files changed

+201
-36
lines changed

lib/PuppeteerSharp.Tests/FrameTests/WaitForFunctionTests.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,11 @@ public async Task ShouldThrowNegativePollingInterval()
8585

8686
[Fact]
8787
public async Task ShouldReturnTheSuccessValueAsAJSHandle()
88-
{
89-
Assert.Equal(5, await (await Page.WaitForFunctionAsync("() => 5")).JsonValueAsync<int>());
90-
}
88+
=> Assert.Equal(5, await (await Page.WaitForFunctionAsync("() => 5")).JsonValueAsync<int>());
9189

9290
[Fact]
9391
public async Task ShouldReturnTheWindowAsASuccessValue()
94-
{
95-
Assert.NotNull(await Page.WaitForFunctionAsync("() => window"));
96-
}
92+
=> Assert.NotNull(await Page.WaitForFunctionAsync("() => window"));
9793

9894
[Fact]
9995
public async Task ShouldAcceptElementHandleArguments()
@@ -117,6 +113,16 @@ public async Task ShouldRespectTimeout()
117113
Assert.Contains("waiting for function failed: timeout", exception.Message);
118114
}
119115

116+
[Fact]
117+
public async Task ShouldRespectDefaultTimeout()
118+
{
119+
Page.DefaultTimeout = 1;
120+
var exception = await Assert.ThrowsAsync<WaitTaskTimeoutException>(()
121+
=> Page.WaitForExpressionAsync("false"));
122+
123+
Assert.Contains("waiting for function failed: timeout", exception.Message);
124+
}
125+
120126
[Fact]
121127
public async Task ShouldDisableTimeoutWhenItsSetTo0()
122128
{

lib/PuppeteerSharp.Tests/PageTests/GotoTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,27 @@ public async Task ShouldFailWhenExceedingDefaultMaximumNavigationTimeout()
139139
Assert.Contains("Timeout Exceeded: 1ms", exception.Message);
140140
}
141141

142+
[Fact]
143+
public async Task ShouldFailWhenExceedingDefaultMaximumTimeout()
144+
{
145+
// Hang for request to the empty.html
146+
Server.SetRoute("/empty.html", context => Task.Delay(-1));
147+
Page.DefaultTimeout = 1;
148+
var exception = await Assert.ThrowsAnyAsync<Exception>(async () => await Page.GoToAsync(TestConstants.EmptyPage));
149+
Assert.Contains("Timeout Exceeded: 1ms", exception.Message);
150+
}
151+
152+
[Fact]
153+
public async Task ShouldPrioritizeDefaultNavigationTimeoutOverDefaultTimeout()
154+
{
155+
// Hang for request to the empty.html
156+
Server.SetRoute("/empty.html", context => Task.Delay(-1));
157+
Page.DefaultTimeout = 0;
158+
Page.DefaultNavigationTimeout = 1;
159+
var exception = await Assert.ThrowsAnyAsync<Exception>(async () => await Page.GoToAsync(TestConstants.EmptyPage));
160+
Assert.Contains("Timeout Exceeded: 1ms", exception.Message);
161+
}
162+
142163
[Fact]
143164
public async Task ShouldDisableTimeoutWhenItsSetTo0()
144165
{

lib/PuppeteerSharp.Tests/PageTests/SetContentTests.cs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Threading.Tasks;
1+
using System;
2+
using System.Threading.Tasks;
23
using Xunit;
34
using Xunit.Abstractions;
45

@@ -45,6 +46,36 @@ public async Task ShouldWorkWithHtml4Doctype()
4546
Assert.Equal($"{doctype}{ExpectedOutput}", result);
4647
}
4748

49+
[Fact]
50+
public async Task ShouldRespectTimeout()
51+
{
52+
const string imgPath = "/img.png";
53+
Server.SetRoute(imgPath, context => Task.Delay(-1));
54+
55+
await Page.GoToAsync(TestConstants.EmptyPage);
56+
var exception = await Assert.ThrowsAnyAsync<TimeoutException>(async () =>
57+
await Page.SetContentAsync($"<img src='{TestConstants.ServerUrl + imgPath}'></img>", new NavigationOptions
58+
{
59+
Timeout = 1
60+
}));
61+
62+
Assert.Contains("Timeout Exceeded: 1ms", exception.Message);
63+
}
64+
65+
[Fact]
66+
public async Task ShouldRespectDefaultTimeout()
67+
{
68+
const string imgPath = "/img.png";
69+
Server.SetRoute(imgPath, context => Task.Delay(-1));
70+
71+
await Page.GoToAsync(TestConstants.EmptyPage);
72+
Page.DefaultTimeout = 1;
73+
var exception = await Assert.ThrowsAnyAsync<TimeoutException>(async () =>
74+
await Page.SetContentAsync($"<img src='{TestConstants.ServerUrl + imgPath}'></img>"));
75+
76+
Assert.Contains("Timeout Exceeded: 1ms", exception.Message);
77+
}
78+
4879
[Fact]
4980
public async Task ShouldAwaitResourcesToLoad()
5081
{

lib/PuppeteerSharp.Tests/PageTests/WaitForRequestTests.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Net;
1+
using System;
2+
using System.Net;
23
using System.Threading.Tasks;
34
using Xunit;
45
using Xunit.Abstractions;
@@ -46,6 +47,30 @@ await Task.WhenAll(
4647
Assert.Equal(TestConstants.ServerUrl + "/digits/2.png", task.Result.Url);
4748
}
4849

50+
[Fact]
51+
public async Task ShouldRespectTimeout()
52+
{
53+
await Page.GoToAsync(TestConstants.EmptyPage);
54+
var exception = await Assert.ThrowsAnyAsync<TimeoutException>(async () =>
55+
await Page.WaitForRequestAsync(request => false, new WaitForOptions
56+
{
57+
Timeout = 1
58+
}));
59+
60+
Assert.Contains("Timeout Exceeded: 1ms", exception.Message);
61+
}
62+
63+
[Fact]
64+
public async Task ShouldRespectDefaultTimeout()
65+
{
66+
await Page.GoToAsync(TestConstants.EmptyPage);
67+
Page.DefaultTimeout = 1;
68+
var exception = await Assert.ThrowsAnyAsync<TimeoutException>(async () =>
69+
await Page.WaitForRequestAsync(request => false));
70+
71+
Assert.Contains("Timeout Exceeded: 1ms", exception.Message);
72+
}
73+
4974
[Fact]
5075
public async Task ShouldWorkWithNoTimeout()
5176
{

lib/PuppeteerSharp.Tests/PageTests/WaitForResponseTests.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Net;
1+
using System;
2+
using System.Net;
23
using System.Threading.Tasks;
34
using Xunit;
45
using Xunit.Abstractions;
@@ -46,6 +47,30 @@ await Task.WhenAll(
4647
Assert.Equal(TestConstants.ServerUrl + "/digits/2.png", task.Result.Url);
4748
}
4849

50+
[Fact]
51+
public async Task ShouldRespectTimeout()
52+
{
53+
await Page.GoToAsync(TestConstants.EmptyPage);
54+
var exception = await Assert.ThrowsAnyAsync<TimeoutException>(async () =>
55+
await Page.WaitForResponseAsync(request => false, new WaitForOptions
56+
{
57+
Timeout = 1
58+
}));
59+
60+
Assert.Contains("Timeout Exceeded: 1ms", exception.Message);
61+
}
62+
63+
[Fact]
64+
public async Task ShouldRespectDefaultTimeout()
65+
{
66+
await Page.GoToAsync(TestConstants.EmptyPage);
67+
Page.DefaultTimeout = 1;
68+
var exception = await Assert.ThrowsAnyAsync<TimeoutException>(async () =>
69+
await Page.WaitForResponseAsync(request => false));
70+
71+
Assert.Contains("Timeout Exceeded: 1ms", exception.Message);
72+
}
73+
4974
[Fact]
5075
public async Task ShouldWorkWithNoTimeout()
5176
{

lib/PuppeteerSharp/DOMWorld.cs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,19 @@ namespace PuppeteerSharp
1010
internal class DOMWorld
1111
{
1212
private readonly FrameManager _frameManager;
13+
private readonly TimeoutSettings _timeoutSettings;
1314
private bool _detached;
1415
private TaskCompletionSource<ExecutionContext> _contextResolveTaskWrapper;
1516
private TaskCompletionSource<ElementHandle> _documentCompletionSource;
1617

1718
internal List<WaitTask> WaitTasks;
1819
internal Frame Frame { get; }
1920

20-
public DOMWorld(FrameManager frameManager, Frame frame)
21+
public DOMWorld(FrameManager frameManager, Frame frame, TimeoutSettings timeoutSettings)
2122
{
2223
_frameManager = frameManager;
2324
Frame = frame;
25+
_timeoutSettings = timeoutSettings;
2426

2527
SetContext(null);
2628

@@ -130,7 +132,7 @@ internal Task<string> GetContentAsync() => EvaluateFunctionAsync<string>(@"() =>
130132
internal async Task SetContentAsync(string html, NavigationOptions options = null)
131133
{
132134
var waitUntil = options?.WaitUntil ?? new[] { WaitUntilNavigation.Load };
133-
var timeout = options?.Timeout ?? Puppeteer.DefaultTimeout;
135+
var timeout = options?.Timeout ?? _timeoutSettings.NavigationTimeout;
134136

135137
// We rely upon the fact that document.open() will reset frame lifecycle with "init"
136138
// lifecycle event. @see https://crrev.com/608658
@@ -348,10 +350,25 @@ internal Task<ElementHandle> WaitForXPathAsync(string xpath, WaitForSelectorOpti
348350
=> WaitForSelectorOrXPathAsync(xpath, true, options);
349351

350352
internal Task<JSHandle> WaitForFunctionAsync(string script, WaitForFunctionOptions options, params object[] args)
351-
=> new WaitTask(this, script, false, "function", options.Polling, options.PollingInterval, options.Timeout, args).Task;
353+
=> new WaitTask(
354+
this,
355+
script,
356+
false,
357+
"function",
358+
options.Polling,
359+
options.PollingInterval,
360+
options.Timeout ?? _timeoutSettings.Timeout,
361+
args).Task;
352362

353363
internal Task<JSHandle> WaitForExpressionAsync(string script, WaitForFunctionOptions options)
354-
=> new WaitTask(this, script, true, "function", options.Polling, options.PollingInterval, options.Timeout).Task;
364+
=> new WaitTask(
365+
this,
366+
script,
367+
true,
368+
"function",
369+
options.Polling,
370+
options.PollingInterval,
371+
options.Timeout ?? _timeoutSettings.Timeout).Task;
355372

356373
internal Task<string> GetTitleAsync() => EvaluateExpressionAsync<string>("document.title");
357374

lib/PuppeteerSharp/Frame.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ internal Frame(FrameManager frameManager, CDPSession client, Frame parentFrame,
6363
WaitTasks = new List<WaitTask>();
6464
LifecycleEvents = new List<string>();
6565

66-
MainWorld = new DOMWorld(FrameManager, this);
67-
SecondaryWorld = new DOMWorld(FrameManager, this);
66+
MainWorld = new DOMWorld(FrameManager, this, FrameManager.TimeoutSettings);
67+
SecondaryWorld = new DOMWorld(FrameManager, this, FrameManager.TimeoutSettings);
6868
}
6969

7070
#region Properties

lib/PuppeteerSharp/FrameManager.cs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@ internal class FrameManager
2020
private const string RefererHeaderName = "referer";
2121
private readonly AsyncDictionaryHelper<string, Frame> _asyncFrames;
2222
private readonly List<string> _isolatedWorlds = new List<string>();
23-
2423
private const string UtilityWorldName = "__puppeteer_utility_world__";
2524

26-
private FrameManager(CDPSession client, Page page, NetworkManager networkManager)
25+
private FrameManager(CDPSession client, Page page, NetworkManager networkManager, TimeoutSettings timeoutSettings)
2726
{
2827
Client = client;
2928
Page = page;
3029
_frames = new ConcurrentDictionary<string, Frame>();
3130
_contextIdToContext = new Dictionary<int, ExecutionContext>();
3231
_logger = Client.Connection.LoggerFactory.CreateLogger<FrameManager>();
3332
NetworkManager = networkManager;
33+
TimeoutSettings = timeoutSettings;
3434
_asyncFrames = new AsyncDictionaryHelper<string, Frame>(_frames, "Frame {0} not found");
3535

3636
Client.MessageReceived += Client_MessageReceived;
@@ -48,14 +48,18 @@ private FrameManager(CDPSession client, Page page, NetworkManager networkManager
4848
internal NetworkManager NetworkManager { get; }
4949
internal Frame MainFrame { get; set; }
5050
internal Page Page { get; }
51-
internal int DefaultNavigationTimeout { get; set; } = 30000;
52-
51+
internal TimeoutSettings TimeoutSettings { get; }
5352
#endregion
5453

5554
#region Public Methods
56-
internal static async Task<FrameManager> CreateFrameManagerAsync(CDPSession client, Page page, NetworkManager networkManager, FrameTree frameTree)
55+
internal static async Task<FrameManager> CreateFrameManagerAsync(
56+
CDPSession client,
57+
Page page,
58+
NetworkManager networkManager,
59+
FrameTree frameTree,
60+
TimeoutSettings timeoutSettings)
5761
{
58-
var frameManager = new FrameManager(client, page, networkManager);
62+
var frameManager = new FrameManager(client, page, networkManager, timeoutSettings);
5963
await frameManager.HandleFrameTreeAsync(frameTree).ConfigureAwait(false);
6064
return frameManager;
6165
}
@@ -77,7 +81,7 @@ public async Task<Response> NavigateFrameAsync(Frame frame, string url, Navigati
7781
? NetworkManager.ExtraHTTPHeaders?.GetValueOrDefault(RefererHeaderName)
7882
: options.Referer;
7983
var requests = new Dictionary<string, Request>();
80-
var timeout = options?.Timeout ?? DefaultNavigationTimeout;
84+
var timeout = options?.Timeout ?? TimeoutSettings.NavigationTimeout;
8185

8286
using (var watcher = new LifecycleWatcher(this, frame, options?.WaitUntil, timeout))
8387
{
@@ -125,7 +129,7 @@ private async Task NavigateAsync(CDPSession client, string url, string referrer,
125129

126130
public async Task<Response> WaitForFrameNavigationAsync(Frame frame, NavigationOptions options = null)
127131
{
128-
var timeout = options?.Timeout ?? DefaultNavigationTimeout;
132+
var timeout = options?.Timeout ?? TimeoutSettings.NavigationTimeout;
129133
using (var watcher = new LifecycleWatcher(this, frame, options?.WaitUntil, timeout))
130134
{
131135
var raceTask = await Task.WhenAny(

lib/PuppeteerSharp/NavigationOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public class NavigationOptions
99
/// Maximum navigation time in milliseconds, defaults to 30 seconds, pass <c>0</c> to disable timeout.
1010
/// </summary>
1111
/// <remarks>
12-
/// The default value can be changed by setting the <see cref="Page.DefaultNavigationTimeout"/> property.
12+
/// The default value can be changed by setting the <see cref="Page.DefaultNavigationTimeout"/> or <see cref="Page.DefaultTimeout"/> property.
1313
/// </remarks>
1414
public int? Timeout { get; set; }
1515

0 commit comments

Comments
 (0)