Skip to content

Commit 53e9640

Browse files
Meir017kblok
authored andcommitted
Implement Page.goto tests (#110)
1 parent 161c0f4 commit 53e9640

File tree

10 files changed

+315
-49
lines changed

10 files changed

+315
-49
lines changed

lib/PuppeteerSharp.TestServer/SimpleServer.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ public async Task<T> WaitForRequest<T>(string path, Func<HttpRequest, T> selecto
119119
return request;
120120
}
121121

122+
public Task WaitForRequest(string path) => WaitForRequest<bool>(path, request => true);
123+
122124
private static bool Authenticate(string username, string password, HttpContext context)
123125
{
124126
string authHeader = context.Request.Headers["Authorization"];
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
using Microsoft.AspNetCore.Http;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Net;
5+
using System.Threading.Tasks;
6+
using Xunit;
7+
8+
namespace PuppeteerSharp.Tests.Page
9+
{
10+
[Collection("PuppeteerLoaderFixture collection")]
11+
public class GotoTests : PuppeteerPageBaseTest
12+
{
13+
[Fact]
14+
public async Task ShouldNavigateToAboutBlank()
15+
{
16+
var response = await Page.GoToAsync(TestConstants.AboutBlank);
17+
Assert.Null(response);
18+
}
19+
20+
[Theory]
21+
[InlineData(WaitUntilNavigation.DOMContentLoaded)]
22+
[InlineData(WaitUntilNavigation.Networkidle0)]
23+
[InlineData(WaitUntilNavigation.Networkidle2)]
24+
public async Task ShouldNavigateToEmptyPage(WaitUntilNavigation waitUntil)
25+
{
26+
var response = await Page.GoToAsync(TestConstants.EmptyPage, new NavigationOptions { WaitUntil = new[] { waitUntil } });
27+
Assert.Equal(HttpStatusCode.OK, response.Status);
28+
}
29+
30+
[Fact]
31+
public async Task ShouldFailWhenNavigatingToBadUrl()
32+
{
33+
var exception = await Assert.ThrowsAnyAsync<Exception>(async () => await Page.GoToAsync("asdfasdf"));
34+
Assert.Contains("Cannot navigate to invalid URL", exception.Message);
35+
}
36+
37+
[Fact(Skip = "message is ERR_CERT_COMMON_NAME_INVALID instead of ERR_CERT_AUTHORITY_INVALID")]
38+
public async Task ShouldFailWhenNavigatingToBadSSL()
39+
{
40+
Page.RequestCreated += (sender, e) => Assert.NotNull(e.Request);
41+
Page.RequestFinished += (sender, e) => Assert.NotNull(e.Request);
42+
Page.RequestFailed += (sender, e) => Assert.NotNull(e.Request);
43+
44+
var exception = await Assert.ThrowsAnyAsync<Exception>(async () => await Page.GoToAsync(TestConstants.HttpsPrefix + "/empty.html"));
45+
Assert.Contains("net::ERR_CERT_AUTHORITY_INVALID", exception.Message);
46+
}
47+
48+
[Fact(Skip = "message is ERR_CERT_COMMON_NAME_INVALID instead of ERR_CERT_AUTHORITY_INVALID")]
49+
public async Task ShouldFailWhenNavigatingToBadSSLAfterRedirects()
50+
{
51+
var exception = await Assert.ThrowsAnyAsync<Exception>(async () => await Page.GoToAsync(TestConstants.HttpsPrefix + "/redirect/2.html"));
52+
Assert.Contains("net::ERR_CERT_AUTHORITY_INVALID", exception.Message);
53+
}
54+
55+
[Fact]
56+
public async Task ShouldFailWhenMainResourcesFailedToLoad()
57+
{
58+
var exception = await Assert.ThrowsAnyAsync<Exception>(async () => await Page.GoToAsync("http://localhost:44123/non-existing-url"));
59+
Assert.Contains("net::ERR_CONNECTION_REFUSED", exception.Message);
60+
}
61+
62+
[Fact]
63+
public async Task ShouldFailWhenExceedingMaximumNavigationTimeout()
64+
{
65+
Server.SetRoute("/empty.html", context => Task.Delay(-1));
66+
67+
var exception = await Assert.ThrowsAnyAsync<Exception>(async ()
68+
=> await Page.GoToAsync(TestConstants.EmptyPage, new NavigationOptions { Timeout = 1 }));
69+
Assert.Contains("Navigation Timeout Exceeded: 1ms", exception.Message);
70+
}
71+
72+
[Fact]
73+
public async Task ShouldFailWhenExceedingDefaultMaximumNavigationTimeout()
74+
{
75+
Server.SetRoute("/empty.html", context => Task.Delay(-1));
76+
77+
Page.DefaultNavigationTimeout = 1;
78+
var exception = await Assert.ThrowsAnyAsync<Exception>(async () => await Page.GoToAsync(TestConstants.EmptyPage));
79+
Assert.Contains("Navigation Timeout Exceeded: 1ms", exception.Message);
80+
}
81+
82+
[Fact]
83+
public async Task ShouldDisableTimeoutWhenItsSetTo0()
84+
{
85+
var loaded = false;
86+
void OnLoad(object sender, EventArgs e)
87+
{
88+
loaded = true;
89+
Page.Load -= OnLoad;
90+
}
91+
Page.Load += OnLoad;
92+
93+
await Page.GoToAsync(TestConstants.ServerUrl + "/grid.html", new NavigationOptions { Timeout = 0, WaitUntil = new[] { WaitUntilNavigation.Load } });
94+
Assert.True(loaded);
95+
}
96+
97+
[Fact]
98+
public async Task ShouldWorkWhenNavigatingToValidUrl()
99+
{
100+
var response = await Page.GoToAsync(TestConstants.EmptyPage);
101+
Assert.Equal(HttpStatusCode.OK, response.Status);
102+
}
103+
104+
[Fact]
105+
public async Task ShouldWorkWhenNavigatingToDataUrl()
106+
{
107+
var response = await Page.GoToAsync("data:text/html,hello");
108+
Assert.Equal(HttpStatusCode.OK, response.Status);
109+
}
110+
111+
[Fact]
112+
public async Task ShouldWorkWhenNavigatingTo404()
113+
{
114+
var response = await Page.GoToAsync(TestConstants.ServerUrl + "/not-found");
115+
Assert.Equal(HttpStatusCode.NotFound, response.Status);
116+
}
117+
118+
[Fact]
119+
public async Task ShouldReturnLastResponseInRedirectChain()
120+
{
121+
Server.SetRedirect("/redirect/1.html", "/redirect/2.html");
122+
Server.SetRedirect("/redirect/2.html", "/redirect/3.html");
123+
Server.SetRedirect("/redirect/3.html", TestConstants.EmptyPage);
124+
125+
var response = await Page.GoToAsync(TestConstants.ServerUrl + "/redirect/1.html");
126+
Assert.Equal(HttpStatusCode.OK, response.Status);
127+
Assert.Equal(TestConstants.EmptyPage, response.Url);
128+
}
129+
130+
[Fact]
131+
public async Task ShouldWaitForNetworkIdleToSucceedNavigation()
132+
{
133+
var responses = new List<TaskCompletionSource<Func<HttpResponse, Task>>>();
134+
var fetches = new Dictionary<string, TaskCompletionSource<bool>>();
135+
foreach (var url in new[] {
136+
"/fetch-request-a.js",
137+
"/fetch-request-b.js",
138+
"/fetch-request-c.js",
139+
"/fetch-request-d.js" })
140+
{
141+
fetches[url] = new TaskCompletionSource<bool>();
142+
Server.SetRoute(url, async context =>
143+
{
144+
var taskCompletion = new TaskCompletionSource<Func<HttpResponse, Task>>();
145+
responses.Add(taskCompletion);
146+
fetches[context.Request.Path].SetResult(true);
147+
var actionResponse = await taskCompletion.Task;
148+
await actionResponse(context.Response);
149+
});
150+
}
151+
152+
var initialFetchResourcesRequested = Task.WhenAll(
153+
Server.WaitForRequest("/fetch-request-a.js"),
154+
Server.WaitForRequest("/fetch-request-b.js"),
155+
Server.WaitForRequest("/fetch-request-c.js")
156+
);
157+
var secondFetchResourceRequested = Server.WaitForRequest("/fetch-request-d.js");
158+
159+
var navigationFinished = false;
160+
var navigationTask = Page.GoToAsync(TestConstants.ServerUrl + "/networkidle.html",
161+
new NavigationOptions { WaitUntil = new[] { WaitUntilNavigation.Networkidle0 } })
162+
.ContinueWith(res =>
163+
{
164+
navigationFinished = true;
165+
return res.Result;
166+
});
167+
168+
var pageLoaded = new TaskCompletionSource<bool>();
169+
void WaitPageLoad(object sender, EventArgs e)
170+
{
171+
pageLoaded.SetResult(true);
172+
Page.Load -= WaitPageLoad;
173+
}
174+
Page.Load += WaitPageLoad;
175+
await pageLoaded.Task;
176+
177+
Assert.False(navigationFinished);
178+
179+
await initialFetchResourcesRequested;
180+
181+
Assert.False(navigationFinished);
182+
183+
await Task.WhenAll(
184+
fetches["/fetch-request-a.js"].Task,
185+
fetches["/fetch-request-b.js"].Task,
186+
fetches["/fetch-request-c.js"].Task);
187+
188+
foreach (var actionResponse in responses)
189+
{
190+
actionResponse.SetResult(response =>
191+
{
192+
response.StatusCode = 404;
193+
return response.WriteAsync("File not found");
194+
});
195+
}
196+
197+
responses.Clear();
198+
199+
await secondFetchResourceRequested;
200+
201+
Assert.False(navigationFinished);
202+
203+
await fetches["/fetch-request-d.js"].Task;
204+
205+
foreach (var actionResponse in responses)
206+
{
207+
actionResponse.SetResult(response =>
208+
{
209+
response.StatusCode = 404;
210+
return response.WriteAsync("File not found");
211+
});
212+
}
213+
214+
var navigationResponse = await navigationTask;
215+
Assert.Equal(HttpStatusCode.OK, navigationResponse.Status);
216+
}
217+
218+
[Fact]
219+
public async Task ShouldNavigateToDataURLAndFireDataURLRequests()
220+
{
221+
var requests = new List<Request>();
222+
Page.RequestCreated += (sender, e) => requests.Add(e.Request);
223+
var dataUrl = "data:text/html,<div>yo</div>";
224+
var response = await Page.GoToAsync(dataUrl);
225+
Assert.Equal(HttpStatusCode.OK, response.Status);
226+
Assert.Single(requests);
227+
Assert.Equal(dataUrl, requests[0].Url);
228+
}
229+
230+
[Fact]
231+
public async Task ShouldNavigateToURLWithHashAndFireRequestsWithoutHash()
232+
{
233+
var requests = new List<Request>();
234+
Page.RequestCreated += (sender, e) => requests.Add(e.Request);
235+
var response = await Page.GoToAsync(TestConstants.EmptyPage + "#hash");
236+
Assert.Equal(HttpStatusCode.OK, response.Status);
237+
Assert.Equal(TestConstants.EmptyPage, response.Url);
238+
Assert.Single(requests);
239+
Assert.Equal(TestConstants.EmptyPage, requests[0].Url);
240+
}
241+
}
242+
}

lib/PuppeteerSharp.Tests/Puppeteer/PuppeteerLaunchTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public async Task ShouldWorkInRealLifeWithOptions()
5151
new NavigationOptions()
5252
{
5353
Timeout = 5000,
54-
WaitUntil = new[] { "networkidle0" }
54+
WaitUntil = new[] { WaitUntilNavigation.Networkidle0 }
5555
});
5656
Assert.Equal(response.Status, HttpStatusCode.OK);
5757
}

