Skip to content

Commit 2bfdd9a

Browse files
committed
Stabilize browser suite route readiness
1 parent f1c8109 commit 2bfdd9a

8 files changed

Lines changed: 134 additions & 56 deletions

File tree

full-suite-stabilization.plan.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,18 @@ Tracked failing tests from the current baseline:
251251
- move the remaining SPA route-changing interactions onto the shared `ClickAndContinueAsync(..., noWaitAfter: true)` path
252252
- harden reader timing and reverse-transition assertions against poll jitter while keeping the user-visible behavior contract intact
253253
- route editor open/theme/split/title flows through the shared route helpers and interaction driver so local and CI follow the same readiness path
254+
- [x] `Release Pipeline` run `24234983323` fails remotely in `Shell` and `Editor` after commit `ee5f0fb`
255+
Symptom:
256+
- `Shell` still times out in a small route-transition cluster where the UI remains on `library-page` after import/playback actions instead of completing the intended move into `editor`, `learn`, or `reader`
257+
- `Editor` still flakes in local-history flows, with one test timing out after opening `/settings` and another timing out after a raw page reload while the editor is already visibly present
258+
Root cause:
259+
- several remaining SPA route-changing clicks were still using default Playwright navigation waiting instead of the shared no-wait click contract plus explicit route-ready waits, so CI could stall on scheduled client-side transitions
260+
- some return-to-editor paths only waited for `editor-page` instead of full Monaco readiness
261+
- `EditorLocalHistoryFlowTests` still bypassed the shared route helpers with raw `GotoAsync("/settings")` and raw `ReloadAsync()`, which made the tests diverge from the rest of the browser harness under slower remote startup
262+
Fix path:
263+
- move the remaining route-changing shell, reader, and studio clicks onto `UiInteractionDriver.ClickAndContinueAsync(..., noWaitAfter: true)` where the test already owns the post-click readiness contract
264+
- upgrade learn/teleprompter/editor return waits to the shared ready helpers so route completion is measured by the real interactive surface, not just the shell frame
265+
- route editor local-history settings/reload operations through `ShellRouteDriver.OpenSettingsAsync(...)` and `BrowserRouteDriver.ReloadPageAsync(...)` so local and CI share the same readiness path
254266

255267
## Ordered Plan
256268

@@ -289,6 +301,7 @@ Tracked failing tests from the current baseline:
289301
- `dotnet build ./PrompterOne.slnx -warnaserror` passed
290302
- `dotnet test @./tests/dotnet-test-progress.rsp --solution ./PrompterOne.slnx --max-parallel-test-modules 1` passed with `1162/1162` green in `7m 42.943s`
291303
- post-format verification repeated successfully with `dotnet build ./PrompterOne.slnx -warnaserror` and `dotnet test @./tests/dotnet-test-progress.rsp --solution ./PrompterOne.slnx --max-parallel-test-modules 1`, ending at `1162/1162` green in `7m 35.996s`
304+
- latest post-remediation verification repeated successfully with `dotnet format ./PrompterOne.slnx`, `dotnet build ./PrompterOne.slnx -warnaserror`, and `dotnet test @./tests/dotnet-test-progress.rsp --solution ./PrompterOne.slnx --max-parallel-test-modules 1`, ending at `1162/1162` green in `7m 47.418s`
292305

293306
- [ ] Step 5. Publish directly to `main`.
294307
Actions:
@@ -327,3 +340,9 @@ Tracked failing tests from the current baseline:
327340
- `dotnet test @./tests/dotnet-test-progress.rsp --project ./tests/PrompterOne.Web.UITests.Reader/PrompterOne.Web.UITests.Reader.csproj` passed with `168/168`
328341
- `dotnet test @./tests/dotnet-test-progress.rsp --project ./tests/PrompterOne.Web.UITests.Studio/PrompterOne.Web.UITests.Studio.csproj` passed with `38/38`
329342
- `dotnet test @./tests/dotnet-test-progress.rsp --solution ./PrompterOne.slnx --max-parallel-test-modules 1` passed with `1162/1162` green in `7m 44.199s`
343+
- [x] Follow-up remediation for remote run `24234983323`
344+
Result:
345+
- `dotnet format ./PrompterOne.slnx` passed
346+
- `dotnet build ./PrompterOne.slnx -warnaserror` passed
347+
- `dotnet test @./tests/dotnet-test-progress.rsp --solution ./PrompterOne.slnx --max-parallel-test-modules 1` passed with `1162/1162` green in `7m 47.418s`
348+
- `Shell`, `Reader`, `Studio`, and `Editor` all completed green inside that solution-level validation run

