Skip to content

Commit

Permalink
chore: align MSTest & NUnit Workers implementation (#3042)
Browse files Browse the repository at this point in the history
  • Loading branch information
mxschmitt authored Nov 8, 2024
1 parent a732283 commit d8b42ff
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 167 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
using System.Threading.Tasks;
using Microsoft.Playwright.TestAdapter;

namespace Microsoft.Playwright.MSTest.Services;
namespace Microsoft.Playwright.MSTest;

internal class BrowserService : IWorkerService
{
Expand All @@ -38,14 +38,24 @@ internal class BrowserService : IWorkerService

public Task DisposeAsync() => Browser?.CloseAsync() ?? Task.CompletedTask;

public async Task BuildAsync(PlaywrightTest parentTest)
private BrowserService(IBrowser browser)
{
Browser = browser;
}

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

private static async Task<IBrowser> CreateBrowser(IBrowserType browserType)
{
var accessToken = Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_ACCESS_TOKEN");
var serviceUrl = Environment.GetEnvironmentVariable("PLAYWRIGHT_SERVICE_URL");

if (string.IsNullOrEmpty(accessToken) || string.IsNullOrEmpty(serviceUrl))
{
Browser = await parentTest!.BrowserType!.LaunchAsync(PlaywrightSettingsProvider.LaunchOptions).ConfigureAwait(false);
return await browserType.LaunchAsync(PlaywrightSettingsProvider.LaunchOptions).ConfigureAwait(false);
}
else
{
Expand All @@ -64,7 +74,7 @@ public async Task BuildAsync(PlaywrightTest parentTest)
}
};

Browser = await parentTest!.BrowserType!.ConnectAsync(wsEndpoint, connectOptions).ConfigureAwait(false);
return await browserType.ConnectAsync(wsEndpoint, connectOptions).ConfigureAwait(false);
}
}
}
6 changes: 3 additions & 3 deletions src/Playwright.MSTest/BrowserTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Playwright.MSTest.Services;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Microsoft.Playwright.MSTest;
Expand All @@ -45,13 +44,14 @@ public async Task<IBrowserContext> NewContextAsync(BrowserNewContextOptions? opt
[TestInitialize]
public async Task BrowserSetup()
{
Browser = (await GetService<BrowserService>().ConfigureAwait(false)).Browser;
var service = await BrowserService.Register(this, BrowserType).ConfigureAwait(false);
Browser = service.Browser;
}

[TestCleanup]
public async Task BrowserTearDown()
{
if (TestOK)
if (TestOK())
{
foreach (var context in _contexts)
{
Expand Down
34 changes: 0 additions & 34 deletions src/Playwright.MSTest/IWorkerService.cs

This file was deleted.

2 changes: 1 addition & 1 deletion src/Playwright.MSTest/PageTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ public class PageTest : ContextTest
[TestInitialize]
public async Task PageSetup()
{
Page = await Context!.NewPageAsync().ConfigureAwait(false);
Page = await Context.NewPageAsync().ConfigureAwait(false);
}
}
84 changes: 3 additions & 81 deletions src/Playwright.MSTest/PlaywrightTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,108 +22,30 @@
* SOFTWARE.
*/

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Playwright.Core;
using Microsoft.Playwright.TestAdapter;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Microsoft.Playwright.MSTest;

[TestClass]
public class PlaywrightTest
public class PlaywrightTest : WorkerAwareTest
{
private static int _workerCount = 0;
private static readonly ConcurrentStack<Worker> _allWorkers = new();
private Worker? _currentWorker;
private static readonly Task<IPlaywright> _playwrightTask = Microsoft.Playwright.Playwright.CreateAsync();

public string BrowserName { get; private set; } = null!;
public IPlaywright Playwright { get; private set; } = null!;

public IBrowserType BrowserType { get; private set; } = null!;

public int WorkerIndex => _currentWorker!.WorkerIndex;

[TestInitialize]
public async Task Setup()
public async Task PlaywrightSetup()
{
if (PlaywrightSettingsProvider.ExpectTimeout.HasValue)
{
AssertionsBase.SetDefaultTimeout(PlaywrightSettingsProvider.ExpectTimeout.Value);
}
try
{
Playwright = await _playwrightTask.ConfigureAwait(false);
}
catch (Exception e)
{
Assert.Fail(e.Message, e.StackTrace);
}
Assert.IsNotNull(Playwright, "Playwright could not be instantiated.");
Playwright = await _playwrightTask.ConfigureAwait(false);
BrowserName = PlaywrightSettingsProvider.BrowserName;
BrowserType = Playwright[BrowserName];

// get worker
if (!_allWorkers.TryPop(out _currentWorker))
{
_currentWorker = new();
}
Playwright.Selectors.SetTestIdAttribute("data-testid");
}

[TestCleanup]
public async Task Teardown()
{
if (TestOK)
{
await Task.WhenAll(_currentWorker!.InstantiatedServices.Select(x => x.ResetAsync())).ConfigureAwait(false);
_allWorkers.Push(_currentWorker);
}
else
{
await Task.WhenAll(_currentWorker!.InstantiatedServices.Select(x => x.DisposeAsync())).ConfigureAwait(false);
_currentWorker.InstantiatedServices.Clear();
}
}

public async Task<T> GetService<T>(Func<T>? factory = null) where T : class, IWorkerService, new()
{
factory ??= () => new T();
var serviceType = typeof(T);

var instance = _currentWorker!.InstantiatedServices.SingleOrDefault(x => serviceType.IsInstanceOfType(x));
if (instance == null)
{
instance = factory();
await instance.BuildAsync(this).ConfigureAwait(false);
_currentWorker.InstantiatedServices.Add(instance);
}

if (instance is not T)
throw new Exception("There was a problem instantiating the service.");

return (T)instance;
}

private class Worker
{
public int WorkerIndex { get; } = Interlocked.Increment(ref _workerCount);
public List<IWorkerService> InstantiatedServices { get; } = new();
}

protected bool TestOK
{
get => TestContext!.CurrentTestOutcome == UnitTestOutcome.Passed
|| TestContext!.CurrentTestOutcome == UnitTestOutcome.NotRunnable;
}

public TestContext TestContext { get; set; } = null!;

public static void SetDefaultExpectTimeout(float timeout) => Assertions.SetDefaultExpectTimeout(timeout);

public ILocatorAssertions Expect(ILocator locator) => Assertions.Expect(locator);
Expand Down
83 changes: 83 additions & 0 deletions src/Playwright.MSTest/WorkerAwareTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Playwright.Core;
using Microsoft.Playwright.TestAdapter;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Microsoft.Playwright.MSTest;

public class WorkerAwareTest
{
public TestContext TestContext { get; set; } = null!;

private static readonly ConcurrentStack<Worker> _allWorkers = new();
private Worker _currentWorker = null!;

private class Worker
{
private static int _lastWorkedIndex = 0;
public int WorkerIndex { get; } = Interlocked.Increment(ref _lastWorkedIndex);
public Dictionary<string, IWorkerService> Services = [];
}

public int WorkerIndex => _currentWorker!.WorkerIndex;

public async Task<T> RegisterService<T>(string name, Func<Task<T>> factory) where T : class, IWorkerService
{
if (!_currentWorker.Services.ContainsKey(name))
{
_currentWorker.Services[name] = await factory().ConfigureAwait(false);
}

return (_currentWorker.Services[name] as T)!;
}

[TestInitialize]
public void WorkerSetup()
{
if (PlaywrightSettingsProvider.ExpectTimeout.HasValue)
{
AssertionsBase.SetDefaultTimeout(PlaywrightSettingsProvider.ExpectTimeout.Value);
}

if (!_allWorkers.TryPop(out _currentWorker))
{
_currentWorker = new();
}
}

[TestCleanup]
public async Task WorkerTeardown()
{
if (TestOK())
{
foreach (var kv in _currentWorker.Services)
{
await kv.Value.ResetAsync().ConfigureAwait(false);
}
_allWorkers.Push(_currentWorker);
}
else
{
foreach (var kv in _currentWorker.Services)
{
await kv.Value.DisposeAsync().ConfigureAwait(false);
}
_currentWorker.Services.Clear();
}
}

protected bool TestOK()
{
return TestContext!.CurrentTestOutcome == UnitTestOutcome.Passed
|| TestContext!.CurrentTestOutcome == UnitTestOutcome.NotRunnable;
}
}

public interface IWorkerService
{
public Task ResetAsync();
public Task DisposeAsync();
}
12 changes: 6 additions & 6 deletions src/Playwright.NUnit/ContextTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ public class ContextTest : BrowserTest
{
public IBrowserContext Context { get; private set; } = null!;

[SetUp]
public async Task ContextSetup()
{
Context = await NewContext(ContextOptions()).ConfigureAwait(false);
}

public virtual BrowserNewContextOptions ContextOptions()
{
return new()
Expand All @@ -39,10 +45,4 @@ public virtual BrowserNewContextOptions ContextOptions()
ColorScheme = ColorScheme.Light,
};
}

[SetUp]
public async Task ContextSetup()
{
Context = await NewContext(ContextOptions()).ConfigureAwait(false);
}
}
33 changes: 0 additions & 33 deletions src/Playwright.NUnit/IWorkerService.cs

This file was deleted.

Loading

0 comments on commit d8b42ff

Please sign in to comment.