Skip to content

Commit

Permalink
feat(testing-harness): allow connecting remotely
Browse files Browse the repository at this point in the history
  • Loading branch information
mxschmitt committed Jan 24, 2025
1 parent 0586b06 commit 435b6f0
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 34 deletions.
31 changes: 23 additions & 8 deletions src/Playwright.NUnit/BrowserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,27 +41,44 @@ private BrowserService(IBrowser browser)
Browser = browser;
}

public static Task<BrowserService> Register(WorkerAwareTest test, IBrowserType browserType)
public static Task<BrowserService> Register(WorkerAwareTest test, IBrowserType browserType, PlaywrightConnectOptions? connectOptions)
{
return test.RegisterService("Browser", async () => new BrowserService(await CreateBrowser(browserType).ConfigureAwait(false)));
return test.RegisterService("Browser", async () => new BrowserService(await CreateBrowser(browserType, connectOptions).ConfigureAwait(false)));
}

private static async Task<IBrowser> CreateBrowser(IBrowserType browserType)
private static async Task<IBrowser> CreateBrowser(IBrowserType browserType, PlaywrightConnectOptions? connectOptions)
{
if (connectOptions != null)
{
return await browserType.ConnectAsync(connectOptions.WSEndpoint, connectOptions).ConfigureAwait(false);
}

var legacyBrowser = await ConnectToLegacyService(browserType);
if (legacyBrowser != null)
{
return legacyBrowser;
}
return await browserType.LaunchAsync(PlaywrightSettingsProvider.LaunchOptions).ConfigureAwait(false);
}

// TODO: Remove after Q3 2025
private static async Task<IBrowser?> ConnectToLegacyService(IBrowserType browserType)
{
var accessToken = Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_ACCESS_TOKEN");
var serviceUrl = Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_URL");

if (string.IsNullOrEmpty(accessToken) || string.IsNullOrEmpty(serviceUrl))
{
return await browserType.LaunchAsync(PlaywrightSettingsProvider.LaunchOptions).ConfigureAwait(false);
return null;
}

var exposeNetwork = Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_EXPOSE_NETWORK") ?? "<loopback>";
var os = Uri.EscapeDataString(Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_OS") ?? "linux");
var runId = Uri.EscapeDataString(Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_RUN_ID") ?? DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture));
var apiVersion = "2023-10-01-preview";
var wsEndpoint = $"{serviceUrl}?os={os}&runId={runId}&api-version={apiVersion}";
var connectOptions = new BrowserTypeConnectOptions

return await browserType.ConnectAsync(wsEndpoint, new BrowserTypeConnectOptions
{
Timeout = 3 * 60 * 1000,
ExposeNetwork = exposeNetwork,
Expand All @@ -70,9 +87,7 @@ private static async Task<IBrowser> CreateBrowser(IBrowserType browserType)
["Authorization"] = $"Bearer {accessToken}",
["x-playwright-launch-options"] = JsonSerializer.Serialize(PlaywrightSettingsProvider.LaunchOptions, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull })
}
};

return await browserType.ConnectAsync(wsEndpoint, connectOptions).ConfigureAwait(false);
}).ConfigureAwait(false);
}

public Task ResetAsync() => Task.CompletedTask;
Expand Down
7 changes: 6 additions & 1 deletion src/Playwright.NUnit/BrowserTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public async Task<IBrowserContext> NewContext(BrowserNewContextOptions? options
[SetUp]
public async Task BrowserSetup()
{
var service = await BrowserService.Register(this, BrowserType).ConfigureAwait(false);
var service = await BrowserService.Register(this, BrowserType, ConnectOptions()).ConfigureAwait(false);
Browser = service.Browser;
}

Expand All @@ -60,4 +60,9 @@ public async Task BrowserTearDown()
_contexts.Clear();
Browser = null!;
}

public virtual PlaywrightConnectOptions? ConnectOptions()
{
return null;
}
}
30 changes: 30 additions & 0 deletions src/Playwright.TestAdapter/PlaywrightConnectOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* MIT License
*
* Copyright (c) Microsoft Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

using Microsoft.Playwright;

public class PlaywrightConnectOptions : BrowserTypeConnectOptions
{
public string WSEndpoint = string.Empty;
}
46 changes: 23 additions & 23 deletions src/Playwright.TestingHarnessTest/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/Playwright.TestingHarnessTest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "playwright.testingharnesstest",
"private": true,
"devDependencies": {
"@playwright/test": "^1.48.2",
"@playwright/test": "1.49.1",
"@types/http-proxy": "^1.17.15",
"fast-xml-parser": "^4.5.0",
"http-proxy": "^1.18.1"
Expand Down
11 changes: 10 additions & 1 deletion src/Playwright.TestingHarnessTest/tests/baseTest.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from 'fs';
import path from 'path';
import childProcess from 'child_process';
import { test as base } from '@playwright/test';
import { test as base, BrowserServer } from '@playwright/test';
import { XMLParser } from 'fast-xml-parser';

type RunResult = {
Expand All @@ -17,7 +17,16 @@ type RunResult = {

export const test = base.extend<{
runTest: (files: Record<string, string>, command: string, env?: NodeJS.ProcessEnv) => Promise<RunResult>;
launchServer: ({ port: number }) => Promise<void>;
}>({
launchServer: async ({ playwright }, use) => {
const servers: BrowserServer[] = [];
await use(async ({port}: {port: number}) => {
servers.push(await playwright.chromium.launchServer({ port }));
});
for (const server of servers)
await server.close();
},
runTest: async ({ }, use, testInfo) => {
const testResults: RunResult[] = [];
await use(async (files, command, env) => {
Expand Down
46 changes: 46 additions & 0 deletions src/Playwright.TestingHarnessTest/tests/nunit/basic.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -506,3 +506,49 @@ test.describe('Expect() timeout', () => {
expect(result.rawStdout).toContain("LocatorAssertions.ToHaveTextAsync with timeout 123ms")
});
});

test.describe('ConnectOptions', () => {
const ExampleTestWithConnectOptions = `
using System;
using System.Threading.Tasks;
using Microsoft.Playwright.NUnit;
using NUnit.Framework;
namespace Playwright.TestingHarnessTest.NUnit;
public class <class-name> : PageTest
{
[Test]
public async Task Test()
{
await Page.GotoAsync("about:blank");
}
public override PlaywrightConnectOptions ConnectOptions()
{
return new() {
WSEndpoint = "http://127.0.0.1:1234",
};
}
}`;

test('should fail when the server is not reachable', async ({ runTest }) => {
const result = await runTest({
'ExampleTests.cs': ExampleTestWithConnectOptions,
}, 'dotnet test');
expect(result.passed).toBe(0);
expect(result.failed).toBe(1);
expect(result.total).toBe(1);
expect(result.rawStdout).toContain('connect ECONNREFUSED 127.0.0.1:1234')
});

test('should pass when the server is reachable', async ({ runTest, launchServer }) => {
await launchServer({ port: 1234 });
const result = await runTest({
'ExampleTests.cs': ExampleTestWithConnectOptions,
}, 'dotnet test');
expect(result.passed).toBe(1);
expect(result.failed).toBe(0);
expect(result.total).toBe(1);
});
});

0 comments on commit 435b6f0

Please sign in to comment.