LoadSession said the session was loaded before SwitchPersona had set the persona, so a render in between (any CascadingState change) showed the feed a loaded session without a persona, and it said "Empty" until the persona came. The session counts as loaded once the persona is known, or couldn't be used. StreamingTests took that flash for the feed and, on a slower start, posted before the stream was open; it now waits until the app has subscribed to the home stream. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
67 lines
2.6 KiB
C#
67 lines
2.6 KiB
C#
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;
|
|
// the stream counts once the app has subscribed to the home feed on it (it opens after the first page is read,
|
|
// later on a busy page)
|
|
var subscribed = new TaskCompletionSource();
|
|
page.WebSocket += (_, socket) =>
|
|
{
|
|
if (socket.Url.Contains("/api/v1/streaming"))
|
|
socket.FrameSent += (_, frame) =>
|
|
{
|
|
if (frame.Text?.Contains("\"subscribe\"") == true && frame.Text.Contains("\"user\""))
|
|
subscribed.TrySetResult();
|
|
};
|
|
};
|
|
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')");
|
|
subscribed = new();
|
|
await page.GotoAsync($"{Pasture.Site}/");
|
|
await page.Locator("article[data-uri], [data-feed-empty]").First.WaitForAsync(new() { Timeout = 30000 });
|
|
await subscribed.Task.WaitAsync(TimeSpan.FromSeconds(30));
|
|
// (and the server has taken the subscription in)
|
|
await Task.Delay(500);
|
|
|
|
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<string>()}']");
|
|
await Assertions.Expect(card).ToContainTextAsync(text, new() { Timeout = 5000 });
|
|
|
|
await PersonaApi.Call(persona, $"/api/v1/statuses/{post["id"]!.GetValue<string>()}", 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<string>()}", HttpMethod.Delete);
|
|
}
|
|
}
|
|
}
|
|
}
|