85 lines
4.2 KiB
C#
85 lines
4.2 KiB
C#
using System.Text.Json.Nodes;
|
|||
|
|
|
||
|
|
using decePubClient.E2E.Support;
|
||
|
|
|
||
|
|
using Microsoft.Playwright;
|
||
|
|
|
||
|
|
namespace decePubClient.E2E.Actions
|
||
|
|
{
|
||
|
|
// Accounts in decePub: found by searching their handle (PrivaPub resolves it), opened as a profile, followed and
|
||
|
|
// unfollowed there; the follow is checked on the account's own server, where the persona must appear as a follower.
|
||
|
|
public sealed class ProfileTests(Browser browser)
|
||
|
|
{
|
||
|
|
static readonly string[] Platforms = ["gts", "mastodon", "akkoma", "misskey", "sharkey"];
|
||
|
|
|
||
|
|
public static TheoryData<string> Origins() => new(Platforms);
|
||
|
|
|
||
|
|
// an account of the platform that the persona does not follow yet, from the town's own sessions
|
||
|
|
static (string Platform, string UserName, string Token) Stranger(string platform, Pasture.Persona persona)
|
||
|
|
{
|
||
|
|
var sessions = JsonNode.Parse(File.ReadAllText(Path.Combine(Pasture.Root, ".state", "town", "sessions.json")))!.AsObject();
|
||
|
|
var candidates = sessions.Where(kv => kv.Key.StartsWith(platform + "/") && !kv.Key.Contains("/st_"))
|
||
|
|
.Select(kv => (platform, kv.Value!["account"]!["username"]!.GetValue<string>(), kv.Value!["token"]!.GetValue<string>()))
|
||
|
|
.ToList();
|
||
|
|
return candidates.Last();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Theory]
|
||
|
|
[MemberData(nameof(Origins))]
|
||
|
|
public async Task A_remote_account_found_by_its_handle_is_followed_and_unfollowed_from_its_profile(string platform)
|
||
|
|
{
|
||
|
|
var persona = Pasture.Personas().First();
|
||
|
|
var (_, userName, _) = Stranger(platform, persona);
|
||
|
|
var handle = $"{userName}@{platform}.test";
|
||
|
|
await using var session = await SignIn.As(browser, persona);
|
||
|
|
await Results.Cell("client.action.follow", platform, handle, async () =>
|
||
|
|
{
|
||
|
|
await session.Page.GotoAsync($"{Pasture.Site}/search?q={Uri.EscapeDataString("@" + handle)}");
|
||
|
|
var profile = session.Page.Locator("article[data-account-id]").First;
|
||
|
|
await profile.WaitForAsync(new() { Timeout = 30000 });
|
||
|
|
await Assertions.Expect(profile).ToContainTextAsync("@" + handle);
|
||
|
|
|
||
|
|
var follow = profile.GetByRole(AriaRole.Button).Filter(new() { HasTextRegex = new System.Text.RegularExpressions.Regex("^(Follow|Unfollow|Cancel the request)$") }).First;
|
||
|
|
if ((await follow.InnerTextAsync()).Trim() != "Follow")
|
||
|
|
{
|
||
|
|
await follow.ClickAsync();
|
||
|
|
await Assertions.Expect(follow).ToHaveTextAsync("Follow", new() { Timeout = 15000 });
|
||
|
|
}
|
||
|
|
await follow.ClickAsync();
|
||
|
|
await Assertions.Expect(follow).Not.ToHaveTextAsync("Follow", new() { Timeout = 15000 });
|
||
|
|
Assert.True(await Pasture.Eventually(async () => await FollowedOn(platform, userName, persona.UserName), 45),
|
||
|
|
$"{handle} never learnt that {persona.UserName} follows it");
|
||
|
|
|
||
|
|
await follow.ClickAsync();
|
||
|
|
await Assertions.Expect(follow).ToHaveTextAsync("Follow", new() { Timeout = 15000 });
|
||
|
|
Assert.True(await Pasture.Eventually(async () => !await FollowedOn(platform, userName, persona.UserName), 45),
|
||
|
|
$"{handle} still has {persona.UserName} as a follower after the unfollow");
|
||
|
|
await session.AssertGuards();
|
||
|
|
}, session.Page);
|
||
|
|
}
|
||
|
|
|
||
|
|
// whether the peer itself lists the persona as following (or asking to follow) its account
|
||
|
|
static async Task<bool> FollowedOn(string platform, string userName, string persona)
|
||
|
|
{
|
||
|
|
var result = await Pasture.Town("drive", platform, userName, "relationship", $"{{\"acct\": \"{persona}@privapub.test\"}}");
|
||
|
|
return result?["followed_by"]?.GetValue<bool>() == true || (await Pasture.Town("drive", platform, userName, "pending", "{}"))
|
||
|
|
.AsArray().Any(a => a?.GetValue<string>()?.StartsWith(persona + "@") == true);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task The_personas_own_profile_lists_its_posts()
|
||
|
|
{
|
||
|
|
var persona = Pasture.Personas().First();
|
||
|
|
await using var session = await SignIn.As(browser, persona);
|
||
|
|
await Results.Cell("client.render.profile", "privapub", persona.UserName, async () =>
|
||
|
|
{
|
||
|
|
await session.Page.GotoAsync($"{Pasture.Site}/account/{persona.LocalId}");
|
||
|
|
var profile = session.Page.Locator("article[data-account-id]").First;
|
||
|
|
await profile.WaitForAsync(new() { Timeout = 30000 });
|
||
|
|
await Assertions.Expect(profile).ToContainTextAsync("@" + persona.UserName);
|
||
|
|
await session.Page.Locator("article[data-uri], [data-feed-empty]").First.WaitForAsync(new() { Timeout = 30000 });
|
||
|
|
await session.AssertGuards();
|
||
|
|
}, session.Page);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|