84 lines
3.9 KiB
C#
84 lines
3.9 KiB
C#
using System.Text.Json.Nodes;
|
|||
|
|
|
||
|
|
using decePubClient.E2E.Support;
|
||
|
|
|
||
|
|
using Microsoft.Playwright;
|
||
|
|
|
||
|
|
namespace decePubClient.E2E.Render
|
||
|
|
{
|
||
|
|
// One object of each kind from each platform, opened in decePub (/expand/{id}) by a persona it was for, and checked
|
||
|
|
// against what its author put in it: the text, the content warning, every picture's alt text and its proxied source,
|
||
|
|
// the poll's options, the quoted post. town.sh expect says what each object holds and who may read it.
|
||
|
|
public sealed class RenderMatrixTests(Browser browser)
|
||
|
|
{
|
||
|
|
static readonly Lazy<JsonArray> Expected = new(() => Pasture.Town("expect").GetAwaiter().GetResult().AsArray());
|
||
|
|
|
||
|
|
public static TheoryData<string, string, string> Samples()
|
||
|
|
{
|
||
|
|
var data = new TheoryData<string, string, string>();
|
||
|
|
var seen = new HashSet<string>();
|
||
|
|
var personas = Pasture.Personas().Select(p => p.UserName).ToHashSet();
|
||
|
|
foreach (var item in Expected.Value)
|
||
|
|
{
|
||
|
|
var key = $"{item!["origin"]}|{item["kind"]}|{item["visibility"]}";
|
||
|
|
if (!item["readers"]!.AsArray().Any(r => personas.Contains(r!.GetValue<string>())) || !seen.Add(key))
|
||
|
|
continue;
|
||
|
|
data.Add(item["origin"]!.GetValue<string>(), $"{item["kind"]}.{item["visibility"]}", item["ref"]!.GetValue<string>());
|
||
|
|
}
|
||
|
|
return data;
|
||
|
|
}
|
||
|
|
|
||
|
|
[Theory]
|
||
|
|
[MemberData(nameof(Samples))]
|
||
|
|
public async Task Renders_as_written(string origin, string kind, string reference)
|
||
|
|
{
|
||
|
|
var item = Expected.Value.First(i => i!["ref"]!.GetValue<string>() == reference)!;
|
||
|
|
var personas = Pasture.Personas();
|
||
|
|
var reader = item["readers"]!.AsArray().Select(r => r!.GetValue<string>())
|
||
|
|
.Select(name => personas.FirstOrDefault(p => p.UserName == name)).First(p => p is not null);
|
||
|
|
|
||
|
|
await Results.Cell($"client.render.{kind}", origin, reference, async () =>
|
||
|
|
{
|
||
|
|
await using var session = await SignIn.As(browser, reader);
|
||
|
|
await session.Page.GotoAsync($"{Pasture.Site}/expand/{item["id"]!.GetValue<string>()}");
|
||
|
|
var card = session.Page.Locator($"article[data-uri='{item["uri"]!.GetValue<string>()}']").First;
|
||
|
|
await card.WaitForAsync(new() { Timeout = 30000 });
|
||
|
|
|
||
|
|
var marker = item["marker"]!.GetValue<string>();
|
||
|
|
if (item["cw"]?.GetValue<string>() is { } cw)
|
||
|
|
{
|
||
|
|
await Assertions.Expect(card).ToContainTextAsync(cw);
|
||
|
|
Assert.False(await card.GetByText(marker).IsVisibleAsync(), "the text shows before its content warning is opened");
|
||
|
|
await card.GetByText(cw).First.ClickAsync();
|
||
|
|
}
|
||
|
|
await Assertions.Expect(card.Locator(".post-content").First).ToContainTextAsync(marker);
|
||
|
|
|
||
|
|
// each reveal re-renders the media, so reveal the first hidden one until none is left
|
||
|
|
var hidden = card.GetByRole(AriaRole.Button).Filter(new() { HasText = "Sensitive media" });
|
||
|
|
for (var i = 0; i < 8 && await hidden.CountAsync() > 0; i++)
|
||
|
|
await hidden.First.ClickAsync();
|
||
|
|
foreach (var alt in item["alts"]!.AsArray().Select(a => a!.GetValue<string>()))
|
||
|
|
{
|
||
|
|
var picture = card.Locator($"img[alt='{alt}']").First;
|
||
|
|
await Assertions.Expect(picture).ToBeVisibleAsync();
|
||
|
|
var src = new Uri(await picture.GetAttributeAsync("src") ?? "");
|
||
|
|
Assert.Equal("privapub.test", src.Host);
|
||
|
|
Assert.True(await picture.EvaluateAsync<bool>("img => img.complete && img.naturalWidth > 0"), $"picture '{alt}' did not load");
|
||
|
|
}
|
||
|
|
if (item["poll"] is JsonArray options)
|
||
|
|
foreach (var option in options)
|
||
|
|
await Assertions.Expect(card).ToContainTextAsync(option!.GetValue<string>());
|
||
|
|
if (item["quote"]?.GetValue<string>() is { } quoted)
|
||
|
|
{
|
||
|
|
var quotedRef = Expected.Value.FirstOrDefault(i => i!["uri"]!.GetValue<string>() == quoted)?["marker"]?.GetValue<string>();
|
||
|
|
Assert.True(await card.Locator("article").CountAsync() > 0, "the quoted post is not shown");
|
||
|
|
if (quotedRef is not null)
|
||
|
|
await Assertions.Expect(card.Locator("article").First).ToContainTextAsync(quotedRef);
|
||
|
|
}
|
||
|
|
if (item["title"]?.GetValue<string>() is { } title)
|
||
|
|
await Assertions.Expect(card).ToContainTextAsync(title);
|
||
|
|
await session.AssertGuards();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|