Repository navigation
Fix CKEditor 4 typing after frame rewrites, a watchdog restart, and a lost arrow-key choice - #477
Merged
Merged
Conversation
…ewrites The e2e test "ckeditor4 typing accepts a prediction mid-line" failed on master in Firefox. The prediction menu was visible, but Tab did not accept the prediction. Tab moved the focus out of the editor. Root cause: CKEditor 4 writes its editing frame with document.open(). It does this at start and on each setData(). document.open() erases all event listeners of the document and its window, and it replaces the root element. The iframe, its window and the Document object stay. - The MAIN-world bridge adds its listeners again, but it sets itself to "disabled". It waits for the content script to send "enabled" again. The content script did not send it again, because it did not know about the rewrite. Thus the bridge ignored the write request, and Tab did not accept the prediction. - In Chrome, the content script also lost all its listeners and its root observer. After setData(), no prediction showed. The failure was flaky in Firefox because the order of the content script start and the CKEditor frame write changes with CPU load. Under CPU load, 7 of 120 local CKEditor 4 runs failed. Fix: the content script observes the Document node. A MutationObserver on the Document stays after document.open() (measured in Chrome). When the root element changes, the content script destroys its instance and starts a new one on the new document. The new instance adds its listeners again and sends "enabled" to the bridge again. A late config answer does not enable the destroyed instance. Tests: - e2e: "CKEditor 4 setData rewrites its frame with document.open, and typing still accepts a prediction". It fails in Chrome without the fix (Tab is not accepted) and passes 10 of 10 runs with the fix. - unit: a rewritten document starts a new instance that sends "enabled" to the host bridge again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Run the CKEditor 4 typing tests 20 times in each job under CPU load in Firefox (6 jobs) and Chrome (1 job). Remove this workflow before merge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The probe passed: 600 of 600 Firefox runs and 100 of 100 Chrome runs under CPU load. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bartekplus
marked this pull request as ready for review
October 5, 2026 18:20
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
…bserved root The e2e test "ckeditor4 typing expands a snippet in one native undo step" failed at random in Chrome. The menu showed "Best regards", but Tab did not expand the shortcut. Tab moved the focus out of the editor. Root cause: in Chrome, the content script in the CKEditor 4 editing frame can start while CKEditor still writes the frame. Then the document is "loading" and has no body. The runtime observes the root element in place of the body. Later, HostChangeWatcher.watchDog() compared the observed node with document.body. The nodes were not the same, so it restarted the runtime. The restart hid the open menu. When the restart came between the menu and the Tab key, the Tab key went to the browser. Fix: when the observed node is still in the document and contains the current body, the watchdog observes the body and does not restart. A replaced root (a node that is not in the document) still causes a restart. Evidence: 4 parallel Chrome instances under full CPU load ran the snippet test 120 times. Before the fix, 9 of 120 runs failed. With the fix, 120 of 120 runs passed. All CKEditor 4 tests passed 288 of 288 runs under the same load. Tests: a new unit test in tests/content_script.behavior.test.ts fails without the fix. The coverage matrix has a new behavior, late_body_without_restart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ow key
A prediction answer that came after an arrow key moved the menu
selection back to the first row. Then Tab accepted a word that the user
did not choose. This occurs when the answer for the typed text is late:
the user presses ArrowDown on the old menu, and the new answer resets
the selection.
Reproduction: type "th" in an input. The menu shows "the", "that",
"this". Press ArrowDown to "that". A new answer for the same text comes.
Before this fix, Tab inserted "the ".
Fix: the keyboard handler records the suggestion that the user moved to
(entry.chosenSuggestion). A new answer keeps that suggestion highlighted
when the answer contains it. If the answer does not contain it, the
first row is highlighted. An edit or a cleared menu clears the choice.
Tests:
- e2e: "A late prediction answer keeps the suggestion that the user
chose with an arrow key". It sends a new answer after ArrowDown. It
failed without the fix ("the " in place of "that ") and passes 5 of 5
runs with the fix.
- unit: the keyboard handler records the choice; the session keeps it
for a late answer, drops it when the answer does not contain it, and
clears it on input.
- The coverage matrix has a new behavior, late_answer_keeps_arrow_choice.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The e2e test
ckeditor4 typing accepts a prediction mid-line and keeps the caret after the wordfailed on master in Firefox (run 37345187610). The test is new in #476 and it is flaky.Under CPU load I reproduced it locally: 7 of 120 CKEditor 4 typing runs in Firefox failed. In each failure, the prediction menu was visible, but Tab did not accept the prediction. An event log in the editing frame showed that nobody handled the Tab key, so Tab moved the focus out of the editor.
Root cause
CKEditor 4 writes its editing frame with
document.open(). It does this at start and on eachsetData().document.open()erases all event listeners of the document and its window, and it replaces the root element. The iframe, its window and theDocumentobject stay.editor.setData(), no prediction showed at all.In Firefox it is flaky because the order of "content script starts" and "CKEditor writes the frame" changes with CPU load.
Fix
The content script observes the
Documentnode. AMutationObserveron the document stays afterdocument.open()(I measured this in Chrome; the event listeners do not stay). When the root element changes, the content script destroys its instance and starts a new one on the new document. The new instance adds all its listeners again and sends "enabled" to the bridge again. A late config answer does not enable the destroyed instance.Tests
CKEditor 4 setData rewrites its frame with document.open, and typing still accepts a prediction. In Chrome it fails without the fix (the same "Tab not accepted" failure as the master flake) and passes 10 of 10 runs with it.tests/content_script.behavior.test.ts. It fails without the fix.rewritten_document_restart.bun run check,bun run test,bun run check:e2e:coverage,bun run test:e2eandbun run test:e2e:full --platform=chromepass.Two more fixes (found while I checked the CI of this PR)
2. Chrome: a watchdog restart closed the menu (
ckeditor4 typing expands a snippet)One CI run failed in Chrome: the menu showed "Best regards", but Tab did not expand
ftsig.readyState: "loading", no<body>). Then the runtime observes<html>. LaterHostChangeWatcher.watchDog()saw "observed node ≠document.body" and restarted the runtime. The restart closed the menu. A restart between "menu shown" and Tab sent Tab to the browser.3. A late answer moved the menu selection back to the first row
th, ArrowDown tothat, a new answer comes, Tab insertsthe.A late prediction answer keeps the suggestion that the user chose with an arrow key(failed before the fix, passes 5 of 5 after) and two unit tests.Not in this PR
document.open(). In a rewritten frame, the content script's own key handler accepts with Tab, so I did not change it."We saww teh") once. I did not reproduce that. If it comes back with this fix, it needs its own look.🤖 Generated with Claude Code