diff --git a/packages/stage/src/StageRender.ts b/packages/stage/src/StageRender.ts index 92fa06e5..9b24abad 100644 --- a/packages/stage/src/StageRender.ts +++ b/packages/stage/src/StageRender.ts @@ -194,7 +194,10 @@ export default class StageRender extends EventEmitter { } public postTmagicRuntimeReady() { - this.contentWindow = this.iframe?.contentWindow as RuntimeWindow; + this.contentWindow = (this.iframe?.contentWindow as RuntimeWindow | null) ?? null; + + // iframe 尚未就绪时 contentWindow 为空,等 load 后再注入 magic + if (!this.contentWindow) return; this.contentWindow.magic = this.getMagicApi(); diff --git a/packages/stage/tests/unit/StageRender.spec.ts b/packages/stage/tests/unit/StageRender.spec.ts index 722702ee..2a31e4bd 100644 --- a/packages/stage/tests/unit/StageRender.spec.ts +++ b/packages/stage/tests/unit/StageRender.spec.ts @@ -154,6 +154,24 @@ describe('StageRender - NATIVE', () => { renderer.destroy(); }); + test('contentWindow 未就绪时 mount 不抛错,就绪后注入 magic', async () => { + const host = globalThis.document.createElement('div'); + globalThis.document.body.appendChild(host); + const renderer = new StageRender({ renderType: RenderType.IFRAME, runtimeUrl: '' }); + await expect(renderer.mount(host)).resolves.toBeUndefined(); + expect(renderer.contentWindow).toBeNull(); + + const postMessage = vi.fn(); + Object.defineProperty(renderer.iframe!, 'contentWindow', { + configurable: true, + value: { postMessage, document: globalThis.document }, + }); + renderer.postTmagicRuntimeReady(); + expect(postMessage).toHaveBeenCalledWith({ tmagicRuntimeReady: true }, '*'); + expect(renderer.contentWindow?.magic).toBeDefined(); + renderer.destroy(); + }); + test('IFRAME getElementsFromPoint 考虑 iframe 偏移', async () => { const host = globalThis.document.createElement('div'); globalThis.document.body.appendChild(host);