using System.Text.Json.Nodes; using decePubClient.E2E.Support; using Microsoft.Playwright; namespace decePubClient.E2E.Actions { // A remote thread opened in decePub fills with the replies PrivaPub never received: opening it has PrivaPub read the // thread from its server (Mastodon's FEP-7888 context), and the page reads the thread again a few seconds later public sealed class ThreadTests(Browser browser) { const string Platform = "mastodon"; const string Author = "elif_ms06"; // followed by no persona, so Mastodon never delivers her reply to PrivaPub const string Outsider = "gigi_ms28"; static async Task Drive(string user, string verb, JsonObject parameters) => await Pasture.Town("drive", Platform, user, verb, parameters.ToJsonString()); [Fact] public async Task A_remote_thread_brings_the_replies_that_never_reached_privapub() { var persona = Pasture.Personas().First(); var mark = Guid.NewGuid().ToString("N")[..8]; var root = await Drive(Author, "post", new JsonObject { ["text"] = $"a thread to open {mark}", ["visibility"] = "public" }); var rootUri = root["uri"]!.GetValue(); string replyUri = null; try { var reply = await Drive(Outsider, "post", new JsonObject { ["text"] = $"said where nobody listens {mark}", ["visibility"] = "public", ["reply_to_uri"] = rootUri }); replyUri = reply["uri"]!.GetValue(); var found = await PersonaApi.Call(persona, $"/api/v2/search?q={Uri.EscapeDataString(rootUri)}&resolve=true&type=statuses"); var rootId = found!["statuses"]!.AsArray().Single()!["id"]!.GetValue(); await Task.Delay(3000); Assert.SkipWhen((await Pasture.Stored("privapub", replyUri))[replyUri]?["exists"]?.GetValue() == true, $"{Outsider}'s reply reached PrivaPub by delivery, so the thread proves nothing"); await using var session = await SignIn.As(browser, persona); var page = session.Page; await Results.Cell("client.render.thread-backfill", Platform, persona.UserName, async () => { await page.GotoAsync($"{Pasture.Site}/expand/{rootId}"); await page.Locator($"article[data-uri='{rootUri}']").First.WaitForAsync(new() { Timeout = 30000 }); var answer = page.Locator($"article[data-uri='{replyUri}']"); await Assertions.Expect(answer).ToContainTextAsync($"said where nobody listens {mark}", new() { Timeout = 25000 }); await session.AssertGuards(); }, page); } finally { if (replyUri is not null) await Drive(Outsider, "delete", new JsonObject { ["uri"] = replyUri }); await Drive(Author, "delete", new JsonObject { ["uri"] = rootUri }); } } } }