Files

84 lines
4.1 KiB
C#
Raw Permalink Normal View History

2026-10-06 16:47:19 +02:00
using System.Text.Json.Nodes;
using decePubClient.E2E.Support;
using Microsoft.Playwright;
namespace decePubClient.E2E.Actions
{
// A persona reports a remote account from its profile, with a category, its words and a copy to the account's server:
// PrivaPub's moderators see it, forwarded (/clientapi/moderator/reports). And who liked or boosted a post is listed
// from its card
public sealed class ReportTests(Browser browser)
{
[Fact]
public async Task A_remote_account_is_reported_from_its_profile()
{
var persona = Pasture.Personas().First();
var target = (await PersonaApi.Call(persona, "/api/v2/search?q=mastouser%40mastodon.test&resolve=true&type=accounts"))?["accounts"]?.AsArray().FirstOrDefault();
Assert.SkipWhen(target is null, "no Mastodon: run tools/pasture/run.sh add mastodon");
var targetId = target!["id"]!.GetValue<string>();
var words = $"reported by the e2e tests {Guid.NewGuid():N}"[..40];
await using var session = await SignIn.As(browser, persona);
var page = session.Page;
await Results.Cell("client.action.report", "mastodon", persona.UserName, async () =>
{
await page.GotoAsync($"{Pasture.Site}/account/{Uri.EscapeDataString(targetId)}");
// (the profile's own button: each of its posts' cards has one too)
await page.Locator($"article[data-account-id='{targetId}'] button[data-report]").ClickAsync(new() { Timeout = 30000 });
var dialog = page.Locator("[data-report-dialog]");
await dialog.Locator("[data-report-category]").SelectOptionAsync("Spam");
await dialog.Locator("[data-report-comment]").FillAsync(words);
await Assertions.Expect(dialog.Locator("[data-report-forward]")).ToBeCheckedAsync();
await dialog.Locator("[data-report-send]").ClickAsync();
await Assertions.Expect(dialog).ToHaveCountAsync(0, new() { Timeout = 15000 });
var report = (await PastureAdmin.Get("/clientapi/moderator/reports?resolved=false"))!.AsArray()
.FirstOrDefault(r => r!["comment"]?.GetValue<string>() == words);
Assert.NotNull(report);
Assert.Equal((targetId, "spam", true), (report!["targetAccountId"]!.GetValue<string>(), report["category"]!.GetValue<string>(),
report["forwarded"]!.GetValue<bool>()));
await session.AssertGuards();
}, page);
}
[Fact]
public async Task Who_liked_and_boosted_a_post_is_listed_from_its_card()
{
var personas = Pasture.Personas();
Assert.SkipWhen(personas.Count < 2, "the town has one persona");
var (author, fan) = (personas[0], personas[1]);
var post = (await PersonaApi.Call(author, "/api/v1/statuses", HttpMethod.Post,
new JsonObject { ["status"] = $"like and boost me {Guid.NewGuid():N}"[..28], ["visibility"] = "public" }))!;
var id = post["id"]!.GetValue<string>();
var fanAcct = (await PersonaApi.Call(fan, "/api/v1/accounts/verify_credentials"))!["acct"]!.GetValue<string>();
await PersonaApi.Call(fan, $"/api/v1/statuses/{id}/favourite", HttpMethod.Post);
await PersonaApi.Call(fan, $"/api/v1/statuses/{id}/reblog", HttpMethod.Post);
await using var session = await SignIn.As(browser, author);
var page = session.Page;
try
{
await Results.Cell("client.render.interacted-by", "privapub", author.UserName, async () =>
{
await page.GotoAsync($"{Pasture.Site}/expand/{Uri.EscapeDataString(id)}");
var card = page.Locator($"article[data-uri='{post["uri"]!.GetValue<string>()}']").First;
await card.WaitForAsync(new() { Timeout = 30000 });
foreach (var (button, list) in new[] { ("data-liked-by", "likes"), ("data-boosted-by", "boosts") })
{
await card.Locator("footer [title='Other'] > [role=button]").ClickAsync();
await card.Locator($"button[{button}]").ClickAsync();
var dialog = card.Locator($"[data-interacted-by='{list}']");
await Assertions.Expect(dialog.Locator($"[data-account='{fanAcct}']")).ToHaveCountAsync(1, new() { Timeout = 15000 });
await page.Keyboard.PressAsync("Escape");
await Assertions.Expect(dialog).ToHaveCountAsync(0);
}
await session.AssertGuards();
}, page);
}
finally
{
await PersonaApi.Call(author, $"/api/v1/statuses/{id}", HttpMethod.Delete);
}
}
}
}