Files
calendar/packages/features/tasker/tasks/triggerFormSubmittedNoEvent/triggerFormSubmittedNoEventWorkflow.test.ts
T
+1
Carina WollendorferGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>amit@cal.com <samit91848@gmail.com>CarinaWolliAmit Sharmacoderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>Udit TakkarBenny Joocal.comMorgan
e5f14c9316 feat: form submitted no event booked workflow trigger #2 (#23716)
* refactor: improve _scheduleWorkflowReminders readability and add missing booking trigger events

- Extract complex conditional logic into helper functions (isImmediateTrigger, isTimeBased, shouldProcessWorkflow)
- Add missing workflow trigger events with immediate execution logic
- Update test workflows to use different actions (EMAIL_ATTENDEE, SMS_ATTENDEE) for better differentiation
- Fix translation function mock in confirm.handler.test.ts using mockNoTranslations utility
- Maintain existing functionality while improving code maintainability

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* only show customt emplate for form triggers

* filter outside scheduleWorkflowReminder

* fix type check

* chore: add more tests

* test: add comprehensive unit tests for handleMarkNoShow with webhook and workflow coverage

- Create handleMarkNoShow.test.ts following confirm.handler.test.ts pattern
- Add expectBookingNoShowUpdatedWebhookToHaveBeenFired utility function
- Test both webhook and workflow triggers for BOOKING_NO_SHOW_UPDATED
- Cover attendee/host no-show scenarios, multiple attendees, and error cases
- All 6 unit tests pass with proper mocking of external dependencies

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* Revert "test: add comprehensive unit tests for handleMarkNoShow with webhook and workflow coverage"

This reverts commit 764299220279f0c012392dec24d3150246bfc4ad.

* fix: add new workflow triggers to api/v2

* update swagger docs

* fix: e2e

* fix type check

* fix tests, add test for before after events

* fix unit tests

* revert confirm.handler.test

* fix: unit tests

* dummy form variables

* add routing forms to active on dropdown

* add migration file

* Ui fixes for variables dropdown

* remove other translation keys

* review fixes

* allow routing forms for activeOn

* use repository function to get routing forms

* remove unnecessary code

* adjust logic in update handler

* add triggers to api v2

* remvoe unused file

* rename to getAcitveOnOptions handler

* remove routingFormOptions handler

* clean up getActiveOnOptions

* refactor WorkflowService

* remove logs

* remove unused

* fix: type check

* fix: missed before after events for recurring

* fix: calendarEvent handleMarkNoShow

* fix error message

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* don't query disabled routing forms

* create tasker function

* add tasker code

* move isFormTrigger function

* small adjustments + todo comments

* remove email to host action for form triggers

* throw trpc error if email to host is added as step

* fix dialog on how to use form responses as variables

* remove add variable dropdown for form triggers

* remove form workfows in event workflows tab

* improvements for workflow logic on form submission

* review fixes

* base setup for seperate schedule functions (evt and form)

* add missing BOOKING_PAID workflow trigger

* fix pathname

* fix: test for BOOKING_REQUESTED

* fix activeOn ids

* pass hideBranding and smsReminderNumber

* adjustments to reminderScheduler

* create empty scheduelForForm functions

* pass locale and timezone with form user

* pass formData instead of responses

* pass timeFormat and locale

* reusable function for email sending and reminder creation

* implement scheduleEmailReminderForForm

* remove added editor field from merge conflict

* don't support cal.ai action with form triggers

* throw bad request if form trigger and cal.ai is combined

* add tests for scheduleFormWorkflows

* add form submission tests

* remove form response varibe info

* clean up workflow actions

* fixes for getting template options

* pass triggerType to getAllWorkflows

* move reusable logic to scheduleSMSReminder

* add formdata to param type

* type fixes for text reminder managers

* implement scheduleSMSReminderForForm

* fix import

* fix isAuthorizedToAddActiveOnIds

* disble whatsapp action

* implement triggerFormSubmittedNoEventWorkflow

* code clean up

* Merge branch 'devin/1755107037-add-workflow-triggers' into feat/routing-form-workflow-triggers

* fix type errors

* remove async from getSubmitterEmail

* fix type errors

* revert cal.ai changes

* fix type error

* add sublogger

* code clean up

* fix type errors

* remove label for attendee whatsapp action

* code clean up

* fixes saving teams on org workflows

* fix type error

* code improvements for activeOn ids

* Revert "code improvements for activeOn ids"

This reverts commit 0a3590a4e2ce541b17d63483ad86ed458795a6a3.

* improve variable name

* fix unit tests

* small fixes

* type fixes

* remove unused translation keys

* fix merge conflict issues

* code clean up

* remove SMS action support

* remove more SMS code

