Skip to content

Commit 80daa31

Browse files
committed
Use Playwright in test runner
1 parent 200981e commit 80daa31

File tree

5 files changed

+77
-68
lines changed

5 files changed

+77
-68
lines changed

.github/workflows/WebExtensions.Net-Build.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,12 @@ jobs:
4141
uses: actions/setup-dotnet@v4
4242
with:
4343
dotnet-version: 9.0.x
44-
- name: Setup Chrome and Chrome Driver
45-
uses: nanasess/setup-chromedriver@master
44+
- name: Setup Node
45+
uses: actions/setup-node@v4
46+
with:
47+
node-version: lts/*
48+
- name: Install Playwright Browsers
49+
run: npx playwright install --with-deps
4650
- name: Checkout
4751
uses: actions/checkout@v4
4852
with:

.github/workflows/WebExtensions.Net-PR-Build.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@ jobs:
1616
uses: actions/setup-dotnet@v4
1717
with:
1818
dotnet-version: 9.0.x
19-
- name: Setup Chrome and Chrome Driver
20-
uses: nanasess/setup-chromedriver@master
19+
- name: Setup Node
20+
uses: actions/setup-node@v4
21+
with:
22+
node-version: lts/*
23+
- name: Install Playwright Browsers
24+
run: npx playwright install --with-deps
2125
- name: Checkout
2226
uses: actions/checkout@v4
2327
with:

test/WebExtensions.Net.BrowserExtensionIntegrationTest/wwwroot/TestRunner/BlazorTestRunner.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ class TestResultError extends Error {
8787
skip: spec.properties?.testMethod?.skip,
8888
declaringTypeFullName: spec.properties?.testMethod?.declaringTypeFullName,
8989
methodName: spec.properties?.testMethod?.methodName,
90-
failMessage: spec.failedExceptations?.[0]?.message,
91-
stackTrace: spec.failedExceptations?.[0]?.stack
90+
failMessage: spec.failedExpectations?.[0]?.message,
91+
stackTrace: spec.failedExpectations?.[0]?.stack
9292
};
9393
});
9494
return {

test/WebExtensions.Net.IntegrationTestsRunner/Runner.cs

Lines changed: 62 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
using Microsoft.VisualStudio.TestTools.UnitTesting;
2-
using OpenQA.Selenium;
3-
using OpenQA.Selenium.Chrome;
4-
using System;
1+
using System;
2+
using System.Collections.Generic;
53
using System.IO;
64
using System.Linq;
5+
using System.Text;
76
using System.Text.Json;
87
using System.Threading.Tasks;
8+
using Microsoft.Playwright;
9+
using Microsoft.VisualStudio.TestTools.UnitTesting;
910
using WebExtensions.Net.IntegrationTestsRunner.Helpers;
1011
using WebExtensions.Net.IntegrationTestsRunner.Models;
1112

@@ -19,7 +20,6 @@ public async Task RunTests()
1920
{
2021
var currentDirectory = AppDomain.CurrentDomain.BaseDirectory;
2122
var solutionDirectory = currentDirectory[..currentDirectory.LastIndexOf("\\test")];
22-
var driverPath = "C:\\SeleniumWebDrivers\\ChromeDriver";
2323
var resultsPath = $"{solutionDirectory}\\test\\TestResults";
2424
#if DEBUG
2525
var configuration = "debug";
@@ -34,85 +34,87 @@ public async Task RunTests()
3434
Directory.CreateDirectory(resultsPath);
3535
}
3636

37-
if (!Directory.Exists(driverPath))
38-
{
39-
throw new NotSupportedException($"Download the chromedriver from and extract the executable file to {driverPath}. Download the latest version from https://googlechromelabs.github.io/chrome-for-testing/");
40-
}
41-
4237
try
4338
{
44-
using var webDriver = GetWebDriver(driverPath, extensionPath);
45-
await WaitForExtensionPageLoaded(webDriver);
46-
LaunchTestPage(webDriver);
47-
await WaitForTestToFinish(webDriver);
39+
using var playwright = await Playwright.CreateAsync();
40+
var browser = await LaunchBrowser(playwright, currentDirectory, extensionPath);
41+
var page = await browser.RunAndWaitForPageAsync(static () => Task.CompletedTask);
42+
var consoleMessages = new List<string>();
43+
page.Console += (_, message) =>
44+
{
45+
consoleMessages.Add(message.Text);
46+
};
47+
await LaunchTestPage(page);
48+
await WaitForTestToFinish(page, consoleMessages);
4849

4950
// Test results
50-
var testResults = GetTestResults(webDriver);
51+
var testResults = await GetTestResults(page);
5152
var resultsXML = TestResultsGenerator.Generate(testResults);
5253
var trxFilePath = $"{resultsPath}\\TestResults_{DateTime.UtcNow:yyyy-MM-dd_HH_mm_ss}.trx";
5354
await WriteResultsToFile(trxFilePath, resultsXML);
5455
Console.WriteLine($"Results file: {trxFilePath}");
5556

5657
// Test coverage
57-
var testCoverage = await GetTestCoverageHits(webDriver);
58+
var testCoverage = await GetTestCoverageHits(page);
5859
if (testCoverage is not null)
5960
{
6061
TestCoverageWriter.Write(testCoverage.HitsFilePath, testCoverage.HitsArray);
6162
Console.WriteLine($"Test coverage hits file: {testCoverage.HitsFilePath}");
6263
}
64+
65+
if (testResults.Status == "failed")
66+
{
67+
var errors = new StringBuilder();
68+
errors.AppendLine("One or more test(s) failed.");
69+
var index = 0;
70+
foreach (var testResult in testResults.Tests.Where(test => test.Status == "failed"))
71+
{
72+
index++;
73+
errors.AppendLine(
74+
$"""
75+
// Start Test Result {index} - {testResult.MethodName}
76+
{testResult.FailMessage}
77+
// End Test Result {index} - {testResult.MethodName}
78+
""");
79+
}
80+
throw new TestRunnerException(errors.ToString());
81+
}
6382
}
6483
catch (TestRunnerException testRunnerException)
6584
{
6685
Assert.Fail(testRunnerException.Message);
6786
}
68-
catch (Exception exception)
69-
{
70-
Assert.Fail("Failed to create WebDriver. Exception message: " + exception.Message + Environment.NewLine + "Download the latest version from https://googlechromelabs.github.io/chrome-for-testing/");
71-
}
7287
}
7388

74-
private static ChromeDriver GetWebDriver(string driverPath, string extensionPath)
89+
private static Task<IBrowserContext> LaunchBrowser(IPlaywright playwright, string currentDirectory, string extensionPath)
7590
{
76-
var chromeOptions = new ChromeOptions();
77-
chromeOptions.AddArgument($"load-extension={extensionPath}");
78-
return new ChromeDriver(driverPath, chromeOptions);
79-
}
80-
81-
private static async Task WaitForExtensionPageLoaded(WebDriver webDriver)
82-
{
83-
await Task.Delay(1000);
84-
// wait for 10 seconds
85-
var waitTime = 10 * 1000;
86-
var interval = 500;
87-
var count = waitTime / interval;
88-
while (count > 0)
91+
var userDataDir = Path.Combine(currentDirectory, "chrome");
92+
if (Directory.Exists(userDataDir))
8993
{
90-
count--;
91-
if (webDriver.WindowHandles.Count == 2)
92-
{
93-
webDriver.SwitchTo().Window(webDriver.WindowHandles[1]);
94-
break;
95-
}
96-
await Task.Delay(interval);
94+
Directory.Delete(userDataDir, true);
9795
}
98-
if (!webDriver.Url.StartsWith("chrome-extension://"))
99-
{
100-
webDriver.SwitchTo().Window(webDriver.WindowHandles[0]);
101-
}
102-
if (!webDriver.Url.StartsWith("chrome-extension://"))
96+
Directory.CreateDirectory(userDataDir);
97+
98+
return playwright.Chromium.LaunchPersistentContextAsync(userDataDir, new()
10399
{
104-
throw new TestRunnerException("Failed to wait for extension page to load.");
105-
}
100+
Headless = false,
101+
Channel = "chromium",
102+
Args =
103+
[
104+
$"--disable-extensions-except={extensionPath}",
105+
$"--load-extension={extensionPath}"
106+
]
107+
});
106108
}
107109

108-
private static void LaunchTestPage(WebDriver webDriver)
110+
private static Task LaunchTestPage(IPage page)
109111
{
110-
var extensionUri = new Uri(webDriver.Url);
112+
var extensionUri = new Uri(page.Url);
111113
var testPageUrl = $"{extensionUri.Scheme}://{extensionUri.Host}/tests.html?random=false&coverlet";
112-
webDriver.Navigate().GoToUrl(testPageUrl);
114+
return page.GotoAsync(testPageUrl);
113115
}
114116

115-
private static async Task WaitForTestToFinish(WebDriver webDriver)
117+
private static async Task WaitForTestToFinish(IPage page, IEnumerable<string> consoleMessages)
116118
{
117119
// wait for 30 seconds
118120
var waitTime = 30 * 1000;
@@ -124,19 +126,18 @@ private static async Task WaitForTestToFinish(WebDriver webDriver)
124126
while (count > 0)
125127
{
126128
count--;
127-
finished = (bool)webDriver.ExecuteScript("return window.jsApiReporter && window.jsApiReporter.finished;");
129+
finished = await page.EvaluateAsync<bool>("window.jsApiReporter && window.jsApiReporter.finished");
128130
if (finished)
129131
{
130132
break;
131133
}
132134
await Task.Delay(interval);
133135
}
136+
134137
if (!finished)
135138
{
136-
var logs = webDriver.Manage().Logs
137-
.GetLog(LogType.Browser)
138-
.Where(log => !log.Message.Contains("ThrowExceptionInTest"))
139-
.Select(log => log.Message)
139+
var logs = consoleMessages
140+
.Where(message => !message.Contains("ThrowExceptionInTest"))
140141
.ToList();
141142
if (logs.Count > 0)
142143
{
@@ -146,9 +147,9 @@ private static async Task WaitForTestToFinish(WebDriver webDriver)
146147
}
147148
}
148149

149-
private static TestRunInfo GetTestResults(WebDriver webDriver)
150+
private static async Task<TestRunInfo> GetTestResults(IPage page)
150151
{
151-
var resultsObject = (string)webDriver.ExecuteScript("return JSON.stringify(TestRunner.GetTestResults());");
152+
var resultsObject = await page.EvaluateAsync<string>("JSON.stringify(TestRunner.GetTestResults())");
152153
var testRunResult = JsonSerializer.Deserialize<TestRunInfo>(resultsObject, new JsonSerializerOptions()
153154
{
154155
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
@@ -170,7 +171,7 @@ private static TestRunInfo GetTestResults(WebDriver webDriver)
170171
return testRunResult;
171172
}
172173

173-
private static async Task<TestCoverage> GetTestCoverageHits(WebDriver webDriver)
174+
private static async Task<TestCoverage> GetTestCoverageHits(IPage page)
174175
{
175176
// wait for 5 seconds
176177
var waitTime = 5 * 1000;
@@ -182,7 +183,7 @@ private static async Task<TestCoverage> GetTestCoverageHits(WebDriver webDriver)
182183
while (count > 0)
183184
{
184185
count--;
185-
var resultsObject = (string)webDriver.ExecuteScript("return JSON.stringify(TestRunner.GetTestCoverage());");
186+
var resultsObject = await page.EvaluateAsync<string>("JSON.stringify(TestRunner.GetTestCoverage())");
186187
testCoverage = JsonSerializer.Deserialize<TestCoverage>(resultsObject, new JsonSerializerOptions()
187188
{
188189
PropertyNamingPolicy = JsonNamingPolicy.CamelCase

test/WebExtensions.Net.IntegrationTestsRunner/WebExtensions.Net.IntegrationTestsRunner.csproj

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

99
<ItemGroup>
1010
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
11+
<PackageReference Include="Microsoft.Playwright" Version="1.51.0" />
1112
<PackageReference Include="MSTest.TestAdapter" Version="3.7.3" />
1213
<PackageReference Include="MSTest.TestFramework" Version="3.7.3" />
13-
<PackageReference Include="Selenium.WebDriver" Version="4.28.0" />
1414
<PackageReference Include="System.Xml.XmlSerializer" Version="4.3.0" />
1515
</ItemGroup>
1616

0 commit comments

Comments
 (0)