using System.Text.Json.Nodes; using decePubClient.E2E.Support; using Microsoft.Playwright; namespace decePubClient.E2E.Actions { // The composer beyond words: a poll in a language picked, the persona's own post edited, and a quote, each checked on // PrivaPub public sealed class ComposerTests(Browser browser) { static async Task OpenHome(IPage page) { 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 }); } static async Task Latest(Pasture.Persona persona) => (await PersonaApi.Call(persona, $"/api/v1/accounts/{persona.LocalId}/statuses?limit=1"))!.AsArray().FirstOrDefault(); [Fact] public async Task A_poll_is_published_from_the_composer() { var persona = Pasture.Personas().First(); var text = $"which one {Guid.NewGuid():N}"[..18]; await using var session = await SignIn.As(browser, persona); var page = session.Page; string made = null; try { await Results.Cell("client.action.poll", "privapub", persona.UserName, async () => { await OpenHome(page); await page.GetByRole(AriaRole.Button, new() { Name = "Post" }).First.ClickAsync(); await page.Locator("textarea[data-compose]").First.FillAsync(text); await page.Locator("button[data-poll-toggle]").ClickAsync(); var choices = page.Locator("[data-poll-editor] input[type=text]"); await choices.Nth(0).FillAsync("tea"); await choices.Nth(1).FillAsync("coffee"); // and in the language picked await page.Locator("[data-compose-language]").First.SelectOptionAsync("it"); await page.GetByRole(AriaRole.Button, new() { Name = "Post" }).Last.ClickAsync(); JsonNode latest = null; Assert.True(await Pasture.Eventually(async () => (latest = await Latest(persona))?["content"]?.GetValue().Contains(text) == true, 15), "the poll was never published"); made = latest!["id"]!.GetValue(); Assert.Equal(new[] { "tea", "coffee" }, latest["poll"]!["options"]!.AsArray().Select(o => o!["title"]!.GetValue())); Assert.Equal("it", latest["language"]?.GetValue()); await session.AssertGuards(); }, page); } finally { if (made is not null) await PersonaApi.Call(persona, $"/api/v1/statuses/{made}", HttpMethod.Delete); } } [Fact] public async Task The_personas_own_post_is_edited_and_quoted_from_its_card() { var persona = Pasture.Personas().First(); var text = $"first words {Guid.NewGuid():N}"[..20]; var post = (await PersonaApi.Call(persona, "/api/v1/statuses", HttpMethod.Post, new JsonObject { ["status"] = text, ["visibility"] = "public" }))!; var id = post["id"]!.GetValue(); string quote = null; await using var session = await SignIn.As(browser, persona); var page = session.Page; try { await Results.Cell("client.action.edit-quote", "privapub", persona.UserName, async () => { await OpenHome(page); var card = page.Locator($"article[data-uri='{post["uri"]!.GetValue()}']").First; await card.WaitForAsync(new() { Timeout = 30000 }); await card.Locator("footer [title='Other'] > [role=button]").ClickAsync(); await card.Locator("button[data-edit]").ClickAsync(); var box = card.Locator("textarea[data-compose]"); await Assertions.Expect(box).ToHaveValueAsync(text, new() { Timeout = 10000 }); await box.FillAsync(text + " (edited)"); await card.GetByRole(AriaRole.Button, new() { Name = "Save" }).ClickAsync(); await Assertions.Expect(card).ToContainTextAsync(text + " (edited)", new() { Timeout = 10000 }); Assert.Contains("(edited)", (await PersonaApi.Call(persona, $"/api/v1/statuses/{id}"))!["content"]!.GetValue()); await card.Locator("footer [title='Other'] > [role=button]").ClickAsync(); await card.Locator("button[data-quote]").ClickAsync(); await card.Locator("textarea[data-compose]").FillAsync("quoting myself"); await card.GetByRole(AriaRole.Button, new() { Name = "Quote" }).Last.ClickAsync(); JsonNode latest = null; Assert.True(await Pasture.Eventually(async () => (latest = await Latest(persona))?["content"]?.GetValue().Contains("quoting myself") == true, 15), "the quote was never published"); quote = latest!["id"]!.GetValue(); Assert.Equal(id, (latest["quote"]?["quoted_status"]?["id"] ?? latest["quote"]?["quoted_status_id"])?.GetValue()); await session.AssertGuards(); }, page); } finally { if (quote is not null) await PersonaApi.Call(persona, $"/api/v1/statuses/{quote}", HttpMethod.Delete); await PersonaApi.Call(persona, $"/api/v1/statuses/{id}", HttpMethod.Delete); } } } }