Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 1f53577

Browse files
committedJan 30, 2025·
add XUnit/MSTest
1 parent 9f889d6 commit 1f53577

File tree

6 files changed

+173
-37
lines changed

6 files changed

+173
-37
lines changed
 

‎src/Playwright.MSTest/BrowserService.cs

+44-27
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
using System;
2626
using System.Collections.Generic;
2727
using System.Globalization;
28+
using System.Linq;
2829
using System.Text.Json;
2930
using System.Text.Json.Serialization;
3031
using System.Threading.Tasks;
@@ -34,50 +35,66 @@ namespace Microsoft.Playwright.MSTest;
3435

3536
internal class BrowserService : IWorkerService
3637
{
37-
public IBrowser Browser { get; internal set; } = null!;
38-
39-
public Task ResetAsync() => Task.CompletedTask;
40-
41-
public Task DisposeAsync() => Browser?.CloseAsync() ?? Task.CompletedTask;
38+
public IBrowser Browser { get; private set; }
4239

4340
private BrowserService(IBrowser browser)
4441
{
4542
Browser = browser;
4643
}
4744

48-
public static Task<BrowserService> Register(WorkerAwareTest test, IBrowserType browserType)
45+
public static Task<BrowserService> Register(WorkerAwareTest test, IBrowserType browserType, PlaywrightConnectOptions? connectOptions)
4946
{
50-
return test.RegisterService("Browser", async () => new BrowserService(await CreateBrowser(browserType).ConfigureAwait(false)));
47+
return test.RegisterService("Browser", async () => new BrowserService(await CreateBrowser(browserType, connectOptions).ConfigureAwait(false)));
5148
}
5249

53-
private static async Task<IBrowser> CreateBrowser(IBrowserType browserType)
50+
private static async Task<IBrowser> CreateBrowser(IBrowserType browserType, PlaywrightConnectOptions? connectOptions)
51+
{
52+
if (connectOptions != null)
53+
{
54+
var options = new BrowserTypeConnectOptions(connectOptions);
55+
var headers = options.Headers?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value) ?? [];
56+
headers.Add("x-playwright-launch-options", JsonSerializer.Serialize(PlaywrightSettingsProvider.LaunchOptions, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }));
57+
options.Headers = headers;
58+
return await browserType.ConnectAsync(connectOptions.WSEndpoint, options).ConfigureAwait(false);
59+
}
60+
61+
var legacyBrowser = await ConnectBasedOnEnv(browserType);
62+
if (legacyBrowser != null)
63+
{
64+
return legacyBrowser;
65+
}
66+
return await browserType.LaunchAsync(PlaywrightSettingsProvider.LaunchOptions).ConfigureAwait(false);
67+
}
68+
69+
// TODO: Remove at some point
70+
private static async Task<IBrowser?> ConnectBasedOnEnv(IBrowserType browserType)
5471
{
5572
var accessToken = Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_ACCESS_TOKEN");
5673
var serviceUrl = Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_URL");
5774

5875
if (string.IsNullOrEmpty(accessToken) || string.IsNullOrEmpty(serviceUrl))
5976
{
60-
return await browserType.LaunchAsync(PlaywrightSettingsProvider.LaunchOptions).ConfigureAwait(false);
77+
return null;
6178
}
62-
else
79+
80+
var exposeNetwork = Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_EXPOSE_NETWORK") ?? "<loopback>";
81+
var os = Uri.EscapeDataString(Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_OS") ?? "linux");
82+
var runId = Uri.EscapeDataString(Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_RUN_ID") ?? DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture));
83+
var apiVersion = "2023-10-01-preview";
84+
var wsEndpoint = $"{serviceUrl}?os={os}&runId={runId}&api-version={apiVersion}";
85+
86+
return await browserType.ConnectAsync(wsEndpoint, new BrowserTypeConnectOptions
6387
{
64-
var exposeNetwork = Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_EXPOSE_NETWORK") ?? "<loopback>";
65-
var os = Uri.EscapeDataString(Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_OS") ?? "linux");
66-
var runId = Uri.EscapeDataString(Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_RUN_ID") ?? DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture));
67-
var apiVersion = "2023-10-01-preview";
68-
var wsEndpoint = $"{serviceUrl}?os={os}&runId={runId}&api-version={apiVersion}";
69-
var connectOptions = new BrowserTypeConnectOptions
88+
Timeout = 3 * 60 * 1000,
89+
ExposeNetwork = exposeNetwork,
90+
Headers = new Dictionary<string, string>
7091
{
71-
Timeout = 3 * 60 * 1000,
72-
ExposeNetwork = exposeNetwork,
73-
Headers = new Dictionary<string, string>
74-
{
75-
["Authorization"] = $"Bearer {accessToken}",
76-
["x-playwright-launch-options"] = JsonSerializer.Serialize(PlaywrightSettingsProvider.LaunchOptions, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull })
77-
}
78-
};
79-
80-
return await browserType.ConnectAsync(wsEndpoint, connectOptions).ConfigureAwait(false);
81-
}
92+
["Authorization"] = $"Bearer {accessToken}",
93+
["x-playwright-launch-options"] = JsonSerializer.Serialize(PlaywrightSettingsProvider.LaunchOptions, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull })
94+
}
95+
}).ConfigureAwait(false);
8296
}
97+
98+
public Task ResetAsync() => Task.CompletedTask;
99+
public Task DisposeAsync() => Browser.CloseAsync();
83100
}

