From cc4e65fa00406bf01ce5df0676a105d2bfa0cd8b Mon Sep 17 00:00:00 2001 From: Randal Grant Date: Fri, 30 Jan 2026 15:21:11 +1100 Subject: [PATCH 1/5] pull reusable utility functions out of drag-select test --- .../__tests__/e2e/Tables.spec.mjs | 251 +++++++++--------- 1 file changed, 123 insertions(+), 128 deletions(-) diff --git a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs index e5a89fe1178..2a133d7c1c9 100644 --- a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs @@ -7355,132 +7355,6 @@ test.describe.parallel('Tables', () => { return Boolean(cell && cell._cell); }); - const readTableSelectionCoordinates = async () => { - return await pageOrFrame.evaluate(() => { - const editor = window.lexicalEditor; - if (!editor) { - return null; - } - const selection = editor.getEditorState()._selection; - if (!selection || selection.tableKey == null) { - return null; - } - const anchorElement = editor.getElementByKey(selection.anchor.key); - const focusElement = editor.getElementByKey(selection.focus.key); - const anchorCell = anchorElement?._cell; - const focusCell = focusElement?._cell; - if (!anchorCell || !focusCell) { - return null; - } - return { - anchor: {x: anchorCell.x, y: anchorCell.y}, - focus: {x: focusCell.x, y: focusCell.y}, - }; - }); - }; - - const matchesExpected = (coords, expected) => { - if (!coords) { - return false; - } - const anchorMatches = - expected.anchor == null || - ((expected.anchor.x === undefined || - coords.anchor.x === expected.anchor.x) && - (expected.anchor.y === undefined || - coords.anchor.y === expected.anchor.y)); - const focusMatches = - expected.focus == null || - ((expected.focus.x === undefined || - coords.focus.x === expected.focus.x) && - (expected.focus.y === undefined || - coords.focus.y === expected.focus.y)); - return anchorMatches && focusMatches; - }; - - const waitForTableSelectionCoordinates = async (expected) => { - for (let i = 0; i < 20; i++) { - const coords = await readTableSelectionCoordinates(); - if (matchesExpected(coords, expected)) { - return true; - } - await sleep(50); - } - return false; - }; - - const dispatchPointerDrag = async (dragStart, dragEnd) => { - return await pageOrFrame.evaluate( - ({endPoint, startPoint}) => { - const startTarget = document.elementFromPoint( - startPoint.x, - startPoint.y, - ); - const endTarget = document.elementFromPoint(endPoint.x, endPoint.y); - if (!startTarget || !endTarget) { - return false; - } - const baseEvent = { - bubbles: true, - button: 0, - buttons: 1, - isPrimary: true, - pointerId: 1, - pointerType: 'mouse', - }; - startTarget.dispatchEvent( - new PointerEvent('pointerdown', { - ...baseEvent, - clientX: startPoint.x, - clientY: startPoint.y, - }), - ); - endTarget.dispatchEvent( - new PointerEvent('pointermove', { - ...baseEvent, - clientX: endPoint.x, - clientY: endPoint.y, - }), - ); - endTarget.dispatchEvent( - new PointerEvent('pointerup', { - ...baseEvent, - buttons: 0, - clientX: endPoint.x, - clientY: endPoint.y, - }), - ); - return true; - }, - {endPoint: dragEnd, startPoint: dragStart}, - ); - }; - - const dragAndAssertSelection = async (fromBox, toBox, expected) => { - await dragMouse(page, fromBox, toBox, {slow: true}); - if (await waitForTableSelectionCoordinates(expected)) { - return; - } - const start = { - x: fromBox.x + fromBox.width / 2, - y: fromBox.y + fromBox.height / 2, - }; - const end = { - x: toBox.x + toBox.width / 2, - y: toBox.y + toBox.height / 2, - }; - await dispatchPointerDrag(start, end); - if (await waitForTableSelectionCoordinates(expected)) { - return; - } - const coords = await readTableSelectionCoordinates(); - throw new Error( - `Expected table selection ${JSON.stringify( - expected, - )} but got ${JSON.stringify(coords)}`, - ); - }; - // Test first column: straight drag from top to bottom (no click first) // This tests the fix for issue #8079 - straight drag should work const firstColTop = await selectorBoundingBox( @@ -7492,7 +7366,7 @@ test.describe.parallel('Tables', () => { 'table:first-of-type > tr:nth-of-type(2) > th:nth-child(1)', ); - await dragAndAssertSelection(firstColTop, firstColBottom, { + await dragAndAssertSelection(page, firstColTop, firstColBottom, { anchor: {x: 0, y: 0}, focus: {x: 0, y: 1}, }); @@ -7508,7 +7382,7 @@ test.describe.parallel('Tables', () => { 'table:first-of-type > tr:nth-of-type(2) > td:nth-child(2)', ); - await dragAndAssertSelection(secondColTop, secondColBottom, { + await dragAndAssertSelection(page, secondColTop, secondColBottom, { anchor: {x: 1, y: 0}, focus: {x: 1, y: 1}, }); @@ -7566,3 +7440,124 @@ const TABLE_WITH_MERGED_CELLS = ` `; + +const readTableSelectionCoordinates = async (pageOrFrame) => { + return await pageOrFrame.evaluate(() => { + const editor = window.lexicalEditor; + if (!editor) { + return null; + } + const selection = editor.getEditorState()._selection; + if (!selection || selection.tableKey == null) { + return null; + } + const anchorElement = editor.getElementByKey(selection.anchor.key); + const focusElement = editor.getElementByKey(selection.focus.key); + const anchorCell = anchorElement?._cell; + const focusCell = focusElement?._cell; + if (!anchorCell || !focusCell) { + return null; + } + return { + anchor: {x: anchorCell.x, y: anchorCell.y}, + focus: {x: focusCell.x, y: focusCell.y}, + }; + }); +}; + +const matchesExpected = (coords, expected) => { + if (!coords) { + return false; + } + const anchorMatches = + expected.anchor == null || + ((expected.anchor.x === undefined || + coords.anchor.x === expected.anchor.x) && + (expected.anchor.y === undefined || + coords.anchor.y === expected.anchor.y)); + const focusMatches = + expected.focus == null || + ((expected.focus.x === undefined || coords.focus.x === expected.focus.x) && + (expected.focus.y === undefined || coords.focus.y === expected.focus.y)); + return anchorMatches && focusMatches; +}; + +const waitForTableSelectionCoordinates = async (pageOrFrame, expected) => { + for (let i = 0; i < 20; i++) { + const coords = await readTableSelectionCoordinates(pageOrFrame); + if (matchesExpected(coords, expected)) { + return true; + } + await sleep(50); + } + return false; +}; + +const dispatchPointerDrag = async (pageOrFrame, dragStart, dragEnd) => { + return await pageOrFrame.evaluate( + ({endPoint, startPoint}) => { + const startTarget = document.elementFromPoint(startPoint.x, startPoint.y); + const endTarget = document.elementFromPoint(endPoint.x, endPoint.y); + if (!startTarget || !endTarget) { + return false; + } + const baseEvent = { + bubbles: true, + button: 0, + buttons: 1, + isPrimary: true, + pointerId: 1, + pointerType: 'mouse', + }; + startTarget.dispatchEvent( + new PointerEvent('pointerdown', { + ...baseEvent, + clientX: startPoint.x, + clientY: startPoint.y, + }), + ); + endTarget.dispatchEvent( + new PointerEvent('pointermove', { + ...baseEvent, + clientX: endPoint.x, + clientY: endPoint.y, + }), + ); + endTarget.dispatchEvent( + new PointerEvent('pointerup', { + ...baseEvent, + buttons: 0, + clientX: endPoint.x, + clientY: endPoint.y, + }), + ); + return true; + }, + {endPoint: dragEnd, startPoint: dragStart}, + ); +}; + +const dragAndAssertSelection = async (page, fromBox, toBox, expected) => { + await dragMouse(page, fromBox, toBox, {slow: true}); + if (await waitForTableSelectionCoordinates(page, expected)) { + return; + } + const start = { + x: fromBox.x + fromBox.width / 2, + y: fromBox.y + fromBox.height / 2, + }; + const end = { + x: toBox.x + toBox.width / 2, + y: toBox.y + toBox.height / 2, + }; + await dispatchPointerDrag(page, start, end); + if (await waitForTableSelectionCoordinates(page, expected)) { + return; + } + const coords = await readTableSelectionCoordinates(page); + throw new Error( + `Expected table selection ${JSON.stringify( + expected, + )} but got ${JSON.stringify(coords)}`, + ); +}; From cff6521e9e33479949a409547d57a2e82883f3c7 Mon Sep 17 00:00:00 2001 From: Randal Grant Date: Fri, 30 Jan 2026 17:38:41 +1100 Subject: [PATCH 2/5] add e2e tests for existing drag in/out behaviour --- .../__tests__/e2e/Tables.spec.mjs | 214 +++++++++++++++--- .../__tests__/utils/index.mjs | 6 +- 2 files changed, 190 insertions(+), 30 deletions(-) diff --git a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs index 2a133d7c1c9..77f90e8d884 100644 --- a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs @@ -6263,7 +6263,7 @@ test.describe.parallel('Tables', () => { page, 'table > tr:nth-of-type(4) > *:nth-child(4)', ), - {mouseDown: true, mouseUp: false, slow: true}, + {mouseDown: true, mouseUp: false, steps: 5}, ); await assertHTML( @@ -6398,7 +6398,7 @@ test.describe.parallel('Tables', () => { page, 'table > tr:nth-of-type(3) > *:nth-child(5)', ), - {mouseDown: false, mouseUp: true, slow: true}, + {mouseDown: false, mouseUp: true, steps: 5}, ); await assertHTML( page, @@ -7366,6 +7366,31 @@ test.describe.parallel('Tables', () => { 'table:first-of-type > tr:nth-of-type(2) > th:nth-child(1)', ); + const dragAndAssertSelection = async (fromBox, toBox, expected) => { + await dragMouse(page, fromBox, toBox, {steps: 5}); + if (await waitForTableSelectionCoordinates(page, expected)) { + return; + } + const start = { + x: fromBox.x + fromBox.width / 2, + y: fromBox.y + fromBox.height / 2, + }; + const end = { + x: toBox.x + toBox.width / 2, + y: toBox.y + toBox.height / 2, + }; + await dispatchPointerDrag(page, start, end); + if (await waitForTableSelectionCoordinates(page, expected)) { + return; + } + const coords = await readTableSelectionCoordinates(page); + throw new Error( + `Expected table selection ${JSON.stringify( + expected, + )} but got ${JSON.stringify(coords)}`, + ); + }; + await dragAndAssertSelection(page, firstColTop, firstColBottom, { anchor: {x: 0, y: 0}, focus: {x: 0, y: 1}, @@ -7387,6 +7412,166 @@ test.describe.parallel('Tables', () => { focus: {x: 1, y: 1}, }); }); + + test('Drag-select before table into table selects entire table', async ({ + page, + isPlainText, + isCollab, + }) => { + test.skip(isPlainText); + await initialize({isCollab, page}); + + await focusEditor(page); + + await page.keyboard.insertText('textBefore'); + await insertTable(page, 2, 2); + + await page.waitForSelector( + 'table:first-of-type td, table:first-of-type th', + ); + + const firstParagraph = await selectorBoundingBox( + page, + 'p:has-text("textBefore")', + ); + const firstCell = await selectorBoundingBox( + page, + 'table:first-of-type > tr:first-of-type > th:first-of-type', + ); + + await dragMouse(page, firstParagraph, firstCell, { + positionStart: 'start', + slow: true, + }); + + // selection starts in the text and ends in the last cell of the table + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [0, 0, 0], + focusOffset: 1, + focusPath: [1, 0, 2, 1], + }); + }); + + test('Drag-select from first cell to before table selects entire table', async ({ + page, + isPlainText, + isCollab, + }) => { + test.skip(isPlainText); + await initialize({isCollab, page}); + + await focusEditor(page); + + await page.keyboard.insertText('textBefore'); + await insertTable(page, 2, 2); + + await page.waitForSelector( + 'table:first-of-type td, table:first-of-type th', + ); + + const firstParagraph = await selectorBoundingBox( + page, + 'p:has-text("textBefore")', + ); + const firstCell = await selectorBoundingBox( + page, + 'table:first-of-type > tr:first-of-type > th:first-of-type', + ); + + await dragMouse(page, firstCell, firstParagraph, { + positionEnd: 'start', + steps: 5, + }); + + // selection starts in the text and ends in the last cell of the table + await assertSelection(page, { + anchorOffset: 1, + anchorPath: [1, 0, 2, 1], + focusOffset: 0, + focusPath: [0, 0, 0], + }); + }); + + test('Drag-select after table into table selects entire table', async ({ + page, + isPlainText, + isCollab, + }) => { + test.skip(isPlainText); + await initialize({isCollab, page}); + + await focusEditor(page); + + await insertTable(page, 2, 2); + await moveToEditorEnd(page); + await page.keyboard.insertText('textAfter'); + + await page.waitForSelector( + 'table:first-of-type td, table:first-of-type th', + ); + + const lastParagraph = await selectorBoundingBox( + page, + 'p:has-text("textAfter")', + ); + const lastCell = await selectorBoundingBox( + page, + 'table:first-of-type > tr:last-of-type > td:first-of-type', + ); + await dragMouse(page, lastParagraph, lastCell, { + positionStart: 'start', + steps: 5, + }); + + // selection starts in the text and ends in the first cell of the table + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [2, 0, 0], + focusOffset: 0, + focusPath: [1, 0, 1, 0], + }); + }); + + test('Drag-select from last cell to after table selects entire table', async ({ + page, + isPlainText, + isCollab, + }) => { + test.skip(isPlainText); + await initialize({isCollab, page}); + + await focusEditor(page); + + await insertTable(page, 2, 2); + await moveToEditorEnd(page); + await page.keyboard.insertText('textAfter'); + + await page.waitForSelector( + 'table:first-of-type td, table:first-of-type th', + ); + + const lastParagraph = await selectorBoundingBox( + page, + 'p:has-text("textAfter")', + ); + const lastCell = await selectorBoundingBox( + page, + 'table:first-of-type > tr:last-of-type > td:first-of-type', + ); + await dragMouse(page, lastCell, lastParagraph, { + positionEnd: 'start', + steps: 5, + }); + + // selection starts in the text and ends in the first cell of the table + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [1, 0, 1, 0], + focusOffset: 0, + focusPath: [2, 0, 0], + }); + }); }); const TABLE_WITH_MERGED_CELLS = ` @@ -7536,28 +7721,3 @@ const dispatchPointerDrag = async (pageOrFrame, dragStart, dragEnd) => { {endPoint: dragEnd, startPoint: dragStart}, ); }; - -const dragAndAssertSelection = async (page, fromBox, toBox, expected) => { - await dragMouse(page, fromBox, toBox, {slow: true}); - if (await waitForTableSelectionCoordinates(page, expected)) { - return; - } - const start = { - x: fromBox.x + fromBox.width / 2, - y: fromBox.y + fromBox.height / 2, - }; - const end = { - x: toBox.x + toBox.width / 2, - y: toBox.y + toBox.height / 2, - }; - await dispatchPointerDrag(page, start, end); - if (await waitForTableSelectionCoordinates(page, expected)) { - return; - } - const coords = await readTableSelectionCoordinates(page); - throw new Error( - `Expected table selection ${JSON.stringify( - expected, - )} but got ${JSON.stringify(coords)}`, - ); -}; diff --git a/packages/lexical-playground/__tests__/utils/index.mjs b/packages/lexical-playground/__tests__/utils/index.mjs index ef08aa00960..68f9c951e2e 100644 --- a/packages/lexical-playground/__tests__/utils/index.mjs +++ b/packages/lexical-playground/__tests__/utils/index.mjs @@ -826,7 +826,7 @@ export async function dragMouse( positionEnd = 'middle', mouseDown = true, mouseUp = true, - slow = false, + steps = 1, } = opts; let fromX = fromBoundingBox.x; let fromY = fromBoundingBox.y; @@ -851,7 +851,7 @@ export async function dragMouse( if (mouseDown) { await page.mouse.down(); } - await page.mouse.move(toX, toY, slow ? 10 : 1); + await page.mouse.move(toX, toY, {steps}); if (mouseUp) { await page.mouse.up(); } @@ -1027,7 +1027,7 @@ export async function selectCellsFromTableCords( // const firstBox = await firstRowFirstColumnCell.boundingBox(); // const secondBox = await secondRowSecondCell.boundingBox(); - // await dragMouse(page, firstBox, secondBox, {slow: true}); + // await dragMouse(page, firstBox, secondBox, {steps: 5}); } export async function clickTableCellActiveButton(page) { From b3dd74949e157383676b6c7072b0d6842aa46c4a Mon Sep 17 00:00:00 2001 From: Randal Grant Date: Mon, 2 Feb 2026 11:12:54 +1100 Subject: [PATCH 3/5] Fix 2x2 test --- packages/lexical-playground/__tests__/e2e/Tables.spec.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs index 77f90e8d884..cb478b31cd5 100644 --- a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs @@ -7391,7 +7391,7 @@ test.describe.parallel('Tables', () => { ); }; - await dragAndAssertSelection(page, firstColTop, firstColBottom, { + await dragAndAssertSelection(firstColTop, firstColBottom, { anchor: {x: 0, y: 0}, focus: {x: 0, y: 1}, }); @@ -7407,7 +7407,7 @@ test.describe.parallel('Tables', () => { 'table:first-of-type > tr:nth-of-type(2) > td:nth-child(2)', ); - await dragAndAssertSelection(page, secondColTop, secondColBottom, { + await dragAndAssertSelection(secondColTop, secondColBottom, { anchor: {x: 1, y: 0}, focus: {x: 1, y: 1}, }); From 6765534efabc17bcc87f7a969d4ff29aecda2308 Mon Sep 17 00:00:00 2001 From: Randal Grant Date: Mon, 2 Feb 2026 11:35:59 +1100 Subject: [PATCH 4/5] add nested drag tests assertion is incorrect, will adjust after implementation is fixed --- .../__tests__/e2e/Tables.spec.mjs | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs index cb478b31cd5..242de3288c5 100644 --- a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs @@ -7572,6 +7572,166 @@ test.describe.parallel('Tables', () => { focusPath: [2, 0, 0], }); }); + + test('Drag-select inside nested table to outside table (backwards) selects nested table only', async ({ + page, + isPlainText, + isCollab, + }) => { + test.skip(isPlainText); + await initialize({hasNestedTables: true, isCollab, page}); + + await focusEditor(page); + + await insertTable(page, 2, 2); + await page.locator('table:first-of-type td').click(); + await page.keyboard.type('beforeText'); + await insertTable(page, 1, 1); + await page.keyboard.press('ArrowDown'); + await page.keyboard.type('afterText'); + + const nestedBeforeText = await selectorBoundingBox( + page, + 'p:has-text("beforeText")', + ); + const nestedFirstCell = await selectorBoundingBox( + page, + 'table table > tr:first-of-type > th:first-of-type', + ); + + await dragMouse(page, nestedFirstCell, nestedBeforeText, { + positionEnd: 'start', + steps: 5, + }); + + // selection starts in the text and ends in the last cell of the nested table + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [1, 0, 1, 1, 1], + focusOffset: 0, + focusPath: [1, 0, 1, 1, 1], + }); + }); + + test('Drag-select into nested table (forward) does not select parent cell', async ({ + page, + isPlainText, + isCollab, + }) => { + test.skip(isPlainText); + await initialize({hasNestedTables: true, isCollab, page}); + + await focusEditor(page); + + await insertTable(page, 2, 2); + await page.locator('table:first-of-type td').click(); + await page.keyboard.type('beforeText'); + await insertTable(page, 1, 1); + await page.keyboard.press('ArrowDown'); + await page.keyboard.type('afterText'); + + const nestedBeforeText = await selectorBoundingBox( + page, + 'p:has-text("beforeText")', + ); + const nestedFirstCell = await selectorBoundingBox( + page, + 'table table > tr:first-of-type > th:first-of-type', + ); + + await dragMouse(page, nestedBeforeText, nestedFirstCell, { + positionStart: 'start', + steps: 5, + }); + + // selection starts in the text and ends in the last cell of the nested table + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [1, 0, 1, 1, 1], + focusOffset: 0, + focusPath: [1, 0, 1, 1, 1], + }); + }); + + test('Drag-select inside nested table to outside table (forward) selects nested table only', async ({ + page, + isPlainText, + isCollab, + }) => { + test.skip(isPlainText); + await initialize({hasNestedTables: true, isCollab, page}); + + await focusEditor(page); + + await insertTable(page, 2, 2); + await page.locator('table:first-of-type td').click(); + await page.keyboard.type('beforeText'); + await insertTable(page, 1, 1); + await page.keyboard.press('ArrowDown'); + await page.keyboard.type('afterText'); + + const nestedLastRow = await selectorBoundingBox( + page, + 'table table > tr:last-of-type > th:first-of-type', + ); + const nestedAfterText = await selectorBoundingBox( + page, + 'p:has-text("afterText")', + ); + + await dragMouse(page, nestedLastRow, nestedAfterText, { + positionEnd: 'start', + steps: 5, + }); + + // selection starts in the first nested cell and ends at end of the text + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [1, 0, 1, 1, 1], + focusOffset: 0, + focusPath: [1, 0, 1, 1, 1], + }); + }); + + test('Drag-select into nested table (backwards) does not select parent cell', async ({ + page, + isPlainText, + isCollab, + }) => { + test.skip(isPlainText); + await initialize({hasNestedTables: true, isCollab, page}); + + await focusEditor(page); + + await insertTable(page, 2, 2); + await page.locator('table:first-of-type td').click(); + await page.keyboard.type('beforeText'); + await insertTable(page, 1, 1); + await page.keyboard.press('ArrowDown'); + await page.keyboard.type('afterText'); + + const nestedLastRow = await selectorBoundingBox( + page, + 'table table > tr:last-of-type > th:first-of-type', + ); + const nestedAfterText = await selectorBoundingBox( + page, + 'p:has-text("afterText")', + ); + + await dragMouse(page, nestedAfterText, nestedLastRow, { + positionStart: 'start', + steps: 5, + }); + + // selection starts in the first nested cell and ends at end of the text + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [1, 0, 1, 1, 1], + focusOffset: 0, + focusPath: [1, 0, 1, 1, 1], + }); + }); }); const TABLE_WITH_MERGED_CELLS = ` From 5ed20bdafa5e81ab975d5c3f1b0aa485bb6034ab Mon Sep 17 00:00:00 2001 From: Randal Grant Date: Mon, 2 Feb 2026 14:15:42 +1100 Subject: [PATCH 5/5] add 'fixme' tests for broken nested table behaviour --- .../__tests__/e2e/Tables.spec.mjs | 310 +++++++++--------- 1 file changed, 158 insertions(+), 152 deletions(-) diff --git a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs index 242de3288c5..980bfae8036 100644 --- a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs @@ -7573,165 +7573,171 @@ test.describe.parallel('Tables', () => { }); }); - test('Drag-select inside nested table to outside table (backwards) selects nested table only', async ({ - page, - isPlainText, - isCollab, - }) => { - test.skip(isPlainText); - await initialize({hasNestedTables: true, isCollab, page}); - - await focusEditor(page); - - await insertTable(page, 2, 2); - await page.locator('table:first-of-type td').click(); - await page.keyboard.type('beforeText'); - await insertTable(page, 1, 1); - await page.keyboard.press('ArrowDown'); - await page.keyboard.type('afterText'); - - const nestedBeforeText = await selectorBoundingBox( - page, - 'p:has-text("beforeText")', - ); - const nestedFirstCell = await selectorBoundingBox( - page, - 'table table > tr:first-of-type > th:first-of-type', - ); - - await dragMouse(page, nestedFirstCell, nestedBeforeText, { - positionEnd: 'start', - steps: 5, - }); - - // selection starts in the text and ends in the last cell of the nested table - await assertSelection(page, { - anchorOffset: 0, - anchorPath: [1, 0, 1, 1, 1], - focusOffset: 0, - focusPath: [1, 0, 1, 1, 1], - }); - }); - - test('Drag-select into nested table (forward) does not select parent cell', async ({ - page, - isPlainText, - isCollab, - }) => { - test.skip(isPlainText); - await initialize({hasNestedTables: true, isCollab, page}); - - await focusEditor(page); - - await insertTable(page, 2, 2); - await page.locator('table:first-of-type td').click(); - await page.keyboard.type('beforeText'); - await insertTable(page, 1, 1); - await page.keyboard.press('ArrowDown'); - await page.keyboard.type('afterText'); - - const nestedBeforeText = await selectorBoundingBox( - page, - 'p:has-text("beforeText")', - ); - const nestedFirstCell = await selectorBoundingBox( - page, - 'table table > tr:first-of-type > th:first-of-type', - ); - - await dragMouse(page, nestedBeforeText, nestedFirstCell, { - positionStart: 'start', - steps: 5, - }); - - // selection starts in the text and ends in the last cell of the nested table - await assertSelection(page, { - anchorOffset: 0, - anchorPath: [1, 0, 1, 1, 1], - focusOffset: 0, - focusPath: [1, 0, 1, 1, 1], - }); - }); - - test('Drag-select inside nested table to outside table (forward) selects nested table only', async ({ - page, - isPlainText, - isCollab, - }) => { - test.skip(isPlainText); - await initialize({hasNestedTables: true, isCollab, page}); - - await focusEditor(page); - - await insertTable(page, 2, 2); - await page.locator('table:first-of-type td').click(); - await page.keyboard.type('beforeText'); - await insertTable(page, 1, 1); - await page.keyboard.press('ArrowDown'); - await page.keyboard.type('afterText'); - - const nestedLastRow = await selectorBoundingBox( - page, - 'table table > tr:last-of-type > th:first-of-type', - ); - const nestedAfterText = await selectorBoundingBox( - page, - 'p:has-text("afterText")', - ); - - await dragMouse(page, nestedLastRow, nestedAfterText, { - positionEnd: 'start', - steps: 5, - }); + test.describe.fixme( + 'Drag-select nested table tests', + 'These tests are all erroneously selecting the parent cell', + () => { + test('Drag-select out of nested table (backwards) does not select parent cell', async ({ + page, + isPlainText, + isCollab, + }) => { + test.skip(isPlainText); + await initialize({hasNestedTables: true, isCollab, page}); + + await focusEditor(page); + + await insertTable(page, 2, 2); + await page.locator('table:first-of-type td').click(); + await page.keyboard.type('beforeText'); + await insertTable(page, 1, 1); + await page.keyboard.press('ArrowDown'); + await page.keyboard.type('afterText'); + + const nestedBeforeText = await selectorBoundingBox( + page, + 'p:has-text("beforeText")', + ); + const nestedFirstCell = await selectorBoundingBox( + page, + 'table table > tr:first-of-type > th:first-of-type', + ); + + await dragMouse(page, nestedFirstCell, nestedBeforeText, { + positionEnd: 'start', + steps: 5, + }); - // selection starts in the first nested cell and ends at end of the text - await assertSelection(page, { - anchorOffset: 0, - anchorPath: [1, 0, 1, 1, 1], - focusOffset: 0, - focusPath: [1, 0, 1, 1, 1], - }); - }); + // fixme: this is the whole cell of the parent table + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [1, 0, 2, 1, 0, 0, 0], + focusOffset: 0, + focusPath: [1, 0, 2, 1, 0, 0, 0], + }); + }); - test('Drag-select into nested table (backwards) does not select parent cell', async ({ - page, - isPlainText, - isCollab, - }) => { - test.skip(isPlainText); - await initialize({hasNestedTables: true, isCollab, page}); + test('Drag-select into nested table (forward) does not select parent cell', async ({ + page, + isPlainText, + isCollab, + }) => { + test.skip(isPlainText); + await initialize({hasNestedTables: true, isCollab, page}); + + await focusEditor(page); + + await insertTable(page, 2, 2); + await page.locator('table:first-of-type td').click(); + await page.keyboard.type('beforeText'); + await insertTable(page, 1, 1); + await page.keyboard.press('ArrowDown'); + await page.keyboard.type('afterText'); + + const nestedBeforeText = await selectorBoundingBox( + page, + 'p:has-text("beforeText")', + ); + const nestedFirstCell = await selectorBoundingBox( + page, + 'table table > tr:first-of-type > th:first-of-type', + ); + + await dragMouse(page, nestedBeforeText, nestedFirstCell, { + positionStart: 'start', + steps: 5, + }); - await focusEditor(page); + // fixme: this is the whole cell of the parent table + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [1, 0, 2, 1, 1, 0, 1, 0, 0], + focusOffset: 0, + focusPath: [1, 0, 2, 1, 1, 0, 1, 0, 0], + }); + }); - await insertTable(page, 2, 2); - await page.locator('table:first-of-type td').click(); - await page.keyboard.type('beforeText'); - await insertTable(page, 1, 1); - await page.keyboard.press('ArrowDown'); - await page.keyboard.type('afterText'); + test('Drag-select out of nested table (forward) does not select parent cell', async ({ + page, + isPlainText, + isCollab, + }) => { + test.skip(isPlainText); + await initialize({hasNestedTables: true, isCollab, page}); + + await focusEditor(page); + + await insertTable(page, 2, 2); + await page.locator('table:first-of-type td').click(); + await page.keyboard.type('beforeText'); + await insertTable(page, 1, 1); + await page.keyboard.press('ArrowDown'); + await page.keyboard.type('afterText'); + + const nestedLastRow = await selectorBoundingBox( + page, + 'table table > tr:last-of-type > th:first-of-type', + ); + const nestedAfterText = await selectorBoundingBox( + page, + 'p:has-text("afterText")', + ); + + await dragMouse(page, nestedLastRow, nestedAfterText, { + positionEnd: 'start', + steps: 5, + }); - const nestedLastRow = await selectorBoundingBox( - page, - 'table table > tr:last-of-type > th:first-of-type', - ); - const nestedAfterText = await selectorBoundingBox( - page, - 'p:has-text("afterText")', - ); + // fixme: this is the whole cell of the parent table + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [1, 0, 2, 1, 2, 0, 0], + focusOffset: 0, + focusPath: [1, 0, 2, 1, 2, 0, 0], + }); + }); - await dragMouse(page, nestedAfterText, nestedLastRow, { - positionStart: 'start', - steps: 5, - }); + test('Drag-select into nested table (backwards) does not select parent cell', async ({ + page, + isPlainText, + isCollab, + }) => { + test.skip(isPlainText); + await initialize({hasNestedTables: true, isCollab, page}); + + await focusEditor(page); + + await insertTable(page, 2, 2); + await page.locator('table:first-of-type td').click(); + await page.keyboard.type('beforeText'); + await insertTable(page, 1, 1); + await page.keyboard.press('ArrowDown'); + await page.keyboard.type('afterText'); + + const nestedLastRow = await selectorBoundingBox( + page, + 'table table > tr:last-of-type > th:first-of-type', + ); + const nestedAfterText = await selectorBoundingBox( + page, + 'p:has-text("afterText")', + ); + + await dragMouse(page, nestedAfterText, nestedLastRow, { + positionStart: 'start', + steps: 5, + }); - // selection starts in the first nested cell and ends at end of the text - await assertSelection(page, { - anchorOffset: 0, - anchorPath: [1, 0, 1, 1, 1], - focusOffset: 0, - focusPath: [1, 0, 1, 1, 1], - }); - }); + // fixme: This selector is not correct. Will need to investigate once the underlying bug is addressed. + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [0], + focusOffset: 0, + focusPath: [0], + }); + }); + }, + ); }); const TABLE_WITH_MERGED_CELLS = `