Skip to content

Commit 5739c6b

Browse files
authored
Implement PuppeteerLoaderFixture (#80)
This class will help us download chromium and setup a WebServer in a CI server
1 parent 5f54919 commit 5739c6b

File tree

5 files changed

+125
-7
lines changed

5 files changed

+125
-7
lines changed

lib/PuppeteerSharp.Tests/Page/PdfTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77

88
namespace PuppeteerSharp.Tests.Page
99
{
10+
[Collection("PuppeteerLoaderFixture collection")]
1011
public class PdfTests : PuppeteerBaseTest
1112
{
12-
1313
[Fact]
1414
public async Task ShouldBeAbleToSaveFile()
1515
{

lib/PuppeteerSharp.Tests/Page/ScreenshotTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88

99
namespace PuppeteerSharp.Tests.Page
1010
{
11+
[Collection("PuppeteerLoaderFixture collection")]
1112
public class ScreenshotTests : PuppeteerBaseTest
1213
{
13-
1414
[Fact]
1515
public async Task ShouldWorkWithFile()
1616
{

lib/PuppeteerSharp.Tests/Puppeteer/PuppeteerLaunchTests.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,9 @@
33

44
namespace PuppeteerSharp.Tests.Puppeteer
55
{
6+
[Collection("PuppeteerLoaderFixture collection")]
67
public class PuppeteerLaunchTests
78
{
8-
public PuppeteerLaunchTests()
9-
{
10-
Downloader.CreateDefault().DownloadRevisionAsync(TestConstants.ChromiumRevision).GetAwaiter().GetResult();
11-
}
12-
139
[Fact]
1410
public async Task ShouldSupportIgnoreHTTPSErrorsOption()
1511
{
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
using Xunit;
3+
4+
namespace PuppeteerSharp.Tests
5+
{
6+
[CollectionDefinition("PuppeteerLoaderFixture collection")]
7+
public class DatabaseCollection : ICollectionFixture<PuppeteerLoaderFixture>
8+
{
9+
// This class has no code, and is never created. Its purpose is simply
10+
// to be the place to apply [CollectionDefinition] and all the
11+
// ICollectionFixture<> interfaces.
12+
//Recipe from https://xunit.github.io/docs/shared-context.html#class-fixture
13+
}
14+
15+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.IO;
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
7+
namespace PuppeteerSharp.Tests
8+
{
9+
public class PuppeteerLoaderFixture : IDisposable
10+
{
11+
Process _webServerProcess = null;
12+
13+
public PuppeteerLoaderFixture()
14+
{
15+
SetupAsync().GetAwaiter().GetResult();
16+
}
17+
18+
public void Dispose()
19+
{
20+
int processId = 0;
21+
22+
try
23+
{
24+
processId = _webServerProcess.Id;
25+
}
26+
catch (InvalidOperationException)
27+
{
28+
//We might get an InvalidOperationException if the process is in an invalid state
29+
}
30+
catch (Exception ex)
31+
{
32+
throw new Exception("Unable to kill webserver", ex);
33+
}
34+
35+
if (processId != 0 && Process.GetProcessById(processId) != null)
36+
{
37+
_webServerProcess.Kill();
38+
}
39+
40+
}
41+
42+
private async Task SetupAsync()
43+
{
44+
var downloaderTask = Downloader.CreateDefault().DownloadRevisionAsync(TestConstants.ChromiumRevision);
45+
var serverTask = StartWebServerAsync();
46+
47+
await Task.WhenAll(downloaderTask, serverTask);
48+
49+
}
50+
51+
private async Task StartWebServerAsync()
52+
{
53+
var taskWrapper = new TaskCompletionSource<bool>();
54+
const int timeout = 2000;
55+
56+
var build = Directory.GetCurrentDirectory().Contains("Debug") ? "Debug" : "Release";
57+
var webServerPath = Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..", "..",
58+
"PuppeteerSharp.TestServer");
59+
60+
_webServerProcess = new Process();
61+
_webServerProcess.StartInfo.FileName = "dotnet";
62+
_webServerProcess.StartInfo.WorkingDirectory = webServerPath;
63+
_webServerProcess.StartInfo.Arguments = $"./bin/{build}/netcoreapp2.0/PuppeteerSharp.TestServer.dll";
64+
65+
_webServerProcess.StartInfo.RedirectStandardOutput = true;
66+
_webServerProcess.StartInfo.RedirectStandardError = true;
67+
68+
_webServerProcess.OutputDataReceived += (sender, e) =>
69+
{
70+
Console.WriteLine(e.Data);
71+
if (e.Data != null &&
72+
taskWrapper.Task.Status != TaskStatus.RanToCompletion &&
73+
//Though this is not bulletproof for the purpose of local testing
74+
//We assume that if the address is already in use is because we have another
75+
//process hosting the site
76+
(e.Data.Contains("Now listening on") || e.Data.Contains("ADDRINUSE")))
77+
{
78+
taskWrapper.SetResult(true);
79+
}
80+
};
81+
82+
_webServerProcess.Exited += (sender, e) =>
83+
{
84+
taskWrapper.SetException(new Exception("Unable to start web server"));
85+
};
86+
87+
Timer timer = null;
88+
//We have to declare timer before initializing it because if we don't do this
89+
//we can't dispose it in the action created in the constructor
90+
timer = new Timer((state) =>
91+
{
92+
if (taskWrapper.Task.Status != TaskStatus.RanToCompletion)
93+
{
94+
taskWrapper.SetException(
95+
new Exception($"Timed out after {timeout} ms while trying to connect to WebServer! "));
96+
}
97+
timer.Dispose();
98+
}, null, timeout, 0);
99+
100+
_webServerProcess.Start();
101+
_webServerProcess.BeginOutputReadLine();
102+
103+
await taskWrapper.Task;
104+
}
105+
106+
}
107+
}

0 commit comments

Comments
 (0)