diff --git a/packages/app-store/_components/eventTypeAppCardInterface.test.tsx b/packages/app-store/_components/eventTypeAppCardInterface.test.tsx
new file mode 100644
index 0000000000..505cb0234d
--- /dev/null
+++ b/packages/app-store/_components/eventTypeAppCardInterface.test.tsx
@@ -0,0 +1,97 @@
+import { render, screen } from "@testing-library/react";
+import type { CredentialOwner } from "types";
+import { vi } from "vitest";
+
+import type { RouterOutputs } from "@calcom/trpc";
+
+import { DynamicComponent } from "./DynamicComponent";
+import { EventTypeAppCard } from "./EventTypeAppCardInterface";
+
+vi.mock("./DynamicComponent", async () => {
+ const actual = (await vi.importActual("./DynamicComponent")) as object;
+ return {
+ ...actual,
+ DynamicComponent: vi.fn(() =>
MockedDynamicComponent
),
+ };
+});
+
+afterEach(() => {
+ vi.clearAllMocks();
+});
+
+const getAppDataMock = vi.fn();
+const setAppDataMock = vi.fn();
+const mockProps = {
+ app: {
+ name: "TestApp",
+ slug: "testapp",
+ credentialOwner: {},
+ } as RouterOutputs["viewer"]["integrations"]["items"][number] & { credentialOwner?: CredentialOwner },
+ eventType: {},
+ getAppData: getAppDataMock,
+ setAppData: setAppDataMock,
+ LockedIcon: MockedIcon
,
+ disabled: false,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+} as any;
+
+describe("Tests for EventTypeAppCard component", () => {
+ test("Should render DynamicComponent with correct slug", () => {
+ render();
+
+ expect(DynamicComponent).toHaveBeenCalledWith(
+ expect.objectContaining({
+ slug: mockProps.app.slug,
+ }),
+ {}
+ );
+
+ expect(screen.getByText("MockedDynamicComponent")).toBeInTheDocument();
+ });
+
+ test("Should invoke getAppData and setAppData from context on render", () => {
+ render(
+
+ );
+
+ expect(getAppDataMock).toHaveBeenCalled();
+ expect(setAppDataMock).toHaveBeenCalled();
+ });
+
+ test("Should render DynamicComponent with 'stripepayment' slug for stripe app", () => {
+ const stripeProps = {
+ ...mockProps,
+ app: {
+ ...mockProps.app,
+ slug: "stripe",
+ },
+ };
+
+ render();
+
+ expect(DynamicComponent).toHaveBeenCalledWith(
+ expect.objectContaining({
+ slug: "stripepayment",
+ }),
+ {}
+ );
+
+ expect(screen.getByText("MockedDynamicComponent")).toBeInTheDocument();
+ });
+
+ test("Should display error boundary message on child component error", () => {
+ (DynamicComponent as jest.Mock).mockImplementation(() => {
+ return Error("Mocked error from DynamicComponent");
+ });
+
+ render();
+ const errorMessage = screen.getByText(`There is some problem with ${mockProps.app.name} App`);
+ expect(errorMessage).toBeInTheDocument();
+ });
+});
diff --git a/packages/app-store/test-setup.ts b/packages/app-store/test-setup.ts
new file mode 100644
index 0000000000..eb345413c0
--- /dev/null
+++ b/packages/app-store/test-setup.ts
@@ -0,0 +1,27 @@
+import matchers from "@testing-library/jest-dom/matchers";
+import { cleanup } from "@testing-library/react";
+import { afterEach, expect, vi } from "vitest";
+
+vi.mock("@calcom/lib/OgImages", async () => {
+ return {};
+});
+
+vi.mock("@calcom/lib/hooks/useLocale", () => ({
+ useLocale: () => {
+ return {
+ t: (str: string) => str,
+ };
+ },
+}));
+
+global.ResizeObserver = vi.fn().mockImplementation(() => ({
+ observe: vi.fn(),
+ unobserve: vi.fn(),
+ disconnect: vi.fn(),
+}));
+
+expect.extend(matchers);
+
+afterEach(() => {
+ cleanup();
+});
diff --git a/vitest.workspace.ts b/vitest.workspace.ts
index 0940105554..1cdfa7156f 100644
--- a/vitest.workspace.ts
+++ b/vitest.workspace.ts
@@ -37,6 +37,15 @@ const workspaces = packagedEmbedTestsOnly
setupFiles: ["packages/ui/components/test-setup.ts"],
},
},
+ {
+ test: {
+ globals: true,
+ name: "EventTypeAppCardInterface components",
+ include: ["packages/app-store/_components/**/*.{test,spec}.{ts,js,tsx}"],
+ environment: "jsdom",
+ setupFiles: ["packages/app-store/test-setup.ts"],
+ },
+ },
];
export default defineWorkspace(workspaces);