From 6bc45298226f96ff79e0c070c8b2ce39727e8477 Mon Sep 17 00:00:00 2001 From: Anujmishra2004 <157341928+anujmishra03@users.noreply.github.com> Date: Mon, 14 Sep 2026 14:05:09 +0530 Subject: [PATCH] fix(embed-core): guard iframe ready handler (#30135) Co-authored-by: Bandhan Majumder Co-authored-by: Bandhan Majumder <133476557+bandhan-majumder@users.noreply.github.com> --- packages/embeds/embed-core/src/embed.test.ts | 42 ++++++++++++++++++++ packages/embeds/embed-core/src/embed.ts | 6 ++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/packages/embeds/embed-core/src/embed.test.ts b/packages/embeds/embed-core/src/embed.test.ts index 6ee7bb9584..1c26d087db 100644 --- a/packages/embeds/embed-core/src/embed.test.ts +++ b/packages/embeds/embed-core/src/embed.test.ts @@ -325,6 +325,48 @@ describe("Cal", () => { }); }); + describe("__iframeReady handler", () => { + function fireIframeReady(ns: string) { + const errors: unknown[] = []; + const onError = (e: ErrorEvent) => { + errors.push(e.error); + e.preventDefault(); + }; + window.addEventListener("error", onError); + window.dispatchEvent( + new CustomEvent(`CAL:${ns}:__iframeReady`, { + detail: { type: "__iframeReady", namespace: ns, data: { isPrerendering: false } }, + }) + ); + window.removeEventListener("error", onError); + return errors; + } + + it("ignores __iframeReady on an instance that has no iframe", () => { + const instanceWithIframe = new CalClass("dup-ns", []); + const host = document.createElement("div"); + document.body.appendChild(host); + instanceWithIframe.api.inline({ calLink: "user/30min", elementOrSelector: host }); + const instanceWithoutIframe = new CalClass("dup-ns", []); + + expect(fireIframeReady("dup-ns")).toEqual([]); + expect(instanceWithIframe.iframeReady).toBe(true); + expect(instanceWithoutIframe.iframeReady).toBeFalsy(); + }); + + it("marks the iframe ready and visible when the instance owns an iframe", () => { + const cal = new CalClass("ready-ns", []); + const host = document.createElement("div"); + document.body.appendChild(host); + cal.api.inline({ calLink: "user/30min", elementOrSelector: host }); + cal.iframe!.style.visibility = "hidden"; + + expect(fireIframeReady("ready-ns")).toEqual([]); + expect(cal.iframeReady).toBe(true); + expect(cal.iframe!.style.visibility).toBe(""); + }); + }); + /** * We don't mock the createIframe method as it could update the 'this' objects which could affect the test, so we avoid mocking it */ diff --git a/packages/embeds/embed-core/src/embed.ts b/packages/embeds/embed-core/src/embed.ts index 7fd8363ae8..7c49bc193e 100644 --- a/packages/embeds/embed-core/src/embed.ts +++ b/packages/embeds/embed-core/src/embed.ts @@ -460,8 +460,12 @@ export class Cal { }); this.actionManager.on("__iframeReady", (e) => { + if (!this.iframe) { + return; + } + this.iframeReady = true; - if (this.iframe && !e.detail.data.isPrerendering) { + if (!e.detail.data.isPrerendering) { // It's a bit late to make the iframe visible here. We just needed to wait for the HTML tag of the embedded calLink to be rendered(which then informs the browser of the color-scheme) // TODO: Right now it would wait for embed-iframe.js bundle to be loaded as well. We can speed that up by inlining the JS that informs about color-scheme being set in the HTML. // But it's okay to do it here for now because the embedded calLink also keeps itself hidden till it receives `parentKnowsIframeReady` message(It has it's own reasons for that)