File: Playwright\PlaywrightTest.cs
Web Access
Project: src\aspnetcore\src\Components\Testing\src\Microsoft.AspNetCore.Components.Testing.csproj (Microsoft.AspNetCore.Components.Testing)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Microsoft.Playwright;
 
namespace Microsoft.AspNetCore.Components.Testing.Playwright;
 
/// <summary>
/// Base class for MSTest tests that need access to a shared <see cref="IPlaywright"/>
/// instance and the static <see cref="Expect(IPage)"/> assertion helpers. Mirrors the
/// shape of <c>Microsoft.Playwright.MSTest.PlaywrightTest</c> without taking a
/// dependency on that package.
/// </summary>
/// <remarks>
/// The <see cref="IPlaywright"/> instance is created lazily on first access and is
/// shared by every test in the test assembly. It is intentionally not disposed —
/// the underlying Node.js driver process is reaped when the test host exits.
/// </remarks>
public abstract class PlaywrightTest : UITest
{
    private static IPlaywright? s_playwright;
    private static readonly SemaphoreSlim s_initLock = new(1, 1);
 
    /// <summary>The shared Playwright instance. Initialized on first use.</summary>
    public IPlaywright Playwright =>
        s_playwright ?? throw new InvalidOperationException(
            $"Playwright has not been initialized. Call {nameof(EnsurePlaywrightAsync)} from a test " +
            "initializer or use a derived class that does so (e.g. BrowserTest, ContextTest, PageTest).");
 
    /// <summary>
    /// Returns the shared <see cref="IPlaywright"/>, creating it on first call. Safe to
    /// invoke concurrently — initialization is serialized.
    /// </summary>
    public static async Task<IPlaywright> EnsurePlaywrightAsync()
    {
        if (s_playwright is not null)
        {
            return s_playwright;
        }
 
        await s_initLock.WaitAsync().ConfigureAwait(false);
        try
        {
            s_playwright ??= await Microsoft.Playwright.Playwright.CreateAsync().ConfigureAwait(false);
            return s_playwright;
        }
        finally
        {
            s_initLock.Release();
        }
    }
 
    /// <summary>Returns assertions on the given <see cref="IPage"/>.</summary>
    public static IPageAssertions Expect(IPage page) => Assertions.Expect(page);
 
    /// <summary>Returns assertions on the given <see cref="ILocator"/>.</summary>
    public static ILocatorAssertions Expect(ILocator locator) => Assertions.Expect(locator);
 
    /// <summary>Returns assertions on the given <see cref="IAPIResponse"/>.</summary>
    public static IAPIResponseAssertions Expect(IAPIResponse response) => Assertions.Expect(response);
}