Skip to content

Commit 6f813bd

Browse files
authored
Abort page.waitForRequest/Response when page closes (#1290)
* Abort page.waitForRequest/Response when page closes * cr * cr
1 parent 04a3722 commit 6f813bd

File tree

3 files changed

+88
-2
lines changed

3 files changed

+88
-2
lines changed

lib/PuppeteerSharp.Tests/PageTests/CloseTests.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,24 @@ public async Task ShouldSetThePageCloseState()
7878
Assert.True(Page.IsClosed);
7979
}
8080

81+
[Fact]
82+
public async Task ShouldTerminateNetworkWaiters()
83+
{
84+
var newPage = await Context.NewPageAsync();
85+
var requestTask = newPage.WaitForRequestAsync(TestConstants.EmptyPage);
86+
var responseTask = newPage.WaitForResponseAsync(TestConstants.EmptyPage);
87+
88+
await newPage.CloseAsync();
89+
90+
var exception = await Assert.ThrowsAsync<TargetClosedException>(() => requestTask);
91+
Assert.Contains("Target closed", exception.Message);
92+
Assert.DoesNotContain("Timeout", exception.Message);
93+
94+
exception = await Assert.ThrowsAsync<TargetClosedException>(() => responseTask);
95+
Assert.Contains("Target closed", exception.Message);
96+
Assert.DoesNotContain("Timeout", exception.Message);
97+
}
98+
8199
[Fact(Timeout = 10000)]
82100
public async Task ShouldCloseWhenConnectionBreaksPrematurely()
83101
{
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Threading.Tasks;
2+
using Xunit;
3+
using Xunit.Abstractions;
4+
5+
namespace PuppeteerSharp.Tests.BrowserTests.Events
6+
{
7+
[Collection(TestConstants.TestFixtureCollectionName)]
8+
public class BrowserCloseTests : PuppeteerBrowserBaseTest
9+
{
10+
public BrowserCloseTests(ITestOutputHelper output) : base(output)
11+
{
12+
}
13+
14+
[Fact]
15+
public async Task ShouldTerminateNetworkWaiters()
16+
{
17+
using (var browser = await Puppeteer.LaunchAsync(TestConstants.DefaultBrowserOptions()))
18+
using (var remote = await Puppeteer.ConnectAsync(new ConnectOptions { BrowserWSEndpoint = browser.WebSocketEndpoint }))
19+
{
20+
var newPage = await remote.NewPageAsync();
21+
var requestTask = newPage.WaitForRequestAsync(TestConstants.EmptyPage);
22+
var responseTask = newPage.WaitForResponseAsync(TestConstants.EmptyPage);
23+
24+
await browser.CloseAsync();
25+
26+
var exception = await Assert.ThrowsAsync<TargetClosedException>(() => requestTask);
27+
Assert.Contains("Target closed", exception.Message);
28+
Assert.DoesNotContain("Timeout", exception.Message);
29+
30+
exception = await Assert.ThrowsAsync<TargetClosedException>(() => responseTask);
31+
Assert.Contains("Target closed", exception.Message);
32+
Assert.DoesNotContain("Timeout", exception.Message);
33+
}
34+
}
35+
}
36+
}

lib/PuppeteerSharp/Page.cs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public class Page : IDisposable
4646
private bool _screenshotBurstModeOn;
4747
private ScreenshotOptions _screenshotBurstModeOptions;
4848
private readonly TaskCompletionSource<bool> _closeCompletedTcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
49+
private TaskCompletionSource<bool> _sessionClosedTcs;
4950
private readonly TimeoutSettings _timeoutSettings;
5051
private bool _fileChooserInterceptionIsDisabled;
5152
private ConcurrentDictionary<Guid, TaskCompletionSource<FileChooser>> _fileChooserInterceptors;
@@ -347,6 +348,25 @@ public int DefaultTimeout
347348
internal bool HasPopupEventListeners => Popup?.GetInvocationList().Any() == true;
348349
internal FrameManager FrameManager { get; private set; }
349350

351+
private Task SessionClosedTask
352+
{
353+
get
354+
{
355+
if (_sessionClosedTcs == null)
356+
{
357+
_sessionClosedTcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
358+
Client.Disconnected += clientDisconnected;
359+
360+
void clientDisconnected(object sender, EventArgs e)
361+
{
362+
_sessionClosedTcs.TrySetException(new TargetClosedException("Target closed", "Session closed"));
363+
Client.Disconnected -= clientDisconnected;
364+
}
365+
}
366+
367+
return _sessionClosedTcs.Task;
368+
}
369+
}
350370
#endregion
351371

352372
#region Public Methods
@@ -1520,11 +1540,17 @@ void requestEventListener(object sender, RequestEventArgs e)
15201540

15211541
FrameManager.NetworkManager.Request += requestEventListener;
15221542

1523-
return await requestTcs.Task.WithTimeout(timeout, t =>
1543+
await Task.WhenAny(requestTcs.Task, SessionClosedTask).WithTimeout(timeout, t =>
15241544
{
15251545
FrameManager.NetworkManager.Request -= requestEventListener;
15261546
return new TimeoutException($"Timeout Exceeded: {t.TotalMilliseconds}ms exceeded");
15271547
}).ConfigureAwait(false);
1548+
1549+
if (SessionClosedTask.IsFaulted)
1550+
{
1551+
await SessionClosedTask;
1552+
}
1553+
return await requestTcs.Task;
15281554
}
15291555

15301556
/// <summary>
@@ -1574,7 +1600,13 @@ void responseEventListener(object sender, ResponseCreatedEventArgs e)
15741600

15751601
FrameManager.NetworkManager.Response += responseEventListener;
15761602

1577-
return await responseTcs.Task.WithTimeout(timeout).ConfigureAwait(false);
1603+
await Task.WhenAny(responseTcs.Task, SessionClosedTask).WithTimeout(timeout).ConfigureAwait(false);
1604+
1605+
if (SessionClosedTask.IsFaulted)
1606+
{
1607+
await SessionClosedTask;
1608+
}
1609+
return await responseTcs.Task;
15781610
}
15791611

15801612
/// <summary>

0 commit comments

Comments
 (0)