diff --git a/packages/app-store/routing-forms/lib/formSubmissionUtils.test.ts b/packages/app-store/routing-forms/lib/formSubmissionUtils.test.ts index 6e34ae3e92..a8adb058fc 100644 --- a/packages/app-store/routing-forms/lib/formSubmissionUtils.test.ts +++ b/packages/app-store/routing-forms/lib/formSubmissionUtils.test.ts @@ -122,6 +122,47 @@ describe("_onFormSubmission", () => { }); expect(sendGenericWebhookPayload).toHaveBeenCalledTimes(1); }); + + it("should normalize identifiers with spaces to hyphens in rootData for webhook templates", async () => { + const formWithSpaces = { + ...mockForm, + fields: [ + { + id: "field-1", + identifier: "attendee name", + label: "Attendee Name", + type: "text", + required: false, + }, + ] as Field[], + }; + + const responseWithSpaces: FormResponse = { + "field-1": { label: "Attendee Name", value: "John Doe" }, + }; + + const mockWebhook: GetWebhooksReturnType[number] = { + id: "wh-1", + secret: "secret", + subscriberUrl: "https://example.com/webhook", + payloadTemplate: null, + appId: null, + eventTriggers: [WebhookTriggerEvents.FORM_SUBMITTED], + time: null, + timeUnit: null, + }; + vi.mocked(getWebhooks).mockResolvedValueOnce([mockWebhook]); + + await _onFormSubmission(formWithSpaces, responseWithSpaces, responseId); + + expect(sendGenericWebhookPayload).toHaveBeenCalledWith( + expect.objectContaining({ + rootData: expect.objectContaining({ + "attendee-name": "John Doe", // Spaces replaced with hyphens for template access + }), + }) + ); + }); }); describe("Workflows", () => { diff --git a/packages/app-store/routing-forms/lib/formSubmissionUtils.ts b/packages/app-store/routing-forms/lib/formSubmissionUtils.ts index 98f02306fc..31b8a77de2 100644 --- a/packages/app-store/routing-forms/lib/formSubmissionUtils.ts +++ b/packages/app-store/routing-forms/lib/formSubmissionUtils.ts @@ -20,6 +20,15 @@ import getFieldIdentifier from "./getFieldIdentifier"; const moduleLogger = logger.getSubLogger({ prefix: ["routing-forms/lib/formSubmissionUtils"] }); +/** + * Normalizes an identifier for use in Handlebars templates by replacing spaces with hyphens. + * This allows webhook payload templates to use {{identifier-with-hyphens}} syntax + * even when the form field identifier contains spaces (e.g., "attendee name" → "attendee-name"). + */ +function normalizeIdentifierForHandlebars(identifier: string): string { + return identifier.replace(/\s+/g, "-"); +} + type SelectFieldWebhookResponse = string | number | string[] | { label: string; id: string | null }; export type FORM_SUBMITTED_WEBHOOK_RESPONSES = Record< string, @@ -184,7 +193,8 @@ export async function _onFormSubmission( rootData: { // Send responses unwrapped at root level for backwards compatibility ...Object.entries(fieldResponsesByIdentifier).reduce((acc, [key, value]) => { - acc[key] = value.value; + const normalizedKey = normalizeIdentifierForHandlebars(key); + acc[normalizedKey] = value.value; return acc; }, {} as Record), },