‎src/Playwright.MSTest/BrowserTest.cs

+6-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public async Task<IBrowserContext> NewContextAsync(BrowserNewContextOptions? opt
4444
[TestInitialize]
4545
public async Task BrowserSetup()
4646
{
47-
var service = await BrowserService.Register(this, BrowserType).ConfigureAwait(false);
47+
var service = await BrowserService.Register(this, BrowserType, ConnectOptions()).ConfigureAwait(false);
4848
Browser = service.Browser;
4949
}
5050

@@ -61,4 +61,9 @@ public async Task BrowserTearDown()
6161
_contexts.Clear();
6262
Browser = null!;
6363
}
64+
65+
public virtual PlaywrightConnectOptions? ConnectOptions()
66+
{
67+
return null;
68+
}
6469
}

‎src/Playwright.TestingHarnessTest/tests/mstest/basic.spec.ts

+46
Original file line numberDiff line numberDiff line change
@@ -509,3 +509,49 @@ test.describe('Expect() timeout', () => {
509509
expect(result.rawStdout).toContain("LocatorAssertions.ToHaveTextAsync with timeout 123ms")
510510
});
511511
});
512+
513+
test.describe('ConnectOptions', () => {
514+
const ExampleTestWithConnectOptions = `
515+
using System;
516+
using System.Threading.Tasks;
517+
using Microsoft.Playwright.MSTest;
518+
using Microsoft.VisualStudio.TestTools.UnitTesting;
519+
520+
namespace Playwright.TestingHarnessTest.MSTest;
521+
522+
[TestClass]
523+
public class <class-name> : PageTest
524+
{
525+
[TestMethod]
526+
public async Task Test()
527+
{
528+
await Page.GotoAsync("about:blank");
529+
}
530+
public override PlaywrightConnectOptions ConnectOptions()
531+
{
532+
return new() {
533+
WSEndpoint = "http://127.0.0.1:1234",
534+
};
535+
}
536+
}`;
537+
538+
test('should fail when the server is not reachable', async ({ runTest }) => {
539+
const result = await runTest({
540+
'ExampleTests.cs': ExampleTestWithConnectOptions,
541+
}, 'dotnet test');
542+
expect(result.passed).toBe(0);
543+
expect(result.failed).toBe(1);
544+
expect(result.total).toBe(1);
545+
expect(result.rawStdout).toContain('connect ECONNREFUSED 127.0.0.1:1234')
546+
});
547+
548+
test('should pass when the server is reachable', async ({ runTest, launchServer }) => {
549+
await launchServer({ port: 1234 });
550+
const result = await runTest({
551+
'ExampleTests.cs': ExampleTestWithConnectOptions,
552+
}, 'dotnet test');
553+
expect(result.passed).toBe(1);
554+
expect(result.failed).toBe(0);
555+
expect(result.total).toBe(1);
556+
});
557+
});

‎src/Playwright.TestingHarnessTest/tests/xunit/basic.spec.ts

+43
Original file line numberDiff line numberDiff line change
@@ -556,3 +556,46 @@ test.describe('Expect() timeout', () => {
556556
expect(result.rawStdout).toContain("LocatorAssertions.ToHaveTextAsync with timeout 123ms")
557557
});
558558
});
559+
560+
test.describe('ConnectOptions', () => {
561+
const ExampleTestWithConnectOptions = `
562+
using System;
563+
using System.Threading.Tasks;
564+
using Microsoft.Playwright.Xunit;
565+
using Xunit;
566+
namespace Playwright.TestingHarnessTest.Xunit;
567+
public class <class-name> : PageTest
568+
{
569+
[Fact]
570+
public async Task Test()
571+
{
572+
await Page.GotoAsync("about:blank");
573+
}
574+
public override PlaywrightConnectOptions ConnectOptions()
575+
{
576+
return new() {
577+
WSEndpoint = "http://127.0.0.1:1234",
578+
};
579+
}
580+
}`;
581+
582+
test('should fail when the server is not reachable', async ({ runTest }) => {
583+
const result = await runTest({
584+
'ExampleTests.cs': ExampleTestWithConnectOptions,
585+
}, 'dotnet test');
586+
expect(result.passed).toBe(0);
587+
expect(result.failed).toBe(1);
588+
expect(result.total).toBe(1);
589+
expect(result.rawStdout).toContain('connect ECONNREFUSED 127.0.0.1:1234')
590+
});
591+
592+
test('should pass when the server is reachable', async ({ runTest, launchServer }) => {
593+
await launchServer({ port: 1234 });
594+
const result = await runTest({
595+
'ExampleTests.cs': ExampleTestWithConnectOptions,
596+
}, 'dotnet test');
597+
expect(result.passed).toBe(1);
598+
expect(result.failed).toBe(0);
599+
expect(result.total).toBe(1);
600+
});
601+
});