* add missing imports

* set custom template for form action

* type fixes

* fix tasker endpoint

* fix duplicate check

* fix workfows.test.ts

* use repository funciton to getHideBranding

* code clean up

* fix hasDuplicateSubmission

* code clean up

* select only needed properties

* remove repository functions

* Revert "remove repository functions"

This reverts commit 7aa47b1c59c9abd7f964ebf26f746934c53a44f4.

* add scheduleWorkflows function

* Revert "add scheduleWorkflows function"

This reverts commit fe5db4fe3b65e2743c95475d585300cab98beed7.

* move type to /types

* Revert "move type to /types"

This reverts commit 91e0152154594b3772a801a426260068a8ccea54.

* revert changes causing type errors

* remove import

* remove unused import

* Revert "remove unused import"

This reverts commit 1916768c875ea5d0ac5598ccb8f9c796c5622dc9.

* revert changed from attempt to fix type errors

* pass object to gt all workflows

* fix isAuthorized check

* trigger filtering

* remove form submitted no event booked code

* remove form submitted no event from schema

* remove more code

* remove test

* fixes

* add getSubmitterEmail function

* add trigger

* small fixes

* add missing workflow DTOs

* small fixes

* use activeOnWithChildren

* fix active on when switching trigger type

* remove add variable dropdown

* add getAllWorkflowsFromRoutingForm to WorkflowService

* fix error caused by undefined evt

* fix type error

* fix type error

* fix tests

* code clean up

* final fixes and clean up

* remove console.log

* remove template text form from triggers

* add routing form repoditory function

* fix bug with key

* fix test

* add missing trigger in update-workflow.input.ts

* ForEvt and ForForm function for aiPhoneCallManager

* chore: add support for form workflows on api v2

* fixup! chore: add support for form workflows on api v2

* use only repository functions in update handler

* move all prisma queries from list.handler

* review suggestions

* chore: handle workflows api v2

* chore: handle workflows api v2, split in 2 endpoints

* fix workflow step creation

* remove connect agent and fixes types

* add type to workflow

* chore: use workflow type in apiv2 WorkflowsOutputService

* update worklfow type on update

* chore: use workflow type in apiv2 WorkflowsOutputService

* fix template body for torm trigger

* some UI fixes for email subject/body

* resetting email body when changing form triggers

* use type field to query workflows

* clean up all old active on values

* remove responseId from all funciton calls

* remove undefined from updateTemplate

* refactor: split routing form and event-type workflows code

* refactor: split routing form and event-type workflows code

* fix template  text when adding action

* chore: don't rename WorkflowActivationDto to avoid ci blocking

* refine update schedule to use only allowed actions

* fix type error

* don't allow whatsapp action with form trigger

* fix type error

* return early if activeOn array is empty

* fix: from step type in BaseFormWorkflowStepDto

* fixup! fix: from step type in BaseFormWorkflowStepDto

* api v2 updates

* move all prisma calls to repository (service/workflows.ts)

* use FORM_TRIGGER_WORKFLOW_EVENTS for form queries

* use userRepository

* use FORM_TRIGGER_WORKFLOW_EVENTS in isFormTrigger

* code clean up

* code clean up

* use repository functions in formSubmissionValidation.ts

* add back trpc  import

* fix agent repository functions

* remove unsued import

* fixes for offset api v2

* add missing responseId

* fix failing test

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: amit@cal.com <samit91848@gmail.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Amit Sharma <74371312+Amit91848@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Benny Joo <sldisek783@gmail.com>
Co-authored-by: cal.com <morgan@cal.com>
Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
2025-10-13 16:13:56 +00:00

178 lines
5.6 KiB
TypeScript

