Merged
Conversation
c74ef1b to
e494542
Compare
Add shared mock stubs for @WordPress packages that crash when imported in the test environment. Flatten existing directory-based mocks (i18n, components) to top-level files for consistency. Remove exports that have no effect on test outcomes — the files themselves are still needed to prevent Vitest from importing the real modules. Tests declare vi.mock('module') without a factory to use the shared stub, and override locally only when test-specific behavior is needed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove @wordpress/preferences (editor.test.jsx) and @wordpress/i18n (editor-load-notice, offline-indicator) mocks that have no effect on test outcomes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…aded Replace the IntersectionObserver in use-editor-visible with a new useEditorReady hook that coordinates two conditions before signaling the native host via onEditorLoaded: 1. All window.editor.* bridge methods are assigned (from useHostBridge) 2. The editor content is visible in the viewport (via IntersectionObserver on the VisualEditor/TextEditor root element) useEditorReady returns a callback ref (for DOM attachment observation), a standard ref (for imperative access in useHostBridge), and a markBridgeReady callback. The callback ref is forwarded to VisualEditor/TextEditor via forwardRef so the observer fires when the actual editor content is in the viewport — not just the wrapper div. The editorLoaded() call is deferred by one frame via requestAnimationFrame so the browser has painted the editor content before the native host starts the fade-in animation. Remove the now-unused useEditorVisible hook and add the missing window.editor.focus cleanup on unmount. The error path in editor-environment.js retains its own editorLoaded() call since useEditorReady won't run when initialization fails. Addresses CMM-2008 and CMM-2009. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add isReady guards to undo(), redo(), dismissTopModal(), isCodeEditorEnabled, appendTextAtCursor(), getContent(), and getTitleAndContent(). Previously only setContent() was guarded. Reset isReady to false in controllerWebContentProcessDidTerminate so JS bridge calls are blocked until the editor re-emits onEditorLoaded after a WebView process crash and reload. Fire-and-forget methods silently return when not ready. Async throwing methods (getContent, getTitleAndContent) throw EditorNotReadyError so callers can handle the case explicitly. Addresses CMM-2008 and CMM-2009. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Verify window.editor.* methods are assigned and markBridgeReady is called, and that all methods are cleaned up on unmount. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
e494542 to
5cb4d59
Compare
kean
approved these changes
Apr 1, 2026
| /// | ||
| /// - parameter text: The text to append at the cursor position. | ||
| public func appendTextAtCursor(_ text: String) { | ||
| guard isReady else { return } |
Contributor
There was a problem hiding this comment.
Does it actually happen? If yes, it might be worth saving it as "pending update" and applying automatically when the editor is ready. Not sure if it's worth it though. If there is a spinner, and you hit Cmd+V via the keyboard, you probably wouldn't expect it to work.
Member
Author
There was a problem hiding this comment.
No, I did not observe any reports of this occurring nor did I produce it. The guard was applied universally to avoid unexpected errors.
I agree. Stashing and later applying the pending update would be nice, but I'm not sure how realistic that being a real problem is currently. I'll likely defer that type of improvement until a problem surfaces.
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.
What?
Ensure the iOS native-to-web bridge is fully initialized before signaling editor readiness, and guard all JS bridge calls against early invocation.
Why?
Fix CMM-2008. Fix CMM-2009.
The
onEditorLoadedsignal was firing (viaIntersectionObserver) beforewindow.editor.*methods were assigned in theuseHostBridgeReact effect. When native iOS code called bridge methods immediately after receiving the signal — e.g.,getTitleAndContent()during an autosave triggered by opening the block inserter — the methods wereundefined, causing TypeErrors (CMM-2008) or ReferenceErrors (CMM-2009).How?
JS side
IntersectionObserverinuse-editor-visiblewith a newuseEditorReadyhook that coordinates two conditions before dispatchingonEditorLoaded:window.editor.*bridge methods have been assigned (signaled byuseHostBridgevia amarkBridgeReadycallback)IntersectionObserveron theVisualEditor/TextEditorroot element, received throughforwardRef)useEditorReadyso theIntersectionObserverattaches when React mounts the editor content — not on initial render when the element doesn't exist yet.editorLoaded()by one frame viarequestAnimationFrameso the browser has painted the editor content before the native host starts the fade-in animation.window.editor.focuscleanup on unmount.iOS side
isReadyguards toundo(),redo(),dismissTopModal(),isCodeEditorEnabled,appendTextAtCursor(),getContent(), andgetTitleAndContent(). Previously onlysetContent()was guarded.isReadytofalseincontrollerWebContentProcessDidTerminateso bridge calls are blocked until the editor re-emitsonEditorLoadedafter a WebView process crash.EditorNotReadyError.Tests
use-host-bridgetests verifyingwindow.editor.*methods are assigned andmarkBridgeReadyis called, and that all methods are cleaned up on unmount.Test infrastructure (first two commits)
@wordpressmock stubs into__mocks__/directory.vi.mock()calls from existing tests.Testing Instructions
Accessibility Testing Instructions
N/A — no UI changes.
Screenshots or screencast
N/A