‎src/Playwright.Xunit/BrowserService.cs

+28-8
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
using System;
2626
using System.Collections.Generic;
2727
using System.Globalization;
28+
using System.Linq;
2829
using System.Text.Json;
2930
using System.Text.Json.Serialization;
3031
using System.Threading.Tasks;
@@ -41,27 +42,48 @@ private BrowserService(IBrowser browser)
4142
Browser = browser;
4243
}
4344

44-
public static Task<BrowserService> Register(WorkerAwareTest test, IBrowserType browserType)
45+
public static Task<BrowserService> Register(WorkerAwareTest test, IBrowserType browserType, PlaywrightConnectOptions? connectOptions)
4546
{
46-
return test.RegisterService("Browser", async () => new BrowserService(await CreateBrowser(browserType).ConfigureAwait(false)));
47+
return test.RegisterService("Browser", async () => new BrowserService(await CreateBrowser(browserType, connectOptions).ConfigureAwait(false)));
4748
}
4849

49-
private static async Task<IBrowser> CreateBrowser(IBrowserType browserType)
50+
private static async Task<IBrowser> CreateBrowser(IBrowserType browserType, PlaywrightConnectOptions? connectOptions)
51+
{
52+
if (connectOptions != null)
53+
{
54+
var options = new BrowserTypeConnectOptions(connectOptions);
55+
var headers = options.Headers?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value) ?? [];
56+
headers.Add("x-playwright-launch-options", JsonSerializer.Serialize(PlaywrightSettingsProvider.LaunchOptions, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }));
57+
options.Headers = headers;
58+
return await browserType.ConnectAsync(connectOptions.WSEndpoint, options).ConfigureAwait(false);
59+
}
60+
61+
var legacyBrowser = await ConnectBasedOnEnv(browserType);
62+
if (legacyBrowser != null)
63+
{
64+
return legacyBrowser;
65+
}
66+
return await browserType.LaunchAsync(PlaywrightSettingsProvider.LaunchOptions).ConfigureAwait(false);
67+
}
68+
69+
// TODO: Remove at some point
70+
private static async Task<IBrowser?> ConnectBasedOnEnv(IBrowserType browserType)
5071
{
5172
var accessToken = Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_ACCESS_TOKEN");
5273
var serviceUrl = Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_URL");
5374

5475
if (string.IsNullOrEmpty(accessToken) || string.IsNullOrEmpty(serviceUrl))
5576
{
56-
return await browserType.LaunchAsync(PlaywrightSettingsProvider.LaunchOptions).ConfigureAwait(false);
77+
return null;
5778
}
5879

5980
var exposeNetwork = Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_EXPOSE_NETWORK") ?? "<loopback>";
6081
var os = Uri.EscapeDataString(Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_OS") ?? "linux");
6182
var runId = Uri.EscapeDataString(Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_RUN_ID") ?? DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture));
6283
var apiVersion = "2023-10-01-preview";
6384
var wsEndpoint = $"{serviceUrl}?os={os}&runId={runId}&api-version={apiVersion}";
64-
var connectOptions = new BrowserTypeConnectOptions
85+
86+
return await browserType.ConnectAsync(wsEndpoint, new BrowserTypeConnectOptions
6587
{
6688
Timeout = 3 * 60 * 1000,
6789
ExposeNetwork = exposeNetwork,
@@ -70,9 +92,7 @@ private static async Task<IBrowser> CreateBrowser(IBrowserType browserType)
7092
["Authorization"] = $"Bearer {accessToken}",
7193
["x-playwright-launch-options"] = JsonSerializer.Serialize(PlaywrightSettingsProvider.LaunchOptions, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull })
7294
}
73-
};
74-
75-
return await browserType.ConnectAsync(wsEndpoint, connectOptions).ConfigureAwait(false);
95+
}).ConfigureAwait(false);
7696
}
7797

7898
public Task ResetAsync() => Task.CompletedTask;

‎src/Playwright.Xunit/BrowserTest.cs

+6-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public async Task<IBrowserContext> NewContext(BrowserNewContextOptions? options
4242
public override async Task InitializeAsync()
4343
{
4444
await base.InitializeAsync().ConfigureAwait(false);
45-
var service = await BrowserService.Register(this, BrowserType).ConfigureAwait(false);
45+
var service = await BrowserService.Register(this, BrowserType, ConnectOptions()).ConfigureAwait(false);
4646
Browser = service.Browser;
4747
}
4848

@@ -59,4 +59,9 @@ public override async Task DisposeAsync()
5959
Browser = null!;
6060
await base.DisposeAsync().ConfigureAwait(false);
6161
}
62+
63+
public virtual PlaywrightConnectOptions? ConnectOptions()
64+
{
65+
return null;
66+
}
6267
}

0 commit comments

Comments
 (0)
Please sign in to comment.