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 GumbyPageTests : 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(".*Gumby")] private static partial Regex GumbyUrlRegex(); [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 GumbyOptionShouldBePresentInMenu() { // Confirm we've found the Gumby link in the header var gumbyPageLink = _page!.GetByRole(AriaRole.Link, new PageGetByRoleOptions { Name = "Gumby" }); await Expect(gumbyPageLink).ToHaveAttributeAsync("href", "/Gumby"); } [Test] public async Task NavigationToGumbyPageShouldSucceed() { await GotoGumby(_page!); await PageSnap(_page!, "gumby.png"); await Expect(_page!).ToHaveURLAsync(GumbyUrlRegex()); } [Test] public async Task GumbyImageShouldBePresentOnBrowser() { await GotoGumby(_page!); Expect(_page!.GetByRole(AriaRole.Img, new PageGetByRoleOptions { Name = "Gumby" })); } [Test] public async Task ResponseFromButtonShouldNotTakeTooLong() { /* * This test will sometimes pass, and sometimes fail, if the randomizer on MyWebApp is working correctly. * That is BY DESIGN. It's meant to show (at least in a rudimentary way) how a Playwright test can be used * to do synthetic monitoring. */ await GotoGumby(_page!); const int delay = 10; //MyWebApp is set to 12 seconds, so it should fail sometimes const int delayMillis = delay * 1000; // A thousand milliseconds in a second await _page!.GetByText("Clear").ClickAsync(); //clear the label first. await PageSnap(_page!, "gumby-before-button-press.png"); await _page!.GetByText("Press Me!").ClickAsync(); await PageSnap(_page!, "/gumby-after-button-press-during-wait.png"); await Expect(_page!.Locator("label[id=result]")) .ToContainTextAsync("You Pressed The Button", new LocatorAssertionsToContainTextOptions {Timeout = delayMillis}); await PageSnap(_page!, "gumby-after-test-completion.png"); } /*** 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 GotoGumby(IPage page) { await page.GetByRole(AriaRole.Link, new PageGetByRoleOptions { Name = "Gumby" }).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"); } }