| File: Infrastructure\TestLockClient.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.Infrastructure; /// <summary> /// High-level client for deterministic async state control via <see cref="TestLockProvider"/>. /// Encapsulates session ID generation, cookie setup, and lock release HTTP calls. /// </summary> /// <remarks> /// <para>Create a client, then use <see cref="Lock"/> to gate server-side async operations:</para> /// <code> /// var locks = await TestLockClient.CreateAsync(server, context); /// await using (locks.Lock("weather-data")) /// { /// // Verify loading state while data is blocked /// } /// // Lock released automatically /// </code> /// </remarks> public class TestLockClient { private readonly ServerInstance _server; private readonly string _sessionId; TestLockClient(ServerInstance server, string sessionId) { _server = server; _sessionId = sessionId; } /// <summary> /// Creates a lock client, generates a unique session ID, and sets /// the <c>test-session-id</c> cookie on the browser context. /// </summary> /// <param name="server">The server instance to control locks on.</param> /// <param name="context">The browser context to set the session cookie on.</param> /// <returns>A <see cref="TestLockClient"/> bound to the server and session.</returns> public static async Task<TestLockClient> CreateAsync( ServerInstance server, IBrowserContext context) { var sessionId = Guid.NewGuid().ToString("N")[..8]; await context.SetTestSession(server, sessionId).ConfigureAwait(false); return new TestLockClient(server, sessionId); } /// <summary> /// Creates a lock handle for the given name. The server-side lock key /// is <c>{sessionId}:{name}</c>. The lock is released when the handle is /// disposed or when <see cref="RemoteLock.ReleaseAsync"/> is called explicitly. /// </summary> /// <param name="name">The lock name (combined with the session ID to form the full key).</param> /// <returns>A <see cref="RemoteLock"/> that releases the named gate on disposal.</returns> public RemoteLock Lock(string name) => new(_server, $"{_sessionId}:{name}"); }