lib/PuppeteerSharp.Tests/TestConstants.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ public static class TestConstants
1414
public static readonly string CrossProcessHttpPrefix = "http://127.0.0.1:8907";
1515
public static readonly string EmptyPage = $"{ServerUrl}/empty.html";
1616
public static readonly string CrossProcessUrl = ServerIpUrl;
17-
17+
1818
public static readonly DeviceDescriptor IPhone = DeviceDescriptors.Get(DeviceDescriptorName.IPhone6);
1919
public static readonly DeviceDescriptor IPhone6Landscape = DeviceDescriptors.Get(DeviceDescriptorName.IPhone6Landscape);
20-
20+
2121
public static LaunchOptions DefaultBrowserOptions() => new LaunchOptions
2222
{
2323
SlowMo = Convert.ToInt32(Environment.GetEnvironmentVariable("SLOW_MO")),

lib/PuppeteerSharp/Browser.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,12 @@ public async Task Initialize()
6060

6161
public async Task<Page> NewPageAsync()
6262
{
63-
var targetId = (await Connection.SendAsync("Target.createTarget", new Dictionary<string, object>(){
63+
string targetId = (await Connection.SendAsync("Target.createTarget", new Dictionary<string, object>(){
6464
{"url", "about:blank"}
6565
})).targetId.ToString();
6666

6767
var target = _targets[targetId];
68+
await target.InitializedTask;
6869
return await target.Page();
6970
}
7071

lib/PuppeteerSharp/NavigationOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
public class NavigationOptions
44
{
55
public int? Timeout { get; set; }
6-
public string[] WaitUntil { get; set; }
6+
public WaitUntilNavigation[] WaitUntil { get; set; }
77
}
88
}

0 commit comments

Comments
 (0)