test(playwright): Templates duplicate-name + create-cancel edge cases (Wave 4)
This commit is contained in:
@@ -120,4 +120,96 @@ public class TemplateCrudTests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SkippableFact]
|
||||||
|
public async Task CreateTemplate_DuplicateName_ShowsInlineError()
|
||||||
|
{
|
||||||
|
Skip.IfNot(await ClusterAvailability.IsAvailableAsync(), ClusterAvailability.SkipReason);
|
||||||
|
|
||||||
|
// CLI-seed an existing base template, then UI-attempt to create a duplicate.
|
||||||
|
// Base (non-derived) Template.Name has a unique index
|
||||||
|
// (HasIndex(t => t.Name).IsUnique().HasFilter("[IsDerived]=0")) and
|
||||||
|
// TemplateService.CreateTemplateAsync has no friendly duplicate pre-check,
|
||||||
|
// so the DB-constraint exception is caught into _formError and rendered inline
|
||||||
|
// in div.text-danger.small with no navigation (stays on /create).
|
||||||
|
// (Empirically confirmed: duplicate create surfaces inline; duplicate-name path used.)
|
||||||
|
var name = CliRunner.UniqueName("tmpl");
|
||||||
|
var seededId = await CliRunner.CreateTemplateAsync(name);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var page = await _fixture.NewAuthenticatedPageAsync();
|
||||||
|
|
||||||
|
await page.GotoAsync($"{PlaywrightFixture.BaseUrl}/design/templates/create");
|
||||||
|
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
|
||||||
|
|
||||||
|
// Fill the Name input with the duplicate name and click Create.
|
||||||
|
await page.Locator("div.mb-3:has(label:has-text('Name')) input.form-control").FillAsync(name);
|
||||||
|
await page.ClickAsync("button.btn.btn-success:has-text('Create')");
|
||||||
|
|
||||||
|
// Web-first assertions: the inline error becomes visible and we stay on /create.
|
||||||
|
// Do NOT assert a literal message — it is the DB-constraint exception text.
|
||||||
|
await Assertions.Expect(page.Locator("div.text-danger.small")).ToBeVisibleAsync();
|
||||||
|
await Assertions.Expect(page)
|
||||||
|
.ToHaveURLAsync(new System.Text.RegularExpressions.Regex("/design/templates/create"));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Delete the seeded source template, then sweep any leftover by name.
|
||||||
|
await CliRunner.DeleteTemplateAsync(seededId);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (var id in await CliRunner.ListTemplateIdsByNamePrefixAsync(name))
|
||||||
|
{
|
||||||
|
await CliRunner.DeleteTemplateAsync(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Best-effort — swallow to avoid masking the original test failure.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[SkippableFact]
|
||||||
|
public async Task CreateTemplate_Cancel_ReturnsToListWithoutCreating()
|
||||||
|
{
|
||||||
|
Skip.IfNot(await ClusterAvailability.IsAvailableAsync(), ClusterAvailability.SkipReason);
|
||||||
|
|
||||||
|
var name = CliRunner.UniqueName("tmpl");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var page = await _fixture.NewAuthenticatedPageAsync();
|
||||||
|
|
||||||
|
await page.GotoAsync($"{PlaywrightFixture.BaseUrl}/design/templates/create");
|
||||||
|
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
|
||||||
|
|
||||||
|
// Fill the Name input, then click Cancel — Blazor navigates back to the list.
|
||||||
|
await page.Locator("div.mb-3:has(label:has-text('Name')) input.form-control").FillAsync(name);
|
||||||
|
await page.ClickAsync("button.btn.btn-outline-secondary:has-text('Cancel')");
|
||||||
|
|
||||||
|
// excludePath: "/create" rejects the /design/templates/create URL we came from.
|
||||||
|
await PlaywrightFixture.WaitForPathAsync(page, "/design/templates", excludePath: "/create");
|
||||||
|
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
|
||||||
|
|
||||||
|
// Nothing was created: no template exists with our unique name.
|
||||||
|
Assert.Empty(await CliRunner.ListTemplateIdsByNamePrefixAsync(name));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Defensive sweep by name in case of an unexpected create.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (var id in await CliRunner.ListTemplateIdsByNamePrefixAsync(name))
|
||||||
|
{
|
||||||
|
await CliRunner.DeleteTemplateAsync(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Best-effort — swallow to avoid masking the original test failure.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user