import prismaMock from "../../../../../tests/libs/__mocks__/prismaMock";
import { describe, expect, it, beforeEach, vi } from "vitest";
import type { z } from "zod";
import { scheduleWorkflowReminders } from "@calcom/ee/workflows/lib/reminders/reminderScheduler";
import type { ZTriggerFormSubmittedNoEventWorkflowPayloadSchema } from "@calcom/features/tasker/tasks/triggerFormSubmittedNoEvent/triggerFormSubmittedNoEventWorkflow";
import { triggerFormSubmittedNoEventWorkflow } from "@calcom/features/tasker/tasks/triggerFormSubmittedNoEvent/triggerFormSubmittedNoEventWorkflow";
import { WorkflowTriggerEvents, WorkflowActions, WorkflowTemplates, TimeUnit } from "@calcom/prisma/enums";
import { shouldTriggerFormSubmittedNoEvent } from "./formSubmissionValidation";
// Mock the scheduleWorkflowReminders function
vi.mock("@calcom/ee/workflows/lib/reminders/reminderScheduler", () => ({
scheduleWorkflowReminders: vi.fn(() => Promise.resolve()),
}));
// Mock the form submission validation
vi.mock("./formSubmissionValidation", () => ({
shouldTriggerFormSubmittedNoEvent: vi.fn(() => Promise.resolve(true)),
}));
// Mock the logger
vi.mock("@calcom/lib/logger", () => ({
default: {
getSubLogger: vi.fn(() => ({ error: vi.fn() })),
error: vi.fn(),
},
}));
const mockScheduleWorkflowReminders = vi.mocked(scheduleWorkflowReminders);
const mockShouldTriggerFormSubmittedNoEvent = vi.mocked(shouldTriggerFormSubmittedNoEvent);
type WorkflowPayload = z.infer<typeof ZTriggerFormSubmittedNoEventWorkflowPayloadSchema>;
function expectFormSubmittedNoEventWorkflowToBeCalled(payload: WorkflowPayload) {
expect(mockScheduleWorkflowReminders).toHaveBeenCalledWith(
expect.objectContaining({
workflows: [payload.workflow],
formData: {
responses: payload.responses,
user: {
email: payload.form.user.email,
timeFormat: payload.form.user.timeFormat,
locale: payload.form.user.locale ?? "en",
},
},
hideBranding: payload.hideBranding,
smsReminderNumber: payload.smsReminderNumber,
})
);
}
describe("Form submitted, no event booked workflow trigger", () => {
beforeEach(() => {
vi.clearAllMocks();
// Mock the form response queries to return empty arrays by default
prismaMock.app_RoutingForms_FormResponse.findMany.mockResolvedValue([]);
});
it(`should trigger workflow when form was submitted but no booking was made`, async () => {
const payload: WorkflowPayload = {
responseId: 1,
form: {
id: "1234",
userId: 1,
teamId: null,
fields: [{ type: "text", identifier: "Test field 1" }],
user: {
email: "test@example.com",
timeFormat: 12,
locale: "en",
},
},
responses: {
"Test field 1": {
value: "Test input 1",
response: "Test input 1",
},
},
hideBranding: false,
smsReminderNumber: null,
submittedAt: new Date("2024-01-01T10:00:00Z"),
workflow: {
id: 1,
name: "Test Workflow 1",
teamId: null,
trigger: WorkflowTriggerEvents.FORM_SUBMITTED_NO_EVENT,
time: 15,
timeUnit: TimeUnit.MINUTE,
userId: 1,
steps: [
{
id: 1,
action: WorkflowActions.EMAIL_ATTENDEE,
sendTo: null,
template: WorkflowTemplates.CUSTOM,
reminderBody: "Follow up on your form submission",
emailSubject: "Follow Up",
sender: null,
includeCalendarEvent: false,
numberVerificationPending: false,
numberRequired: false,
verifiedAt: null,
},
],
},
};
const payloadString = JSON.stringify(payload);
// Mock that no booking exists
prismaMock.booking.findFirst.mockResolvedValue(null);
await triggerFormSubmittedNoEventWorkflow(payloadString);
expectFormSubmittedNoEventWorkflowToBeCalled(payload);
});
it(`should not trigger workflow when form was submitted and also booking was made after`, async () => {
const payload: WorkflowPayload = {
responseId: 2,
form: {
id: "6789",
userId: 2,
teamId: null,
fields: [{ type: "text", identifier: "Test field 2" }],
user: {
email: "test2@example.com",
timeFormat: 24,
locale: "en",
},
},
responses: {
"Test field 2": {
value: "Test input 2",
response: "Test input 2",
},
},
hideBranding: false,
smsReminderNumber: null,
submittedAt: new Date("2024-01-01T11:00:00Z"),
workflow: {
id: 2,
name: "Test Workflow 2",
teamId: null,
trigger: WorkflowTriggerEvents.FORM_SUBMITTED_NO_EVENT,
time: 30,
timeUnit: TimeUnit.MINUTE,
userId: 2,
steps: [
{
id: 2,
action: WorkflowActions.SMS_ATTENDEE,
sendTo: null,
template: WorkflowTemplates.CUSTOM,
reminderBody: "SMS follow up",
emailSubject: null,
sender: null,
includeCalendarEvent: false,
numberVerificationPending: false,
numberRequired: false,
verifiedAt: null,
},
],
},
};
const payloadString = JSON.stringify(payload);
// Mock that validation should not trigger (booking exists)
mockShouldTriggerFormSubmittedNoEvent.mockResolvedValue(false);
await triggerFormSubmittedNoEventWorkflow(payloadString);
// Should not call scheduleWorkflowReminders when validation fails
expect(mockScheduleWorkflowReminders).not.toHaveBeenCalled();
});
});