Files
calendar/packages/app-store/routing-forms/lib/formSubmissionUtils.test.ts
T
Benny JooandGitHub e91bf53d80 refactor: Remove circular deps between @calcom/lib and @calcom/features [2] (#24438)
* move SystemField to features

* migrate workflow service

* merge two tests for team repository

* update imports and migrate team repository

* migrate delegation credential repository

* migrate credential repository

* migrate entityPermissionUtils

* migrate hashedLink service and repository

* migrate membership service

* update imports

* remove file

* migrate buildEventUrlFromBooking

* migrate getAllUserBookings to features

* update imports

* update organizationMock

* migrate slots

* migrate date-ranges to schedules dir

* migrate getAggregatedAvailability

* fix

* refactor

* migrate useCreateEventType hook to features

* migrate assignValueToUser

* migrate validateUsername to auth features

* migrate system field back to lib

* migrate getLabelValueMapFromResponses back to lib

* update imports

* use relative path

* fix type checks

* fix

* fix

* fix tests

* update gh codeowners

* fix

* fix
2025-10-17 06:48:08 -03:00

256 lines
7.9 KiB
TypeScript

import "@calcom/lib/__mocks__/logger";
import { prisma } from "@calcom/prisma/__mocks__/prisma";
import { describe, it, vi, expect, beforeEach, afterEach } from "vitest";
import { WorkflowService } from "@calcom/features/ee/workflows/lib/service/WorkflowService";
import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks";
import { sendGenericWebhookPayload } from "@calcom/features/webhooks/lib/sendPayload";
import {
WebhookTriggerEvents,
WorkflowTriggerEvents,
WorkflowActions,
WorkflowTemplates,
} from "@calcom/prisma/enums";
import { _onFormSubmission } from "./formSubmissionUtils";
vi.mock("@calcom/prisma", () => ({
prisma,
}));
// Mock dependencies
vi.mock("@calcom/lib/getOrgIdFromMemberOrTeamId", () => ({
default: vi.fn(() => Promise.resolve(1)),
}));
vi.mock("@calcom/features/webhooks/lib/getWebhooks", () => ({
default: vi.fn(() => Promise.resolve([])),
}));
vi.mock("@calcom/features/webhooks/lib/sendPayload", () => ({
sendGenericWebhookPayload: vi.fn(() => Promise.resolve()),
}));
vi.mock("@calcom/features/tasker", () => {
const tasker = {
create: vi.fn(() => Promise.resolve()),
};
return { default: Promise.resolve(tasker) };
});
// Mock workflow dependencies
vi.mock("@calcom/features/ee/workflows/lib/service/WorkflowService", () => ({
WorkflowService: {
getAllWorkflowsFromRoutingForm: vi.fn(() => Promise.resolve([])),
scheduleFormWorkflows: vi.fn(() => Promise.resolve()),
},
}));
const mockSendEmail = vi.fn(() => Promise.resolve());
const mockResponseEmailConstructor = vi.fn();
vi.mock("../emails/templates/response-email", () => ({
default: class MockResponseEmail {
sendEmail = mockSendEmail;
constructor(...args: unknown[]) {
mockResponseEmailConstructor(...args);
}
},
}));
describe("_onFormSubmission", () => {
const mockForm = {
id: "form-1",
name: "Test Form",
fields: [
{ id: "field-1", identifier: "email", label: "Email", type: "email" },
{ id: "field-2", identifier: "name", label: "Name", type: "text" },
],
user: { id: 1, email: "test@example.com", timeFormat: 12, locale: "en" },
teamId: null,
settings: { emailOwnerOnSubmission: true },
};
const mockResponse = {
"field-1": { label: "Email", value: "test@response.com" },
"field-2": { label: "Name", value: "Test Name" },
};
const responseId = 123;
beforeEach(() => {
vi.clearAllMocks();
});
afterEach(() => {
vi.restoreAllMocks();
});
describe("Webhooks", () => {
it("should call FORM_SUBMITTED webhooks", async () => {
vi.mocked(getWebhooks).mockResolvedValueOnce([{ id: "wh-1", secret: "secret" } as any]);
await _onFormSubmission(mockForm as any, mockResponse, responseId);
expect(getWebhooks).toHaveBeenCalledWith({
userId: 1,
teamId: null,
orgId: 1,
triggerEvent: WebhookTriggerEvents.FORM_SUBMITTED,
});
expect(sendGenericWebhookPayload).toHaveBeenCalledTimes(1);
});
});
describe("Workflows", () => {
it("should call WorkflowService.scheduleFormWorkflows for FORM_SUBMITTED workflows", async () => {
const mockWorkflows = [
{
id: 1,
name: "Form Submitted Workflow",
userId: 1,
teamId: null,
trigger: WorkflowTriggerEvents.FORM_SUBMITTED,
time: null,
timeUnit: null,
steps: [
{
id: 1,
action: WorkflowActions.EMAIL_ATTENDEE,
sendTo: null,
reminderBody: "Thank you for your submission!",
emailSubject: "Form Received",
template: WorkflowTemplates.CUSTOM,
verifiedAt: new Date(),
includeCalendarEvent: false,
numberVerificationPending: false,
numberRequired: false,
},
],
},
];
vi.mocked(WorkflowService.getAllWorkflowsFromRoutingForm).mockResolvedValueOnce(mockWorkflows as any);
await _onFormSubmission(mockForm as any, mockResponse, responseId);
expect(WorkflowService.getAllWorkflowsFromRoutingForm).toHaveBeenCalledWith(mockForm);
expect(WorkflowService.scheduleFormWorkflows).toHaveBeenCalledWith({
workflows: mockWorkflows,
responses: {
email: {
value: "test@response.com",
response: "test@response.com",
},
name: { value: "Test Name", response: "Test Name" },
},
responseId,
form: {
...mockForm,
fields: mockForm.fields.map((field) => ({
type: field.type,
identifier: field.identifier,
})),
},
});
});
it("should call WorkflowService.scheduleFormWorkflows for FORM_SUBMITTED_NO_EVENT workflows", async () => {
const mockWorkflows = [
{
id: 2,
name: "Form Follow-up Workflow",
userId: 1,
teamId: null,
trigger: WorkflowTriggerEvents.FORM_SUBMITTED_NO_EVENT,
time: 30,
timeUnit: "MINUTE",
steps: [
{
id: 2,
action: WorkflowActions.EMAIL_ATTENDEE,
sendTo: null,
reminderBody: "Follow up on your form submission",
emailSubject: "Follow Up",
template: WorkflowTemplates.CUSTOM,
verifiedAt: new Date(),
includeCalendarEvent: false,
numberVerificationPending: false,
numberRequired: false,
},
],
},
];
vi.mocked(WorkflowService.getAllWorkflowsFromRoutingForm).mockResolvedValueOnce(mockWorkflows as any);
await _onFormSubmission(mockForm as any, mockResponse, responseId);
expect(WorkflowService.getAllWorkflowsFromRoutingForm).toHaveBeenCalledWith(mockForm);
expect(WorkflowService.scheduleFormWorkflows).toHaveBeenCalledWith({
workflows: mockWorkflows,
responses: {
email: {
value: "test@response.com",
response: "test@response.com",
},
name: { value: "Test Name", response: "Test Name" },
},
responseId,
form: {
...mockForm,
fields: mockForm.fields.map((field) => ({
type: field.type,
identifier: field.identifier,
})),
},
});
});
});
describe("Response Email", () => {
it("should send response email to team members for a team form", async () => {
const teamForm = {
...mockForm,
teamId: 1,
userWithEmails: ["team-member1@example.com", "team-member2@example.com"],
user: { id: 1, email: "test@example.com", timeFormat: 12, locale: "en" },
};
await _onFormSubmission(teamForm as any, mockResponse, responseId);
expect(mockResponseEmailConstructor).toHaveBeenCalledWith({
form: teamForm,
toAddresses: ["team-member1@example.com", "team-member2@example.com"],
orderedResponses: [mockResponse["field-1"], mockResponse["field-2"]],
});
expect(mockSendEmail).toHaveBeenCalled();
});
it("should send response email to owner when enabled", async () => {
const ownerForm = {
...mockForm,
settings: { emailOwnerOnSubmission: true },
};
await _onFormSubmission(ownerForm as any, mockResponse, responseId);
expect(mockResponseEmailConstructor).toHaveBeenCalledWith({
form: ownerForm,
toAddresses: [ownerForm.user.email],
orderedResponses: [mockResponse["field-1"], mockResponse["field-2"]],
});
expect(mockSendEmail).toHaveBeenCalled();
});
it("should not send response email to owner when disabled", async () => {
const ownerForm = {
...mockForm,
settings: { emailOwnerOnSubmission: false },
};
await _onFormSubmission(ownerForm as any, mockResponse, responseId);
expect(mockResponseEmailConstructor).not.toHaveBeenCalled();
expect(mockSendEmail).not.toHaveBeenCalled();
});
});
});