tests/PrompterOne.Web.UITests.Editor/Editor/EditorLocalHistoryFlowTests.cs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Microsoft.Playwright;
12
using PrompterOne.Shared.Contracts;
23
using static Microsoft.Playwright.Assertions;
34

@@ -37,7 +38,11 @@ await UiScenarioArtifacts.CapturePageAsync(
3738
BrowserTestConstants.EditorFlow.LocalHistoryScenario,
3839
BrowserTestConstants.EditorFlow.LocalHistorySavedStep);
3940

40-
await page.ReloadAsync();
41+
await BrowserRouteDriver.ReloadPageAsync(
42+
page,
43+
CurrentRoute(page),
44+
UiTestIds.Editor.Page,
45+
"editor-local-history-reload-saved");
4146
await EditorMonacoDriver.WaitUntilReadyAsync(page);
4247
await page.GetByTestId(UiTestIds.Editor.ToolsTab).ClickAsync();
4348
await Expect(sourceInput).ToHaveValueAsync(secondRevisionText);
@@ -50,7 +55,11 @@ await UiScenarioArtifacts.CapturePageAsync(
5055
BrowserTestConstants.EditorFlow.LocalHistoryScenario,
5156
BrowserTestConstants.EditorFlow.LocalHistoryRestoredStep);
5257

53-
await page.ReloadAsync();
58+
await BrowserRouteDriver.ReloadPageAsync(
59+
page,
60+
CurrentRoute(page),
61+
UiTestIds.Editor.Page,
62+
"editor-local-history-reload-restored");
5463
await EditorMonacoDriver.WaitUntilReadyAsync(page);
5564
await page.GetByTestId(UiTestIds.Editor.ToolsTab).ClickAsync();
5665
await Expect(sourceInput).ToHaveValueAsync(firstRevisionText);
@@ -70,7 +79,7 @@ await EditorIsolatedDraftDriver.CreateSeededDraftAsync(
7079
var sourceInput = EditorMonacoDriver.SourceInput(page);
7180
var originalText = await sourceInput.InputValueAsync();
7281

73-
await page.GotoAsync(BrowserTestConstants.Routes.Settings);
82+
await ShellRouteDriver.OpenSettingsAsync(page, "editor-local-history-settings-disable");
7483
await page.GetByTestId(UiTestIds.Settings.NavFiles).ClickAsync();
7584
await Expect(page.GetByTestId(UiTestIds.Settings.FilesPanel)).ToBeVisibleAsync();
7685
await page.GetByTestId(UiTestIds.Settings.FileAutoSave).ClickAsync();
@@ -91,11 +100,15 @@ await UiScenarioArtifacts.CapturePageAsync(
91100
BrowserTestConstants.EditorFlow.LocalHistoryAutosaveScenario,
92101
BrowserTestConstants.EditorFlow.LocalHistoryAutosaveDisabledStep);
93102

94-
await page.ReloadAsync();
103+
await BrowserRouteDriver.ReloadPageAsync(
104+
page,
105+
CurrentRoute(page),
106+
UiTestIds.Editor.Page,
107+
"editor-local-history-reload-autosave-disabled");
95108
await EditorMonacoDriver.WaitUntilReadyAsync(page);
96109
await Expect(sourceInput).ToHaveValueAsync(originalText);
97110

98-
await page.GotoAsync(BrowserTestConstants.Routes.Settings);
111+
await ShellRouteDriver.OpenSettingsAsync(page, "editor-local-history-settings-enable");
99112
await page.GetByTestId(UiTestIds.Settings.NavFiles).ClickAsync();
100113
await page.GetByTestId(UiTestIds.Settings.FileAutoSave).ClickAsync();
101114
await Expect(page.GetByTestId(UiTestIds.Settings.FileAutoSave))
@@ -119,8 +132,15 @@ await UiScenarioArtifacts.CapturePageAsync(
119132
BrowserTestConstants.EditorFlow.LocalHistoryAutosaveScenario,
120133
BrowserTestConstants.EditorFlow.LocalHistoryAutosaveEnabledStep);
121134

122-
await page.ReloadAsync();
135+
await BrowserRouteDriver.ReloadPageAsync(
136+
page,
137+
CurrentRoute(page),
138+
UiTestIds.Editor.Page,
139+
"editor-local-history-reload-autosave-enabled");
123140
await EditorMonacoDriver.WaitUntilReadyAsync(page);
124141
await Expect(sourceInput).ToHaveValueAsync(resavedText);
125142
});
143+
144+
private static string CurrentRoute(IPage page) =>
145+
new Uri(page.Url).PathAndQuery;
126146
}

