Skip to content

Commit e3e40dd

Browse files
Meir017kblok
authored andcommitted
Implemented Puppeteer.launch tests (#79)
* added Network redirects should report SecurityDetails test * fixed Network redirects should report SecurityDetails test * added should reject all promises when browser is closed test * fixed test NetworkRedirectsShouldReportSecurityDetails * added should reject if executable path is invalid test * fixed throw NavigationException * fixed Network redirects should report SecurityDetails test * fixed should reject if executable path is invalid test * added userDataDir option & userDataDir argument tests * cleaned usings * added should return the default chrome arguments test * working version * cleaned ForceKillChrome
1 parent e1785dd commit e3e40dd

File tree

8 files changed

+142
-16
lines changed

8 files changed

+142
-16
lines changed

lib/PuppeteerSharp.TestServer/Startup.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Threading.Tasks;
66
using Microsoft.AspNetCore.Builder;
77
using Microsoft.AspNetCore.Hosting;
8+
using Microsoft.AspNetCore.Rewrite;
89
using Microsoft.Extensions.Configuration;
910
using Microsoft.Extensions.DependencyInjection;
1011

@@ -31,6 +32,8 @@ public void ConfigureServices(IServiceCollection services)
3132

3233
public void Configure(IApplicationBuilder app)
3334
{
35+
app.UseRewriter(new RewriteOptions()
36+
.AddRedirect("plzredirect", "empty.html"));
3437
app.UseStaticFiles();
3538
}
3639
}

lib/PuppeteerSharp.Tests/Puppeteer/PuppeteerLaunchTests.cs

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
using System.Threading.Tasks;
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Net;
6+
using System.Threading.Tasks;
27
using Xunit;
38

49
namespace PuppeteerSharp.Tests.Puppeteer
@@ -34,5 +39,87 @@ public async Task ShouldWorkInRealLife()
3439

3540
await browser.CloseAsync();
3641
}
42+
43+
[Fact(Skip = "test is not part of v1.0.0")]
44+
public async Task NetworkRedirectsShouldReportSecurityDetails()
45+
{
46+
var options = TestConstants.DefaultBrowserOptions();
47+
options.IgnoreHTTPSErrors = true;
48+
49+
var browser = await PuppeteerSharp.Puppeteer.LaunchAsync(options, TestConstants.ChromiumRevision);
50+
var page = await browser.NewPageAsync();
51+
52+
var responses = new List<Response>();
53+
page.ResponseCreated += (sender, e) => responses.Add(e.Response);
54+
55+
await page.GoToAsync(TestConstants.HttpsPrefix + "/plzredirect");
56+
Assert.Equal(2, responses.Count);
57+
Assert.Equal(HttpStatusCode.Redirect, responses[0].Status);
58+
var securityDetails = responses[0].SecurityDetails;
59+
Assert.Equal("TLS 1.2", securityDetails.Protocol);
60+
61+
await page.CloseAsync();
62+
await browser.CloseAsync();
63+
}
64+
65+
[Fact(Skip = "https://github.com/kblok/puppeteer-sharp/issues/76")]
66+
public async Task ShouldRejectAllPromisesWhenBrowserIsClosed()
67+
{
68+
var browser = await PuppeteerSharp.Puppeteer.LaunchAsync(TestConstants.DefaultBrowserOptions(), TestConstants.ChromiumRevision);
69+
var page = await browser.NewPageAsync();
70+
71+
var neverResolves = page.EvaluateHandle("() => new Promise(r => {})");
72+
await browser.CloseAsync();
73+
74+
await neverResolves;
75+
var exception = await Assert.ThrowsAsync<Exception>(() => neverResolves);
76+
Assert.Contains("Protocol error", exception.Message);
77+
}
78+
79+
[Fact]
80+
public async Task ShouldRejectIfExecutablePathIsInvalid()
81+
{
82+
var options = TestConstants.DefaultBrowserOptions();
83+
options.ExecutablePath = "random-invalid-path";
84+
85+
var exception = await Assert.ThrowsAsync<FileNotFoundException>(() => PuppeteerSharp.Puppeteer.LaunchAsync(options, TestConstants.ChromiumRevision));
86+
Assert.Equal("Failed to launch chrome! path to executable does not exist", exception.Message);
87+
Assert.Equal(options.ExecutablePath, exception.FileName);
88+
}
89+
90+
[Fact]
91+
public async Task UserDataDirOption()
92+
{
93+
var userDataDir = Launcher.GetTemporaryDirectory();
94+
var options = TestConstants.DefaultBrowserOptions();
95+
options.UserDataDir = userDataDir;
96+
97+
var browser = await PuppeteerSharp.Puppeteer.LaunchAsync(options, TestConstants.ChromiumRevision);
98+
Assert.True(Directory.GetFiles(userDataDir).Length > 0);
99+
await browser.CloseAsync();
100+
Assert.True(Directory.GetFiles(userDataDir).Length > 0);
101+
// Directory.Delete(userDataDir, true);
102+
}
103+
104+
[Fact]
105+
public async Task UserDataDirArgument()
106+
{
107+
var userDataDir = Launcher.GetTemporaryDirectory();
108+
var options = TestConstants.DefaultBrowserOptions();
109+
options.Args = options.Args.Concat(new[] { $"--user-data-dir={userDataDir}" }).ToArray();
110+
111+
var browser = await PuppeteerSharp.Puppeteer.LaunchAsync(options, TestConstants.ChromiumRevision);
112+
Assert.True(Directory.GetFiles(userDataDir).Length > 0);
113+
await browser.CloseAsync();
114+
Assert.True(Directory.GetFiles(userDataDir).Length > 0);
115+
// Directory.Delete(userDataDir, true);
116+
}
117+
118+
[Fact]
119+
public void ShouldReturnTheDefaultChromeArguments()
120+
{
121+
var args = PuppeteerSharp.Puppeteer.DefaultArgs;
122+
Assert.Contains("--no-first-run", args);
123+
}
37124
}
38125
}

