using Microsoft.Playwright; using Tests.E2e.Infra; using Tests.E2e.PageObjectModels; using Xunit.Abstractions; namespace Tests.E2e; public class RouterCardTests( PlaywrightFixture fixture, ITestOutputHelper output) : E2ETestBase(fixture, output) { private readonly PlaywrightFixture _fixture = fixture; private readonly ITestOutputHelper _output = output; [Fact] public async Task User_Can_Edit_Router_Model_And_Features() { (IBrowserContext context, IPage page) = await CreatePageAsync(); var name = $"e2e-fw-{Guid.NewGuid():N}"[..16]; try { await page.GotoAsync(_fixture.BaseUrl); var layout = new MainLayoutPom(page); await layout.AssertLoadedAsync(); await layout.GotoHardwareAsync(); var hardwareTree = new HardwareTreePom(page); await hardwareTree.AssertLoadedAsync(); await hardwareTree.GotoRoutersListAsync(); var list = new RouterListPom(page); await list.AssertLoadedAsync(); await list.AddRouterAsync(name); await list.AssertRouterExists(name); // Go to details page so we can exercise the card component await list.OpenRouterAsync(name); var card = new RouterCardPom(page); await Assertions.Expect(card.RouterItem(name)).ToBeVisibleAsync(); // Enter edit mode await card.EnterEditModeAsync(name); // Update Model + toggle features var newModel = "e2e-model-123"; await card.ModelInput(name).FillAsync(newModel); // Ensure both toggles are ON (idempotent) if (!await card.ManagedCheckbox(name).IsCheckedAsync()) await card.ManagedCheckbox(name).CheckAsync(); if (!await card.PoeCheckbox(name).IsCheckedAsync()) await card.PoeCheckbox(name).CheckAsync(); await card.SaveEditsAsync(name); // Validate view mode reflects changes await Assertions.Expect(card.ModelValue(name)).ToHaveTextAsync(newModel); await Assertions.Expect(card.ManagedBadge(name)).ToBeVisibleAsync(); await Assertions.Expect(card.PoeBadge(name)).ToBeVisibleAsync(); } catch (Exception) { _output.WriteLine("TEST FAILED — Capturing diagnostics"); _output.WriteLine($"Current URL: {page.Url}"); var html = await page.ContentAsync(); _output.WriteLine("==== DOM SNAPSHOT START ===="); _output.WriteLine(html); _output.WriteLine("==== DOM SNAPSHOT END ===="); throw; } finally { await context.CloseAsync(); } } [Fact] public async Task User_Can_Rename_Router_From_Details_Page() { (IBrowserContext context, IPage page) = await CreatePageAsync(); var name = $"e2e-fw-{Guid.NewGuid():N}"[..16]; var renamed = $"{name}-ren"; try { await page.GotoAsync(_fixture.BaseUrl); var layout = new MainLayoutPom(page); await layout.AssertLoadedAsync(); await layout.GotoHardwareAsync(); var hardwareTree = new HardwareTreePom(page); await hardwareTree.AssertLoadedAsync(); await hardwareTree.GotoRoutersListAsync(); var list = new RouterListPom(page); await list.AssertLoadedAsync(); await list.AddRouterAsync(name); await list.OpenRouterAsync(name); var card = new RouterCardPom(page); await card.RenameRouterAsync(name, renamed); // after rename we should be on new URL and see the renamed card root await Assertions.Expect(card.RouterItem(renamed)).ToBeVisibleAsync(); } catch (Exception) { _output.WriteLine("TEST FAILED — Capturing diagnostics"); _output.WriteLine($"Current URL: {page.Url}"); var html = await page.ContentAsync(); _output.WriteLine("==== DOM SNAPSHOT START ===="); _output.WriteLine(html); _output.WriteLine("==== DOM SNAPSHOT END ===="); throw; } finally { await context.CloseAsync(); } } [Fact] public async Task User_Can_Clone_Router_From_Details_Page() { (IBrowserContext context, IPage page) = await CreatePageAsync(); var name = $"e2e-fw-{Guid.NewGuid():N}"[..16]; var clone = $"{name}-cpy"; try { await page.GotoAsync(_fixture.BaseUrl); var layout = new MainLayoutPom(page); await layout.AssertLoadedAsync(); await layout.GotoHardwareAsync(); var hardwareTree = new HardwareTreePom(page); await hardwareTree.AssertLoadedAsync(); await hardwareTree.GotoRoutersListAsync(); var list = new RouterListPom(page); await list.AssertLoadedAsync(); await list.AddRouterAsync(name); await list.OpenRouterAsync(name); var card = new RouterCardPom(page); await card.CloneRouterAsync(name, clone); // should be on the clone's details URL and see the clone card await Assertions.Expect(card.RouterItem(clone)).ToBeVisibleAsync(); } catch (Exception) { _output.WriteLine("TEST FAILED — Capturing diagnostics"); _output.WriteLine($"Current URL: {page.Url}"); var html = await page.ContentAsync(); _output.WriteLine("==== DOM SNAPSHOT START ===="); _output.WriteLine(html); _output.WriteLine("==== DOM SNAPSHOT END ===="); throw; } finally { await context.CloseAsync(); } } [Fact] public async Task User_Can_Delete_Router_From_Details_Page() { (IBrowserContext context, IPage page) = await CreatePageAsync(); var name = $"e2e-fw-{Guid.NewGuid():N}"[..16]; try { await page.GotoAsync(_fixture.BaseUrl); var layout = new MainLayoutPom(page); await layout.AssertLoadedAsync(); await layout.GotoHardwareAsync(); var hardwareTree = new HardwareTreePom(page); await hardwareTree.AssertLoadedAsync(); await hardwareTree.GotoRoutersListAsync(); var list = new RouterListPom(page); await list.AssertLoadedAsync(); await list.AddRouterAsync(name); await list.OpenRouterAsync(name); var card = new RouterCardPom(page); await card.DeleteRouterAsync(name); // After delete, your page navigates away (Nav.NavigateTo("/hardware/tree")) await page.WaitForURLAsync("**/hardware/tree"); } catch (Exception) { _output.WriteLine("TEST FAILED — Capturing diagnostics"); _output.WriteLine($"Current URL: {page.Url}"); var html = await page.ContentAsync(); _output.WriteLine("==== DOM SNAPSHOT START ===="); _output.WriteLine(html); _output.WriteLine("==== DOM SNAPSHOT END ===="); throw; } finally { await context.CloseAsync(); } } [Fact] public async Task User_Can_Add_And_Remove_Tags_From_Router_Card() { (IBrowserContext context, IPage page) = await CreatePageAsync(); var name = $"e2e-ap-{Guid.NewGuid():N}"[..16]; try { await page.GotoAsync(_fixture.BaseUrl); var layout = new MainLayoutPom(page); await layout.AssertLoadedAsync(); await layout.GotoHardwareAsync(); var hardwareTree = new HardwareTreePom(page); await hardwareTree.AssertLoadedAsync(); await hardwareTree.GotoRoutersListAsync(); var list = new RouterListPom(page); await list.AssertLoadedAsync(); await list.AddRouterAsync(name); await page.WaitForURLAsync($"**/resources/hardware/{name}"); var card = new RouterCardPom(page); TagsPom tags = card.Tags; // ------------------------------------------------- // Add multiple tags in one modal interaction // ------------------------------------------------- await tags.AddTagsAsync("router", "Foo", "Bar", "Baz"); await tags.AssertTagVisibleAsync("router", "Foo"); await tags.AssertTagVisibleAsync("router", "Bar"); await tags.AssertTagVisibleAsync("router", "Baz"); // ------------------------------------------------- // Remove a single tag // ------------------------------------------------- await tags.RemoveTagAsync("router", "Bar"); await tags.AssertTagNotVisibleAsync("router", "Bar"); await tags.AssertTagVisibleAsync("router", "Foo"); await tags.AssertTagVisibleAsync("router", "Baz"); // ------------------------------------------------- // Reload to verify persistence // ------------------------------------------------- await page.ReloadAsync(); await tags.AssertTagVisibleAsync("router", "Foo"); await tags.AssertTagVisibleAsync("router", "Baz"); await tags.AssertTagNotVisibleAsync("router", "Bar"); await context.CloseAsync(); } finally { await context.CloseAsync(); } } }