using Microsoft.Playwright;
using ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests.Cluster;
namespace ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests.Design;
///
/// End-to-end round-trip for the Template design pages:
/// create → add attribute → delete, all via the Central UI against the
/// running dev cluster.
///
[Collection("Playwright")]
public class TemplateCrudTests
{
private readonly PlaywrightFixture _fixture;
public TemplateCrudTests(PlaywrightFixture fixture)
{
_fixture = fixture;
}
[SkippableFact]
public async Task CreateAddAttributeDelete_Template_RoundTrips()
{
Skip.IfNot(await ClusterAvailability.IsAvailableAsync(), ClusterAvailability.SkipReason);
var name = $"zztest-tmpl-{Guid.NewGuid().ToString("N")[..8]}";
var page = await _fixture.NewAuthenticatedPageAsync();
try
{
// ── CREATE ────────────────────────────────────────────────────────────────
await page.GotoAsync($"{PlaywrightFixture.BaseUrl}/design/templates/create");
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
// Name input is label-anchored:
// followed by .
// Use the label's sibling input scoped to the containing div to avoid any
// strict-mode violation from the Description input (also form-control).
await page.Locator("div.mb-3:has(label:has-text('Name')) input.form-control").FillAsync(name);
// Leave Parent Template at the default "(None - root template)".
// Click the green Create button.
await page.ClickAsync("button.btn.btn-success:has-text('Create')");
// After a successful create, Blazor navigates to /design/templates/{id}.
// Poll window.location until the path matches /design/templates/ + digits
// and does not still say /create.
await PlaywrightFixture.WaitForPathAsync(page, "/design/templates/", excludePath: "/create");
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
// Sanity: we must be on a numeric template detail URL.
Assert.Matches(@"/design/templates/\d+$", page.Url);
// ── ADD ATTRIBUTE ─────────────────────────────────────────────────────────
// The Attributes tab is the default-active tab (_activeTab = "attributes"),
// so we don't need to click it, but we do wait for the tab panel to render.
await Assertions.Expect(
page.Locator("button.nav-link:has-text('Attributes')"))
.ToBeVisibleAsync();
// Click Add Attribute.
await page.ClickAsync("button.btn.btn-primary.btn-sm:has-text('Add Attribute')");
// The modal is a page-local .modal.show.d-block — NOT the global DialogHost.
// DialogHost adds a `fade` class; the page-local modal does not, so :not(.fade)
// ensures we match only the page-local Add-Attribute modal.
var modal = page.Locator(".modal.show.d-block:not(.fade)");
await Assertions.Expect(modal).ToBeVisibleAsync();
await Assertions.Expect(modal.Locator(".modal-title")).ToHaveTextAsync("Add Attribute");
// Fill Name field inside the modal.
await modal.Locator("div.col-12:has(label:has-text('Name')) input.form-control").FillAsync("Val");
// Select Data Type = Double.
// The select is label-anchored: +