test(playwright): token-endpoint tests tolerate DisableLogin

Under DisableLogin /auth/token deliberately answers 404 (lane K). The tests
now probe it: on a login-disabled rig TokenEndpoint_ReturnsJwt skips and the
bad-credentials test asserts 404 (the exchange is closed); with login enabled
they keep the 200 + JWT and 401 assertions.
This commit is contained in:
Joseph Doherty
2026-10-22 14:01:40 -04:00
parent 4ae3ed3fdd
commit a04eb3a752
@@ -74,15 +74,17 @@ public class LoginTests
Assert.Equal(200, status); // redirect followed to login page
}
/// <summary>Verifies that the token endpoint returns a JWT for valid credentials.</summary>
/// <summary>
/// Verifies that the token endpoint returns a JWT for valid credentials. Skipped when the
/// rig runs with <c>DisableLogin</c>, where <c>/auth/token</c> deliberately answers 404.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
[SkippableFact]
public async Task TokenEndpoint_ReturnsJwt()
{
var page = await _fixture.NewPageAsync();
await page.GotoAsync($"{PlaywrightFixture.BaseUrl}/login");
await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded);
var page = await OpenLoginPageAsync();
Skip.If(await TokenEndpointDisabledAsync(page),
"Login is disabled on this rig: POST /auth/token answers 404 by design, so no JWT is issued.");
var result = await page.EvaluateAsync<JsonElement>(@"
async () => {
@@ -101,29 +103,50 @@ public class LoginTests
Assert.Equal("multi-role", result.GetProperty("username").GetString());
}
/// <summary>Verifies that the token endpoint returns HTTP 401 for invalid credentials.</summary>
/// <summary>
/// Verifies that the token endpoint rejects invalid credentials: HTTP 401 with login
/// enabled, or HTTP 404 under <c>DisableLogin</c> (the exchange is closed entirely, so
/// even bad credentials can never reach a credential check).
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task TokenEndpoint_InvalidCredentials_Returns401()
{
var page = await _fixture.NewPageAsync();
var page = await OpenLoginPageAsync();
var disabled = await TokenEndpointDisabledAsync(page);
var status = await PostTokenAsync(page, "baduser", "badpass");
Assert.Equal(disabled ? 404 : 401, status);
}
private async Task<IPage> OpenLoginPageAsync()
{
var page = await _fixture.NewPageAsync();
await page.GotoAsync($"{PlaywrightFixture.BaseUrl}/login");
await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded);
return page;
}
var status = await page.EvaluateAsync<int>(@"
async () => {
/// <summary>
/// Probes whether the rig runs with <c>DisableLogin</c>: the token exchange then answers
/// 404 for any request (AuthEndpoints.HandleTokenAsync), while with login enabled a
/// valid-credential POST is a 200 and never a 404.
/// </summary>
private static async Task<bool> TokenEndpointDisabledAsync(IPage page) =>
await PostTokenAsync(page, PlaywrightFixture.TestUsername, PlaywrightFixture.TestPassword) == 404;
private static Task<int> PostTokenAsync(IPage page, string username, string password) =>
page.EvaluateAsync<int>(@"
async ([u, p]) => {
const resp = await fetch('/auth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'username=baduser&password=badpass'
body: new URLSearchParams({ username: u, password: p }).toString()
});
return resp.status;
}
");
Assert.Equal(401, status);
}
", new object[] { username, password });
private static ILocatorAssertions Expect(ILocator locator) =>
Assertions.Expect(locator);