2026-10-05 06:20:18 +02:00
|
|
|
using System.Text.Json.Nodes;
|
|
|
|
|
|
|
|
|
|
using decePubClient.E2E.Support;
|
|
|
|
|
|
|
|
|
|
using Microsoft.Playwright;
|
|
|
|
|
|
|
|
|
|
namespace decePubClient.E2E.Actions
|
|
|
|
|
{
|
|
|
|
|
// Administration as the pasture's administrator (pastureroot, whom the scenarios make): a server blocked for everyone
|
|
|
|
|
// and unblocked, the federation statistics, and the reports moderators handle; each change checked on /clientapi
|
|
|
|
|
public sealed class AdministrationTests(Browser browser)
|
|
|
|
|
{
|
2026-10-06 16:47:19 +02:00
|
|
|
const string Root = PastureAdmin.Root;
|
|
|
|
|
static readonly Pasture.Persona Admin = new("alice", "alice", Root, PastureAdmin.Password, null, null, null);
|
2026-10-05 06:20:18 +02:00
|
|
|
|
2026-10-06 16:47:19 +02:00
|
|
|
static Task<JsonNode> AsAdmin(string path) => PastureAdmin.Get(path);
|
2026-10-05 06:20:18 +02:00
|
|
|
|
|
|
|
|
static async Task<ILocator> Open(IPage page, string section)
|
|
|
|
|
{
|
|
|
|
|
await page.GotoAsync($"{Pasture.Site}/administration");
|
|
|
|
|
var header = page.Locator(".collapse-title", new() { HasText = section }).First;
|
|
|
|
|
await header.ClickAsync();
|
|
|
|
|
return header.Locator("xpath=..");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task A_server_is_blocked_for_everyone_and_unblocked()
|
|
|
|
|
{
|
|
|
|
|
const string server = "instance-block-by-e2e.example";
|
|
|
|
|
await using var session = await SignIn.As(browser, Admin);
|
|
|
|
|
var page = session.Page;
|
|
|
|
|
await Results.Cell("client.admin.server-block", "privapub", Root, async () =>
|
|
|
|
|
{
|
|
|
|
|
var panel = await Open(page, "Blocked servers");
|
|
|
|
|
var blocks = panel.Locator("[data-server-blocks]");
|
|
|
|
|
await blocks.WaitForAsync(new() { Timeout = 30000 });
|
|
|
|
|
await blocks.Locator("[data-server-block-domain]").FillAsync(server);
|
|
|
|
|
await blocks.GetByRole(AriaRole.Button, new() { Name = "Block server" }).ClickAsync();
|
|
|
|
|
var row = blocks.Locator($"[data-server-block='{server}']");
|
|
|
|
|
await Assertions.Expect(row).ToContainTextAsync("Suspended", new() { Timeout = 15000 });
|
|
|
|
|
Assert.Contains((await AsAdmin("/clientapi/admin/domainblocks/list"))!.AsArray(), b => b!["domain"]!.GetValue<string>() == server);
|
|
|
|
|
|
|
|
|
|
await row.GetByRole(AriaRole.Button, new() { Name = "Unblock" }).ClickAsync();
|
|
|
|
|
await Assertions.Expect(row).ToHaveCountAsync(0, new() { Timeout = 15000 });
|
|
|
|
|
Assert.DoesNotContain((await AsAdmin("/clientapi/admin/domainblocks/list"))!.AsArray(), b => b!["domain"]!.GetValue<string>() == server);
|
|
|
|
|
await session.AssertGuards();
|
|
|
|
|
}, page);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task The_federation_statistics_and_the_reports_are_shown()
|
|
|
|
|
{
|
|
|
|
|
await using var session = await SignIn.As(browser, Admin);
|
|
|
|
|
var page = session.Page;
|
|
|
|
|
await Results.Cell("client.admin.statistics", "privapub", Root, async () =>
|
|
|
|
|
{
|
|
|
|
|
var panel = await Open(page, "Statistics");
|
|
|
|
|
await Assertions.Expect(panel.Locator("[data-statistics-overview]")).ToBeVisibleAsync(new() { Timeout = 30000 });
|
|
|
|
|
var expected = (await AsAdmin("/clientapi/admin/statistics/hosts?days=30&sort=traffic&page=1&limit=50"))!["hosts"]!.AsArray()
|
|
|
|
|
.Select(h => h!["host"]!.GetValue<string>()).Take(5).ToList();
|
|
|
|
|
Assert.NotEmpty(expected);
|
|
|
|
|
foreach (var host in expected)
|
|
|
|
|
await Assertions.Expect(panel.Locator($"[data-statistics-host='{host}']")).ToHaveCountAsync(1, new() { Timeout = 15000 });
|
|
|
|
|
|
|
|
|
|
var reports = await Open(page, "Reports");
|
|
|
|
|
await Assertions.Expect(reports.Locator("[data-reports]")).ToBeVisibleAsync(new() { Timeout = 30000 });
|
|
|
|
|
var open = (await AsAdmin("/clientapi/moderator/reports?resolved=false"))!.AsArray().Count;
|
|
|
|
|
await Assertions.Expect(reports.Locator("[data-report-id]")).ToHaveCountAsync(open, new() { Timeout = 15000 });
|
|
|
|
|
await session.AssertGuards();
|
|
|
|
|
}, page);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|