* fix: add missing vi.mock() calls to prevent vitest worker shutdown flakiness
Add vi.mock() calls for modules that trigger background network requests
or database connections during import. These transitive imports can cause
the vitest worker RPC to shut down while pending fetch/network operations
are still in flight, resulting in flaky test failures with:
Error: [vitest-worker]: Closing rpc while "fetch" was pending
The primary modules mocked are:
- @calcom/app-store/delegationCredential (triggers credential lookups)
- @calcom/prisma (triggers database initialization)
- @calcom/features/calendars/lib/CalendarManager (triggers calendar API calls)
- @calcom/features/auth/lib/verifyEmail (triggers email service)
- @calcom/lib/domainManager/organization (triggers domain lookups)
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: remove conflicting empty prisma mocks from files with prismock/prismaMock setups
- Remove vi.mock('@calcom/prisma', () => ({ default: {}, prisma: {} })) from 28 files
that already have prismock/prismaMock test doubles. Vitest hoists all vi.mock() calls
and the last one wins, so these empty mocks were overriding the functional test doubles.
- Fix CalendarSubscriptionService.test.ts to reuse the shared mock from
__mocks__/delegationCredential instead of creating a new unconfigured vi.fn()
- Remove DelegationCredentialRepository.test.ts empty prisma mock (different pattern)
- Remove vi.mock from inside beforeEach in intentToCreateOrg.handler.test.ts
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: add comprehensive delegationCredential mock exports to prevent CI test failures
The vi.mock blocks for @calcom/app-store/delegationCredential were missing
exports that the code under test transitively imports (e.g.
enrichUsersWithDelegationCredentials, enrichUserWithDelegationCredentialsIncludeServiceAccountKey,
buildAllCredentials, getFirstDelegationConferencingCredentialAppLocation).
Added all exports with passthrough implementations so the booking flow
works correctly without triggering real network requests.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: correct credential mock return shapes to match real module API
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: revert unintended yarn.lock changes
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
511 lines
19 KiB
TypeScript
511 lines
19 KiB
TypeScript
import "@calcom/lib/__mocks__/logger";
|
|
|
|
import { createHash } from "node:crypto";
|
|
import { getAbsoluteEventTypeRedirectUrlWithEmbedSupport } from "@calcom/app-store/routing-forms/getEventTypeRedirectUrl";
|
|
import { getResponseToStore } from "@calcom/app-store/routing-forms/lib/getResponseToStore";
|
|
import { getSerializableForm } from "@calcom/app-store/routing-forms/lib/getSerializableForm";
|
|
import { findMatchingRoute } from "@calcom/app-store/routing-forms/lib/processRoute";
|
|
import { substituteVariables } from "@calcom/app-store/routing-forms/lib/substituteVariables";
|
|
import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains";
|
|
import { isAuthorizedToViewFormOnOrgDomain } from "@calcom/features/routing-forms/lib/isAuthorizedToViewForm";
|
|
import { PrismaRoutingFormRepository } from "@calcom/features/routing-forms/repositories/PrismaRoutingFormRepository";
|
|
import { UserRepository } from "@calcom/features/users/repositories/UserRepository";
|
|
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
|
|
import type { GetServerSidePropsContext } from "next";
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
import { getRoutedUrl } from "./getRoutedUrl";
|
|
import { getUrlSearchParamsToForward } from "./getUrlSearchParamsToForward";
|
|
import { handleResponse } from "./handleResponse";
|
|
|
|
// Mock dependencies
|
|
vi.mock("./getUrlSearchParamsToForward");
|
|
vi.mock("./handleResponse");
|
|
vi.mock("@calcom/lib/checkRateLimitAndThrowError");
|
|
vi.mock("@calcom/features/routing-forms/repositories/PrismaRoutingFormRepository");
|
|
vi.mock("@calcom/features/users/repositories/UserRepository", () => {
|
|
return {
|
|
UserRepository: vi.fn().mockImplementation(function () {
|
|
return {
|
|
enrichUserWithItsProfile: vi.fn(),
|
|
};
|
|
}),
|
|
};
|
|
});
|
|
vi.mock("@calcom/features/ee/organizations/lib/orgDomains");
|
|
vi.mock("@calcom/features/routing-forms/lib/isAuthorizedToViewForm");
|
|
vi.mock("@calcom/app-store/routing-forms/lib/getSerializableForm");
|
|
vi.mock("@calcom/app-store/routing-forms/lib/getResponseToStore");
|
|
vi.mock("@calcom/app-store/routing-forms/lib/processRoute");
|
|
vi.mock("@calcom/app-store/routing-forms/lib/substituteVariables");
|
|
vi.mock("@calcom/app-store/routing-forms/getEventTypeRedirectUrl");
|
|
vi.mock("@calcom/app-store/routing-forms/enrichFormWithMigrationData", () => ({
|
|
enrichFormWithMigrationData: vi.fn((form) => form),
|
|
}));
|
|
vi.mock("@calcom/lib/sentryWrapper", () => ({
|
|
withReporting: (fn: unknown) => fn,
|
|
}));
|
|
vi.mock("@calcom/features/routing-trace/di/RoutingTraceService.container", () => ({
|
|
getRoutingTraceService: vi.fn(() => ({
|
|
addStep: vi.fn(),
|
|
getStepsCount: vi.fn().mockReturnValue(0),
|
|
savePendingRoutingTrace: vi.fn().mockResolvedValue(undefined),
|
|
processForBooking: vi.fn().mockResolvedValue(undefined),
|
|
})),
|
|
}));
|
|
|
|
vi.mock("@calcom/prisma", () => ({
|
|
default: {},
|
|
prisma: {},
|
|
}));
|
|
|
|
const mockForm: {
|
|
id: string;
|
|
user: { id: number; name: string };
|
|
team: null;
|
|
name: string;
|
|
fields: never[];
|
|
routes: never[];
|
|
userId: number;
|
|
teamId: null;
|
|
createdAt: Date;
|
|
updatedAt: Date;
|
|
description: null;
|
|
enabled: boolean;
|
|
isDefault: boolean;
|
|
fieldsOrder: never[];
|
|
position: number;
|
|
slug: string;
|
|
} = {
|
|
id: "form-id",
|
|
user: { id: 1, name: "Test User" },
|
|
team: null,
|
|
name: "Test Form",
|
|
fields: [],
|
|
routes: [],
|
|
userId: 1,
|
|
teamId: null,
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
description: null,
|
|
enabled: true,
|
|
isDefault: false,
|
|
fieldsOrder: [],
|
|
position: 0,
|
|
slug: "test-form",
|
|
};
|
|
|
|
const mockSerializableForm: {
|
|
id: string;
|
|
fields: { id: string; type: string; label: string; identifier: string }[];
|
|
routes: never[];
|
|
user: { id: number };
|
|
} = {
|
|
id: "form-id",
|
|
fields: [{ id: "email", type: "email", label: "Email", identifier: "email" }],
|
|
routes: [],
|
|
user: { id: 1 },
|
|
};
|
|
|
|
const mockContext = (
|
|
query: Record<string, unknown>,
|
|
url: string = "/link/form-id"
|
|
): Pick<GetServerSidePropsContext, "query" | "req"> => ({
|
|
query: { form: "form-id", ...query },
|
|
req: { url },
|
|
});
|
|
|
|
describe("getRoutedUrl", () => {
|
|
beforeEach(() => {
|
|
vi.resetAllMocks();
|
|
// Provide default mock implementations
|
|
vi.mocked(orgDomainConfig).mockReturnValue({ currentOrgDomain: null, isValidOrgDomain: false });
|
|
vi.mocked(PrismaRoutingFormRepository.findFormByIdIncludeUserTeamAndOrg).mockResolvedValue(null);
|
|
|
|
const mockEnrichUserWithItsProfile = vi.fn().mockImplementation(async ({ user }) => user);
|
|
const mockUserRepository = vi.mocked(UserRepository);
|
|
if (mockUserRepository && typeof mockUserRepository.mockImplementation === "function") {
|
|
mockUserRepository.mockImplementation(function () {
|
|
return {
|
|
enrichUserWithItsProfile: mockEnrichUserWithItsProfile,
|
|
} as unknown as InstanceType<typeof UserRepository>;
|
|
});
|
|
}
|
|
vi.mocked(isAuthorizedToViewFormOnOrgDomain).mockReturnValue(true);
|
|
vi.mocked(getSerializableForm).mockResolvedValue(mockSerializableForm as never);
|
|
vi.mocked(findMatchingRoute).mockReturnValue(null);
|
|
vi.mocked(handleResponse).mockResolvedValue({
|
|
teamMembersMatchingAttributeLogic: null,
|
|
formResponse: { id: 1 },
|
|
queuedFormResponse: null,
|
|
attributeRoutingConfig: null,
|
|
timeTaken: {},
|
|
crmContactOwnerEmail: null,
|
|
crmContactOwnerRecordType: null,
|
|
crmAppSlug: null,
|
|
isPreview: false,
|
|
});
|
|
vi.mocked(substituteVariables).mockImplementation((value) => value);
|
|
vi.mocked(getUrlSearchParamsToForward).mockReturnValue(new URLSearchParams());
|
|
vi.mocked(getAbsoluteEventTypeRedirectUrlWithEmbedSupport).mockImplementation(
|
|
({ eventTypeRedirectUrl }) => eventTypeRedirectUrl
|
|
);
|
|
vi.mocked(getResponseToStore).mockReturnValue({ email: "test@cal.com" });
|
|
});
|
|
|
|
it("should return notFound if query params are invalid", async () => {
|
|
const context = {
|
|
query: { wrong_param: "value" }, // 'form' is missing
|
|
req: { url: "/link/form-id" },
|
|
};
|
|
// @ts-expect-error we are testing invalid input
|
|
const result = await getRoutedUrl(context);
|
|
expect(result).toEqual({ notFound: true });
|
|
});
|
|
|
|
it("should return notFound if form is not found", async () => {
|
|
vi.mocked(PrismaRoutingFormRepository.findFormByIdIncludeUserTeamAndOrg).mockResolvedValue(null);
|
|
const context = mockContext({});
|
|
|
|
const result = await getRoutedUrl(context);
|
|
expect(result).toEqual({ notFound: true });
|
|
expect(PrismaRoutingFormRepository.findFormByIdIncludeUserTeamAndOrg).toHaveBeenCalledWith("form-id");
|
|
});
|
|
|
|
it("should return notFound if user is not authorized", async () => {
|
|
vi.mocked(PrismaRoutingFormRepository.findFormByIdIncludeUserTeamAndOrg).mockResolvedValue(
|
|
mockForm as never
|
|
);
|
|
vi.mocked(isAuthorizedToViewFormOnOrgDomain).mockReturnValue(false);
|
|
|
|
const context = mockContext({});
|
|
const result = await getRoutedUrl(context);
|
|
|
|
expect(result).toEqual({ notFound: true });
|
|
expect(isAuthorizedToViewFormOnOrgDomain).toHaveBeenCalledWith({
|
|
user: mockForm.user,
|
|
team: mockForm.team,
|
|
currentOrgDomain: null,
|
|
});
|
|
});
|
|
|
|
it("should throw an error if no matching route is found", async () => {
|
|
vi.mocked(PrismaRoutingFormRepository.findFormByIdIncludeUserTeamAndOrg).mockResolvedValue(
|
|
mockForm as never
|
|
);
|
|
vi.mocked(getSerializableForm).mockResolvedValue(mockSerializableForm as never);
|
|
vi.mocked(findMatchingRoute).mockReturnValue(null);
|
|
|
|
const context = mockContext({});
|
|
await expect(getRoutedUrl(context)).rejects.toThrow("No matching route could be found");
|
|
expect(findMatchingRoute).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
form: mockSerializableForm,
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should return props with a message for customPageMessage action", async () => {
|
|
vi.mocked(PrismaRoutingFormRepository.findFormByIdIncludeUserTeamAndOrg).mockResolvedValue(
|
|
mockForm as never
|
|
);
|
|
const message = "This is a custom message";
|
|
const mockRoute = { id: "route1", action: { type: "customPageMessage", value: message } };
|
|
vi.mocked(findMatchingRoute).mockReturnValue(mockRoute as never);
|
|
|
|
const context = mockContext({});
|
|
const result = await getRoutedUrl(context);
|
|
|
|
expect(result).toEqual({
|
|
props: {
|
|
isEmbed: false,
|
|
form: mockSerializableForm,
|
|
message: message,
|
|
errorMessage: null,
|
|
},
|
|
});
|
|
expect(handleResponse).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
form: mockSerializableForm,
|
|
})
|
|
);
|
|
expect(findMatchingRoute).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
form: mockSerializableForm,
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should return a redirect for eventTypeRedirectUrl action and substitute variables", async () => {
|
|
vi.mocked(PrismaRoutingFormRepository.findFormByIdIncludeUserTeamAndOrg).mockResolvedValue(
|
|
mockForm as never
|
|
);
|
|
const redirectUrl = "test-user/30min/{email}";
|
|
const mockRoute = { id: "route1", action: { type: "eventTypeRedirectUrl", value: redirectUrl } };
|
|
vi.mocked(findMatchingRoute).mockReturnValue(mockRoute as never);
|
|
const substitutedUrl = "test-user/30min/test@cal.com";
|
|
vi.mocked(substituteVariables).mockReturnValue(substitutedUrl);
|
|
vi.mocked(getAbsoluteEventTypeRedirectUrlWithEmbedSupport).mockReturnValue(`/${substitutedUrl}`);
|
|
|
|
const context = mockContext({ email: "test@cal.com" });
|
|
const result = await getRoutedUrl(context);
|
|
|
|
expect(substituteVariables).toHaveBeenCalledWith(
|
|
redirectUrl,
|
|
{ email: "test@cal.com" },
|
|
mockSerializableForm.fields
|
|
);
|
|
expect(getUrlSearchParamsToForward).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
searchParams: expect.any(URLSearchParams),
|
|
formResponse: { email: "test@cal.com" },
|
|
fields: mockSerializableForm.fields,
|
|
})
|
|
);
|
|
expect(getAbsoluteEventTypeRedirectUrlWithEmbedSupport).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
eventTypeRedirectUrl: substitutedUrl,
|
|
})
|
|
);
|
|
expect(result).toEqual({
|
|
redirect: {
|
|
destination: `/${substitutedUrl}`,
|
|
permanent: false,
|
|
},
|
|
});
|
|
});
|
|
|
|
it("should return a redirect for externalRedirectUrl action", async () => {
|
|
vi.mocked(PrismaRoutingFormRepository.findFormByIdIncludeUserTeamAndOrg).mockResolvedValue(
|
|
mockForm as never
|
|
);
|
|
const redirectUrl = "https://example.com";
|
|
const mockRoute = { id: "route1", action: { type: "externalRedirectUrl", value: redirectUrl } };
|
|
vi.mocked(findMatchingRoute).mockReturnValue(mockRoute as never);
|
|
|
|
const context = mockContext({ email: "test@cal.com" });
|
|
const result = await getRoutedUrl(context);
|
|
|
|
const searchParams = new URLSearchParams({
|
|
...(context.query as Record<string, string>),
|
|
"cal.action": "externalRedirectUrl",
|
|
});
|
|
expect(result).toEqual({
|
|
redirect: {
|
|
destination: `${redirectUrl}?${searchParams.toString()}`,
|
|
permanent: false,
|
|
},
|
|
});
|
|
expect(findMatchingRoute).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
form: mockSerializableForm,
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should call handleResponse with correct response prop obtained from getResponseToStore", async () => {
|
|
vi.mocked(PrismaRoutingFormRepository.findFormByIdIncludeUserTeamAndOrg).mockResolvedValue(
|
|
mockForm as never
|
|
);
|
|
const redirectUrl = "test-user/30min";
|
|
const mockRoute = { id: "route1", action: { type: "eventTypeRedirectUrl", value: redirectUrl } };
|
|
vi.mocked(findMatchingRoute).mockReturnValue(mockRoute as never);
|
|
vi.mocked(getAbsoluteEventTypeRedirectUrlWithEmbedSupport).mockReturnValue(`/${redirectUrl}`);
|
|
vi.mocked(getResponseToStore).mockReturnValue({ "xxx-xxx": { value: "test@cal.com" } } as never);
|
|
|
|
const context = mockContext({ email: "test@cal.com" });
|
|
await getRoutedUrl(context);
|
|
|
|
expect(getResponseToStore).toHaveBeenCalledWith({
|
|
formFields: mockSerializableForm.fields,
|
|
fieldsResponses: { email: "test@cal.com" },
|
|
});
|
|
|
|
expect(handleResponse).toHaveBeenCalledWith(
|
|
expect.objectContaining({ response: { "xxx-xxx": { value: "test@cal.com" } } })
|
|
);
|
|
});
|
|
|
|
it("should throw an error if rate limit is exceeded", async () => {
|
|
vi.mocked(checkRateLimitAndThrowError).mockRejectedValue(new Error("Rate limit exceeded"));
|
|
const context = mockContext({ email: "test@cal.com" });
|
|
const expectedHash = createHash("sha256")
|
|
.update(JSON.stringify({ email: "test@cal.com" }))
|
|
.digest("hex");
|
|
|
|
await expect(getRoutedUrl(context)).rejects.toThrow("Rate limit exceeded");
|
|
expect(checkRateLimitAndThrowError).toHaveBeenCalledWith({
|
|
identifier: `form:form-id:hash:${expectedHash}`,
|
|
});
|
|
});
|
|
|
|
describe("Dry Run", () => {
|
|
it("should call handleResponse with isPreview:true", async () => {
|
|
vi.mocked(PrismaRoutingFormRepository.findFormByIdIncludeUserTeamAndOrg).mockResolvedValue(
|
|
mockForm as never
|
|
);
|
|
const redirectUrl = "test-user/30min";
|
|
const mockRoute = { id: "route1", action: { type: "eventTypeRedirectUrl", value: redirectUrl } };
|
|
vi.mocked(findMatchingRoute).mockReturnValue(mockRoute as never);
|
|
vi.mocked(getAbsoluteEventTypeRedirectUrlWithEmbedSupport).mockReturnValue(`/${redirectUrl}`);
|
|
|
|
const context = mockContext({ "cal.isBookingDryRun": "true" });
|
|
await getRoutedUrl(context);
|
|
|
|
expect(handleResponse).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
isPreview: true,
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("Fallback action", () => {
|
|
it("should use fallbackAction for external redirect when no team members found", async () => {
|
|
vi.mocked(PrismaRoutingFormRepository.findFormByIdIncludeUserTeamAndOrg).mockResolvedValue(
|
|
mockForm as never
|
|
);
|
|
const mainRedirectUrl = "test-user/30min";
|
|
const fallbackUrl = "https://example.com/fallback";
|
|
const mockRoute = {
|
|
id: "route1",
|
|
action: { type: "eventTypeRedirectUrl", value: mainRedirectUrl },
|
|
};
|
|
vi.mocked(findMatchingRoute).mockReturnValue(mockRoute as never);
|
|
vi.mocked(handleResponse).mockResolvedValue({
|
|
teamMembersMatchingAttributeLogic: [],
|
|
formResponse: { id: 1 },
|
|
queuedFormResponse: null,
|
|
attributeRoutingConfig: null,
|
|
timeTaken: {},
|
|
crmContactOwnerEmail: null,
|
|
crmContactOwnerRecordType: null,
|
|
crmAppSlug: null,
|
|
isPreview: false,
|
|
fallbackAction: { type: "externalRedirectUrl", value: fallbackUrl },
|
|
});
|
|
|
|
const context = mockContext({ email: "test@cal.com" });
|
|
const result = await getRoutedUrl(context);
|
|
|
|
expect(result).toEqual({
|
|
redirect: {
|
|
destination: expect.stringContaining(fallbackUrl),
|
|
permanent: false,
|
|
},
|
|
});
|
|
});
|
|
|
|
it("should use fallbackAction for custom page message when no team members found", async () => {
|
|
vi.mocked(PrismaRoutingFormRepository.findFormByIdIncludeUserTeamAndOrg).mockResolvedValue(
|
|
mockForm as never
|
|
);
|
|
const mainRedirectUrl = "test-user/30min";
|
|
const customMessage = "No team members available";
|
|
const mockRoute = {
|
|
id: "route1",
|
|
action: { type: "eventTypeRedirectUrl", value: mainRedirectUrl },
|
|
};
|
|
vi.mocked(findMatchingRoute).mockReturnValue(mockRoute as never);
|
|
vi.mocked(handleResponse).mockResolvedValue({
|
|
teamMembersMatchingAttributeLogic: [],
|
|
formResponse: { id: 1 },
|
|
queuedFormResponse: null,
|
|
attributeRoutingConfig: null,
|
|
timeTaken: {},
|
|
crmContactOwnerEmail: null,
|
|
crmContactOwnerRecordType: null,
|
|
crmAppSlug: null,
|
|
isPreview: false,
|
|
fallbackAction: { type: "customPageMessage", value: customMessage },
|
|
});
|
|
|
|
const context = mockContext({ email: "test@cal.com" });
|
|
const result = await getRoutedUrl(context);
|
|
|
|
expect(result).toEqual({
|
|
props: {
|
|
isEmbed: false,
|
|
form: mockSerializableForm,
|
|
message: customMessage,
|
|
errorMessage: null,
|
|
},
|
|
});
|
|
});
|
|
|
|
it("should use main action when fallbackAction is null", async () => {
|
|
vi.mocked(PrismaRoutingFormRepository.findFormByIdIncludeUserTeamAndOrg).mockResolvedValue(
|
|
mockForm as never
|
|
);
|
|
const redirectUrl = "test-user/30min";
|
|
const mockRoute = { id: "route1", action: { type: "eventTypeRedirectUrl", value: redirectUrl } };
|
|
vi.mocked(findMatchingRoute).mockReturnValue(mockRoute as never);
|
|
vi.mocked(getAbsoluteEventTypeRedirectUrlWithEmbedSupport).mockReturnValue(`/${redirectUrl}`);
|
|
vi.mocked(handleResponse).mockResolvedValue({
|
|
teamMembersMatchingAttributeLogic: [123],
|
|
formResponse: { id: 1 },
|
|
queuedFormResponse: null,
|
|
attributeRoutingConfig: null,
|
|
timeTaken: {},
|
|
crmContactOwnerEmail: null,
|
|
crmContactOwnerRecordType: null,
|
|
crmAppSlug: null,
|
|
isPreview: false,
|
|
fallbackAction: null,
|
|
});
|
|
|
|
const context = mockContext({ email: "test@cal.com" });
|
|
const result = await getRoutedUrl(context);
|
|
|
|
expect(result).toEqual({
|
|
redirect: {
|
|
destination: `/${redirectUrl}`,
|
|
permanent: false,
|
|
},
|
|
});
|
|
});
|
|
|
|
it("should use fallbackAction for event type redirect when no team members found", async () => {
|
|
vi.mocked(PrismaRoutingFormRepository.findFormByIdIncludeUserTeamAndOrg).mockResolvedValue(
|
|
mockForm as never
|
|
);
|
|
const mainRedirectUrl = "test-user/30min";
|
|
const fallbackRedirectUrl = "test-user/60min";
|
|
const mockRoute = {
|
|
id: "route1",
|
|
action: { type: "eventTypeRedirectUrl", value: mainRedirectUrl },
|
|
};
|
|
vi.mocked(findMatchingRoute).mockReturnValue(mockRoute as never);
|
|
vi.mocked(substituteVariables).mockReturnValue(fallbackRedirectUrl);
|
|
vi.mocked(getAbsoluteEventTypeRedirectUrlWithEmbedSupport).mockReturnValue(`/${fallbackRedirectUrl}`);
|
|
vi.mocked(handleResponse).mockResolvedValue({
|
|
teamMembersMatchingAttributeLogic: [],
|
|
formResponse: { id: 1 },
|
|
queuedFormResponse: null,
|
|
attributeRoutingConfig: null,
|
|
timeTaken: {},
|
|
crmContactOwnerEmail: null,
|
|
crmContactOwnerRecordType: null,
|
|
crmAppSlug: null,
|
|
isPreview: false,
|
|
fallbackAction: { type: "eventTypeRedirectUrl", value: fallbackRedirectUrl },
|
|
});
|
|
|
|
const context = mockContext({ email: "test@cal.com" });
|
|
const result = await getRoutedUrl(context);
|
|
|
|
expect(substituteVariables).toHaveBeenCalledWith(
|
|
fallbackRedirectUrl,
|
|
{ email: "test@cal.com" },
|
|
mockSerializableForm.fields
|
|
);
|
|
expect(result).toEqual({
|
|
redirect: {
|
|
destination: `/${fallbackRedirectUrl}`,
|
|
permanent: false,
|
|
},
|
|
});
|
|
});
|
|
});
|
|
});
|