From 4e16ba90e643e3cc9d31610e0053580aee305999 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Fri, 24 Jan 2025 15:27:00 +0100 Subject: [PATCH 1/5] feat(testing-harness): allow connecting remotely --- src/Playwright.NUnit/BrowserService.cs | 31 +++++++++---- src/Playwright.NUnit/BrowserTest.cs | 7 ++- .../PlaywrightConnectOptions.cs | 30 ++++++++++++ .../package-lock.json | 46 +++++++++---------- .../package.json | 4 +- .../tests/baseTest.ts | 13 +++++- .../tests/nunit/basic.spec.ts | 46 +++++++++++++++++++ 7 files changed, 141 insertions(+), 36 deletions(-) create mode 100644 src/Playwright.TestAdapter/PlaywrightConnectOptions.cs diff --git a/src/Playwright.NUnit/BrowserService.cs b/src/Playwright.NUnit/BrowserService.cs index 9f0857ec0f..955d6f8e27 100644 --- a/src/Playwright.NUnit/BrowserService.cs +++ b/src/Playwright.NUnit/BrowserService.cs @@ -41,19 +41,35 @@ private BrowserService(IBrowser browser) Browser = browser; } - public static Task Register(WorkerAwareTest test, IBrowserType browserType) + public static Task 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 CreateBrowser(IBrowserType browserType) + private static async Task 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 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") ?? ""; @@ -61,7 +77,8 @@ private static async Task CreateBrowser(IBrowserType browserType) 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, @@ -70,9 +87,7 @@ private static async Task 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; diff --git a/src/Playwright.NUnit/BrowserTest.cs b/src/Playwright.NUnit/BrowserTest.cs index 3f4592aa22..4691949699 100644 --- a/src/Playwright.NUnit/BrowserTest.cs +++ b/src/Playwright.NUnit/BrowserTest.cs @@ -43,7 +43,7 @@ public async Task 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; } @@ -60,4 +60,9 @@ public async Task BrowserTearDown() _contexts.Clear(); Browser = null!; } + + public virtual PlaywrightConnectOptions? ConnectOptions() + { + return null; + } } diff --git a/src/Playwright.TestAdapter/PlaywrightConnectOptions.cs b/src/Playwright.TestAdapter/PlaywrightConnectOptions.cs new file mode 100644 index 0000000000..be47967e44 --- /dev/null +++ b/src/Playwright.TestAdapter/PlaywrightConnectOptions.cs @@ -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; +} diff --git a/src/Playwright.TestingHarnessTest/package-lock.json b/src/Playwright.TestingHarnessTest/package-lock.json index a984611bf9..9d35402a58 100644 --- a/src/Playwright.TestingHarnessTest/package-lock.json +++ b/src/Playwright.TestingHarnessTest/package-lock.json @@ -7,19 +7,19 @@ "": { "name": "playwright.testingharnesstest", "devDependencies": { - "@playwright/test": "^1.48.2", + "@playwright/test": "1.49.1", "@types/node": "^22.12.0", "fast-xml-parser": "^4.5.0" } }, "node_modules/@playwright/test": { - "version": "1.48.2", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.2.tgz", - "integrity": "sha512-54w1xCWfXuax7dz4W2M9uw0gDyh+ti/0K/MxcCUxChFh37kkdxPdfZDw5QBbuPUJHr1CiHJ1hXgSs+GgeQc5Zw==", + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.1.tgz", + "integrity": "sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.48.2" + "playwright": "1.49.1" }, "bin": { "playwright": "cli.js" @@ -77,13 +77,13 @@ } }, "node_modules/playwright": { - "version": "1.48.2", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.2.tgz", - "integrity": "sha512-NjYvYgp4BPmiwfe31j4gHLa3J7bD2WiBz8Lk2RoSsmX38SVIARZ18VYjxLjAcDsAhA+F4iSEXTSGgjua0rrlgQ==", + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.1.tgz", + "integrity": "sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.48.2" + "playwright-core": "1.49.1" }, "bin": { "playwright": "cli.js" @@ -96,9 +96,9 @@ } }, "node_modules/playwright-core": { - "version": "1.48.2", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.2.tgz", - "integrity": "sha512-sjjw+qrLFlriJo64du+EK0kJgZzoQPsabGF4lBvsid+3CNIZIYLgnMj9V6JY5VhM2Peh20DJWIVpVljLLnlawA==", + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.1.tgz", + "integrity": "sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -124,12 +124,12 @@ }, "dependencies": { "@playwright/test": { - "version": "1.48.2", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.2.tgz", - "integrity": "sha512-54w1xCWfXuax7dz4W2M9uw0gDyh+ti/0K/MxcCUxChFh37kkdxPdfZDw5QBbuPUJHr1CiHJ1hXgSs+GgeQc5Zw==", + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.1.tgz", + "integrity": "sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g==", "dev": true, "requires": { - "playwright": "1.48.2" + "playwright": "1.49.1" } }, "@types/node": { @@ -158,19 +158,19 @@ "optional": true }, "playwright": { - "version": "1.48.2", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.2.tgz", - "integrity": "sha512-NjYvYgp4BPmiwfe31j4gHLa3J7bD2WiBz8Lk2RoSsmX38SVIARZ18VYjxLjAcDsAhA+F4iSEXTSGgjua0rrlgQ==", + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.1.tgz", + "integrity": "sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==", "dev": true, "requires": { "fsevents": "2.3.2", - "playwright-core": "1.48.2" + "playwright-core": "1.49.1" } }, "playwright-core": { - "version": "1.48.2", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.2.tgz", - "integrity": "sha512-sjjw+qrLFlriJo64du+EK0kJgZzoQPsabGF4lBvsid+3CNIZIYLgnMj9V6JY5VhM2Peh20DJWIVpVljLLnlawA==", + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.1.tgz", + "integrity": "sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==", "dev": true }, "strnum": { diff --git a/src/Playwright.TestingHarnessTest/package.json b/src/Playwright.TestingHarnessTest/package.json index e396e232cc..a01067610d 100644 --- a/src/Playwright.TestingHarnessTest/package.json +++ b/src/Playwright.TestingHarnessTest/package.json @@ -2,8 +2,8 @@ "name": "playwright.testingharnesstest", "private": true, "devDependencies": { - "@playwright/test": "^1.48.2", "@types/node": "^22.12.0", - "fast-xml-parser": "^4.5.0" + "fast-xml-parser": "^4.5.0", + "@playwright/test": "1.49.1" } } diff --git a/src/Playwright.TestingHarnessTest/tests/baseTest.ts b/src/Playwright.TestingHarnessTest/tests/baseTest.ts index 6561aa0cbe..cec1cd2f40 100644 --- a/src/Playwright.TestingHarnessTest/tests/baseTest.ts +++ b/src/Playwright.TestingHarnessTest/tests/baseTest.ts @@ -2,7 +2,7 @@ import fs from 'fs'; import http from 'http'; 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'; import { AddressInfo } from 'net'; @@ -21,6 +21,7 @@ export const test = base.extend<{ proxyServer: ProxyServer; testMode: 'nunit' | 'mstest' | 'xunit'; runTest: (files: Record, command: string, env?: NodeJS.ProcessEnv) => Promise; + launchServer: ({ port: number }) => Promise; }>({ proxyServer: async ({}, use) => { const proxyServer = new ProxyServer(); @@ -29,7 +30,15 @@ export const test = base.extend<{ await proxyServer.stop(); }, testMode: null, - runTest: async ({ testMode }, use, testInfo) => { + 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) => { const testDir = testInfo.outputPath(); diff --git a/src/Playwright.TestingHarnessTest/tests/nunit/basic.spec.ts b/src/Playwright.TestingHarnessTest/tests/nunit/basic.spec.ts index 4e64c3f155..19f002f363 100644 --- a/src/Playwright.TestingHarnessTest/tests/nunit/basic.spec.ts +++ b/src/Playwright.TestingHarnessTest/tests/nunit/basic.spec.ts @@ -487,3 +487,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 : 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); + }); +}); From 5f6eb1d097dbac32c7df61a119399f84239614b5 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Fri, 24 Jan 2025 15:55:31 +0100 Subject: [PATCH 2/5] review --- src/Playwright.NUnit/BrowserService.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Playwright.NUnit/BrowserService.cs b/src/Playwright.NUnit/BrowserService.cs index 955d6f8e27..0574f3e3d9 100644 --- a/src/Playwright.NUnit/BrowserService.cs +++ b/src/Playwright.NUnit/BrowserService.cs @@ -25,6 +25,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -50,10 +51,14 @@ private static async Task CreateBrowser(IBrowserType browserType, Play { if (connectOptions != null) { - return await browserType.ConnectAsync(connectOptions.WSEndpoint, connectOptions).ConfigureAwait(false); + var options = new BrowserTypeConnectOptions(connectOptions); + var headers = options.Headers?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value) ?? []; + headers.Add("x-playwright-launch-options", JsonSerializer.Serialize(PlaywrightSettingsProvider.LaunchOptions, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull })); + options.Headers = headers; + return await browserType.ConnectAsync(connectOptions.WSEndpoint, options).ConfigureAwait(false); } - var legacyBrowser = await ConnectToLegacyService(browserType); + var legacyBrowser = await ConnectBasedOnEnv(browserType); if (legacyBrowser != null) { return legacyBrowser; @@ -61,8 +66,8 @@ private static async Task CreateBrowser(IBrowserType browserType, Play return await browserType.LaunchAsync(PlaywrightSettingsProvider.LaunchOptions).ConfigureAwait(false); } - // TODO: Remove after Q3 2025 - private static async Task ConnectToLegacyService(IBrowserType browserType) + // TODO: Remove at some point + private static async Task ConnectBasedOnEnv(IBrowserType browserType) { var accessToken = Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_ACCESS_TOKEN"); var serviceUrl = Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_URL"); From 77b76985cfcc0465e55175d8a22a57269178dc21 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Thu, 30 Jan 2025 09:33:57 +0100 Subject: [PATCH 3/5] add XUnit/MSTest --- src/Playwright.MSTest/BrowserService.cs | 71 ++++++++++++------- src/Playwright.MSTest/BrowserTest.cs | 7 +- .../tests/mstest/basic.spec.ts | 46 ++++++++++++ .../tests/xunit/basic.spec.ts | 43 +++++++++++ src/Playwright.Xunit/BrowserService.cs | 36 +++++++--- src/Playwright.Xunit/BrowserTest.cs | 7 +- 6 files changed, 173 insertions(+), 37 deletions(-) diff --git a/src/Playwright.MSTest/BrowserService.cs b/src/Playwright.MSTest/BrowserService.cs index 3c62691631..99526e1700 100644 --- a/src/Playwright.MSTest/BrowserService.cs +++ b/src/Playwright.MSTest/BrowserService.cs @@ -25,6 +25,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -34,50 +35,66 @@ namespace Microsoft.Playwright.MSTest; internal class BrowserService : IWorkerService { - public IBrowser Browser { get; internal set; } = null!; - - public Task ResetAsync() => Task.CompletedTask; - - public Task DisposeAsync() => Browser?.CloseAsync() ?? Task.CompletedTask; + public IBrowser Browser { get; private set; } private BrowserService(IBrowser browser) { Browser = browser; } - public static Task Register(WorkerAwareTest test, IBrowserType browserType) + public static Task 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 CreateBrowser(IBrowserType browserType) + private static async Task CreateBrowser(IBrowserType browserType, PlaywrightConnectOptions? connectOptions) + { + if (connectOptions != null) + { + var options = new BrowserTypeConnectOptions(connectOptions); + var headers = options.Headers?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value) ?? []; + headers.Add("x-playwright-launch-options", JsonSerializer.Serialize(PlaywrightSettingsProvider.LaunchOptions, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull })); + options.Headers = headers; + return await browserType.ConnectAsync(connectOptions.WSEndpoint, options).ConfigureAwait(false); + } + + var legacyBrowser = await ConnectBasedOnEnv(browserType); + if (legacyBrowser != null) + { + return legacyBrowser; + } + return await browserType.LaunchAsync(PlaywrightSettingsProvider.LaunchOptions).ConfigureAwait(false); + } + + // TODO: Remove at some point + private static async Task ConnectBasedOnEnv(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; } - else + + var exposeNetwork = Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_EXPOSE_NETWORK") ?? ""; + 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}"; + + return await browserType.ConnectAsync(wsEndpoint, new BrowserTypeConnectOptions { - var exposeNetwork = Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_EXPOSE_NETWORK") ?? ""; - 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 + Timeout = 3 * 60 * 1000, + ExposeNetwork = exposeNetwork, + Headers = new Dictionary { - Timeout = 3 * 60 * 1000, - ExposeNetwork = exposeNetwork, - Headers = new Dictionary - { - ["Authorization"] = $"Bearer {accessToken}", - ["x-playwright-launch-options"] = JsonSerializer.Serialize(PlaywrightSettingsProvider.LaunchOptions, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }) - } - }; - - return await browserType.ConnectAsync(wsEndpoint, connectOptions).ConfigureAwait(false); - } + ["Authorization"] = $"Bearer {accessToken}", + ["x-playwright-launch-options"] = JsonSerializer.Serialize(PlaywrightSettingsProvider.LaunchOptions, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }) + } + }).ConfigureAwait(false); } + + public Task ResetAsync() => Task.CompletedTask; + public Task DisposeAsync() => Browser.CloseAsync(); } diff --git a/src/Playwright.MSTest/BrowserTest.cs b/src/Playwright.MSTest/BrowserTest.cs index f34bec19ff..922f486289 100644 --- a/src/Playwright.MSTest/BrowserTest.cs +++ b/src/Playwright.MSTest/BrowserTest.cs @@ -44,7 +44,7 @@ public async Task NewContextAsync(BrowserNewContextOptions? opt [TestInitialize] 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; } @@ -61,4 +61,9 @@ public async Task BrowserTearDown() _contexts.Clear(); Browser = null!; } + + public virtual PlaywrightConnectOptions? ConnectOptions() + { + return null; + } } diff --git a/src/Playwright.TestingHarnessTest/tests/mstest/basic.spec.ts b/src/Playwright.TestingHarnessTest/tests/mstest/basic.spec.ts index 16b6b70d2c..9c92aa2b36 100644 --- a/src/Playwright.TestingHarnessTest/tests/mstest/basic.spec.ts +++ b/src/Playwright.TestingHarnessTest/tests/mstest/basic.spec.ts @@ -491,3 +491,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.MSTest; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + namespace Playwright.TestingHarnessTest.MSTest; + + [TestClass] + public class : PageTest + { + [TestMethod] + 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); + }); +}); diff --git a/src/Playwright.TestingHarnessTest/tests/xunit/basic.spec.ts b/src/Playwright.TestingHarnessTest/tests/xunit/basic.spec.ts index e8db07be81..bf5a336526 100644 --- a/src/Playwright.TestingHarnessTest/tests/xunit/basic.spec.ts +++ b/src/Playwright.TestingHarnessTest/tests/xunit/basic.spec.ts @@ -537,3 +537,46 @@ 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.Xunit; + using Xunit; + namespace Playwright.TestingHarnessTest.Xunit; + public class : PageTest + { + [Fact] + 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); + }); +}); diff --git a/src/Playwright.Xunit/BrowserService.cs b/src/Playwright.Xunit/BrowserService.cs index 316abc7f97..9b5f46bae9 100644 --- a/src/Playwright.Xunit/BrowserService.cs +++ b/src/Playwright.Xunit/BrowserService.cs @@ -25,6 +25,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -41,19 +42,39 @@ private BrowserService(IBrowser browser) Browser = browser; } - public static Task Register(WorkerAwareTest test, IBrowserType browserType) + public static Task 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 CreateBrowser(IBrowserType browserType) + private static async Task CreateBrowser(IBrowserType browserType, PlaywrightConnectOptions? connectOptions) + { + if (connectOptions != null) + { + var options = new BrowserTypeConnectOptions(connectOptions); + var headers = options.Headers?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value) ?? []; + headers.Add("x-playwright-launch-options", JsonSerializer.Serialize(PlaywrightSettingsProvider.LaunchOptions, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull })); + options.Headers = headers; + return await browserType.ConnectAsync(connectOptions.WSEndpoint, options).ConfigureAwait(false); + } + + var legacyBrowser = await ConnectBasedOnEnv(browserType); + if (legacyBrowser != null) + { + return legacyBrowser; + } + return await browserType.LaunchAsync(PlaywrightSettingsProvider.LaunchOptions).ConfigureAwait(false); + } + + // TODO: Remove at some point + private static async Task ConnectBasedOnEnv(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") ?? ""; @@ -61,7 +82,8 @@ private static async Task CreateBrowser(IBrowserType browserType) 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, @@ -70,9 +92,7 @@ private static async Task 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; diff --git a/src/Playwright.Xunit/BrowserTest.cs b/src/Playwright.Xunit/BrowserTest.cs index 0540bfb17a..d6a0acef3b 100644 --- a/src/Playwright.Xunit/BrowserTest.cs +++ b/src/Playwright.Xunit/BrowserTest.cs @@ -42,7 +42,7 @@ public async Task NewContext(BrowserNewContextOptions? options public override async Task InitializeAsync() { await base.InitializeAsync().ConfigureAwait(false); - var service = await BrowserService.Register(this, BrowserType).ConfigureAwait(false); + var service = await BrowserService.Register(this, BrowserType, ConnectOptions()).ConfigureAwait(false); Browser = service.Browser; } @@ -59,4 +59,9 @@ public override async Task DisposeAsync() Browser = null!; await base.DisposeAsync().ConfigureAwait(false); } + + public virtual PlaywrightConnectOptions? ConnectOptions() + { + return null; + } } From a789a275f507966082168c3cacb651afe149e3f7 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Thu, 30 Jan 2025 13:45:29 +0100 Subject: [PATCH 4/5] chore: review feedback --- src/Playwright.MSTest/BrowserTest.cs | 6 +++--- src/Playwright.NUnit/BrowserTest.cs | 6 +++--- src/Playwright.TestAdapter/PlaywrightConnectOptions.cs | 2 +- src/Playwright.Xunit/BrowserTest.cs | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Playwright.MSTest/BrowserTest.cs b/src/Playwright.MSTest/BrowserTest.cs index 922f486289..f7ab383382 100644 --- a/src/Playwright.MSTest/BrowserTest.cs +++ b/src/Playwright.MSTest/BrowserTest.cs @@ -44,7 +44,7 @@ public async Task NewContextAsync(BrowserNewContextOptions? opt [TestInitialize] public async Task BrowserSetup() { - var service = await BrowserService.Register(this, BrowserType, ConnectOptions()).ConfigureAwait(false); + var service = await BrowserService.Register(this, BrowserType, await ConnectOptionsAsync()).ConfigureAwait(false); Browser = service.Browser; } @@ -62,8 +62,8 @@ public async Task BrowserTearDown() Browser = null!; } - public virtual PlaywrightConnectOptions? ConnectOptions() + public virtual Task ConnectOptionsAsync() { - return null; + return Task.FromResult(null); } } diff --git a/src/Playwright.NUnit/BrowserTest.cs b/src/Playwright.NUnit/BrowserTest.cs index 4691949699..7efdcfbafc 100644 --- a/src/Playwright.NUnit/BrowserTest.cs +++ b/src/Playwright.NUnit/BrowserTest.cs @@ -43,7 +43,7 @@ public async Task NewContext(BrowserNewContextOptions? options [SetUp] public async Task BrowserSetup() { - var service = await BrowserService.Register(this, BrowserType, ConnectOptions()).ConfigureAwait(false); + var service = await BrowserService.Register(this, BrowserType, await ConnectOptionsAsync()).ConfigureAwait(false); Browser = service.Browser; } @@ -61,8 +61,8 @@ public async Task BrowserTearDown() Browser = null!; } - public virtual PlaywrightConnectOptions? ConnectOptions() + public virtual Task ConnectOptionsAsync() { - return null; + return Task.FromResult(null); } } diff --git a/src/Playwright.TestAdapter/PlaywrightConnectOptions.cs b/src/Playwright.TestAdapter/PlaywrightConnectOptions.cs index be47967e44..881b6d044f 100644 --- a/src/Playwright.TestAdapter/PlaywrightConnectOptions.cs +++ b/src/Playwright.TestAdapter/PlaywrightConnectOptions.cs @@ -22,7 +22,7 @@ * SOFTWARE. */ -using Microsoft.Playwright; +namespace Microsoft.Playwright.TestAdapter; public class PlaywrightConnectOptions : BrowserTypeConnectOptions { diff --git a/src/Playwright.Xunit/BrowserTest.cs b/src/Playwright.Xunit/BrowserTest.cs index d6a0acef3b..a4b6de7589 100644 --- a/src/Playwright.Xunit/BrowserTest.cs +++ b/src/Playwright.Xunit/BrowserTest.cs @@ -42,7 +42,7 @@ public async Task NewContext(BrowserNewContextOptions? options public override async Task InitializeAsync() { await base.InitializeAsync().ConfigureAwait(false); - var service = await BrowserService.Register(this, BrowserType, ConnectOptions()).ConfigureAwait(false); + var service = await BrowserService.Register(this, BrowserType, await ConnectOptionsAsync()).ConfigureAwait(false); Browser = service.Browser; } @@ -60,8 +60,8 @@ public override async Task DisposeAsync() await base.DisposeAsync().ConfigureAwait(false); } - public virtual PlaywrightConnectOptions? ConnectOptions() + public virtual Task ConnectOptionsAsync() { - return null; + return Task.FromResult(null); } } From b6ee12c028426d7a16403dd688ee0dce67a826ea Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Thu, 30 Jan 2025 15:35:45 +0100 Subject: [PATCH 5/5] review feedback --- src/Playwright.MSTest/BrowserService.cs | 10 ++-- src/Playwright.MSTest/BrowserTest.cs | 5 +- src/Playwright.NUnit/BrowserService.cs | 10 ++-- src/Playwright.NUnit/BrowserTest.cs | 5 +- .../PlaywrightConnectOptions.cs | 30 ------------ .../package-lock.json | 46 +++++++++---------- .../package.json | 2 +- .../tests/baseTest.ts | 2 +- .../tests/mstest/basic.spec.ts | 7 ++- .../tests/nunit/basic.spec.ts | 7 ++- .../tests/xunit/basic.spec.ts | 9 ++-- src/Playwright.Xunit/BrowserService.cs | 10 ++-- src/Playwright.Xunit/BrowserTest.cs | 5 +- 13 files changed, 54 insertions(+), 94 deletions(-) delete mode 100644 src/Playwright.TestAdapter/PlaywrightConnectOptions.cs diff --git a/src/Playwright.MSTest/BrowserService.cs b/src/Playwright.MSTest/BrowserService.cs index 99526e1700..84c06274b7 100644 --- a/src/Playwright.MSTest/BrowserService.cs +++ b/src/Playwright.MSTest/BrowserService.cs @@ -42,20 +42,20 @@ private BrowserService(IBrowser browser) Browser = browser; } - public static Task Register(WorkerAwareTest test, IBrowserType browserType, PlaywrightConnectOptions? connectOptions) + public static Task Register(WorkerAwareTest test, IBrowserType browserType, (string, BrowserTypeConnectOptions?)? connectOptions) { return test.RegisterService("Browser", async () => new BrowserService(await CreateBrowser(browserType, connectOptions).ConfigureAwait(false))); } - private static async Task CreateBrowser(IBrowserType browserType, PlaywrightConnectOptions? connectOptions) + private static async Task CreateBrowser(IBrowserType browserType, (string WSEndpoint, BrowserTypeConnectOptions? Options)? connectOptions) { - if (connectOptions != null) + if (connectOptions.HasValue && connectOptions.Value.WSEndpoint != null) { - var options = new BrowserTypeConnectOptions(connectOptions); + var options = new BrowserTypeConnectOptions(connectOptions?.Options ?? new()); var headers = options.Headers?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value) ?? []; headers.Add("x-playwright-launch-options", JsonSerializer.Serialize(PlaywrightSettingsProvider.LaunchOptions, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull })); options.Headers = headers; - return await browserType.ConnectAsync(connectOptions.WSEndpoint, options).ConfigureAwait(false); + return await browserType.ConnectAsync(connectOptions!.Value.WSEndpoint, options).ConfigureAwait(false); } var legacyBrowser = await ConnectBasedOnEnv(browserType); diff --git a/src/Playwright.MSTest/BrowserTest.cs b/src/Playwright.MSTest/BrowserTest.cs index f7ab383382..904ae25bd8 100644 --- a/src/Playwright.MSTest/BrowserTest.cs +++ b/src/Playwright.MSTest/BrowserTest.cs @@ -62,8 +62,5 @@ public async Task BrowserTearDown() Browser = null!; } - public virtual Task ConnectOptionsAsync() - { - return Task.FromResult(null); - } + public virtual Task<(string, BrowserTypeConnectOptions?)?> ConnectOptionsAsync() => Task.FromResult<(string, BrowserTypeConnectOptions?)?>(null); } diff --git a/src/Playwright.NUnit/BrowserService.cs b/src/Playwright.NUnit/BrowserService.cs index 0574f3e3d9..0457008dfb 100644 --- a/src/Playwright.NUnit/BrowserService.cs +++ b/src/Playwright.NUnit/BrowserService.cs @@ -42,20 +42,20 @@ private BrowserService(IBrowser browser) Browser = browser; } - public static Task Register(WorkerAwareTest test, IBrowserType browserType, PlaywrightConnectOptions? connectOptions) + public static Task Register(WorkerAwareTest test, IBrowserType browserType, (string, BrowserTypeConnectOptions?)? connectOptions) { return test.RegisterService("Browser", async () => new BrowserService(await CreateBrowser(browserType, connectOptions).ConfigureAwait(false))); } - private static async Task CreateBrowser(IBrowserType browserType, PlaywrightConnectOptions? connectOptions) + private static async Task CreateBrowser(IBrowserType browserType, (string WSEndpoint, BrowserTypeConnectOptions? Options)? connectOptions) { - if (connectOptions != null) + if (connectOptions.HasValue && connectOptions.Value.WSEndpoint != null) { - var options = new BrowserTypeConnectOptions(connectOptions); + var options = new BrowserTypeConnectOptions(connectOptions?.Options ?? new()); var headers = options.Headers?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value) ?? []; headers.Add("x-playwright-launch-options", JsonSerializer.Serialize(PlaywrightSettingsProvider.LaunchOptions, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull })); options.Headers = headers; - return await browserType.ConnectAsync(connectOptions.WSEndpoint, options).ConfigureAwait(false); + return await browserType.ConnectAsync(connectOptions!.Value.WSEndpoint, options).ConfigureAwait(false); } var legacyBrowser = await ConnectBasedOnEnv(browserType); diff --git a/src/Playwright.NUnit/BrowserTest.cs b/src/Playwright.NUnit/BrowserTest.cs index 7efdcfbafc..529fe64e59 100644 --- a/src/Playwright.NUnit/BrowserTest.cs +++ b/src/Playwright.NUnit/BrowserTest.cs @@ -61,8 +61,5 @@ public async Task BrowserTearDown() Browser = null!; } - public virtual Task ConnectOptionsAsync() - { - return Task.FromResult(null); - } + public virtual Task<(string, BrowserTypeConnectOptions?)?> ConnectOptionsAsync() => Task.FromResult<(string, BrowserTypeConnectOptions?)?>(null); } diff --git a/src/Playwright.TestAdapter/PlaywrightConnectOptions.cs b/src/Playwright.TestAdapter/PlaywrightConnectOptions.cs deleted file mode 100644 index 881b6d044f..0000000000 --- a/src/Playwright.TestAdapter/PlaywrightConnectOptions.cs +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ - -namespace Microsoft.Playwright.TestAdapter; - -public class PlaywrightConnectOptions : BrowserTypeConnectOptions -{ - public string WSEndpoint = string.Empty; -} diff --git a/src/Playwright.TestingHarnessTest/package-lock.json b/src/Playwright.TestingHarnessTest/package-lock.json index 9d35402a58..ccff052ea6 100644 --- a/src/Playwright.TestingHarnessTest/package-lock.json +++ b/src/Playwright.TestingHarnessTest/package-lock.json @@ -7,19 +7,19 @@ "": { "name": "playwright.testingharnesstest", "devDependencies": { - "@playwright/test": "1.49.1", + "@playwright/test": "1.50.0", "@types/node": "^22.12.0", "fast-xml-parser": "^4.5.0" } }, "node_modules/@playwright/test": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.1.tgz", - "integrity": "sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g==", + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.0.tgz", + "integrity": "sha512-ZGNXbt+d65EGjBORQHuYKj+XhCewlwpnSd/EDuLPZGSiEWmgOJB5RmMCCYGy5aMfTs9wx61RivfDKi8H/hcMvw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.49.1" + "playwright": "1.50.0" }, "bin": { "playwright": "cli.js" @@ -77,13 +77,13 @@ } }, "node_modules/playwright": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.1.tgz", - "integrity": "sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==", + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.0.tgz", + "integrity": "sha512-+GinGfGTrd2IfX1TA4N2gNmeIksSb+IAe589ZH+FlmpV3MYTx6+buChGIuDLQwrGNCw2lWibqV50fU510N7S+w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.49.1" + "playwright-core": "1.50.0" }, "bin": { "playwright": "cli.js" @@ -96,9 +96,9 @@ } }, "node_modules/playwright-core": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.1.tgz", - "integrity": "sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==", + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.0.tgz", + "integrity": "sha512-CXkSSlr4JaZs2tZHI40DsZUN/NIwgaUPsyLuOAaIZp2CyF2sN5MM5NJsyB188lFSSozFxQ5fPT4qM+f0tH/6wQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -124,12 +124,12 @@ }, "dependencies": { "@playwright/test": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.1.tgz", - "integrity": "sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g==", + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.0.tgz", + "integrity": "sha512-ZGNXbt+d65EGjBORQHuYKj+XhCewlwpnSd/EDuLPZGSiEWmgOJB5RmMCCYGy5aMfTs9wx61RivfDKi8H/hcMvw==", "dev": true, "requires": { - "playwright": "1.49.1" + "playwright": "1.50.0" } }, "@types/node": { @@ -158,19 +158,19 @@ "optional": true }, "playwright": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.1.tgz", - "integrity": "sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==", + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.0.tgz", + "integrity": "sha512-+GinGfGTrd2IfX1TA4N2gNmeIksSb+IAe589ZH+FlmpV3MYTx6+buChGIuDLQwrGNCw2lWibqV50fU510N7S+w==", "dev": true, "requires": { "fsevents": "2.3.2", - "playwright-core": "1.49.1" + "playwright-core": "1.50.0" } }, "playwright-core": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.1.tgz", - "integrity": "sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==", + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.0.tgz", + "integrity": "sha512-CXkSSlr4JaZs2tZHI40DsZUN/NIwgaUPsyLuOAaIZp2CyF2sN5MM5NJsyB188lFSSozFxQ5fPT4qM+f0tH/6wQ==", "dev": true }, "strnum": { diff --git a/src/Playwright.TestingHarnessTest/package.json b/src/Playwright.TestingHarnessTest/package.json index a01067610d..2f1df75269 100644 --- a/src/Playwright.TestingHarnessTest/package.json +++ b/src/Playwright.TestingHarnessTest/package.json @@ -4,6 +4,6 @@ "devDependencies": { "@types/node": "^22.12.0", "fast-xml-parser": "^4.5.0", - "@playwright/test": "1.49.1" + "@playwright/test": "1.50.0" } } diff --git a/src/Playwright.TestingHarnessTest/tests/baseTest.ts b/src/Playwright.TestingHarnessTest/tests/baseTest.ts index cec1cd2f40..024c38d77e 100644 --- a/src/Playwright.TestingHarnessTest/tests/baseTest.ts +++ b/src/Playwright.TestingHarnessTest/tests/baseTest.ts @@ -38,7 +38,7 @@ export const test = base.extend<{ for (const server of servers) await server.close(); }, - runTest: async ({ }, use, testInfo) => { + runTest: async ({ testMode }, use, testInfo) => { const testResults: RunResult[] = []; await use(async (files, command, env) => { const testDir = testInfo.outputPath(); diff --git a/src/Playwright.TestingHarnessTest/tests/mstest/basic.spec.ts b/src/Playwright.TestingHarnessTest/tests/mstest/basic.spec.ts index 9c92aa2b36..80ef324d1d 100644 --- a/src/Playwright.TestingHarnessTest/tests/mstest/basic.spec.ts +++ b/src/Playwright.TestingHarnessTest/tests/mstest/basic.spec.ts @@ -496,6 +496,7 @@ test.describe('ConnectOptions', () => { const ExampleTestWithConnectOptions = ` using System; using System.Threading.Tasks; + using Microsoft.Playwright; using Microsoft.Playwright.MSTest; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -509,11 +510,9 @@ test.describe('ConnectOptions', () => { { await Page.GotoAsync("about:blank"); } - public override PlaywrightConnectOptions ConnectOptions() + public override async Task<(string, BrowserTypeConnectOptions)?> ConnectOptionsAsync() { - return new() { - WSEndpoint = "http://127.0.0.1:1234", - }; + return ("http://127.0.0.1:1234", null); } }`; diff --git a/src/Playwright.TestingHarnessTest/tests/nunit/basic.spec.ts b/src/Playwright.TestingHarnessTest/tests/nunit/basic.spec.ts index 19f002f363..495e064322 100644 --- a/src/Playwright.TestingHarnessTest/tests/nunit/basic.spec.ts +++ b/src/Playwright.TestingHarnessTest/tests/nunit/basic.spec.ts @@ -492,6 +492,7 @@ test.describe('ConnectOptions', () => { const ExampleTestWithConnectOptions = ` using System; using System.Threading.Tasks; + using Microsoft.Playwright; using Microsoft.Playwright.NUnit; using NUnit.Framework; @@ -505,11 +506,9 @@ test.describe('ConnectOptions', () => { await Page.GotoAsync("about:blank"); } - public override PlaywrightConnectOptions ConnectOptions() + public override async Task<(string, BrowserTypeConnectOptions)?> ConnectOptionsAsync() { - return new() { - WSEndpoint = "http://127.0.0.1:1234", - }; + return ("http://127.0.0.1:1234", null); } }`; diff --git a/src/Playwright.TestingHarnessTest/tests/xunit/basic.spec.ts b/src/Playwright.TestingHarnessTest/tests/xunit/basic.spec.ts index bf5a336526..d5c2896f99 100644 --- a/src/Playwright.TestingHarnessTest/tests/xunit/basic.spec.ts +++ b/src/Playwright.TestingHarnessTest/tests/xunit/basic.spec.ts @@ -542,9 +542,12 @@ test.describe('ConnectOptions', () => { const ExampleTestWithConnectOptions = ` using System; using System.Threading.Tasks; + using Microsoft.Playwright; using Microsoft.Playwright.Xunit; using Xunit; + namespace Playwright.TestingHarnessTest.Xunit; + public class : PageTest { [Fact] @@ -552,11 +555,9 @@ test.describe('ConnectOptions', () => { { await Page.GotoAsync("about:blank"); } - public override PlaywrightConnectOptions ConnectOptions() + public override async Task<(string, BrowserTypeConnectOptions)?> ConnectOptionsAsync() { - return new() { - WSEndpoint = "http://127.0.0.1:1234", - }; + return ("http://127.0.0.1:1234", null); } }`; diff --git a/src/Playwright.Xunit/BrowserService.cs b/src/Playwright.Xunit/BrowserService.cs index 9b5f46bae9..0b5d0f8988 100644 --- a/src/Playwright.Xunit/BrowserService.cs +++ b/src/Playwright.Xunit/BrowserService.cs @@ -42,20 +42,20 @@ private BrowserService(IBrowser browser) Browser = browser; } - public static Task Register(WorkerAwareTest test, IBrowserType browserType, PlaywrightConnectOptions? connectOptions) + public static Task Register(WorkerAwareTest test, IBrowserType browserType, (string, BrowserTypeConnectOptions?)? connectOptions) { return test.RegisterService("Browser", async () => new BrowserService(await CreateBrowser(browserType, connectOptions).ConfigureAwait(false))); } - private static async Task CreateBrowser(IBrowserType browserType, PlaywrightConnectOptions? connectOptions) + private static async Task CreateBrowser(IBrowserType browserType, (string WSEndpoint, BrowserTypeConnectOptions? Options)? connectOptions) { - if (connectOptions != null) + if (connectOptions.HasValue && connectOptions.Value.WSEndpoint != null) { - var options = new BrowserTypeConnectOptions(connectOptions); + var options = new BrowserTypeConnectOptions(connectOptions?.Options ?? new()); var headers = options.Headers?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value) ?? []; headers.Add("x-playwright-launch-options", JsonSerializer.Serialize(PlaywrightSettingsProvider.LaunchOptions, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull })); options.Headers = headers; - return await browserType.ConnectAsync(connectOptions.WSEndpoint, options).ConfigureAwait(false); + return await browserType.ConnectAsync(connectOptions!.Value.WSEndpoint, options).ConfigureAwait(false); } var legacyBrowser = await ConnectBasedOnEnv(browserType); diff --git a/src/Playwright.Xunit/BrowserTest.cs b/src/Playwright.Xunit/BrowserTest.cs index a4b6de7589..e76e791a77 100644 --- a/src/Playwright.Xunit/BrowserTest.cs +++ b/src/Playwright.Xunit/BrowserTest.cs @@ -60,8 +60,5 @@ public override async Task DisposeAsync() await base.DisposeAsync().ConfigureAwait(false); } - public virtual Task ConnectOptionsAsync() - { - return Task.FromResult(null); - } + public virtual Task<(string, BrowserTypeConnectOptions?)?> ConnectOptionsAsync() => Task.FromResult<(string, BrowserTypeConnectOptions?)?>(null); }