using System.Text.Json.Nodes; using decePubClient.E2E.Support; using Microsoft.Playwright; namespace decePubClient.E2E.Actions { // The home feed hears of a new post and of its deletion through PrivaPub's streaming API, in seconds, where polling // would take up to 45 public sealed class StreamingTests(Browser browser) { [Fact] public async Task A_post_made_elsewhere_waits_behind_the_new_button_and_its_deletion_takes_it_away() { var persona = Pasture.Personas().First(); var text = $"streamed {Guid.NewGuid():N}"[..21]; await using var session = await SignIn.As(browser, persona); var page = session.Page; JsonNode post = null; try { await Results.Cell("client.render.stream", "privapub", persona.UserName, async () => { await page.GotoAsync($"{Pasture.Site}/"); await page.EvaluateAsync("() => localStorage.removeItem('FeedFilter')"); await page.GotoAsync($"{Pasture.Site}/"); await page.Locator("article[data-uri], [data-feed-empty]").First.WaitForAsync(new() { Timeout = 30000 }); // the stream opens once the first page is shown await Task.Delay(1500); post = await PersonaApi.Call(persona, "/api/v1/statuses", HttpMethod.Post, new JsonObject { ["status"] = text, ["visibility"] = "unlisted" }); var fresh = page.GetByRole(AriaRole.Button, new() { Name = "1 new" }); await fresh.WaitForAsync(new() { Timeout = 10000 }); await fresh.ClickAsync(); var card = page.Locator($"article[data-uri='{post!["uri"]!.GetValue()}']"); await Assertions.Expect(card).ToContainTextAsync(text, new() { Timeout = 5000 }); await PersonaApi.Call(persona, $"/api/v1/statuses/{post["id"]!.GetValue()}", HttpMethod.Delete); post = null; await Assertions.Expect(card).ToHaveCountAsync(0, new() { Timeout = 10000 }); await session.AssertGuards(); }, page); } finally { if (post is not null) await PersonaApi.Call(persona, $"/api/v1/statuses/{post["id"]!.GetValue()}", HttpMethod.Delete); } } } }