Files
ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Transport/TransportExportTests.cs
T
Joseph Doherty 513fa1aa16 docs(tests): fix CommentChecker findings across tests/ — 13,392 → 0 (repo-wide scan clean)
Comment/XML-doc changes only:
- add summaries to ~10k test methods, fixtures, fakes and helpers
  (+ <param> on theories, <returns> on async Task methods,
  <inheritdoc/> on interface implementations the checker can resolve)
- strip ~2.6k project-tracking references (WP*, P*-*, row-NN, Task N,
  #NN, Component-0NN) from comments, keeping the explanatory text;
  reword false positives in comments only
- real docs on fakes implementing BCL/library interfaces
  (IDisposable, ILogger, IOptionsMonitor, IAsyncLifetime)
- reword the last 5 src/ false positives (CWE-1236, failures-1,
  year-0001, M365)

Only non-comment edits: four one-line nested classes split across lines
so members can carry docs. Build 0 errors / 0 warnings.
2026-10-07 15:05:49 -04:00

123 lines
6.7 KiB
C#

using Microsoft.Playwright;
using ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests.Cluster;
namespace ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests.Transport;
/// <summary>
/// Happy-path end-to-end for the Transport Export wizard.
///
/// <para>
/// Drives the full four-step wizard at <c>/design/transport/export</c> against the
/// running dev cluster, exporting a single throwaway template the test creates via
/// the CLI:
/// </para>
/// <list type="number">
/// <item>Step 1 — Select : filter to the zztest template and tick its checkbox.</item>
/// <item>Step 2 — Review : confirm the resolved closure (Next).</item>
/// <item>Step 3 — Encrypt: supply a matching passphrase (≥ 8 chars) and Export.</item>
/// <item>Step 4 — Download: assert the success summary.</item>
/// </list>
///
/// <para>
/// Step 1's template list is a <c>TemplateFolderTree</c> in checkbox mode. The inner
/// <c>TreeView</c> renders an <c>&lt;input type="checkbox" class="tv-checkbox"&gt;</c>
/// per node and the name in a sibling <c>span.tv-label</c>; there is no
/// <c>&lt;label for&gt;</c> association, and in checkbox mode clicking the label text
/// does NOT toggle the box (content-click only selects in Single mode). So the test
/// clicks the checkbox <c>input</c> itself, scoped to the row carrying the template's
/// label text.
/// </para>
///
/// <para>
/// Step 4's download is a JS-interop blob stream (NOT a DOM <c>&lt;a download&gt;</c>),
/// so the test asserts the success DOM (<c>[data-testid='download-summary']</c>) rather
/// than waiting for a Playwright download event — which would hang, since no
/// browser-level download fires.
/// </para>
/// </summary>
[Collection("Playwright")]
public sealed class TransportExportTests
{
private readonly PlaywrightFixture _fixture;
/// <summary>Initializes the test class with the shared Playwright fixture.</summary>
/// <param name="fixture">The shared Playwright fixture.</param>
public TransportExportTests(PlaywrightFixture fixture)
{
_fixture = fixture;
}
/// <summary>Verifies that exporting a throwaway template through the wizard reaches the download summary.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[SkippableFact]
public async Task ExportTemplate_ReachesDownloadSummary()
{
Skip.IfNot(await ClusterAvailability.IsAvailableAsync(), ClusterAvailability.SkipReason);
var tmplName = CliRunner.UniqueName("exptmpl");
var tmplId = await CliRunner.CreateTemplateAsync(tmplName);
await CliRunner.AddAttributeAsync(tmplId, "Value", "Double");
try
{
var page = await _fixture.NewAuthenticatedPageAsync("multi-role", "password");
await page.GotoAsync($"{PlaywrightFixture.BaseUrl}/design/transport/export");
// Wait for step 1 to render (OnInitializedAsync makes 8 repo calls over SignalR
// before the template tree appears — NetworkIdle is an unreliable proxy for this).
await Assertions.Expect(page.Locator("[data-testid='group-templates']"))
.ToBeVisibleAsync(new() { Timeout = 15_000 });
// ── STEP 1: Select ────────────────────────────────────────────────────────
// Narrow the tree to just the zztest template, then tick its checkbox.
await page.Locator("#export-filter").FillAsync(tmplName);
// The template node is a TreeView leaf row: a checkbox input plus a
// span.tv-label carrying the name. Clicking the label text is a no-op in
// checkbox mode, so we click the input directly, scoped to the row whose
// label matches the unique zztest name.
var templateCheckbox = page
.Locator("[data-testid='group-templates'] li")
.Filter(new() { Has = page.Locator($"span.tv-label:text-is('{tmplName}')") })
.Locator("input.tv-checkbox")
.First;
await Assertions.Expect(templateCheckbox).ToBeVisibleAsync(new() { Timeout = 10_000 });
await templateCheckbox.CheckAsync();
// Next enables only once a selection exists; clicking it resolves the closure.
var step1Next = page.Locator("button.btn.btn-primary:has-text('Next')");
await Assertions.Expect(step1Next).ToBeEnabledAsync(new() { Timeout = 10_000 });
await step1Next.ClickAsync();
// ── STEP 2: Review ────────────────────────────────────────────────────────
// The seed group lists the picked template; Next is always enabled here.
// Scope the Next click to the step 2 panel — identified by its unique
// #include-deps toggle — so it cannot accidentally match a step 1 button.
await Assertions.Expect(page.Locator("[data-testid='seed-group']"))
.ToBeVisibleAsync(new() { Timeout = 15_000 });
await page.Locator("div:has(#include-deps) button.btn.btn-primary:has-text('Next')")
.ClickAsync();
// ── STEP 3: Encrypt ───────────────────────────────────────────────────────
const string passphrase = "zztest-passphrase-123";
await Assertions.Expect(page.Locator("#passphrase"))
.ToBeVisibleAsync(new() { Timeout = 10_000 });
await page.Locator("#passphrase").FillAsync(passphrase);
await page.Locator("#passphrase-confirm").FillAsync(passphrase);
// Export enables only when the two passphrases match AND length ≥ 8.
var exportBtn = page.Locator("button.btn.btn-primary:has-text('Export')");
await Assertions.Expect(exportBtn).ToBeEnabledAsync(new() { Timeout = 10_000 });
await exportBtn.ClickAsync();
// ── STEP 4: Download ──────────────────────────────────────────────────────
// JS-interop blob download — assert the success DOM, never WaitForDownload.
var summary = page.Locator("[data-testid='download-summary']");
await Assertions.Expect(summary).ToBeVisibleAsync(new() { Timeout = 20_000 });
await Assertions.Expect(summary).ToContainTextAsync("Bundle ready");
}
finally
{
await CliRunner.DeleteTemplateAsync(tmplId);
}
}
}