using Microsoft.Playwright; namespace Enciphered.Blazor.UIComponents.Tests; [TestFixture] public class CardTests : PlaywrightTestBase { // ── Helpers ────────────────────────────────────────────────────────────── private async Task GoToCardsAsync() { await Page.GotoAsync($"{BaseUrl}/cards", new PageGotoOptions { WaitUntil = WaitUntilState.NetworkIdle }); await Page.WaitForSelectorAsync("[data-testid='card-basic']", new PageWaitForSelectorOptions { Timeout = 10_000 }); } private ILocator Card(string testId) => Page.Locator($"[data-testid='{testId}']"); // ──────────────────────────────────────────── // Basic card – structure // ──────────────────────────────────────────── [Test] public async Task BasicCard_Is_Visible() { await GoToCardsAsync(); await Expect(Card("card-basic")).ToBeVisibleAsync(); } [Test] public async Task BasicCard_Has_Rounded_Border_Classes() { await GoToCardsAsync(); var card = Card("card-basic"); await Expect(card).ToHaveClassAsync(new System.Text.RegularExpressions.Regex("rounded-xl")); await Expect(card).ToHaveClassAsync(new System.Text.RegularExpressions.Regex("border")); } [Test] public async Task BasicCard_Renders_Title() { await GoToCardsAsync(); var title = Card("card-basic").Locator("h3"); await Expect(title).ToBeVisibleAsync(); await Expect(title).ToHaveTextAsync("Card Title"); } [Test] public async Task BasicCard_Renders_Description() { await GoToCardsAsync(); var desc = Card("card-basic").Locator("[data-slot='card-description']"); await Expect(desc).ToBeVisibleAsync(); await Expect(desc).ToHaveTextAsync("Card Description"); } [Test] public async Task BasicCard_Renders_Content() { await GoToCardsAsync(); var content = Card("card-basic").Locator("p:has-text('Card Content')"); await Expect(content).ToBeVisibleAsync(); } [Test] public async Task BasicCard_Renders_Footer() { await GoToCardsAsync(); var footer = Card("card-basic").Locator("p:has-text('Card Footer')"); await Expect(footer).ToBeVisibleAsync(); } [Test] public async Task BasicCard_Description_Appears_Below_Title() { await GoToCardsAsync(); var title = Card("card-basic").Locator("h3"); var desc = Card("card-basic").Locator("[data-slot='card-description']"); var titleBox = await title.BoundingBoxAsync(); var descBox = await desc.BoundingBoxAsync(); Assert.That(titleBox, Is.Not.Null, "Title bounding box should exist"); Assert.That(descBox, Is.Not.Null, "Description bounding box should exist"); Assert.That(descBox!.Y, Is.GreaterThan(titleBox!.Y), "Description should be positioned below the title"); } // ──────────────────────────────────────────── // Login card – header with action // ──────────────────────────────────────────── [Test] public async Task LoginCard_Is_Visible() { await GoToCardsAsync(); await Expect(Card("card-login")).ToBeVisibleAsync(); } [Test] public async Task LoginCard_Renders_Title() { await GoToCardsAsync(); var title = Card("card-login").Locator("h3"); await Expect(title).ToHaveTextAsync("Login to your account"); } [Test] public async Task LoginCard_Renders_Action() { await GoToCardsAsync(); var action = Card("card-login").Locator("[data-slot='card-action']"); await Expect(action).ToBeVisibleAsync(); await Expect(action).ToContainTextAsync("Sign Up"); } [Test] public async Task LoginCard_Action_Is_Right_Of_Title() { await GoToCardsAsync(); var title = Card("card-login").Locator("h3"); var action = Card("card-login").Locator("[data-slot='card-action']"); var titleBox = await title.BoundingBoxAsync(); var actionBox = await action.BoundingBoxAsync(); Assert.That(titleBox, Is.Not.Null); Assert.That(actionBox, Is.Not.Null); Assert.That(actionBox!.X, Is.GreaterThan(titleBox!.X), "Action should be to the right of the title"); } [Test] public async Task LoginCard_Renders_Description() { await GoToCardsAsync(); var desc = Card("card-login").Locator("[data-slot='card-description']"); await Expect(desc).ToContainTextAsync("Enter your email below"); } [Test] public async Task LoginCard_Has_Email_Input() { await GoToCardsAsync(); var email = Card("card-login").Locator("input#email"); await Expect(email).ToBeVisibleAsync(); } [Test] public async Task LoginCard_Has_Password_Input() { await GoToCardsAsync(); var password = Card("card-login").Locator("input#password"); await Expect(password).ToBeVisibleAsync(); } [Test] public async Task LoginCard_Has_Login_Button() { await GoToCardsAsync(); var btn = Card("card-login").Locator("button:has-text('Login')").First; await Expect(btn).ToBeVisibleAsync(); } [Test] public async Task LoginCard_Has_Google_Button() { await GoToCardsAsync(); var btn = Card("card-login").Locator("button:has-text('Login with Google')"); await Expect(btn).ToBeVisibleAsync(); } // ──────────────────────────────────────────── // Image card // ──────────────────────────────────────────── [Test] public async Task ImageCard_Is_Visible() { await GoToCardsAsync(); await Expect(Card("card-image")).ToBeVisibleAsync(); } [Test] public async Task ImageCard_Renders_Image() { await GoToCardsAsync(); var img = Card("card-image").Locator("img"); await Expect(img).ToBeVisibleAsync(); await Expect(img).ToHaveAttributeAsync("alt", "Event cover"); } [Test] public async Task ImageCard_Image_Appears_Above_Title() { await GoToCardsAsync(); var img = Card("card-image").Locator("img"); var title = Card("card-image").Locator("h3"); var imgBox = await img.BoundingBoxAsync(); var titleBox = await title.BoundingBoxAsync(); Assert.That(imgBox, Is.Not.Null); Assert.That(titleBox, Is.Not.Null); Assert.That(titleBox!.Y, Is.GreaterThan(imgBox!.Y), "Title should be below the image"); } [Test] public async Task ImageCard_Renders_Title() { await GoToCardsAsync(); var title = Card("card-image").Locator("h3"); await Expect(title).ToHaveTextAsync("Design systems meetup"); } [Test] public async Task ImageCard_Renders_Featured_Badge() { await GoToCardsAsync(); var badge = Card("card-image").Locator("[data-slot='card-action']"); await Expect(badge).ToContainTextAsync("Featured"); } [Test] public async Task ImageCard_Renders_Description() { await GoToCardsAsync(); var desc = Card("card-image").Locator("[data-slot='card-description']"); await Expect(desc).ToContainTextAsync("A practical talk on component APIs"); } [Test] public async Task ImageCard_Has_View_Event_Button() { await GoToCardsAsync(); var btn = Card("card-image").Locator("button:has-text('View Event')"); await Expect(btn).ToBeVisibleAsync(); } // ──────────────────────────────────────────── // All three cards render on the page // ──────────────────────────────────────────── [Test] public async Task CardsPage_Renders_Three_Cards() { await GoToCardsAsync(); await Expect(Card("card-basic")).ToBeVisibleAsync(); await Expect(Card("card-login")).ToBeVisibleAsync(); await Expect(Card("card-image")).ToBeVisibleAsync(); } }