lib/PuppeteerSharp/Launcher.cs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace PuppeteerSharp
1313
{
1414
public class Launcher
1515
{
16-
private static readonly string[] _defaultArgs = {
16+
internal static readonly string[] DefaultArgs = {
1717
"--disable-background-networking",
1818
"--disable-background-timer-throttling",
1919
"--disable-client-side-phishing-detection",
@@ -30,7 +30,7 @@ public class Launcher
3030
"--safebrowsing-disable-auto-update",
3131
};
3232

33-
public static readonly string[] _automationArgs = {
33+
internal static readonly string[] AutomationArgs = {
3434
"--enable-automation",
3535
"--password-store=basic",
3636
"--use-mock-keychain"
@@ -44,27 +44,27 @@ public class Launcher
4444

4545
internal async Task<Browser> LaunchAsync(LaunchOptions options, int chromiumRevision)
4646
{
47-
var chromeArguments = new List<string>(_defaultArgs);
47+
var chromeArguments = new List<string>(DefaultArgs);
4848

4949
if (options.AppMode)
5050
{
5151
options.Headless = false;
5252
}
5353
else
5454
{
55-
chromeArguments.AddRange(_automationArgs);
55+
chromeArguments.AddRange(AutomationArgs);
5656
}
5757

58-
if (options.Args.Any(i => i.StartsWith("--user-data-dir", StringComparison.Ordinal)))
58+
if (!options.Args.Any(i => i.StartsWith("--user-data-dir", StringComparison.Ordinal)))
5959
{
6060
if (string.IsNullOrEmpty(options.UserDataDir))
6161
{
6262
_temporaryUserDataDir = GetTemporaryDirectory();
63-
chromeArguments.Add($"--user-data-dir=${_temporaryUserDataDir}");
63+
chromeArguments.Add($"--user-data-dir={_temporaryUserDataDir}");
6464
}
6565
else
6666
{
67-
chromeArguments.Add($"--user-data-dir=${options.UserDataDir}");
67+
chromeArguments.Add($"--user-data-dir={options.UserDataDir}");
6868
}
6969
}
7070

@@ -92,6 +92,10 @@ internal async Task<Browser> LaunchAsync(LaunchOptions options, int chromiumRevi
9292
var revisionInfo = downloader.RevisionInfo(Downloader.CurrentPlatform, chromiumRevision);
9393
chromeExecutable = revisionInfo.ExecutablePath;
9494
}
95+
if (!File.Exists(chromeExecutable))
96+
{
97+
throw new FileNotFoundException("Failed to launch chrome! path to executable does not exist", chromeExecutable);
98+
}
9599

96100
if (options.Args.Any())
97101
{
@@ -104,7 +108,7 @@ internal async Task<Browser> LaunchAsync(LaunchOptions options, int chromiumRevi
104108

105109
SetEnvVariables(_chromeProcess.StartInfo.Environment, options.Env, Environment.GetEnvironmentVariables());
106110

107-
if(!options.DumpIO)
111+
if (!options.DumpIO)
108112
{
109113
_chromeProcess.StartInfo.RedirectStandardOutput = false;
110114
_chromeProcess.StartInfo.RedirectStandardError = false;
@@ -215,6 +219,7 @@ private async Task ForceKillChrome()
215219
if (_chromeProcess.Id != 0 && Process.GetProcessById(_chromeProcess.Id) != null)
216220
{
217221
_chromeProcess.Kill();
222+
_chromeProcess.WaitForExit();
218223
}
219224

220225
if (_temporaryUserDataDir != null)

lib/PuppeteerSharp/NetworkManager.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,8 @@ private void OnResponseReceived(MessageEventArgs e)
184184
_client,
185185
request,
186186
(HttpStatusCode)e.MessageData.response.status,
187-
((JObject)e.MessageData.response.headers).ToObject<Dictionary<string, object>>());
187+
((JObject)e.MessageData.response.headers).ToObject<Dictionary<string, object>>(),
188+
e.MessageData.response.securityDetails?.ToObject<SecurityDetails>());
188189

189190
request.Response = response;
190191

@@ -284,9 +285,9 @@ private void HandleRequestStart(string requestId, string interceptionId, string
284285
});
285286
}
286287

287-
private void HandleRequestRedirect(Request request, HttpStatusCode redirectStatus, Dictionary<string, object> redirectHeaders)
288+
private void HandleRequestRedirect(Request request, HttpStatusCode redirectStatus, Dictionary<string, object> redirectHeaders, SecurityDetails securityDetails = null)
288289
{
289-
var response = new Response(_client, request, redirectStatus, redirectHeaders);
290+
var response = new Response(_client, request, redirectStatus, redirectHeaders, securityDetails);
290291
request.Response = response;
291292
_requestIdToRequest.Remove(request.RequestId);
292293

@@ -346,7 +347,8 @@ private void OnRequestWillBeSent(MessageEventArgs e)
346347
HandleRequestRedirect(
347348
request,
348349
(HttpStatusCode)e.MessageData.redirectResponse.status,
349-
e.MessageData.redirectResponse.headers.ToObject<Dictionary<string, object>>());
350+
e.MessageData.redirectResponse.headers.ToObject<Dictionary<string, object>>(),
351+
e.MessageData.redirectResponse.securityDetails?.ToObject<SecurityDetails>());
350352
}
351353

352354
HandleRequestStart(

lib/PuppeteerSharp/Page.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ private async Task Navigate(Session client, string url, string referrer)
688688

689689
if (response.errorText != null)
690690
{
691-
throw new NavigationException(response.errorText);
691+
throw new NavigationException(response.errorText.ToString());
692692
}
693693
}
694694

lib/PuppeteerSharp/Puppeteer.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ namespace PuppeteerSharp
66
{
77
public class Puppeteer
88
{
9+
public static string[] DefaultArgs => Launcher.DefaultArgs;
10+
911
public static async Task<Browser> LaunchAsync(LaunchOptions options, int chromiumRevision)
1012
{
1113
return await new Launcher().LaunchAsync(options, chromiumRevision);

lib/PuppeteerSharp/Response.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class Response
1313
private bool _ok;
1414
private string _url;
1515

16-
public Response(Session client, Request request, HttpStatusCode status, Dictionary<string, object> headers)
16+
public Response(Session client, Request request, HttpStatusCode status, Dictionary<string, object> headers, SecurityDetails securityDetails)
1717
{
1818
_client = client;
1919
Request = request;
@@ -26,7 +26,7 @@ public Response(Session client, Request request, HttpStatusCode status, Dictiona
2626
{
2727
Headers[keyValue.Key] = keyValue.Value;
2828
}
29-
29+
SecurityDetails = securityDetails;
3030
}
3131

3232
#region Properties
@@ -38,6 +38,7 @@ public Response(Session client, Request request, HttpStatusCode status, Dictiona
3838
public Task<string> ContentTask => ContentTaskWrapper.Task;
3939
public TaskCompletionSource<string> ContentTaskWrapper { get; internal set; }
4040
public Request Request { get; internal set; }
41+
public SecurityDetails SecurityDetails { get; internal set; }
4142
#endregion
4243

4344
#region Public Methods
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System.Collections.Generic;
2+
using System.Net;
3+
using System.Threading.Tasks;
4+
using Newtonsoft.Json.Linq;
5+
6+
namespace PuppeteerSharp
7+
{
8+
public class SecurityDetails
9+
{
10+
public SecurityDetails(string subjectName, string issuer, int validFrom, int validTo, string protocol)
11+
{
12+
SubjectName = subjectName;
13+
Issuer = issuer;
14+
ValidFrom = validFrom;
15+
ValidTo = validTo;
16+
Protocol = protocol;
17+
}
18+
19+
public string SubjectName { get; }
20+
public string Issuer { get; }
21+
public int ValidFrom { get; }
22+
public int ValidTo { get; }
23+
public string Protocol { get; }
24+
25+
}
26+
}

0 commit comments

Comments
 (0)