Skip to content

[lexical-playground] Chore: De-flake collab "Undo with collaboration on" e2e test#8637

Merged
etrepum merged 2 commits into
facebook:mainfrom
etrepum:claude/eloquent-bardeen-5wnJp
Jun 4, 2026
Merged

[lexical-playground] Chore: De-flake collab "Undo with collaboration on" e2e test#8637
etrepum merged 2 commits into
facebook:mainfrom
etrepum:claude/eloquent-bardeen-5wnJp

Conversation

@etrepum

@etrepum etrepum commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator

Description

The "Undo with collaboration on" test intermittently failed on webkit (and is racy on all browsers) with a partial undo: e.g. after undoing the "hello world again" burst the middle paragraph still showed "hello world aga", or after undoing the checklist a list item or "a" remained, instead of the expected empty paragraph.

Root cause: in collab, @lexical/history is disabled in favor of the Yjs UndoManager, which coalesces consecutive local edits into one undo stack item only while each lands within captureTimeout (500ms) of the previous, measured with Date.now(). Unlike the local-history clock that advanceHistoryClock drives, that timer is not injectable, so under CI load a stall longer than the window silently splits a single logical edit group across multiple stack items. The test issues one undo() per group and asserts the whole group reverts, so a split leaves a partial revert.

Fix: add freezeCollabUndoGrouping(), which sets the UndoManager's captureTimeout to Infinity for the edited frame. Grouping is then driven solely by explicit boundaries -- advanceHistoryClock's stopCapturing() and the stopCapturing() the UndoManager runs automatically after every undo/redo (both reset lastChange to 0). Edits in between always coalesce regardless of timing, so a burst reverts as a unit. This does not change any asserted behavior: a run that happened to stay under the 500ms window already grouped the same way.

Test plan

Test changes only

…on" e2e test

The "Undo with collaboration on" test intermittently failed on webkit
(and is racy on all browsers) with a partial undo: e.g. after undoing
the "hello world again" burst the middle paragraph still showed
"hello world aga", or after undoing the checklist a list item or "a"
remained, instead of the expected empty paragraph.

Root cause: in collab, @lexical/history is disabled in favor of the Yjs
UndoManager, which coalesces consecutive local edits into one undo stack
item only while each lands within captureTimeout (500ms) of the previous,
measured with Date.now(). Unlike the local-history clock that
advanceHistoryClock drives, that timer is not injectable, so under CI
load a stall longer than the window silently splits a single logical edit
group across multiple stack items. The test issues one undo() per group
and asserts the whole group reverts, so a split leaves a partial revert.

Fix: add freezeCollabUndoGrouping(), which sets the UndoManager's
captureTimeout to Infinity for the edited frame. Grouping is then driven
solely by explicit boundaries -- advanceHistoryClock's stopCapturing()
and the stopCapturing() the UndoManager runs automatically after every
undo/redo (both reset lastChange to 0). Edits in between always coalesce
regardless of timing, so a burst reverts as a unit. This does not change
any asserted behavior: a run that happened to stay under the 500ms window
already grouped the same way.

https://claude.ai/code/session_01MznZZ3zPCNqBWLvstr9P9J
@vercel

vercel Bot commented Jun 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
lexical Ready Ready Preview, Comment Jun 4, 2026 4:02pm
lexical-playground Ready Ready Preview, Comment Jun 4, 2026 4:02pm

Request Review

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jun 4, 2026
@etrepum etrepum added the extended-tests Run extended e2e tests on a PR label Jun 4, 2026
@etrepum etrepum added this pull request to the merge queue Jun 4, 2026
Merged via the queue into facebook:main with commit 838545e Jun 4, 2026
46 checks passed
@etrepum etrepum deleted the claude/eloquent-bardeen-5wnJp branch June 4, 2026 17:00

@potatowagon potatowagon left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed by Navi (Tater Thoughts Bobblehead) on behalf of @potatowagon.

LGTM ✅ — Excellent de-flaking fix for collab undo tests.

What this does: Introduces a freezeCollabUndoGrouping(page) test utility that sets the Yjs UndoManager's captureTimeout to Infinity during test execution. This ensures that undo grouping is purely boundary-driven (explicit stopCapturing() calls) rather than wall-clock-driven (500ms default window), preventing CI stalls from splitting edit groups across multiple undo stack items.

What I checked:

  • ✅ Logic correctness: The fix correctly identifies the root cause — Yjs UndoManager coalesces edits only within its captureTimeout window. Under CI load, a >500ms stall between keystrokes splits what should be a single group. Setting to Infinity removes the time dimension while keeping boundary-driven grouping intact.
  • ✅ Edge cases: The helper is properly guarded (if (!IS_COLLAB) return), correctly polls via waitForFunction until the UndoManager is available (handles async collab connection), accesses it via the well-known symbol Symbol.for('@lexical/yjs/UndoManager'), and is idempotent.
  • ✅ No behavioral change: The test assertions remain unchanged — a run that naturally stayed under 500ms already grouped the same way. Only flaky intermittent splits are eliminated.
  • ✅ Thorough documentation: The JSDoc explains the mechanism, rationale, and interaction with advanceHistoryClock.
  • ✅ No www compat concerns — test-only change.
  • ✅ CI: All checks green.

Safe to land. This eliminates a well-understood class of CI flakiness without changing any test semantics.

@etrepum etrepum mentioned this pull request Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. extended-tests Run extended e2e tests on a PR

4 participants