From be84cf897ddd02d4c79277bde287f53ac613f80b Mon Sep 17 00:00:00 2001 From: Gerard Rovira Date: Sat, 31 Oct 2026 21:06:57 -0400 Subject: [PATCH] [lexical-y] Chore: Point the known-failure tests at open issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Two markers in `@lexical/y`'s tests named nothing a reader could follow, and one lane failed on a known gc-only case: - `UndoRunEnds.test.ts`: its 14 `test.fails` groups (81 cells) named only #9561, a pull request parked as a draft. Each now names the open issue that tracks it: #9681 (an undo of text typed inside a run deletes that text's run ends, so a collaborator's plain text next to it takes the run's value; D74) or #9682 (an undo of a run's value leaves it after a restore the undo has seen; D64, documented in y.md's Limits, Undo). The file's header says so and that #9561 fixes both. - `regressions/Formats.test.ts`, F30A-1: the italic case fails with gc on (`LEXICAL_Y_GC=1`, which #9679 added), for 3 client id orders, the same on main before #9679. It is now a `test.fails` naming #9683 with gc on only, so the gc-on lane is green. - `regressions/PasteRemadeLine.test.ts` names #9587, which GitHub had closed by mistake (#9598's "Not fixed: #9587" reads as a closing keyword); the repro still fails on main, and the issue is reopened. No change to the test. No behavior change; tests only. ## Test plan ### Before ``` $ LEXICAL_Y_GC=1 pnpm exec vitest run --project unit packages/lexical-y/src/__tests__/unit/regressions/Formats.test.ts -t F30A-1 × italic over "b ", italic removed from "b"; the removal undone ‖ "b" italic again (ids 1,2,3) × italic over "b ", italic removed from "b"; the removal undone ‖ "b" italic again (ids 3,2,1) × italic over "b ", italic removed from "b"; the removal undone ‖ "b" italic again (ids 2,3,1) AssertionError: expected '"a" "b"[I] " cd ef" / "next"' to be '"a" "b "[I] "cd ef" / "next"' Tests 3 failed | 8 passed | 187 skipped (198) ``` `UndoRunEnds.test.ts` with every `test.fails` turned into `test`: 81 failed, 98 passed, on gc off and gc on (each of the 81 is one of the two issues' shapes; the issues carry standalone repros that fail on main). ### After ``` $ pnpm exec vitest run --project unit packages/lexical-y/src/__tests__/unit/UndoRunEnds.test.ts packages/lexical-y/src/__tests__/unit/regressions/Formats.test.ts Tests 292 passed | 85 expected fail (377) $ LEXICAL_Y_GC=1 pnpm exec vitest run --project unit packages/lexical-y/src/__tests__/unit/UndoRunEnds.test.ts packages/lexical-y/src/__tests__/unit/regressions/Formats.test.ts Tests 289 passed | 88 expected fail (377) ``` Whole `@lexical/y` unit project (`vitest run --project unit packages/lexical-y/`), gc off and on (`LEXICAL_Y_GC=1`): ``` Tests 1 failed | 18528 passed | 291 expected fail | 130 skipped (18950) Tests 18526 passed | 294 expected fail | 130 skipped (18950) ``` The one failure is `DisposeMemory.test.ts` (heap held above its 8 MB bound) with 24 workers. It passes alone and 12 at a time, and the same full-suite run fails it on main before #9679 (cfcd3c40, 9.4 MB): a heap bound that full-suite load can exceed, unrelated to this change. --- .../src/__tests__/unit/UndoRunEnds.test.ts | 27 ++++++++++++++++--- .../unit/regressions/Formats.test.ts | 5 +++- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/packages/lexical-y/src/__tests__/unit/UndoRunEnds.test.ts b/packages/lexical-y/src/__tests__/unit/UndoRunEnds.test.ts index 76bf75cfe9b..5a4ba96c6fc 100644 --- a/packages/lexical-y/src/__tests__/unit/UndoRunEnds.test.ts +++ b/packages/lexical-y/src/__tests__/unit/UndoRunEnds.test.ts @@ -15,10 +15,14 @@ // restore with " mid", and " plain" turns bold on every client (and a // comment covers it the same way). A delete of " mid" by hand keeps them. // -// The cases marked test.fails fail on main and pass with #9561 (an undo -// keeps the run ends of the text it removes), parked as a draft: with it, a -// collaborator's undo of text typed inside a run, concurrent with the undo -// of that run's value, gives the value back to the rest of the run (#9593). +// The cases marked test.fails fail on main, each tracked by the issue named +// above it: #9681 (an undo of text typed inside a run deletes that text's +// run ends; D74) or #9682 (an undo of a run's value leaves it after a +// restore the undo has seen; D64, documented in y.md's Limits, Undo). +// #9561 (an undo keeps the run ends of the text it removes) fixes both and +// is parked as a draft: with it, a collaborator's undo of text typed inside +// a run, concurrent with the undo of that run's value, gives the value back +// to the rest of the run (#9593). import {$addMarkID, $getNodeMarkIDs, $removeMarkID} from '@lexical/mark'; import {$patchStyleText} from '@lexical/selection'; @@ -129,6 +133,7 @@ async function race(t: Setup, undo: 'undo' | 'delete' | 'none') { } describe('an undo keeps the run ends of the text it removes', () => { + // #9681: an undo of text typed inside a run deletes its run ends. test.fails.each(ORDERS)( 'bold: text typed after its null stays plain (ids %i %i %i)', async (...ids) => { @@ -137,6 +142,7 @@ describe('an undo keeps the run ends of the text it removes', () => { }, ); + // #9681: an undo of text typed inside a run deletes its run ends. test.fails.each(ORDERS)( 'comment: text typed after its null stays uncommented (ids %i %i %i)', async (...ids) => { @@ -157,6 +163,7 @@ describe('an undo keeps the run ends of the text it removes', () => { }, ); + // #9681: an undo of text typed inside a run deletes its run ends. test.fails.each(ORDERS)( 'a paragraph inserted into a bold run split by Enter (ids %i %i %i)', async (...ids) => { @@ -195,6 +202,7 @@ describe('an undo keeps the run ends of the text it removes', () => { }, ); + // #9681: an undo of text typed inside a run deletes its run ends. test.fails.each(ORDERS)( 'bold text typed into plain text: text typed before it inside its run stays bold (ids %i %i %i)', async (...ids) => { @@ -226,6 +234,7 @@ describe('an undo keeps the run ends of the text it removes', () => { }, ); + // #9681: an undo of text typed inside a run deletes its run ends. test.fails('a redo puts the text back with its own value', async () => { const t = await start([1, 2, 3], 'bold'); expect(await race(t, 'undo')).toBe('one*| plain| two*'); @@ -275,6 +284,8 @@ describe('an undo keeps the run ends of the text it removes', () => { // an undo of that bold must not leave the content after the pair bold. describe('an undo of the run such run ends restate', () => { for (const how of ['undo', 'delete'] as const) { + // #9682 for the delete: the delete keeps F's run ends, and A's undo of + // the bold leaves it after F's restore. (how === 'delete' ? test.fails : test).each(ORDERS)( `F types " mid" into A's bold and ${how}s it; A undoes the bold, redoes it, undoes it (ids %i %i %i)`, async (...ids) => { @@ -316,6 +327,7 @@ describe('an undo of the run such run ends restate', () => { }); describe('undo run ends, more orders of events', () => { + // #9681: an undo of text typed inside a run deletes its run ends. test.fails.each(ORDERS)( "F has seen E's text when it undoes; then A undoes the bold (ids %i %i %i)", async (...ids) => { @@ -451,6 +463,7 @@ describe('undo run ends, more orders of events', () => { expect(t.a.read(() => $getRoot().getTextContent())).toBe('x'); expect([um.undoStack.length, um.redoStack.length]).toEqual([0, 2]); }); + // #9681: an undo of text typed inside a run deletes its run ends. test.fails.each([[[1, 2, 3, 4]], [[4, 3, 2, 1]]])( "text a third peer typed inside the collaborator's text stays plain too (ids %j)", async ids => { @@ -625,6 +638,7 @@ describe('undo run ends, more orders of events', () => { }, ); + // #9681: an undo of text typed inside a run deletes its run ends. test.fails.each(ORDERS)( 'the end a kept restore relies on stays ended when a collaborator deletes the run (ids %i %i %i)', async (...ids) => { @@ -817,6 +831,7 @@ describe('undo run ends, more orders of events', () => { ).toContain('T'); }, ); + // #9682: an undo of a run's value leaves it after a restore it has seen. test.fails.each( ORDERS.flatMap(ids => [ ['after " mid"', ...ids], @@ -1088,6 +1103,7 @@ describe('run ends an undo kept, after changes made since', () => { ); }); + // #9681: an undo of text typed inside a run deletes its run ends. test.fails.each(ORDERS)( 'with text a collaborator typed after the null: it stays plain, and a redo gives " two" its bold back (ids %i %i %i)', async (...ids) => { @@ -1123,6 +1139,7 @@ describe('run ends an undo kept, after changes made since', () => { }, ); + // #9681: an undo of text typed inside a run deletes its run ends. test.fails.each(ORDERS)( 'type, delete, undo, undo: text typed after the null stays plain (ids %i %i %i)', async (...ids) => { @@ -1202,6 +1219,7 @@ describe('run ends an undo kept, after changes made since', () => { }, ); + // #9682: an undo of a run's value leaves it after a restore it has seen. test.fails.each(ORDERS)( 'an undo ends its value past the restore of text it has seen, still there (ids %i %i %i)', async (...ids) => { @@ -1381,6 +1399,7 @@ describe('run ends an undo kept, after changes made since', () => { }, ); + // #9681: an undo of text typed inside a run deletes its run ends. test.fails.each(ORDERS)( 'style: text typed after its null stays unstyled (ids %i %i %i)', async (...ids) => { diff --git a/packages/lexical-y/src/__tests__/unit/regressions/Formats.test.ts b/packages/lexical-y/src/__tests__/unit/regressions/Formats.test.ts index c7c30f933e5..4239212c1a7 100644 --- a/packages/lexical-y/src/__tests__/unit/regressions/Formats.test.ts +++ b/packages/lexical-y/src/__tests__/unit/regressions/Formats.test.ts @@ -38,6 +38,7 @@ import { type Peer, setup, shape, + WITH_GC, } from '../../utils/harness'; function attach(peer: Peer) { @@ -907,12 +908,14 @@ describe('F30A-1: undo of a format change ‖ the same change made again', () => ], ]; for (const [name, $first, $second, $again, expected] of cases) { + // #9683: with gc on, the italic case takes the italic off the space. + const knownGcFailure = WITH_GC && name.startsWith('italic'); for (const ids of [ [1, 2, 3], [3, 2, 1], [2, 3, 1], ]) { - test(`${name} (ids ${ids})`, async () => { + (knownGcFailure ? test.fails : test)(`${name} (ids ${ids})`, async () => { const t = await setup($init, {ids}); t.a.update(() => { $first();