test(e2e): Transport import wrong-passphrase shows error and stays on passphrase step
This commit is contained in:
+82
@@ -156,4 +156,86 @@ public class TransportImportTests
|
|||||||
try { File.Delete(bundlePath); } catch { /* best-effort */ }
|
try { File.Delete(bundlePath); } catch { /* best-effort */ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Negative path: feed a real encrypted bundle, then submit the WRONG
|
||||||
|
/// passphrase at Step 2. Per
|
||||||
|
/// <c>TransportImport.razor.cs::SubmitPassphraseAsync</c>, the importer throws
|
||||||
|
/// <see cref="System.Security.Cryptography.CryptographicException"/>, which
|
||||||
|
/// increments <c>_failedUnlockAttempts</c> to 1 (below the configured
|
||||||
|
/// <c>MaxUnlockAttemptsPerSession</c> of 3, so no lockout / no re-upload),
|
||||||
|
/// sets <c>_errorMessage = "Wrong passphrase. Please try again."</c>, clears
|
||||||
|
/// the passphrase field, and leaves <c>_step</c> on Passphrase. The wizard
|
||||||
|
/// therefore renders the <c>[data-testid='error-message']</c> alert, keeps
|
||||||
|
/// <c>#import-passphrase</c> visible, and never reaches the Diff step — so
|
||||||
|
/// <c>[data-testid='diff-summary']</c> stays absent.
|
||||||
|
///
|
||||||
|
/// <para>
|
||||||
|
/// We never reach the diff/apply, so the source template is deliberately NOT
|
||||||
|
/// deleted before import; teardown drops it by name prefix.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
[SkippableFact]
|
||||||
|
public async Task ImportWithWrongPassphrase_ShowsErrorAndStaysOnPassphraseStep()
|
||||||
|
{
|
||||||
|
Skip.IfNot(await ClusterAvailability.IsAvailableAsync(), ClusterAvailability.SkipReason);
|
||||||
|
|
||||||
|
var tmplName = CliRunner.UniqueName("wrongpass");
|
||||||
|
var bundlePath = Path.Combine(Path.GetTempPath(), tmplName + ".scadabundle");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// ── ARRANGE: build + export a synthetic single-template encrypted bundle ──
|
||||||
|
int tmplId = await CliRunner.CreateTemplateAsync(tmplName);
|
||||||
|
await CliRunner.AddAttributeAsync(tmplId, "Value", "Double");
|
||||||
|
await CliRunner.BundleExportAsync(bundlePath, tmplId, "correct-passphrase-1", "src-env");
|
||||||
|
|
||||||
|
var page = await _fixture.NewAuthenticatedPageAsync("multi-role", "password");
|
||||||
|
|
||||||
|
// ── STEP 1: Upload ────────────────────────────────────────────────────────
|
||||||
|
await page.GotoAsync($"{PlaywrightFixture.BaseUrl}/design/transport/import");
|
||||||
|
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
|
||||||
|
|
||||||
|
await page.Locator("#bundle-input").SetInputFilesAsync(bundlePath);
|
||||||
|
await Assertions.Expect(page.Locator("[data-testid='encrypted-bundle-notice']"))
|
||||||
|
.ToBeVisibleAsync(new() { Timeout = 15_000 });
|
||||||
|
|
||||||
|
await page.Locator("button.btn.btn-primary:has-text('Next')").ClickAsync();
|
||||||
|
|
||||||
|
// ── STEP 2: Passphrase (wrong) ────────────────────────────────────────────
|
||||||
|
await Assertions.Expect(page.Locator("#import-passphrase"))
|
||||||
|
.ToBeVisibleAsync(new() { Timeout = 10_000 });
|
||||||
|
await page.Locator("#import-passphrase").FillAsync("WRONG-passphrase-xyz");
|
||||||
|
await page.Locator("button.btn.btn-primary:has-text('Unlock')").ClickAsync();
|
||||||
|
|
||||||
|
// The wrong passphrase surfaces the typed error, keeps the passphrase
|
||||||
|
// input visible (still on Step 2), and never reveals the diff summary.
|
||||||
|
await Assertions.Expect(page.Locator("[data-testid='error-message']"))
|
||||||
|
.ToContainTextAsync("Wrong passphrase. Please try again.", new() { Timeout = 10_000 });
|
||||||
|
await Assertions.Expect(page.Locator("#import-passphrase")).ToBeVisibleAsync();
|
||||||
|
await Assertions.Expect(page.Locator("[data-testid='diff-summary']")).ToBeHiddenAsync();
|
||||||
|
|
||||||
|
// Secondary indicator: one failed attempt recorded (1 of MaxUnlockAttempts).
|
||||||
|
await Assertions.Expect(page.Locator("[data-testid='unlock-attempts']"))
|
||||||
|
.ToContainTextAsync("Failed unlock attempts: 1 of");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// The source template was never deleted (we never reached apply), so
|
||||||
|
// teardown drops it by name prefix and removes the staged bundle.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (var id in await CliRunner.ListTemplateIdsByNamePrefixAsync(tmplName))
|
||||||
|
{
|
||||||
|
await CliRunner.DeleteTemplateAsync(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Best-effort — never mask the test's own failure.
|
||||||
|
}
|
||||||
|
|
||||||
|
try { File.Delete(bundlePath); } catch { /* best-effort */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user