import type { Page } from "@playwright/test"; export const createEmbedsFixture = (page: Page) => { return { /** * @deprecated * Use 'gotoPlayground' instead, to navigate. It calls `addEmbedListeners` automatically. */ async addEmbedListeners(calNamespace: string) { await page.addInitScript( ({ calNamespace }: { calNamespace: string }) => { console.log( "PlaywrightTest - InitScript:", "Adding listener for __iframeReady on namespace:", calNamespace ); // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-ignore window.eventsFiredStoreForPlaywright = window.eventsFiredStoreForPlaywright || {}; // Add a postMessage listener immediately to capture __iframeReady events // This avoids the race condition where the event fires before Cal.ns[namespace] is ready // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-ignore if (!window.postMessageListenerAdded) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-ignore window.postMessageListenerAdded = true; window.addEventListener("message", (event) => { // Filter for Cal.com embed messages if ( event.data && typeof event.data === "object" && event.data.originator === "CAL" && event.data.type ) { const { type, namespace, data } = event.data; console.log("PlaywrightTest postMessage:", `Received ${type} for namespace ${namespace}`); // Set iframeReady when we receive __iframeReady event for our namespace if (type === "__iframeReady" && namespace === calNamespace) { console.log("PlaywrightTest postMessage:", "Setting window.iframeReady = true"); // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-ignore window.iframeReady = true; } // Store the event in our event store // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-ignore const store = window.eventsFiredStoreForPlaywright; if (store) { const eventStore = (store[`${type}-${namespace}`] = store[`${type}-${namespace}`] || []); eventStore.push({ type, namespace, fullType: `CAL:${namespace}:${type}`, data }); } } }); } document.addEventListener("DOMContentLoaded", function tryAddingListener() { if (parent !== window) { // Firefox seems to execute this snippet for iframe as well. Avoid that. It must be executed only for parent frame. // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-ignore window.initialBodyVisibility = document.body.style.visibility; // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-ignore window.initialBodyBackground = document.body.style.background; // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-ignore window.initialValuesSet = true; return; } // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-ignore let api = window.Cal; if (!api) { console.log("PlaywrightTest:", "window.Cal not available yet, trying again"); setTimeout(tryAddingListener, 500); return; } if (calNamespace) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-ignore api = window.Cal.ns[calNamespace]; console.log("Using api from namespace-", { calNamespace, api }); } if (!api) { console.log(`namespace "${calNamespace}" not found yet - Trying again`); setTimeout(tryAddingListener, 500); return; } console.log("PlaywrightTest:", `Adding listener for __iframeReady on namespace:${calNamespace}`); api("on", { action: "*", callback: (e) => { console.log("Playwright Embed Fixture: Received event", JSON.stringify(e.detail)); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore window.iframeReady = true; // Technically if there are multiple cal embeds, it can be set due to some other iframe. But it works for now. Improve it when it doesn't work // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const store = window.eventsFiredStoreForPlaywright; const eventStore = (store[`${e.detail.type}-${e.detail.namespace}`] = store[`${e.detail.type}-${e.detail.namespace}`] || []); eventStore.push(e.detail); }, }); }); }, { calNamespace } ); page.on("console", (msg) => { console.log(`Browser Console: ${msg.type()}: ${msg.text()}`); }); page.on("framenavigated", async (frame) => { console.log(`Navigation occurred in frame: ${frame.url()}`); }); page.on("pageerror", (error) => { console.error(`Page error: ${error.message}`); }); page.on("requestfailed", (request) => { console.error(`Failed request: ${request.url()}, ${request.failure()?.errorText}`); }); }, async getActionFiredDetails({ calNamespace, actionType }: { calNamespace: string; actionType: string }) { if (!page.isClosed()) { return await page.evaluate( ({ actionType, calNamespace }) => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-ignore return window.eventsFiredStoreForPlaywright[`${actionType}-${calNamespace}`]; }, { actionType, calNamespace } ); } }, async gotoPlayground({ calNamespace, url }: { calNamespace: string; url: string }) { await this.addEmbedListeners(calNamespace); await page.goto(url); }, }; };