Files
decePubClient/tests/e2e/Actions/DiscoveryTests.cs
T

111 lines
5.9 KiB
C#
Raw Normal View History

using System.Text.Json.Nodes;
using decePubClient.E2E.Support;
using Microsoft.Playwright;
namespace decePubClient.E2E.Actions
{
// Posts written for later, hashtags followed and what Explore shows, each checked against PrivaPub's own answer
public sealed class DiscoveryTests(Browser browser)
{
[Fact]
public async Task A_post_scheduled_in_the_composer_waits_is_moved_and_is_dropped()
{
var persona = Pasture.Personas().First();
var text = $"later {Guid.NewGuid():N}"[..20];
await using var session = await SignIn.As(browser, persona);
var page = session.Page;
await Results.Cell("client.action.schedule", "privapub", persona.UserName, async () =>
{
await page.EvaluateAsync("() => localStorage.removeItem('FeedFilter')");
await page.GotoAsync($"{Pasture.Site}/");
await page.GetByRole(AriaRole.Button, new() { Name = "Post" }).First.ClickAsync();
await page.Locator("textarea").First.FillAsync(text);
await page.Locator("button[data-schedule]").ClickAsync();
await page.Locator("input[data-schedule-at]").FillAsync(DateTime.Now.AddHours(2).ToString("yyyy-MM-ddTHH:mm"));
await page.GetByRole(AriaRole.Button, new() { Name = "Schedule" }).ClickAsync();
JsonNode waiting = null;
Assert.True(await Pasture.Eventually(async () => (waiting = (await PersonaApi.Call(persona, "/api/v1/scheduled_statuses"))!.AsArray()
.FirstOrDefault(s => s!["params"]!["text"]?.GetValue<string>() == text)) is not null, 15), "PrivaPub never kept the scheduled post");
var id = waiting!["id"]!.GetValue<string>();
Assert.DoesNotContain((await PersonaApi.Call(persona, $"/api/v1/accounts/{persona.LocalId}/statuses?limit=10"))!.AsArray(),
s => s!["content"]!.GetValue<string>().Contains(text));
await page.GotoAsync($"{Pasture.Site}/scheduled");
var item = page.Locator($"article[data-scheduled-id='{id}']");
await Assertions.Expect(item).ToContainTextAsync(text, new() { Timeout = 15000 });
var later = DateTime.Now.AddHours(5);
await item.Locator("input[type=datetime-local]").FillAsync(later.ToString("yyyy-MM-ddTHH:mm"));
await item.GetByRole(AriaRole.Button, new() { Name = "Move" }).ClickAsync();
Assert.True(await Pasture.Eventually(async () =>
(await PersonaApi.Call(persona, $"/api/v1/scheduled_statuses/{id}"))?["scheduled_at"]?.GetValue<DateTime>().ToUniversalTime()
is { } at && Math.Abs((at - later.ToUniversalTime()).TotalMinutes) < 2, 15), "PrivaPub never moved the post");
await item.GetByRole(AriaRole.Button, new() { Name = "Never publish it" }).ClickAsync();
2026-10-06 23:28:22 +02:00
await page.Locator("[data-confirm-yes]").ClickAsync();
await Assertions.Expect(item).ToHaveCountAsync(0, new() { Timeout = 15000 });
Assert.Null(await PersonaApi.Call(persona, $"/api/v1/scheduled_statuses/{id}"));
await session.AssertGuards();
}, page);
}
[Fact]
public async Task A_hashtag_is_followed_from_its_feed_tab_and_listed_in_explore()
{
var persona = Pasture.Personas().First();
var tag = $"e2etag{Guid.NewGuid():N}"[..14];
await using var session = await SignIn.As(browser, persona);
var page = session.Page;
try
{
await Results.Cell("client.action.follow-tag", "privapub", persona.UserName, async () =>
{
// a reader finds the hashtag through search, which opens it as a tab of the feed
await page.GotoAsync($"{Pasture.Site}/search?q={Uri.EscapeDataString("#" + tag)}");
await page.GetByRole(AriaRole.Button, new() { Name = "#" + tag }).ClickAsync(new() { Timeout = 30000 });
var follow = page.Locator("button[data-tag-follow]");
await Assertions.Expect(follow).ToContainTextAsync($"Follow #{tag}", new() { Timeout = 30000 });
await follow.ClickAsync();
await Assertions.Expect(follow).ToContainTextAsync($"Stop following #{tag}", new() { Timeout = 15000 });
Assert.True((await PersonaApi.Call(persona, $"/api/v1/tags/{tag}"))!["following"]!.GetValue<bool>());
await page.GotoAsync($"{Pasture.Site}/explore");
await page.GetByRole(AriaRole.Tab, new() { Name = "Followed hashtags" }).ClickAsync();
var row = page.Locator($"[data-tag='{tag}']");
await row.WaitForAsync(new() { Timeout = 15000 });
await row.GetByRole(AriaRole.Button, new() { Name = "Unfollow" }).ClickAsync();
await Assertions.Expect(row).ToHaveCountAsync(0, new() { Timeout = 15000 });
Assert.False((await PersonaApi.Call(persona, $"/api/v1/tags/{tag}"))!["following"]!.GetValue<bool>());
await session.AssertGuards();
}, page);
}
finally
{
await PersonaApi.Call(persona, $"/api/v1/tags/{tag}/unfollow", HttpMethod.Post);
}
}
[Fact]
public async Task Explore_shows_what_privapub_says_is_trending_and_its_directory()
{
var persona = Pasture.Personas().First();
var trending = (await PersonaApi.Call(persona, "/api/v1/trends/tags?limit=20"))!.AsArray().Select(t => t!["name"]!.GetValue<string>()).ToList();
var directory = (await PersonaApi.Call(persona, "/api/v1/directory?order=active&local=false&limit=40"))!.AsArray().Select(a => a!["id"]!.GetValue<string>()).ToList();
await using var session = await SignIn.As(browser, persona);
var page = session.Page;
await Results.Cell("client.render.explore", "privapub", persona.UserName, async () =>
{
await page.GotoAsync($"{Pasture.Site}/explore");
await page.Locator("[data-tag], [data-feed-empty]").First.WaitForAsync(new() { Timeout = 30000 });
var shownTags = await page.Locator("[data-tag]").EvaluateAllAsync<string[]>("rows => rows.map(r => r.dataset.tag)");
Assert.Equal(trending, shownTags);
await page.GetByRole(AriaRole.Tab, new() { Name = "People" }).ClickAsync();
await page.Locator("[data-account], [data-feed-empty]").First.WaitForAsync(new() { Timeout = 30000 });
var shownPeople = await page.Locator("[data-account]").EvaluateAllAsync<string[]>("rows => rows.map(r => r.dataset.account)");
Assert.Equal(directory, shownPeople);
await session.AssertGuards();
}, page);
}
}
}