test(e2e): cover Topology Deploy action
This commit is contained in:
+109
@@ -0,0 +1,109 @@
|
||||
using Microsoft.Playwright;
|
||||
using ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests.Cluster;
|
||||
using Xunit;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests.Deployment;
|
||||
|
||||
/// <summary>
|
||||
/// E2E coverage for the per-instance deploy-family actions exposed from the
|
||||
/// Topology tree's right-click context menu. This is the first of the
|
||||
/// deploy-action tests; the <see cref="OpenInstanceContextMenuAsync"/> helper
|
||||
/// (navigate → expand → locate the instance row → right-click) is shared so the
|
||||
/// Enable/Disable/Delete tests can extend this file without re-deriving the tree
|
||||
/// navigation.
|
||||
///
|
||||
/// <para>
|
||||
/// Each fact mints a fresh ephemeral instance on the real <c>site-a</c> (via
|
||||
/// <see cref="DeploymentFixture.CreateInstanceAsync"/>) so it carries the
|
||||
/// expected <c>Deploy</c> (not <c>Redeploy</c>) menu state, exercises the action
|
||||
/// against the live cluster, then deletes the instance in a <c>finally</c>.
|
||||
/// Outcomes are tolerant: the relay to <c>site-a</c> may return a deployed
|
||||
/// confirmation or a fast error, but either way a single outcome toast appears.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Collection("Playwright")]
|
||||
public class DeploymentActionTests : IClassFixture<DeploymentFixture>
|
||||
{
|
||||
private readonly PlaywrightFixture _pw;
|
||||
private readonly DeploymentFixture _cluster;
|
||||
|
||||
public DeploymentActionTests(PlaywrightFixture pw, DeploymentFixture cluster)
|
||||
{
|
||||
_pw = pw;
|
||||
_cluster = cluster;
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public async Task Deploy_Instance_ShowsOutcomeToast()
|
||||
{
|
||||
Skip.IfNot(_cluster.Available, ClusterAvailability.SkipReason);
|
||||
|
||||
var (instanceId, uniqueName) = await _cluster.CreateInstanceAsync();
|
||||
try
|
||||
{
|
||||
var page = await _pw.NewAuthenticatedPageAsync();
|
||||
await OpenInstanceContextMenuAsync(page, uniqueName);
|
||||
|
||||
// A fresh instance is NotDeployed, so the action reads "Deploy" (it would
|
||||
// read "Redeploy" only for a stale, already-deployed node). Deploy has no
|
||||
// confirm dialog — clicking relays to site-a immediately.
|
||||
await page.Locator(".dropdown-menu.show button.dropdown-item", new() { HasText = "Deploy" })
|
||||
.ClickAsync();
|
||||
|
||||
// The relay outcome surfaces on a toast — deployed confirmation or a fast
|
||||
// error. We assert exactly one toast (the single-toast contract), not which
|
||||
// outcome, since the live cluster may answer either way. The toast
|
||||
// auto-dismisses ~5s after it appears, so assert promptly with a generous
|
||||
// wait for the relay round-trip.
|
||||
var toast = page.Locator(".toast");
|
||||
await Assertions.Expect(toast).ToBeVisibleAsync(new() { Timeout = 15_000 });
|
||||
Assert.Equal(1, await toast.CountAsync());
|
||||
}
|
||||
finally
|
||||
{
|
||||
await CliRunner.DeleteInstanceAsync(instanceId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigates to the Topology page, expands the tree so the instance row under
|
||||
/// <c>site-a → zztest area</c> is rendered, locates the row by its
|
||||
/// <paramref name="uniqueName"/> label, and opens its right-click context menu.
|
||||
/// Returns the located row so callers can re-target it if needed.
|
||||
///
|
||||
/// <para>
|
||||
/// Live updates are switched off first: the page reloads the tree on a 15s timer,
|
||||
/// which would collapse a freshly-expanded node and tear down an open context
|
||||
/// menu mid-interaction. With it off the tree stays stable through the action.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
private static async Task<ILocator> OpenInstanceContextMenuAsync(IPage page, string uniqueName)
|
||||
{
|
||||
await page.GotoAsync($"{PlaywrightFixture.BaseUrl}/deployment/topology");
|
||||
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
|
||||
|
||||
// Stop the 15s live-updates timer from rebuilding the tree under us.
|
||||
var liveToggle = page.Locator("#live-updates");
|
||||
if (await liveToggle.IsCheckedAsync())
|
||||
{
|
||||
await liveToggle.UncheckAsync();
|
||||
}
|
||||
|
||||
// ExpandAll() recurses every branch (site → area → …), so one click reveals
|
||||
// the nested instance row under site-a's zztest area.
|
||||
await page.Locator("button[aria-label='Expand all areas']").ClickAsync();
|
||||
|
||||
var row = page.Locator("div.tv-row", new() { HasText = uniqueName });
|
||||
await Assertions.Expect(row).ToBeVisibleAsync(new() { Timeout = 15_000 });
|
||||
|
||||
// The tree scrolls inside a fixed-height container; bring the row into view
|
||||
// so the right-click lands on it and the menu renders at a usable position.
|
||||
await row.ScrollIntoViewIfNeededAsync();
|
||||
await row.ClickAsync(new() { Button = MouseButton.Right });
|
||||
|
||||
await Assertions.Expect(page.Locator(".dropdown-menu.show"))
|
||||
.ToBeVisibleAsync(new() { Timeout = 5_000 });
|
||||
|
||||
return row;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user