tests/PrompterOne.Web.UITests.Reader/Learn/EditorLearnScreenFlowTests.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ await Expect(page.GetByTestId(UiTestIds.Editor.SegmentNavigation(2))).ToHaveAttr
3535
await Expect(page.GetByTestId(UiTestIds.Editor.SourceHighlight)).ToContainTextAsync("Benefits Block");
3636

3737
await Expect(page.GetByTestId(UiTestIds.Header.EditorLearn)).ToBeVisibleAsync();
38-
await page.GetByTestId(UiTestIds.Header.EditorLearn).ClickAsync();
39-
await BrowserRouteDriver.WaitForRouteAsync(page, BrowserTestConstants.Routes.LearnDemo);
40-
await Expect(page.GetByTestId(UiTestIds.Learn.Page)).ToBeVisibleAsync(new() { Timeout = BrowserTestConstants.Timing.ExtendedVisibleTimeoutMs });
38+
await UiInteractionDriver.ClickAndContinueAsync(
39+
page.GetByTestId(UiTestIds.Header.EditorLearn),
40+
noWaitAfter: true);
41+
await PlaybackRouteDriver.WaitForLearnReadyAsync(page, BrowserTestConstants.Routes.LearnDemo);
4142

4243
await ReaderRouteDriver.OpenLearnAsync(page, BrowserTestConstants.Routes.LearnDemo);
4344
await Expect(page.GetByTestId(UiTestIds.Learn.Page)).ToBeVisibleAsync(new() { Timeout = BrowserTestConstants.Timing.ExtendedVisibleTimeoutMs });

tests/PrompterOne.Web.UITests.Shell/AppShell/HeaderPlaybackLaunchFlowTests.cs

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,43 +20,49 @@ await page.SetViewportSizeAsync(
2020
await ShellRouteDriver.OpenLibraryAsync(page);
2121

2222
await UiInteractionDriver.ClickAndContinueAsync(
23-
page.GetByTestId(UiTestIds.Library.CardLearn(BrowserTestConstants.Scripts.QuantumId)));
24-
await BrowserRouteDriver.WaitForRouteAsync(page, BrowserTestConstants.Routes.LearnQuantum);
25-
await Expect(page.GetByTestId(UiTestIds.Learn.Page)).ToBeVisibleAsync();
23+
page.GetByTestId(UiTestIds.Library.CardLearn(BrowserTestConstants.Scripts.QuantumId)),
24+
noWaitAfter: true);
25+
await PlaybackRouteDriver.WaitForLearnReadyAsync(page, BrowserTestConstants.Routes.LearnQuantum);
2626
await Expect(page.GetByTestId(UiTestIds.Header.Title))
2727
.ToHaveTextAsync(BrowserTestConstants.Scripts.QuantumTitle);
2828
await UiScenarioArtifacts.CapturePageAsync(
2929
page,
3030
BrowserTestConstants.AppShellFlow.PlaybackLaunchScenario,
3131
BrowserTestConstants.AppShellFlow.LearnLaunchStep);
3232

33-
await UiInteractionDriver.ClickAndContinueAsync(page.GetByTestId(UiTestIds.Header.Back));
33+
await UiInteractionDriver.ClickAndContinueAsync(
34+
page.GetByTestId(UiTestIds.Header.Back),
35+
noWaitAfter: true);
3436
await BrowserRouteDriver.WaitForRouteAsync(page, BrowserTestConstants.Routes.EditorQuantum);
35-
await Expect(page.GetByTestId(UiTestIds.Editor.Page)).ToBeVisibleAsync();
37+
await EditorMonacoDriver.WaitUntilReadyAsync(page);
3638
await Expect(page.GetByTestId(UiTestIds.Header.Title))
3739
.ToHaveTextAsync(BrowserTestConstants.Scripts.QuantumTitle);
3840
await UiScenarioArtifacts.CapturePageAsync(
3941
page,
4042
BrowserTestConstants.AppShellFlow.PlaybackLaunchScenario,
4143
BrowserTestConstants.AppShellFlow.LearnBackStep);
4244

