* refactor: apply biome formatting to packages/features (batch 1 - small subdirs) Format small subdirectories in packages/features: di, flags, holidays, oauth, settings, users, assignment-reason, selectedCalendar, hashedLink, host, form, form-builder, availability, data-table, pbac, schedules, troubleshooter, eventtypes, calendar-subscription, and root-level files. Also includes straggler apps/web BookEventForm.tsx. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: apply biome formatting to packages/features (batch 2 - medium subdirs) Format medium subdirectories in packages/features: auth, credentials, calendars, routing-forms, routing-trace, attributes, watchlist, calAIPhone, tasker, and webhooks. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: apply biome formatting to packages/features (batch 3 - bookings + insights) Format bookings and insights subdirectories in packages/features. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: apply biome formatting to packages/features (batch 4 - ee) Format packages/features/ee subdirectory covering billing, workflows, organizations, teams, managed-event-types, round-robin, dsync, integration-attribute-sync, and payments. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: apply biome formatting to packages/features (batch 5 - booking-audit part 1) Format booking-audit di, actions, common, dto, repository, and types subdirectories in packages/features/booking-audit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: apply biome formatting to packages/features (batch 6 - booking-audit part 2) Format booking-audit service subdirectory in packages/features/booking-audit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
295 lines
7.7 KiB
TypeScript
295 lines
7.7 KiB
TypeScript
/**
|
|
* @vitest-environment jsdom
|
|
*/
|
|
import { cleanup, renderHook, waitFor } from "@testing-library/react";
|
|
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
|
|
import type { BookerEvent } from "@calcom/features/bookings/types";
|
|
|
|
import { useInitialFormValues } from "./useInitialFormValues";
|
|
|
|
vi.mock("@calcom/features/bookings/Booker/store", () => ({
|
|
useBookerStore: vi.fn((selector) => {
|
|
const state = {
|
|
bookingData: null,
|
|
formValues: {},
|
|
};
|
|
return selector(state);
|
|
}),
|
|
}));
|
|
|
|
vi.mock("@calcom/features/bookings/lib/getBookingResponsesSchema", () => ({
|
|
getBookingResponsesPartialSchema: vi.fn(() => ({
|
|
parseAsync: vi.fn((data) => Promise.resolve(data)),
|
|
})),
|
|
}));
|
|
|
|
describe("useInitialFormValues - Autofill Disable Feature", () => {
|
|
const mockBookingFields = [
|
|
{ name: "name", type: "text" as const, required: true },
|
|
{ name: "email", type: "email" as const, required: true },
|
|
{ name: "phone", type: "phone" as const, required: false },
|
|
] as unknown as BookerEvent["bookingFields"];
|
|
|
|
const baseProps = {
|
|
rescheduleUid: null,
|
|
isRescheduling: false,
|
|
email: null,
|
|
name: null,
|
|
username: null,
|
|
hasSession: false,
|
|
extraOptions: {},
|
|
prefillFormParams: {
|
|
guests: [],
|
|
name: null,
|
|
},
|
|
};
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
afterEach(() => {
|
|
cleanup();
|
|
});
|
|
|
|
describe("when organization has NOT disabled autofill", () => {
|
|
it("should use URL parameters to prefill form fields", async () => {
|
|
const eventType: Pick<BookerEvent, "bookingFields" | "team" | "owner"> = {
|
|
bookingFields: mockBookingFields,
|
|
team: {
|
|
organizationSettings: {
|
|
disableAutofillOnBookingPage: false,
|
|
},
|
|
},
|
|
owner: null,
|
|
};
|
|
|
|
const extraOptions = {
|
|
phone: "+1234567890",
|
|
customField: "custom value",
|
|
};
|
|
|
|
const prefillFormParams = {
|
|
guests: ["guest1@example.com", "guest2@example.com"],
|
|
name: "John Doe",
|
|
};
|
|
|
|
const { result } = renderHook(() =>
|
|
useInitialFormValues({
|
|
...baseProps,
|
|
eventType,
|
|
extraOptions,
|
|
prefillFormParams,
|
|
})
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.values.responses).toBeDefined();
|
|
});
|
|
|
|
expect(result.current.values.responses).toMatchObject({
|
|
name: "John Doe",
|
|
phone: "+1234567890",
|
|
});
|
|
});
|
|
|
|
it("should use URL parameters when organizationSettings is undefined", async () => {
|
|
const eventType: Pick<BookerEvent, "bookingFields" | "team" | "owner"> = {
|
|
bookingFields: mockBookingFields,
|
|
team: null,
|
|
owner: null,
|
|
};
|
|
|
|
const extraOptions = {
|
|
phone: "+1234567890",
|
|
};
|
|
|
|
const prefillFormParams = {
|
|
guests: [],
|
|
name: "Jane Smith",
|
|
};
|
|
|
|
const { result } = renderHook(() =>
|
|
useInitialFormValues({
|
|
...baseProps,
|
|
eventType,
|
|
extraOptions,
|
|
prefillFormParams,
|
|
})
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.values.responses).toBeDefined();
|
|
});
|
|
|
|
expect(result.current.values.responses).toMatchObject({
|
|
name: "Jane Smith",
|
|
phone: "+1234567890",
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("when organization HAS disabled autofill", () => {
|
|
it("should NOT use URL parameters when team.organizationSettings.disableAutofillOnBookingPage is true", async () => {
|
|
const eventType: Pick<BookerEvent, "bookingFields" | "team" | "owner"> = {
|
|
bookingFields: mockBookingFields,
|
|
team: {
|
|
parent: {
|
|
organizationSettings: {
|
|
disableAutofillOnBookingPage: true,
|
|
},
|
|
},
|
|
},
|
|
owner: null,
|
|
};
|
|
|
|
const extraOptions = {
|
|
phone: "+1234567890",
|
|
customField: "custom value",
|
|
};
|
|
|
|
const prefillFormParams = {
|
|
guests: ["guest1@example.com"],
|
|
name: "John Doe",
|
|
};
|
|
|
|
const { result } = renderHook(() =>
|
|
useInitialFormValues({
|
|
...baseProps,
|
|
eventType,
|
|
extraOptions,
|
|
prefillFormParams,
|
|
})
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.values.responses).toBeDefined();
|
|
});
|
|
|
|
expect(result.current.values.responses?.phone).toBeUndefined();
|
|
expect(result.current.values.responses?.name).toBe("");
|
|
});
|
|
|
|
it("should NOT use URL parameters when team.parent.organizationSettings.disableAutofillOnBookingPage is true", async () => {
|
|
const eventType: Pick<BookerEvent, "bookingFields" | "team" | "owner"> = {
|
|
bookingFields: mockBookingFields,
|
|
team: {
|
|
organizationSettings: null,
|
|
parent: {
|
|
organizationSettings: {
|
|
disableAutofillOnBookingPage: true,
|
|
},
|
|
},
|
|
},
|
|
owner: null,
|
|
};
|
|
|
|
const extraOptions = {
|
|
phone: "+9876543210",
|
|
};
|
|
|
|
const prefillFormParams = {
|
|
guests: [],
|
|
name: "Parent Team User",
|
|
};
|
|
|
|
const { result } = renderHook(() =>
|
|
useInitialFormValues({
|
|
...baseProps,
|
|
eventType,
|
|
extraOptions,
|
|
prefillFormParams,
|
|
})
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.values.responses).toBeDefined();
|
|
});
|
|
|
|
expect(result.current.values.responses?.phone).toBeUndefined();
|
|
expect(result.current.values.responses?.name).toBe("");
|
|
});
|
|
|
|
it("should NOT use URL parameters when owner.organization.organizationSettings.disableAutofillOnBookingPage is true", async () => {
|
|
const eventType: Pick<BookerEvent, "bookingFields" | "team" | "owner"> = {
|
|
bookingFields: mockBookingFields,
|
|
team: null,
|
|
owner: {
|
|
profile: {
|
|
organization: {
|
|
organizationSettings: {
|
|
disableAutofillOnBookingPage: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
const extraOptions = {
|
|
phone: "+5555555555",
|
|
};
|
|
|
|
const prefillFormParams = {
|
|
guests: [],
|
|
name: "Personal Event User",
|
|
};
|
|
|
|
const { result } = renderHook(() =>
|
|
useInitialFormValues({
|
|
...baseProps,
|
|
eventType,
|
|
extraOptions,
|
|
prefillFormParams,
|
|
})
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.values.responses).toBeDefined();
|
|
});
|
|
|
|
expect(result.current.values.responses?.phone).toBeUndefined();
|
|
expect(result.current.values.responses?.name).toBe("");
|
|
});
|
|
});
|
|
|
|
describe("session data handling with autofill disabled", () => {
|
|
it("should not use session email/name when autofill is disabled", async () => {
|
|
const eventType: Pick<BookerEvent, "bookingFields" | "team" | "owner"> = {
|
|
bookingFields: mockBookingFields,
|
|
team: {
|
|
parent: {
|
|
organizationSettings: {
|
|
disableAutofillOnBookingPage: true,
|
|
},
|
|
},
|
|
},
|
|
owner: null,
|
|
};
|
|
|
|
const extraOptions = {
|
|
phone: "+1234567890", // This should be blocked
|
|
};
|
|
|
|
const { result } = renderHook(() =>
|
|
useInitialFormValues({
|
|
...baseProps,
|
|
eventType,
|
|
extraOptions,
|
|
email: "session@example.com", // Session data
|
|
name: "Session User", // Session data
|
|
hasSession: true,
|
|
})
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.values.responses).toBeDefined();
|
|
});
|
|
|
|
expect(result.current.values.responses?.email).toBe("");
|
|
expect(result.current.values.responses?.name).toBe("");
|
|
expect(result.current.values.responses?.phone).toBeUndefined();
|
|
});
|
|
});
|
|
});
|