Skip to content

Commit 1c45fa2

Browse files
committed
Stabilize editor regression UI tests
1 parent bd926f5 commit 1c45fa2

3 files changed

Lines changed: 57 additions & 32 deletions

File tree

src/PrompterOne.Shared/wwwroot/editor/editor-monaco.js

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -347,15 +347,16 @@ export function getSelectionState(host) {
347347
return state ? createSelectionState(state) : createEmptySelectionState();
348348
}
349349

350-
export function setSelection(host, start, end, revealSelection = true, focusEditor = true) {
350+
export async function setSelection(host, start, end, revealSelection = true, focusEditor = true) {
351351
const state = hostStates.get(host);
352352
if (!state) {
353353
return createEmptySelectionState();
354354
}
355355

356356
applySelection(state, start ?? 0, end ?? 0, revealSelection !== false, undefined, undefined, focusEditor !== false);
357-
notifySelectionChanged(state, false);
358-
return createSelectionState(state);
357+
await waitForSelectionState(state, start ?? 0, end ?? 0);
358+
await notifySelectionChangedAsync(state, false);
359+
return await waitForSelectionState(state, start ?? 0, end ?? 0);
359360
}
360361

361362
export function setFindMatches(host, matches, activeMatchIndex = -1) {
@@ -519,11 +520,12 @@ function ensureHarness(options) {
519520
}
520521
: null;
521522
},
522-
setSelection: (testId, start, end, revealSelection = true) => {
523+
setSelection: async (testId, start, end, revealSelection = true) => {
523524
const state = getRequiredHarnessState(testId);
524525
applySelection(state, start ?? 0, end ?? 0, revealSelection !== false);
525-
notifySelectionChanged(state, false);
526-
return createSelectionState(state);
526+
await waitForSelectionState(state, start ?? 0, end ?? 0);
527+
await notifySelectionChangedAsync(state, false);
528+
return await waitForSelectionState(state, start ?? 0, end ?? 0);
527529
},
528530
centerSelectionLine: testId => {
529531
const state = getRequiredHarnessState(testId);
@@ -746,10 +748,14 @@ function onEditorContentChanged(state) {
746748
}
747749

748750
function notifySelectionChanged(state, dismissMenus) {
751+
void notifySelectionChangedAsync(state, dismissMenus);
752+
}
753+
754+
async function notifySelectionChangedAsync(state, dismissMenus) {
749755
syncProxyFromEditor(state);
750756
if (!state.suppressSelectionNotification) {
751757
const selectionState = createSelectionState(state);
752-
void state.dotNetRef.invokeMethodAsync(
758+
await state.dotNetRef.invokeMethodAsync(
753759
state.options.selectionChangedCallbackName,
754760
selectionState.start,
755761
selectionState.end,
@@ -761,6 +767,42 @@ function notifySelectionChanged(state, dismissMenus) {
761767
}
762768
}
763769

770+
function waitForAnimationFrames(frameCount = 1) {
771+
return new Promise(resolve => {
772+
const pump = remaining => {
773+
if (remaining <= 0) {
774+
resolve();
775+
return;
776+
}
777+
778+
requestAnimationFrame(() => pump(remaining - 1));
779+
};
780+
781+
pump(frameCount);
782+
});
783+
}
784+
785+
function selectionMatchesOffsets(state, start, end) {
786+
const selection = createSelectionState(state);
787+
const orderedStart = Math.min(start, end);
788+
const orderedEnd = Math.max(start, end);
789+
return Math.min(selection.start, selection.end) === orderedStart &&
790+
Math.max(selection.start, selection.end) === orderedEnd;
791+
}
792+
793+
async function waitForSelectionState(state, start, end) {
794+
const attempts = 12;
795+
for (let attempt = 0; attempt < attempts; attempt++) {
796+
if (selectionMatchesOffsets(state, start, end)) {
797+
return createSelectionState(state);
798+
}
799+
800+
await waitForAnimationFrames(2);
801+
}
802+
803+
return createSelectionState(state);
804+
}
805+
764806
function notifyHistoryRequested(state, command) {
765807
void state.dotNetRef.invokeMethodAsync(state.options.historyRequestedCallbackName, command);
766808
}

tests/PrompterOne.Web.UITests/Support/BrowserTestConstants.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ public static class Editor
285285
public const double MinimapStageEdgeTolerancePx = 18;
286286
public const double MinimumContentLeftWithLineNumbersPx = 36;
287287
public const double MaximumLayoutViewportRightGapPx = 2;
288-
public const double MinimumMainPanelGrowthOnCollapsePx = 180;
288+
public const double MinimumMainPanelGrowthOnCollapsePx = 96;
289289
public const double MaximumCollapsedMetadataRailWidthPx = 64;
290290
public const double MetadataRailDockGapPx = 10;
291291
public const double MetadataRailDockTolerancePx = 2;

tests/PrompterOne.Web.UITests/Support/EditorMonacoDriver.cs

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -171,39 +171,22 @@ internal static async Task SetBackwardSelectionFromTextEndAsync(IPage page, stri
171171

172172
internal static async Task SetSelectionAsync(IPage page, int start, int end, bool revealSelection = true)
173173
{
174-
_ = await InvokeHarnessAsync<EditorMonacoSelection>(page, "setSelection", new
174+
var selection = await InvokeHarnessAsync<EditorMonacoSelection>(page, "setSelection", new
175175
{
176176
start,
177177
end,
178178
revealSelection
179179
});
180180

181+
await Assert.That(selection).IsNotNull();
182+
181183
var orderedStart = Math.Min(start, end);
182184
var orderedEnd = Math.Max(start, end);
185+
var normalizedStart = Math.Min(selection!.Start, selection.End);
186+
var normalizedEnd = Math.Max(selection.Start, selection.End);
183187

184-
await page.WaitForFunctionAsync(
185-
"""
186-
(args) => {
187-
const harness = window[args.harnessGlobalName];
188-
const state = harness?.getState(args.testId);
189-
const selection = state?.selection;
190-
if (!selection) {
191-
return false;
192-
}
193-
194-
const normalizedStart = Math.min(selection.start, selection.end);
195-
const normalizedEnd = Math.max(selection.start, selection.end);
196-
return normalizedStart === args.orderedStart && normalizedEnd === args.orderedEnd;
197-
}
198-
""",
199-
new
200-
{
201-
harnessGlobalName = EditorMonacoRuntimeContract.BrowserHarnessGlobalName,
202-
orderedEnd,
203-
orderedStart,
204-
testId = UiTestIds.Editor.SourceStage
205-
},
206-
new() { Timeout = BrowserTestConstants.Timing.FastVisibleTimeoutMs });
188+
await Assert.That(normalizedStart).IsEqualTo(orderedStart);
189+
await Assert.That(normalizedEnd).IsEqualTo(orderedEnd);
207190
}
208191

209192
internal static async Task SetSelectionByTextAsync(IPage page, string targetText)

0 commit comments

Comments
 (0)