## What does this PR do?
Fixes an issue where underscores in form field identifiers were being stripped when converting to workflow template variables. According to the documentation, users should be able to use variables like `{COMPANY_NAME}` or `{MONTHLY_INFRASTRUCTURE_SPEND}`, but the regex in `formatIdentifierToVariable` was removing underscores, causing these variables to not match.
**The problem:**
- Form field identifier: `Company_Name` or `Monthly_Infrastructure_Spend`
- Expected variable: `{COMPANY_NAME}` or `{MONTHLY_INFRASTRUCTURE_SPEND}`
- Actual variable (before fix): `{COMPANYNAME}` or `{MONTHLYINFRASTRUCTURESPEND}`
**The fix:**
- Updated the regex from `[^a-zA-Z0-9 ]` to `[^a-zA-Z0-9_ ]` to preserve underscores in `formatIdentifierToVariable`
- Added a private `formatIdentifierToVariableLegacy` function that maintains the old behavior (strips underscores)
- Added `getVariableFormats` helper that returns both current and legacy formats for backward compatibility
- Added `convertResponsesToVariableFormats` helper in `executeAIPhoneCall.ts` to convert form responses to both variable formats
- Updated `customTemplate.ts` matching logic to support both variable formats
- Updated `executeAIPhoneCall.ts` to include both variable formats when building dynamic variables
This ensures existing templates using `{COMPANYNAME}` continue to work while new templates can use the documented `{COMPANY_NAME}` format.
## Mandatory Tasks (DO NOT REMOVE)
- [x] I have self-reviewed the code (A decent size PR without self-review might be rejected).
- [x] I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. N/A - no docs changes needed.
- [x] I confirm automated tests are in place that prove my fix is effective or that my feature works.
## How should this be tested?
1. Create a routing form with a field identifier containing underscores (e.g., `Company_Name`)
2. Create a workflow with a template using `{COMPANY_NAME}` (with underscore)
3. Submit the form and verify the variable is replaced correctly
4. Also test with `{COMPANYNAME}` (without underscore) to verify backward compatibility
**Automated tests added:**
- `customTemplate.test.ts` - 15 tests covering `formatIdentifierToVariable`, `getVariableFormats`, and template variable replacement
- `executeAIPhoneCall.test.ts` - 6 tests covering `convertResponsesToVariableFormats` function for form responses
## Human Review Checklist
- [ ] Verify the regex change `[^a-zA-Z0-9_ ]` correctly preserves underscores
- [ ] Verify backward compatibility: both `{COMPANY_NAME}` and `{COMPANYNAME}` should work for the same form field
- [ ] Verify `convertResponsesToVariableFormats` correctly generates both variable formats
- [ ] Review test coverage for edge cases (empty responses, undefined values)
---
Link to Devin run: https://app.devin.ai/sessions/9d5d90178714493086d94691865c3e07
Requested by: @hariombalhara
<!-- devin-review-badge-begin -->
---
<a href="https://app.devin.ai/review/calcom/cal.com/pull/27571">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1">
<img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin">
</picture>
</a>
<!-- devin-review-badge-end -->
86 lines
2.8 KiB
TypeScript
86 lines
2.8 KiB
TypeScript
import { convertResponsesToVariableFormats } from "@calcom/features/tasker/tasks/executeAIPhoneCall";
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
describe("executeAIPhoneCall - convertResponsesToVariableFormats", () => {
|
|
it("should generate both variable formats for identifiers with underscores", () => {
|
|
const responses = {
|
|
Company_Name: { value: "Acme Corp" },
|
|
Monthly_Infrastructure_Spend: { value: "$5000" },
|
|
};
|
|
|
|
const variables = convertResponsesToVariableFormats(responses);
|
|
|
|
// Should have both underscore and non-underscore versions
|
|
expect(variables.COMPANY_NAME).toBe("Acme Corp");
|
|
expect(variables.COMPANYNAME).toBe("Acme Corp");
|
|
expect(variables.MONTHLY_INFRASTRUCTURE_SPEND).toBe("$5000");
|
|
expect(variables.MONTHLYINFRASTRUCTURESPEND).toBe("$5000");
|
|
});
|
|
|
|
it("should generate single format for identifiers without underscores", () => {
|
|
const responses = {
|
|
"Company Name": { value: "Acme Corp" },
|
|
Email: { value: "test@example.com" },
|
|
};
|
|
|
|
const variables = convertResponsesToVariableFormats(responses);
|
|
|
|
// Space-separated identifiers convert to underscore format
|
|
expect(variables.COMPANY_NAME).toBe("Acme Corp");
|
|
// Simple identifiers stay as-is
|
|
expect(variables.EMAIL).toBe("test@example.com");
|
|
});
|
|
|
|
it("should handle mixed identifiers correctly", () => {
|
|
const responses = {
|
|
Company_Name: { value: "Acme Corp" },
|
|
"Contact Email": { value: "contact@acme.com" },
|
|
Notes: { value: "Some notes" },
|
|
};
|
|
|
|
const variables = convertResponsesToVariableFormats(responses);
|
|
|
|
// Underscore identifier: both formats
|
|
expect(variables.COMPANY_NAME).toBe("Acme Corp");
|
|
expect(variables.COMPANYNAME).toBe("Acme Corp");
|
|
|
|
// Space identifier: single format (space becomes underscore)
|
|
expect(variables.CONTACT_EMAIL).toBe("contact@acme.com");
|
|
|
|
// Simple identifier: single format
|
|
expect(variables.NOTES).toBe("Some notes");
|
|
});
|
|
|
|
it("should preserve the same value for both variable formats", () => {
|
|
const testValue = "Test Value 123";
|
|
const responses = {
|
|
Test_Field: { value: testValue },
|
|
};
|
|
|
|
const variables = convertResponsesToVariableFormats(responses);
|
|
|
|
expect(variables.TEST_FIELD).toBe(testValue);
|
|
expect(variables.TESTFIELD).toBe(testValue);
|
|
expect(variables.TEST_FIELD).toBe(variables.TESTFIELD);
|
|
});
|
|
|
|
it("should handle empty responses", () => {
|
|
const responses = {};
|
|
|
|
const variables = convertResponsesToVariableFormats(responses);
|
|
|
|
expect(Object.keys(variables)).toHaveLength(0);
|
|
});
|
|
|
|
it("should handle undefined values", () => {
|
|
const responses = {
|
|
Field_Name: { value: undefined },
|
|
};
|
|
|
|
const variables = convertResponsesToVariableFormats(responses);
|
|
|
|
expect(variables.FIELD_NAME).toBe("");
|
|
expect(variables.FIELDNAME).toBe("");
|
|
});
|
|
});
|