mirror of
https://github.com/ether/etherpad-lite.git
synced 2026-05-05 12:16:45 +02:00
fix(test): null padDeletionToken before pad init to stop modal focus theft (#7643)
PR #7546 added a one-time pad-deletion-token modal that opens via the clientVars handshake on creator sessions and synchronously focuses its input through setTimeout(0). `goToNewPad`'s previous mitigation hid the modal element after `waitForEditorReady`, but the editor iframe attaches before clientVars arrives, so the hide runs against a still- hidden modal, short-circuits, and the modal opens later mid-test — stealing focus and dropping the next Enter / Tab. Visible on develop in `enter.spec.ts:33` and `indentation.spec.ts:9` across all four Playwright jobs (run 25214868650). Intercept `clientVars` assignment via `page.addInitScript` and null out `padDeletionToken` before `pad.ts`'s `showDeletionTokenModalIfPresent` can read it, so the modal-show short-circuits at the source. The deletion-token spec navigates inline with `page.goto` and does not call this helper, so its modal still appears. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4bda757304
commit
d036cf0e70
@ -133,25 +133,33 @@ const waitForEditorReady = async (page: Page) => {
|
||||
};
|
||||
|
||||
export const goToNewPad = async (page: Page) => {
|
||||
// create a new pad before each test run
|
||||
// Suppress the one-time pad-deletion-token modal in tests. The modal
|
||||
// pops up on creator sessions via the clientVars handshake and steals
|
||||
// focus through a setTimeout, which races with goToNewPad's
|
||||
// waitForEditorReady — the editor iframe attaches before clientVars
|
||||
// arrives, so any post-load DOM hide runs too early and the modal
|
||||
// still opens mid-test, eating Enter / Tab presses (#7546 regression
|
||||
// observed in enter.spec and indentation.spec). Intercept clientVars
|
||||
// assignment instead and null out padDeletionToken before pad.ts can
|
||||
// read it; that way the modal-show short-circuits at the source.
|
||||
// Tests that need to interact with the modal navigate inline and do
|
||||
// not call this helper.
|
||||
await page.addInitScript(() => {
|
||||
let stored: unknown;
|
||||
Object.defineProperty(window, 'clientVars', {
|
||||
configurable: true,
|
||||
get() { return stored; },
|
||||
set(v) {
|
||||
if (v != null && typeof v === 'object') {
|
||||
(v as {padDeletionToken?: string | null}).padDeletionToken = null;
|
||||
}
|
||||
stored = v;
|
||||
},
|
||||
});
|
||||
});
|
||||
const padId = "FRONTEND_TESTS"+randomUUID();
|
||||
await page.goto('http://localhost:9001/p/'+padId);
|
||||
await waitForEditorReady(page);
|
||||
// Creator sessions see the one-time pad-deletion-token modal on first visit.
|
||||
// Hide it directly instead of clicking the ack button — clicking the button
|
||||
// transfers focus out of the pad iframe and breaks subsequent keyboard tests.
|
||||
// Tests that need to interact with the modal should navigate to a new pad
|
||||
// inline instead of using this helper.
|
||||
await page.evaluate(() => {
|
||||
const modal = document.getElementById('deletiontoken-modal');
|
||||
if (modal == null || modal.hidden) return;
|
||||
modal.hidden = true;
|
||||
modal.classList.remove('popup-show');
|
||||
const input = document.getElementById('deletiontoken-value') as HTMLInputElement | null;
|
||||
if (input) input.value = '';
|
||||
const w = window as unknown as {clientVars?: {padDeletionToken?: string | null}};
|
||||
if (w.clientVars != null) w.clientVars.padDeletionToken = null;
|
||||
});
|
||||
return padId;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user