using Microsoft.Playwright; namespace decePubClient.E2E.Support { // Signs a town persona in through the real login page and persona chooser, once per persona per run; later sessions // start from the saved browser state (the AuthData decePub keeps in localStorage). public static class SignIn { static readonly string StateDir = Path.Combine(AppContext.BaseDirectory, ".state"); public static async Task As(Browser browser, Pasture.Persona persona, bool fresh = false) { var state = Path.Combine(StateDir, persona.UserName + ".json"); if (!fresh && File.Exists(state)) { var known = await browser.Open(state); await known.Page.GotoAsync(Pasture.Site + "/"); await known.Page.Locator("article[data-uri], [data-feed-empty]").First.WaitForAsync(new() { Timeout = 30000 }); return known; } var session = await browser.Open(); await Through(session.Page, persona); Directory.CreateDirectory(StateDir); await session.Context.StorageStateAsync(new() { Path = state }); return session; } public static async Task Through(IPage page, Pasture.Persona persona) { try { await Steps(page, persona); } catch { await Evidence(page, "signin-" + persona.UserName); throw; } } // a screenshot and the page's text next to the test output, for a failure seen only in a headless browser public static async Task Evidence(IPage page, string name) { Directory.CreateDirectory(StateDir); await page.ScreenshotAsync(new() { Path = Path.Combine(StateDir, name + ".png"), FullPage = true }); await File.WriteAllTextAsync(Path.Combine(StateDir, name + ".txt"), page.Url + "\n" + await page.InnerTextAsync("body")); } static async Task Steps(IPage page, Pasture.Persona persona) { await page.GotoAsync(Pasture.Site + "/login"); await page.Locator("input[autocomplete=username]").FillAsync(persona.Root); await page.Locator("input[autocomplete=current-password]").FillAsync(persona.Password); await page.Locator("button[type=submit]").ClickAsync(); // a root with several personas picks one; with one it goes straight on var chooser = page.Locator("section button").Filter(new() { HasText = persona.UserName + "@privapub.test" }); await chooser.Or(page.Locator("article[data-uri]")).First.WaitForAsync(new() { Timeout = 30000 }); if (await chooser.CountAsync() > 0) await chooser.First.ClickAsync(); await page.WaitForURLAsync(url => new Uri(url).AbsolutePath == "/", new() { Timeout = 30000 }); } } }