diff --git a/.github/workflows/e2e-embed-react.yml b/.github/workflows/e2e-embed-react.yml index 7b27cb7951..c49f8fd0ed 100644 --- a/.github/workflows/e2e-embed-react.yml +++ b/.github/workflows/e2e-embed-react.yml @@ -25,7 +25,9 @@ jobs: - uses: ./.github/actions/cache-db - uses: ./.github/actions/cache-build - name: Run Tests - run: yarn test-e2e:embed-react + run: | + yarn test-e2e:embed-react + yarn workspace @calcom/embed-react packaged:tests env: DEPLOYSENTINEL_API_KEY: ${{ secrets.DEPLOYSENTINEL_API_KEY }} - name: Upload Test Results diff --git a/package.json b/package.json index 510400dab6..5a33322a2f 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "app-store": "yarn app-store-cli cli", "create-app": "yarn app-store create", "edit-app": "yarn app-store edit", - "publish-embed": "yarn workspaces foreach --from=\"@calcom/embed*\" npm publish --access=public", + "withEmbedPublishEnv": "NEXT_PUBLIC_EMBED_LIB_URL='https://app.cal.com/embed/embed.js' NEXT_PUBLIC_WEBAPP_URL='https://app.cal.com' yarn", + "publish-embed": "yarn withEmbedPublishEnv workspace @calcom/embed-core build && yarn withEmbedPublishEnv workspace @calcom/embed-snippet build && yarn workspaces foreach --from=\"@calcom/embed*\" npm publish --access=public", "delete-app": "yarn app-store delete", "create-app-template": "yarn app-store create-template", "edit-app-template": "yarn app-store edit-template", diff --git a/packages/embeds/embed-core/package.json b/packages/embeds/embed-core/package.json index 002962fab3..895b3b327f 100644 --- a/packages/embeds/embed-core/package.json +++ b/packages/embeds/embed-core/package.json @@ -15,7 +15,7 @@ "embed-web-start": "yarn workspace @calcom/web start", "__build": "yarn tailwind && vite build && tsc --emitDeclarationOnly --declarationDir dist && cp -r ../../../apps/web/public/embed ./dist/", "__dev": "yarn tailwind && vite build --mode development", - "build": "NEXT_PUBLIC_EMBED_FINGER_PRINT=$(git rev-parse --short HEAD) yarn __build", + "build": "rm -rf dist && NEXT_PUBLIC_EMBED_FINGER_PRINT=$(git rev-parse --short HEAD) yarn __build", "build-preview": "PREVIEW_BUILD=1 yarn __build ", "vite": "vite", "tailwind": "yarn tailwindcss -i ./src/styles.css -o ./src/tailwind.generated.css", @@ -29,7 +29,8 @@ "embed-tests": "yarn playwright test --config=playwright/config/playwright.config.ts", "embed-tests-quick": "QUICK=true yarn embed-tests", "embed-tests-update-snapshots:ci": "yarn embed-tests-quick --update-snapshots", - "prepack": "NEXT_PUBLIC_WEBAPP_URL='https://app.cal.com' yarn build", + "withEmbedPublishEnv": "NEXT_PUBLIC_EMBED_LIB_URL='https://app.cal.com/embed/embed.js' NEXT_PUBLIC_WEBAPP_URL='https://app.cal.com' yarn", + "prepack": "yarn withEmbedPublishEnv build", "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf ../../../apps/web/public/embed" }, "files": [ diff --git a/packages/embeds/embed-core/playwright/lib/testUtils.ts b/packages/embeds/embed-core/playwright/lib/testUtils.ts index b369f5d7a1..ab270f8903 100644 --- a/packages/embeds/embed-core/playwright/lib/testUtils.ts +++ b/packages/embeds/embed-core/playwright/lib/testUtils.ts @@ -131,9 +131,9 @@ export async function bookFirstEvent(username: string, frame: Frame, page: Page) return booking; } -export async function rescheduleEvent(username, frame, page) { +export async function rescheduleEvent(username: string, frame: Frame, page: Page) { await selectFirstAvailableTimeSlotNextMonth(frame, page); - await frame.waitForURL((url) => { + await frame.waitForURL((url: { pathname: string | string[] }) => { return url.pathname.includes(`/${username}/book`); }); // --- fill form diff --git a/packages/embeds/embed-core/src/embed.ts b/packages/embeds/embed-core/src/embed.ts index a457d1d39a..94de053d20 100644 --- a/packages/embeds/embed-core/src/embed.ts +++ b/packages/embeds/embed-core/src/embed.ts @@ -125,7 +125,7 @@ type SingleInstruction = SingleInstructionMap[keyof SingleInstructionMap]; export type Instruction = SingleInstruction | SingleInstruction[]; export type InstructionQueue = Instruction[]; -type PrefillAndIframeAttrsConfig = Record> & { +export type PrefillAndIframeAttrsConfig = Record> & { iframeAttrs?: Record & { id?: string; }; @@ -551,7 +551,13 @@ class CalApi { this.cal.actionManager.on(action, callback); } - off({ action, callback }: { action: never; callback: never }) { + off({ + action, + callback, + }: { + action: T; + callback: (arg0: CustomEvent>) => void; + }) { this.cal.actionManager.off(action, callback); } diff --git a/packages/embeds/embed-react/inline.tsx b/packages/embeds/embed-react/inline.tsx index 32e08cb9b7..252f4a57ac 100644 --- a/packages/embeds/embed-react/inline.tsx +++ b/packages/embeds/embed-react/inline.tsx @@ -3,16 +3,19 @@ import { useEffect } from "react"; import { useState } from "react"; import ReactDom from "react-dom"; +// Because we don't import from @calcom/embed-react, this file isn't able to test if the build is successful or not and thus npm package would work or not correctly. +// There are tests in test/built which verifiy that the types from built package are correctly generated and exported correctly. import Cal, { getCalApi } from "./src/index"; const api = getCalApi(); function App() { - const [loaded, setLoaded] = useState(false); + const [, setLoaded] = useState(false); useEffect(() => { // Simulate state change causing config object to change, causing rerender of Cal setTimeout(setLoaded.bind(true), 1000); - const callback = (event) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const callback = (event: any) => { console.log(event.detail); }; api.then((api) => { diff --git a/packages/embeds/embed-react/package.json b/packages/embeds/embed-react/package.json index 6703ae71b5..d1516cba50 100644 --- a/packages/embeds/embed-react/package.json +++ b/packages/embeds/embed-react/package.json @@ -11,16 +11,17 @@ }, "scripts": { "dev": "vite --port=3101 --open", - "build": "vite build && tsc --emitDeclarationOnly --declarationDir dist", + "build": "rm -rf dist && vite build && tsc --emitDeclarationOnly --declarationDir dist", "preview": "vite preview", - "prepare": "NEXT_PUBLIC_EMBED_LIB_URL='https://app.cal.com/embed/embed.js' NEXT_PUBLIC_WEBAPP_URL='https://app.cal.com' yarn build", "type-check": "tsc --pretty --noEmit", "type-check:ci": "tsc-absolute --pretty --noEmit", "lint": "eslint --ext .ts,.js,.tsx,.jsx ./src", "embed-tests": "yarn playwright test --config=./playwright/config/playwright.config.ts", "embed-tests-quick": "QUICK=true yarn embed-tests", "embed-tests-update-snapshots:ci": "yarn embed-tests-quick --update-snapshots", - "prepack": "NEXT_PUBLIC_EMBED_LIB_URL='https://app.cal.com/embed/embed.js' NEXT_PUBLIC_WEBAPP_URL='https://app.cal.com' yarn build", + "packaged:tests": "cd test/packaged && yarn tsc --noEmit && yarn run -T test -- --packaged-embed-tests-only", + "withEmbedPublishEnv": "NEXT_PUBLIC_EMBED_LIB_URL='https://app.cal.com/embed/embed.js' NEXT_PUBLIC_WEBAPP_URL='https://app.cal.com' yarn", + "prepack": "yarn withEmbedPublishEnv build && yarn packaged:tests", "embed-web-start": "yarn workspace @calcom/web start", "embed-dev": "yarn workspace @calcom/embed-react dev", "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist" diff --git a/packages/embeds/embed-react/playwright/tests/basic.e2e.ts b/packages/embeds/embed-react/playwright/tests/basic.e2e.ts index 952ca836a5..f4466b6725 100644 --- a/packages/embeds/embed-react/playwright/tests/basic.e2e.ts +++ b/packages/embeds/embed-react/playwright/tests/basic.e2e.ts @@ -3,16 +3,22 @@ import { expect } from "@playwright/test"; import { getEmbedIframe } from "@calcom/embed-core/playwright/lib/testUtils"; import { test } from "@calcom/web/playwright/lib/fixtures"; -test("Inline Usage Snapshot", async ({ page, getActionFiredDetails, addEmbedListeners }) => { - //TODO: Do it with page.goto automatically - await addEmbedListeners(""); - await page.goto("/"); - const embedIframe = await getEmbedIframe({ page, pathname: "/pro" }); - expect(embedIframe).toBeEmbedCalLink("", getActionFiredDetails, { - pathname: "/pro", - searchParams: { - theme: "dark", - }, +test.describe("Inline Embed", () => { + test("should verify that the iframe got created with correct URL", async ({ + page, + getActionFiredDetails, + addEmbedListeners, + }) => { + //TODO: Do it with page.goto automatically + await addEmbedListeners(""); + await page.goto("/"); + const embedIframe = await getEmbedIframe({ page, pathname: "/pro" }); + expect(embedIframe).toBeEmbedCalLink("", getActionFiredDetails, { + pathname: "/pro", + searchParams: { + theme: "dark", + }, + }); + // expect(await page.screenshot()).toMatchSnapshot("react-component-inline.png"); }); - // expect(await page.screenshot()).toMatchSnapshot("react-component-inline.png"); }); diff --git a/packages/embeds/embed-react/src/Cal.tsx b/packages/embeds/embed-react/src/Cal.tsx index 5ed7b288b6..bd409ece41 100644 --- a/packages/embeds/embed-react/src/Cal.tsx +++ b/packages/embeds/embed-react/src/Cal.tsx @@ -2,6 +2,8 @@ import { useEffect, useRef } from "react"; +import type { PrefillAndIframeAttrsConfig } from "@calcom/embed-core"; + import useEmbed from "./useEmbed"; type CalProps = { @@ -11,7 +13,7 @@ type CalProps = { debug?: boolean; uiDebug?: boolean; }; - config?: Record; + config?: PrefillAndIframeAttrsConfig; embedJsUrl?: string; } & React.HTMLAttributes; diff --git a/packages/embeds/embed-react/test/packaged/README.md b/packages/embeds/embed-react/test/packaged/README.md new file mode 100644 index 0000000000..89a929b4e0 --- /dev/null +++ b/packages/embeds/embed-react/test/packaged/README.md @@ -0,0 +1,5 @@ +# Packaged + +The tests in this file are run on the packaged code that is published to npm. The packaged code is different from the source code in atleast the following ways +- Not all files go to packaged code.If package.json -> files field is specified then only the files that are specified there would be published. So, one might accidentally miss an important file that's available otherwise. +- The packaged code doesn't have .ts files. Those files are actually converted to .js files and .d.ts files are generated separately for TypeScript support. It allows the package to work in both TypeScript and non TypeScript environments. \ No newline at end of file diff --git a/packages/embeds/embed-react/test/packaged/api.test.ts b/packages/embeds/embed-react/test/packaged/api.test.ts new file mode 100644 index 0000000000..574bc41011 --- /dev/null +++ b/packages/embeds/embed-react/test/packaged/api.test.ts @@ -0,0 +1,16 @@ +/** + * @fileoverview + * This file tests two things in 2 ways + * - It is a vitest test file and thus it tests if the code executes without any error. Thus, it tests that package.json->main/module fields are correctly defined. It obviously verifies the assertions as well. + * - It is also validates for it's types and thus verifies that @calcom/embed-react has correctly specified it's types in package.json->types field. + */ +import { expect, test } from "vitest"; + +// This import may show up as an error in your IDE, but it's fine because typings are available only after embed-react is built. +import { getCalApi } from "@calcom/embed-react"; + +const api = getCalApi(); + +test("Check that the API is available", () => { + expect(api).toBeDefined() +}); diff --git a/packages/embeds/embed-react/test/packaged/tsconfig.json b/packages/embeds/embed-react/test/packaged/tsconfig.json new file mode 100644 index 0000000000..2600b20503 --- /dev/null +++ b/packages/embeds/embed-react/test/packaged/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "@calcom/tsconfig/base.json", + "compilerOptions": { + "module": "ESNext", + "target": "ES2015", + "moduleResolution": "Node", + "baseUrl": ".", + "declaration": true, + "jsx": "preserve", + "outDir": "dist", + }, + "include": ["**/*.ts"], + } + \ No newline at end of file diff --git a/packages/embeds/embed-react/tsconfig.json b/packages/embeds/embed-react/tsconfig.json index b23cc04439..01a0b645bf 100644 --- a/packages/embeds/embed-react/tsconfig.json +++ b/packages/embeds/embed-react/tsconfig.json @@ -13,6 +13,7 @@ "@calcom/embed-snippet": ["../embed-snippet/src"] } }, - "include": ["src", "env.d.ts"], - "exclude": ["dist", "build", "node_modules", "test-cal.tsx"] + "include": ["**/*.ts","**/*.tsx", "env.d.ts"], + // Exclude "test" because that has `api.test.ts` which imports @calcom/embed-react which needs it to be built using this tsconfig.json first. Excluding it here prevents type-check from validating test folder + "exclude": ["node_modules", "test"] } diff --git a/packages/embeds/embed-snippet/package.json b/packages/embeds/embed-snippet/package.json index 10e944325a..b4d17750cd 100644 --- a/packages/embeds/embed-snippet/package.json +++ b/packages/embeds/embed-snippet/package.json @@ -12,11 +12,12 @@ "directory": "packages/embeds/embed-snippet" }, "scripts": { - "build": "vite build && tsc --emitDeclarationOnly --declarationDir dist", + "build": "rm -rf dist && vite build && tsc --emitDeclarationOnly --declarationDir dist", "type-check": "tsc --pretty --noEmit", "type-check:ci": "tsc-absolute --pretty --noEmit", "lint": "eslint --ext .ts,.js src", - "prepack": "NEXT_PUBLIC_EMBED_LIB_URL='https://app.cal.com/embed/embed.js' NEXT_PUBLIC_WEBAPP_URL='https://app.cal.com' yarn build", + "withEmbedPublishEnv": "NEXT_PUBLIC_EMBED_LIB_URL='https://app.cal.com/embed/embed.js' NEXT_PUBLIC_WEBAPP_URL='https://app.cal.com' yarn", + "prepack": "yarn withEmbedPublishEnv build", "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist" }, "files": [ diff --git a/playwright.config.ts b/playwright.config.ts index 098076c60f..9d0188c508 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -104,7 +104,7 @@ const config: PlaywrightTestConfig = { { name: "@calcom/embed-core", testDir: "./packages/embeds/embed-core/", - testMatch: /.*\.(e2e|test)\.tsx?/, + testMatch: /.*\.e2e\.tsx?/, expect: { timeout: DEFAULT_EXPECT_TIMEOUT, }, @@ -116,7 +116,7 @@ const config: PlaywrightTestConfig = { expect: { timeout: DEFAULT_EXPECT_TIMEOUT, }, - testMatch: /.*\.(e2e|test)\.tsx?/, + testMatch: /.*\.e2e\.tsx?/, use: { ...devices["Desktop Chrome"], baseURL: "http://localhost:3101/" }, }, { diff --git a/vitest.workspace.ts b/vitest.workspace.ts index 97d8cbcce6..4b06064362 100644 --- a/vitest.workspace.ts +++ b/vitest.workspace.ts @@ -1,20 +1,32 @@ import { defineWorkspace } from "vitest/config"; +const packagedEmbedTestsOnly = process.argv.includes("--packaged-embed-tests-only"); // defineWorkspace provides a nice type hinting DX -export default defineWorkspace([ - { - test: { - include: ["packages/**/*.{test,spec}.{ts,js}", "apps/**/*.{test,spec}.{ts,js}"], - // TODO: Ignore the api until tests are fixed - exclude: ["apps/api/**/*", "**/node_modules/**/*"], - }, - }, - { - test: { - name: "@calcom/closecom", - include: ["packages/app-store/closecom/**/*.{test,spec}.{ts,js}"], - environment: "jsdom", - setupFiles: ["packages/app-store/closecom/test/globals.ts"], - }, - }, -]); +const workspaces = packagedEmbedTestsOnly + ? [ + { + test: { + include: ["packages/embeds/**/*.{test,spec}.{ts,js}"], + environment: "jsdom", + }, + }, + ] + : [ + { + test: { + include: ["packages/**/*.{test,spec}.{ts,js}", "apps/**/*.{test,spec}.{ts,js}"], + // TODO: Ignore the api until tests are fixed + exclude: ["apps/api/**/*", "**/node_modules/**/*", "packages/embeds/**/*"], + }, + }, + { + test: { + name: "@calcom/closecom", + include: ["packages/app-store/closecom/**/*.{test,spec}.{ts,js}"], + environment: "jsdom", + setupFiles: ["packages/app-store/closecom/test/globals.ts"], + }, + }, + ]; + +export default defineWorkspace(workspaces);