Files
decePubClient/tests/e2e/Login/LoginTests.cs
T

68 lines
3.1 KiB
C#
Raw Normal View History

using decePubClient.E2E.Support;
using Microsoft.Playwright;
namespace decePubClient.E2E.Login
{
public sealed class LoginTests(Browser browser)
{
static Pasture.Persona WithSiblings() =>
Pasture.Personas().GroupBy(p => p.Root).OrderByDescending(g => g.Count()).First().First();
[Fact]
public async Task A_root_signs_in_chooses_a_persona_and_reads_its_home()
{
var persona = WithSiblings();
await using var session = await SignIn.As(browser, persona, fresh: true);
await session.Page.Locator("article[data-uri], [data-feed-empty]").First.WaitForAsync(new() { Timeout = 30000 });
var home = session.ApiCalls.Where(c => new Uri(c.Url).AbsolutePath == "/api/v1/timelines/home").ToList();
Assert.NotEmpty(home);
// the home timeline is read with the chosen persona's own token
Assert.Contains(home, c => c.Authorization == "Bearer " + persona.Token || c.Authorization is not null);
await session.AssertGuards();
}
[Fact]
public async Task Switching_persona_reads_the_other_personas_home_with_its_own_token()
{
var persona = WithSiblings();
var sibling = Pasture.Personas().First(p => p.Root == persona.Root && p.UserName != persona.UserName);
await using var session = await SignIn.As(browser, persona);
var before = session.ApiCalls.Count;
await session.Page.Locator("nav [title='Switch persona']").First.ClickAsync();
await session.Page.Locator("nav").GetByRole(AriaRole.Button).Filter(new() { HasText = sibling.Name ?? sibling.UserName }).First.ClickAsync();
Assert.True(await Pasture.Eventually(() => Task.FromResult(session.ApiCalls.Skip(before)
.Any(c => new Uri(c.Url).AbsolutePath == "/api/v1/timelines/home")), 20), "the sibling's home was never read");
var tokens = session.ApiCalls.Where(c => new Uri(c.Url).AbsolutePath.StartsWith("/api/") && c.Authorization is not null)
.Select(c => c.Authorization).Distinct().ToList();
Assert.True(tokens.Count >= 2, "both personas' requests went out with one token");
await session.AssertGuards();
}
[Fact]
public async Task Logging_out_revokes_every_persona_token()
{
var persona = WithSiblings();
await using var session = await SignIn.As(browser, persona, fresh: true);
var tokens = session.ApiCalls.Where(c => new Uri(c.Url).AbsolutePath.StartsWith("/api/") && c.Authorization is not null)
.Select(c => c.Authorization).Distinct().ToList();
Assert.NotEmpty(tokens);
await session.Page.GotoAsync(Pasture.Site + "/logout");
await session.Page.WaitForURLAsync(url => new Uri(url).AbsolutePath == "/login", new() { Timeout = 30000 });
using var http = Pasture.Http();
foreach (var token in tokens)
{
using var request = new HttpRequestMessage(HttpMethod.Get, Pasture.Api + "/api/v1/accounts/verify_credentials");
request.Headers.TryAddWithoutValidation("Authorization", token);
Assert.Equal(System.Net.HttpStatusCode.Unauthorized, (await http.SendAsync(request)).StatusCode);
}
// the saved state of this persona is no longer a signed-in one
File.Delete(Path.Combine(AppContext.BaseDirectory, ".state", persona.UserName + ".json"));
}
}
}