43-
await UiInteractionDriver.ClickAndContinueAsync(page.GetByTestId(UiTestIds.Header.Home));
45+
await UiInteractionDriver.ClickAndContinueAsync(
46+
page.GetByTestId(UiTestIds.Header.Home),
47+
noWaitAfter: true);
4448
await ShellRouteDriver.WaitForLibraryReadyAsync(page, AppRoutes.Library);
4549

4650
await UiInteractionDriver.ClickAndContinueAsync(
47-
page.GetByTestId(UiTestIds.Library.CardRead(BrowserTestConstants.Scripts.QuantumId)));
48-
await BrowserRouteDriver.WaitForRouteAsync(page, BrowserTestConstants.Routes.TeleprompterQuantum);
49-
await Expect(page.GetByTestId(UiTestIds.Teleprompter.Page)).ToBeVisibleAsync();
51+
page.GetByTestId(UiTestIds.Library.CardRead(BrowserTestConstants.Scripts.QuantumId)),
52+
noWaitAfter: true);
53+
await PlaybackRouteDriver.WaitForTeleprompterReadyAsync(page, BrowserTestConstants.Routes.TeleprompterQuantum);
5054
await Expect(page.GetByTestId(UiTestIds.Header.Title))
5155
.ToHaveTextAsync(BrowserTestConstants.Scripts.QuantumTitle);
5256
await UiScenarioArtifacts.CapturePageAsync(
5357
page,
5458
BrowserTestConstants.AppShellFlow.PlaybackLaunchScenario,
5559
BrowserTestConstants.AppShellFlow.TeleprompterLaunchStep);
5660

