Просмотр исходного кода

Fix flaky YAML-import E2E: wait for the Blazor circuit before typing

The WebUI job on PR #339 failed on YamlImportTests: the "Apply" button
stayed disabled for the full 15s timeout. Same prerender race b8f6d23
fixed for the add form — YamlImportPom.GotoAsync navigated and returned
as soon as the textarea was visible, so a FillAsync that landed before
the circuit attached was lost to the static prerendered HTML. The
oninput diff then never ran and Apply never enabled. CI lost this race
intermittently; a fast machine won it, which is why it didn't reproduce
on every run.

GotoAsync now waits for MainLayout's data-circuit-ready probe (the same
signal the add form waits on) before returning, so every subsequent
PasteAsync reaches a live circuit.

Added Importing_Works_Before_The_Circuit_Has_Warmed_Up, mirroring
AddResourceRaceTests: 300ms injected SignalR latency widens the attach
window so the race loses every time. Verified it fails (16s timeout,
matching CI) with the wait removed and passes with it in place.

Not an MCP regression — a pre-existing flake in a test added on staging
(97e7efd) that this PR's CI run happened to trigger.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tim Jones 11 часов назад
Родитель
Сommit
598b2231ff
2 измененных файлов с 46 добавлено и 0 удалено
  1. 6 0
      Tests.E2e/PageObjectModels/YamlImportPom.cs
  2. 40 0
      Tests.E2e/YamlImportTests.cs

+ 6 - 0
Tests.E2e/PageObjectModels/YamlImportPom.cs

@@ -48,6 +48,12 @@ public class YamlImportPom(IPage page) {
     public async Task GotoAsync(string baseUrl) {
         await page.GotoAsync($"{baseUrl}/yaml/import");
         await Assertions.Expect(Input).ToBeVisibleAsync();
+
+        // Never type into the prerendered page: input events are lost before the
+        // circuit attaches, so the oninput diff never runs and Apply stays disabled.
+        // Same race the Add form hit (b8f6d23) — wait for the live circuit first.
+        await Assertions.Expect(page.GetByTestId("circuit-probe"))
+            .ToHaveAttributeAsync("data-circuit-ready", "true");
     }
 
     public async Task PasteAsync(string yaml)

+ 40 - 0
Tests.E2e/YamlImportTests.cs

@@ -152,6 +152,46 @@ public class YamlImportTests(
         }
     }
 
+    // =============================================================
+    // The prerender race (regression guard for the CI flake on #339)
+    // =============================================================
+
+    /// <summary>
+    ///     The import page has the same prerender race the add form had (b8f6d23):
+    ///     text filled before the circuit attaches never fires the oninput diff, so the
+    ///     Apply button stays disabled forever. CI lost this race intermittently; the
+    ///     injected latency loses it every time, proving GotoAsync's circuit wait fixes it.
+    /// </summary>
+    [Fact]
+    public async Task Importing_Works_Before_The_Circuit_Has_Warmed_Up() {
+        (IBrowserContext context, IPage page) = await CreatePageAsync();
+        await BlazorLatency.AddAsync(page, TimeSpan.FromMilliseconds(300));
+
+        var switchA = $"e2e-ra-{Guid.NewGuid():N}"[..14];
+        var switchB = $"e2e-rb-{Guid.NewGuid():N}"[..14];
+
+        try {
+            var import = new YamlImportPom(page);
+            await import.GotoAsync(_fixture.BaseUrl);
+
+            await import.PasteAsync(TwoSwitchesWithConnection(switchA, switchB));
+
+            // The regression: without GotoAsync waiting for the circuit, the fill above
+            // is lost to the prerendered page, the diff never runs, and Apply stays
+            // disabled. Asserting it becomes enabled is the whole point — persistence is
+            // already covered by the non-latency test, and a post-apply navigation would
+            // only reintroduce flakiness under the injected latency.
+            await Assertions.Expect(import.ApplyButton).ToBeEnabledAsync();
+        }
+        catch (Exception) {
+            await DumpAsync(page);
+            throw;
+        }
+        finally {
+            await context.CloseAsync();
+        }
+    }
+
     private async Task DumpAsync(IPage page) {
         _output.WriteLine("TEST FAILED — Capturing diagnostics");
         _output.WriteLine($"Current URL: {page.Url}");