using NUnit.Framework; using System.Text.RegularExpressions; using Microsoft.Playwright; using Microsoft.Playwright.NUnit; using NUnit.Framework.Internal; namespace PlaywrightTests; [Parallelizable(ParallelScope.Self)] [TestFixture] public partial class PokeyPageTests : PageTest { private const string ScreenshotRoot = "../../../screenshots/"; private const string HomeUrl = "http://localhost:5296"; private const int AppInitDelay = 5000; private IPage? _page; private IBrowser? _browser; [GeneratedRegex("Home page")] private static partial Regex HomePageRegex(); [GeneratedRegex(".*Pokey")] private static partial Regex PokeyUrlRegex(); [SetUp] public async Task Init() { _browser = await Playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions() { Headless = true, }); _page = await _browser.NewPageAsync(); await WaitForApp(_page); } [Test] public async Task PokeyOptionShouldBePresentInMenu() { // Confirm we've found the Gumby link in the header var pokeyPageLink = _page!.GetByRole(AriaRole.Link, new PageGetByRoleOptions { Name = "Pokey" }); await Expect(pokeyPageLink).ToHaveAttributeAsync("href", "/Pokey"); } [Test] public async Task NavigationToPokeyPageShouldSucceed() { await GotoPokey(_page!); await PageSnap(_page!, "gumby.png"); await Expect(_page!).ToHaveURLAsync(PokeyUrlRegex()); } [Test] public async Task PokeyImageShouldBePresentOnBrowser() { await GotoPokey(_page!); Expect(_page!.GetByRole(AriaRole.Img, new PageGetByRoleOptions { Name = "Pokey" })); } [Test] public async Task BothTimesShouldBeVisibleOnGet() { await GotoPokey(_page!); var handleList = _page!.QuerySelectorAllAsync("//*[ contains(text(), 'time is' ) ]").Result; Assert.That(handleList, Has.Count.EqualTo(2)); } [Test] public async Task BothTimesShouldMatchOnGet() { await GotoPokey(_page!); var handleList = _page!.QuerySelectorAllAsync("//*[ contains(text(), 'time is' ) ]").Result; var time1= await handleList[0].TextContentAsync(); var time2 = await handleList[1].TextContentAsync(); // ReSharper disable once StringIndexOfIsCultureSpecific.1 var startIndex1 = time1!.IndexOf(" is ") + 4; var dateTime1 = DateTime.Parse(time1[startIndex1..]); // ReSharper disable once StringIndexOfIsCultureSpecific.1 var startIndex2 = time2!.IndexOf(" is ") + 4; var dateTime2 = DateTime.Parse(time1[startIndex2..]); Assert.That(dateTime1, Is.EqualTo(dateTime2)); } /*** HELPERS ***/ private static async Task PageSnap(IPage page, string filename) { await page.ScreenshotAsync(new PageScreenshotOptions { FullPage = true, Path = ScreenshotRoot+"/"+filename}); } private static async Task ElementSnap(ILocator locator, string filename) { await locator.ScreenshotAsync(new LocatorScreenshotOptions { Path = ScreenshotRoot+"/"+filename }); } private static async Task GotoPokey(IPage page) { await page.GetByRole(AriaRole.Link, new PageGetByRoleOptions { Name = "Pokey" }).ClickAsync(); } private static async Task WaitForApp(IPage page) { var pageIsLoaded = false; while (!pageIsLoaded) { try { await page.GotoAsync(HomeUrl, new PageGotoOptions() { Timeout = AppInitDelay }); pageIsLoaded = true; } catch { await Task.Delay(AppInitDelay); } } var appIsLoaded = false; while (!appIsLoaded) { try { var titleAsync = await page.TitleAsync(); if (HomePageRegex().Match(titleAsync).Success) { appIsLoaded = true; continue; }; } catch { // _logger.Information("Error loading app"); } // _logger.Information("App not loaded, delaying before retrying..."); await Task.Delay(AppInitDelay); } // _logger.Information($"{nameof(WaitForApp)} completed"); } }