The Groups page (/groups, in the menu) is where a persona makes a community or a circle (with its invitation code and an optional password), joins one by invitation and leaves one. For the groups it runs it edits them, shows the invitation, lets in or declines the requests to join, and takes members out, through PrivaPub's new /clientapi/group/members, reject and remove. The e2e makes a circle, joins it as another persona with the code, and has the owner take that member out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
59 lines
2.7 KiB
C#
59 lines
2.7 KiB
C#
using decePubClient.E2E.Support;
|
|
|
|
using Microsoft.Playwright;
|
|
|
|
namespace decePubClient.E2E.Actions
|
|
{
|
|
// A circle made in decePub, joined by another persona with its invitation code, and that member taken out by the
|
|
// owner, who alone sees who is in it
|
|
public sealed class GroupTests(Browser browser)
|
|
{
|
|
[Fact]
|
|
public async Task A_circle_is_made_joined_by_invitation_and_its_member_taken_out()
|
|
{
|
|
var personas = Pasture.Personas();
|
|
Assert.SkipWhen(personas.Count < 2, "the town has fewer than two personas");
|
|
var (owner, joiner) = (personas[0], personas[1]);
|
|
var userName = $"e2ecircle{DateTime.UtcNow:MMddHHmmss}";
|
|
await using var ownerSession = await SignIn.As(browser, owner);
|
|
await using var joinerSession = await SignIn.As(browser, joiner);
|
|
var page = ownerSession.Page;
|
|
await Results.Cell("client.action.group", "privapub", owner.UserName, async () =>
|
|
{
|
|
await page.GotoAsync($"{Pasture.Site}/groups");
|
|
var form = page.Locator("[data-group-new]");
|
|
await form.Locator("input[data-group-username]").FillAsync(userName);
|
|
await form.Locator("input[data-group-name]").FillAsync(userName);
|
|
await form.Locator("[data-group-create]").ClickAsync();
|
|
var invitation = page.Locator("[data-group-invitation]");
|
|
await invitation.WaitForAsync(new() { Timeout = 30000 });
|
|
var code = await invitation.InputValueAsync();
|
|
Assert.Equal(64, code.Length);
|
|
|
|
var other = joinerSession.Page;
|
|
await other.GotoAsync($"{Pasture.Site}/groups");
|
|
var join = other.Locator("[data-group-join]");
|
|
await join.Locator("input[data-group-code]").FillAsync(code);
|
|
await join.Locator("[data-group-join-submit]").ClickAsync();
|
|
await other.Locator("article[data-group-id] [data-group-leave]").First.WaitForAsync(new() { Timeout = 30000 });
|
|
|
|
// closed and opened again, so its members are read after the join
|
|
var card = page.Locator("article[data-group-id]").Filter(new() { HasText = "@" + userName });
|
|
await card.Locator("[data-group-manage]").ClickAsync();
|
|
await card.Locator("[data-group-manage]").ClickAsync();
|
|
var member = card.Locator($"[data-member='{joiner.ActorUri}']");
|
|
await member.WaitForAsync(new() { Timeout = 30000 });
|
|
Assert.Equal("false", await member.GetAttributeAsync("data-pending"));
|
|
await member.Locator("[data-member-remove]").ClickAsync();
|
|
await Assertions.Expect(member).ToHaveCountAsync(0, new() { Timeout = 15000 });
|
|
|
|
await other.ReloadAsync();
|
|
await other.Locator("[data-group-new]").WaitForAsync(new() { Timeout = 30000 });
|
|
await Assertions.Expect(other.Locator("article[data-group-id]").Filter(new() { HasText = "@" + userName })).ToHaveCountAsync(0, new() { Timeout = 15000 });
|
|
await ownerSession.AssertGuards();
|
|
await joinerSession.AssertGuards();
|
|
}, page);
|
|
}
|
|
}
|
|
}
|