57-
await UiInteractionDriver.ClickAndContinueAsync(page.GetByTestId(UiTestIds.Header.Back));
61+
await UiInteractionDriver.ClickAndContinueAsync(
62+
page.GetByTestId(UiTestIds.Header.Back),
63+
noWaitAfter: true);
5864
await BrowserRouteDriver.WaitForRouteAsync(page, BrowserTestConstants.Routes.EditorQuantum);
59-
await Expect(page.GetByTestId(UiTestIds.Editor.Page)).ToBeVisibleAsync();
65+
await EditorMonacoDriver.WaitUntilReadyAsync(page);
6066
await Expect(page.GetByTestId(UiTestIds.Header.Title))
6167
.ToHaveTextAsync(BrowserTestConstants.Scripts.QuantumTitle);
6268
await UiScenarioArtifacts.CapturePageAsync(
@@ -77,7 +83,9 @@ await page.SetViewportSizeAsync(
7783

7884
await ShellRouteDriver.OpenGoLiveRouteAsync(page, BrowserTestConstants.Routes.GoLiveDemo);
7985

80-
await UiInteractionDriver.ClickAndContinueAsync(page.GetByTestId(UiTestIds.GoLive.OpenSettings));
86+
await UiInteractionDriver.ClickAndContinueAsync(
87+
page.GetByTestId(UiTestIds.GoLive.OpenSettings),
88+
noWaitAfter: true);
8189
await BrowserRouteDriver.WaitForRouteAsync(page, BrowserTestConstants.Routes.Settings);
8290
await Expect(page.GetByTestId(UiTestIds.Settings.Page)).ToBeVisibleAsync();
8391
await Expect(page.GetByTestId(UiTestIds.Header.Title))
@@ -87,7 +95,9 @@ await UiScenarioArtifacts.CapturePageAsync(
8795
BrowserTestConstants.AppShellFlow.SettingsOriginScenario,
8896
BrowserTestConstants.AppShellFlow.SettingsLaunchStep);
8997

90-
await UiInteractionDriver.ClickAndContinueAsync(page.GetByTestId(UiTestIds.Header.Back));
98+
await UiInteractionDriver.ClickAndContinueAsync(
99+
page.GetByTestId(UiTestIds.Header.Back),
100+
noWaitAfter: true);
91101
await ShellRouteDriver.WaitForGoLiveReadyAsync(page, BrowserTestConstants.Routes.GoLiveDemo);
92102
await UiScenarioArtifacts.CapturePageAsync(
93103
page,

tests/PrompterOne.Web.UITests.Shell/AppShell/NavigationFlowTests.cs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,17 @@ public async Task ShellHeader_OpensGoLive_FromLibraryAndSettings()
2121
{
2222
await ShellRouteDriver.OpenLibraryAsync(page);
2323

24-
await UiInteractionDriver.ClickAndContinueAsync(page.GetByTestId(UiTestIds.Header.GoLive));
24+
await UiInteractionDriver.ClickAndContinueAsync(
25+
page.GetByTestId(UiTestIds.Header.GoLive),
26+
noWaitAfter: true);
2527
await BrowserRouteDriver.WaitForRouteAsync(page, AppRoutes.GoLive);
2628
await Expect(page.GetByTestId(UiTestIds.GoLive.Page)).ToBeVisibleAsync();
2729

2830
await ShellRouteDriver.OpenSettingsAsync(page);
2931

30-
await UiInteractionDriver.ClickAndContinueAsync(page.GetByTestId(UiTestIds.Header.GoLive));
32+
await UiInteractionDriver.ClickAndContinueAsync(
33+
page.GetByTestId(UiTestIds.Header.GoLive),
34+
noWaitAfter: true);
3135
await BrowserRouteDriver.WaitForRouteAsync(page, AppRoutes.GoLive);
3236
await Expect(page.GetByTestId(UiTestIds.GoLive.Page)).ToBeVisibleAsync();
3337
}
@@ -52,9 +56,10 @@ await EditorRouteDriver.OpenReadyAsync(
5256

5357
await page.EvaluateAsync("value => window.__prompterSpaNonce = value", nonce);
5458

55-
await UiInteractionDriver.ClickAndContinueAsync(page.GetByTestId(UiTestIds.Header.EditorLearn));
56-
await BrowserRouteDriver.WaitForRouteAsync(page, BrowserTestConstants.Routes.LearnQuantum);
57-
await Expect(page.GetByTestId(UiTestIds.Learn.Page)).ToBeVisibleAsync();
59+
await UiInteractionDriver.ClickAndContinueAsync(
60+
page.GetByTestId(UiTestIds.Header.EditorLearn),
61+
noWaitAfter: true);
62+
await PlaybackRouteDriver.WaitForLearnReadyAsync(page, BrowserTestConstants.Routes.LearnQuantum);
5863
await Assert.That(await page.EvaluateAsync<string>("() => window.__prompterSpaNonce")).IsEqualTo(nonce);
5964

6065
await EditorRouteDriver.OpenReadyAsync(
@@ -63,14 +68,17 @@ await EditorRouteDriver.OpenReadyAsync(
6368
$"{nameof(ScreenNavigation_UsesSpaRoutingWithoutReloadingBrowserContext)}-return");
6469
await page.EvaluateAsync("value => window.__prompterSpaNonce = value", nonce);
6570

66-
await UiInteractionDriver.ClickAndContinueAsync(page.GetByTestId(UiTestIds.Header.EditorRead));
67-
await BrowserRouteDriver.WaitForRouteAsync(page, BrowserTestConstants.Routes.TeleprompterQuantum);
68-
await Expect(page.GetByTestId(UiTestIds.Teleprompter.Page)).ToBeVisibleAsync();
71+
await UiInteractionDriver.ClickAndContinueAsync(
72+
page.GetByTestId(UiTestIds.Header.EditorRead),
73+
noWaitAfter: true);
74+
await PlaybackRouteDriver.WaitForTeleprompterReadyAsync(page, BrowserTestConstants.Routes.TeleprompterQuantum);
6975
await Assert.That(await page.EvaluateAsync<string>("() => window.__prompterSpaNonce")).IsEqualTo(nonce);
7076

71-
await UiInteractionDriver.ClickAndContinueAsync(page.GetByTestId(UiTestIds.Teleprompter.Back));
77+
await UiInteractionDriver.ClickAndContinueAsync(
78+
page.GetByTestId(UiTestIds.Teleprompter.Back),
79+
noWaitAfter: true);
7280
await BrowserRouteDriver.WaitForRouteAsync(page, BrowserTestConstants.Routes.EditorQuantum);
73-
await Expect(page.GetByTestId(UiTestIds.Editor.Page)).ToBeVisibleAsync();
81+
await EditorMonacoDriver.WaitUntilReadyAsync(page);
7482
await Assert.That(await page.EvaluateAsync<string>("() => window.__prompterSpaNonce")).IsEqualTo(nonce);
7583
}
7684
finally

0 commit comments

Comments
 (0)