From b0c4b5efe99c2e8ece10bff4043655cf85768347 Mon Sep 17 00:00:00 2001 From: Bob Ippolito Date: Mon, 18 May 2026 06:16:56 -0700 Subject: [PATCH 1/3] [ci] Chore: pin Windows e2e runners to windows-2022 (#8522) Co-authored-by: Claude --- .github/workflows/call-e2e-all-tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/call-e2e-all-tests.yml b/.github/workflows/call-e2e-all-tests.yml index c35bd155428..e32ddb03ec1 100644 --- a/.github/workflows/call-e2e-all-tests.yml +++ b/.github/workflows/call-e2e-all-tests.yml @@ -59,7 +59,7 @@ jobs: build-windows: env: node-version: 24.x - runs-on: windows-latest + runs-on: windows-2022 steps: - uses: actions/checkout@v6 - uses: ./.github/actions/setup-pnpm @@ -123,7 +123,7 @@ jobs: editor-mode: ['rich-text', 'plain-text'] uses: ./.github/workflows/call-e2e-test.yml with: - os: 'windows-latest' + os: 'windows-2022' node-version: ${{ matrix.node-version }} browser: ${{ matrix.browser }} editor-mode: ${{ matrix.editor-mode }} @@ -162,7 +162,7 @@ jobs: browser: ['chromium', 'firefox'] uses: ./.github/workflows/call-e2e-test.yml with: - os: 'windows-latest' + os: 'windows-2022' node-version: ${{ matrix.node-version }} browser: ${{ matrix.browser }} editor-mode: 'rich-text-with-collab' From 53d46bf4be3de1e4098403289e307100f3bdbd67 Mon Sep 17 00:00:00 2001 From: Bob Ippolito Date: Mon, 18 May 2026 06:17:23 -0700 Subject: [PATCH 2/3] [lexical-playground] Bug Fix: Fix unawaited playwright promises in e2e test suite (#8521) Co-authored-by: Claude --- eslint.config.mjs | 27 ++++ .../__tests__/e2e/Images.spec.mjs | 5 - .../__tests__/e2e/Tables.spec.mjs | 115 ------------------ .../7266-column-header-merged-cells.spec.mjs | 10 -- .../__tests__/utils/index.mjs | 3 - playwright.config.mjs | 17 ++- 6 files changed, 42 insertions(+), 135 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index ec08a4b9cf2..039a163645b 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -422,6 +422,33 @@ export default [ }, }, + // Override: Playwright e2e tests - flag unawaited promise-returning + // Playwright calls. An un-awaited `page.setViewportSize(...)` (or any + // method with `pause: true` metainfo) under `--debug` leaves + // `Debugger._pausedCall` set indefinitely, causing every subsequent + // `page.pause()` to bail at the "already paused" early-return. + { + files: ['packages/lexical-playground/__tests__/**/*.?(m)js'], + rules: { + 'no-restricted-syntax': [ + ERROR, + 'WithStatement', + { + message: + 'Promise-returning Playwright call must be awaited (or returned). Unawaited calls poison Debugger._pausedCall under --debug and break page.pause().', + selector: + 'ExpressionStatement > CallExpression > MemberExpression[object.name=/^(page|frame|leftFrame|rightFrame|context)$/][property.name=/^(addInitScript|addScriptTag|addStyleTag|bringToFront|check|click|close|dblclick|dispatchEvent|emulateMedia|evaluate|evaluateHandle|exposeBinding|exposeFunction|fill|focus|goBack|goForward|goto|hover|pause|press|reload|screenshot|selectOption|setChecked|setContent|setExtraHTTPHeaders|setInputFiles|setViewportSize|tap|type|uncheck|waitForEvent|waitForFunction|waitForLoadState|waitForNavigation|waitForRequest|waitForResponse|waitForSelector|waitForTimeout|waitForURL)$/]', + }, + { + message: + 'Promise-returning Playwright call must be awaited (or returned). Unawaited calls poison Debugger._pausedCall under --debug and break page.pause().', + selector: + "ExpressionStatement > CallExpression > MemberExpression[object.type='MemberExpression'][object.object.name=/^(page|frame|leftFrame|rightFrame)$/][object.property.name=/^(keyboard|mouse|touchscreen)$/]", + }, + ], + }, + }, + // Override: Index exports - restrict default exports { files: [ diff --git a/packages/lexical-playground/__tests__/e2e/Images.spec.mjs b/packages/lexical-playground/__tests__/e2e/Images.spec.mjs index 500143142f0..9a7b1a686a4 100644 --- a/packages/lexical-playground/__tests__/e2e/Images.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Images.spec.mjs @@ -584,11 +584,6 @@ test.describe('Images', () => { test.fixme(isCollab); test.skip(isPlainText); - await page.setViewportSize({ - height: 1000, - width: 2000, - }); - await focusEditor(page); await page.keyboard.type('HelloWorld'); diff --git a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs index 1da5ff0bb01..619539f4c7e 100644 --- a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs @@ -1785,11 +1785,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 3, 3); @@ -1871,11 +1866,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 3, 3); @@ -1971,11 +1961,6 @@ test.describe.parallel('Tables', () => { test.fixme(IS_COLLAB && IS_LINUX && browserName === 'firefox'); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 3, 3); @@ -2063,11 +2048,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 1, 3); @@ -2160,11 +2140,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 3, 3); @@ -2312,11 +2287,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); // 1. Create a 5x5 table @@ -3027,11 +2997,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 3, 3); @@ -3480,11 +3445,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 2, 2); @@ -3552,11 +3512,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 2, 2); @@ -3620,11 +3575,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 2, 1); @@ -3683,11 +3633,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 2, 2); @@ -3766,11 +3711,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 4, 2); @@ -3844,11 +3784,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 10, 5); @@ -4044,11 +3979,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 10, 5); @@ -4249,11 +4179,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 10, 5); @@ -4454,11 +4379,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 2, 4); @@ -4523,11 +4443,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 2, 4); @@ -4583,11 +4498,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 2, 4); @@ -4638,11 +4548,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await page.keyboard.type('123'); @@ -4663,11 +4568,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 1, 1); @@ -4844,11 +4744,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 4, 4); @@ -5038,11 +4933,6 @@ test.describe.parallel('Tables', () => { test.skip(isPlainText); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - const pageOrFrame = getPageOrFrame(page); await focusEditor(page); @@ -6992,11 +6882,6 @@ test.describe.parallel('Tables', () => { test.fixme(IS_COLLAB && IS_LINUX && browserName === 'firefox'); await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); // Create a 3x3 table diff --git a/packages/lexical-playground/__tests__/regression/7266-column-header-merged-cells.spec.mjs b/packages/lexical-playground/__tests__/regression/7266-column-header-merged-cells.spec.mjs index 65ebffe0211..aa20a98bca2 100644 --- a/packages/lexical-playground/__tests__/regression/7266-column-header-merged-cells.spec.mjs +++ b/packages/lexical-playground/__tests__/regression/7266-column-header-merged-cells.spec.mjs @@ -31,11 +31,6 @@ test.describe('Regression test #7266', () => { await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 4, 4); @@ -151,11 +146,6 @@ test.describe('Regression test #7266', () => { await initialize({isCollab, page}); - if (isCollab) { - // The contextual menu positioning needs fixing (it's hardcoded to show on the right side) - page.setViewportSize({height: 1000, width: 3000}); - } - await focusEditor(page); await insertTable(page, 4, 4); diff --git a/packages/lexical-playground/__tests__/utils/index.mjs b/packages/lexical-playground/__tests__/utils/index.mjs index 2e35fc0eeec..8f63d20b5f8 100644 --- a/packages/lexical-playground/__tests__/utils/index.mjs +++ b/packages/lexical-playground/__tests__/utils/index.mjs @@ -138,9 +138,6 @@ export async function initialize({ isCollab ? 'split/' : '' }?${urlParams.toString()}`; - // Having more horizontal space prevents redundant text wraps for tests - // which affects CMD+ArrowRight/Left navigation - page.setViewportSize({height: 1000, width: isCollab ? 2500 : 1250}); await page.goto(url); await exposeLexicalEditor(page); diff --git a/playwright.config.mjs b/playwright.config.mjs index b1d60985c93..578481e96d6 100644 --- a/playwright.config.mjs +++ b/playwright.config.mjs @@ -8,8 +8,18 @@ import {devices} from '@playwright/test'; -const {CI} = process.env; +const {CI, E2E_EDITOR_MODE, PWDEBUG} = process.env; const IS_CI = CI === 'true'; +// PWDEBUG=1 is set by Playwright's `--debug` flag before this config loads; +// retries during a debug run only add confusion (the test already paused once). +const IS_DEBUG = PWDEBUG === '1'; +const IS_COLLAB = + E2E_EDITOR_MODE === 'rich-text-with-collab' || + E2E_EDITOR_MODE === 'rich-text-with-collab-v2'; +// Collab mode needs extra horizontal space because the contextual menu is +// hardcoded to the right side; non-collab needs enough room that text +// doesn't wrap and break CMD+ArrowRight/Left navigation. +const viewport = {height: 1000, width: IS_COLLAB ? 3000 : 1250}; const config = { forbidOnly: IS_CI, @@ -23,6 +33,7 @@ const config = { slowMo: 50, }, userAgent: undefined, + viewport, }, }, { @@ -34,6 +45,7 @@ const config = { slowMo: 50, }, userAgent: undefined, + viewport, }, }, { @@ -45,10 +57,11 @@ const config = { slowMo: 50, }, userAgent: undefined, + viewport, }, }, ], - retries: IS_CI ? 4 : 1, + retries: IS_DEBUG ? 0 : IS_CI ? 4 : 1, testIgnore: /\/__tests__\/unit\//, timeout: 150000, use: { From a1f462493fddac550fe7921e17a83f2954c506c5 Mon Sep 17 00:00:00 2001 From: Shaurya Singh Date: Mon, 18 May 2026 11:18:07 -0700 Subject: [PATCH 3/3] [lexical-yjs] Chore: Fix RenderSnapshot comment typo (#8527) --- packages/lexical-yjs/src/RenderSnapshot.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lexical-yjs/src/RenderSnapshot.ts b/packages/lexical-yjs/src/RenderSnapshot.ts index 46cd1096197..ee2143c30df 100644 --- a/packages/lexical-yjs/src/RenderSnapshot.ts +++ b/packages/lexical-yjs/src/RenderSnapshot.ts @@ -60,7 +60,7 @@ export const renderSnapshot__EXPERIMENTAL = ( doc.transact(transaction => { // Before rendering, we are going to sanitize ops and split deleted ops - // if they were deleted by seperate users. + // if they were deleted by separate users. const pud = new PermanentUserData(doc); if (pud) { pud.dss.forEach(ds => {