feat: add integration test for RoutingFormResponseField triggers (#21586)
* feat: add integration test for RoutingFormResponseField triggers Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: remove changing field types test case Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: eunjae@cal.com <hey@eunjae.dev>
This commit is contained in:
co-authored by
Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
eunjae@cal.com <hey@eunjae.dev>
parent
a745d8a60a
commit
07d5594085
@@ -0,0 +1,451 @@
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { describe, expect, beforeEach, afterEach, it } from "vitest";
|
||||
|
||||
import prisma from "@calcom/prisma";
|
||||
import { BookingStatus } from "@calcom/prisma/enums";
|
||||
|
||||
describe("RoutingFormResponseField", () => {
|
||||
let userId: number;
|
||||
let formId: string;
|
||||
let eventTypeId: number;
|
||||
let bookingId: number;
|
||||
let responseId: number;
|
||||
const randomId = Math.floor(Math.random() * 1000000);
|
||||
const email = `routing-form-response-field-${randomId}@example.com`;
|
||||
|
||||
beforeEach(async () => {
|
||||
const user = await prisma.user.create({
|
||||
data: {
|
||||
email,
|
||||
username: `routing-form-response-field-testuser-${randomId}`,
|
||||
name: "Test User",
|
||||
},
|
||||
});
|
||||
userId = user.id;
|
||||
|
||||
const eventType = await prisma.eventType.create({
|
||||
data: {
|
||||
title: "Test Event",
|
||||
slug: "test-event",
|
||||
length: 60,
|
||||
userId: user.id,
|
||||
},
|
||||
});
|
||||
eventTypeId = eventType.id;
|
||||
|
||||
const form = await prisma.app_RoutingForms_Form.create({
|
||||
data: {
|
||||
name: "Test Form",
|
||||
userId: user.id,
|
||||
fields: [
|
||||
{
|
||||
id: "text-field-id",
|
||||
type: "text",
|
||||
label: "Name",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: "number-field-id",
|
||||
type: "number",
|
||||
label: "Rating",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
id: "multiselect-field-id",
|
||||
type: "multiselect",
|
||||
label: "Skills",
|
||||
required: false,
|
||||
options: [
|
||||
{
|
||||
id: "skill-1",
|
||||
label: "JavaScript",
|
||||
},
|
||||
{
|
||||
id: "skill-2",
|
||||
label: "TypeScript",
|
||||
},
|
||||
{
|
||||
id: "skill-3",
|
||||
label: "React",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "email-field-id",
|
||||
type: "email",
|
||||
label: "Email",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
formId = form.id;
|
||||
|
||||
const booking = await prisma.booking.create({
|
||||
data: {
|
||||
uid: `routing-form-response-field-${randomId}`,
|
||||
title: "Test Booking",
|
||||
startTime: new Date(),
|
||||
endTime: new Date(Date.now() + 60 * 60 * 1000),
|
||||
userId: user.id,
|
||||
eventTypeId: eventType.id,
|
||||
status: BookingStatus.PENDING,
|
||||
},
|
||||
});
|
||||
bookingId = booking.id;
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (responseId) {
|
||||
await prisma.routingFormResponseField.deleteMany({
|
||||
where: { responseId },
|
||||
});
|
||||
await prisma.routingFormResponseDenormalized.deleteMany({
|
||||
where: { id: responseId },
|
||||
});
|
||||
await prisma.app_RoutingForms_FormResponse.deleteMany({
|
||||
where: { id: responseId },
|
||||
});
|
||||
}
|
||||
if (bookingId) {
|
||||
await prisma.booking.deleteMany({
|
||||
where: { id: bookingId },
|
||||
});
|
||||
}
|
||||
if (formId) {
|
||||
await prisma.app_RoutingForms_Form.deleteMany({
|
||||
where: { id: formId },
|
||||
});
|
||||
}
|
||||
if (eventTypeId) {
|
||||
await prisma.eventType.deleteMany({
|
||||
where: { id: eventTypeId },
|
||||
});
|
||||
}
|
||||
if (userId) {
|
||||
await prisma.user.deleteMany({
|
||||
where: { id: userId },
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("INSERT Trigger Tests", () => {
|
||||
it("should create field entries when form response is created", async () => {
|
||||
const formResponse = await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-all-fields",
|
||||
formId: formId,
|
||||
response: {
|
||||
"text-field-id": {
|
||||
label: "Name",
|
||||
value: "John Doe",
|
||||
},
|
||||
"number-field-id": {
|
||||
label: "Rating",
|
||||
value: 5,
|
||||
},
|
||||
"multiselect-field-id": {
|
||||
label: "Skills",
|
||||
value: ["skill-1", "skill-3"],
|
||||
},
|
||||
"email-field-id": {
|
||||
label: "Email",
|
||||
value: "john.doe@example.com",
|
||||
},
|
||||
},
|
||||
routedToBookingUid: null,
|
||||
},
|
||||
});
|
||||
responseId = formResponse.id;
|
||||
|
||||
const denormalizedResponse = await prisma.routingFormResponseDenormalized.findUnique({
|
||||
where: { id: responseId },
|
||||
include: { fields: true },
|
||||
});
|
||||
|
||||
expect(denormalizedResponse).not.toBeNull();
|
||||
expect(denormalizedResponse?.fields).toBeDefined();
|
||||
expect(denormalizedResponse?.fields).toHaveLength(4);
|
||||
|
||||
const textField = denormalizedResponse?.fields.find((field) => field.fieldId === "text-field-id");
|
||||
expect(textField).toBeDefined();
|
||||
expect(textField?.valueString).toBe("John Doe");
|
||||
expect(textField?.valueNumber).toBeNull();
|
||||
expect(textField?.valueStringArray).toEqual([]);
|
||||
|
||||
const numberField = denormalizedResponse?.fields.find((field) => field.fieldId === "number-field-id");
|
||||
expect(numberField).toBeDefined();
|
||||
expect(numberField?.valueString).toBeNull();
|
||||
expect(numberField?.valueNumber?.equals(new Prisma.Decimal(5))).toBe(true);
|
||||
expect(numberField?.valueStringArray).toEqual([]);
|
||||
|
||||
const multiselectField = denormalizedResponse?.fields.find(
|
||||
(field) => field.fieldId === "multiselect-field-id"
|
||||
);
|
||||
expect(multiselectField).toBeDefined();
|
||||
expect(multiselectField?.valueString).toBeNull();
|
||||
expect(multiselectField?.valueNumber).toBeNull();
|
||||
expect(multiselectField?.valueStringArray).toContain("skill-1");
|
||||
expect(multiselectField?.valueStringArray).toContain("skill-3");
|
||||
expect(multiselectField?.valueStringArray).toHaveLength(2);
|
||||
|
||||
const emailField = denormalizedResponse?.fields.find((field) => field.fieldId === "email-field-id");
|
||||
expect(emailField).toBeDefined();
|
||||
expect(emailField?.valueString).toBe("john.doe@example.com");
|
||||
expect(emailField?.valueNumber).toBeNull();
|
||||
expect(emailField?.valueStringArray).toEqual([]);
|
||||
});
|
||||
|
||||
it("should handle null and undefined field values", async () => {
|
||||
const formResponse = await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-null-values",
|
||||
formId: formId,
|
||||
response: {
|
||||
"text-field-id": {
|
||||
label: "Name",
|
||||
value: null,
|
||||
},
|
||||
"number-field-id": {
|
||||
label: "Rating",
|
||||
value: undefined,
|
||||
},
|
||||
"multiselect-field-id": {
|
||||
label: "Skills",
|
||||
value: [],
|
||||
},
|
||||
"email-field-id": {
|
||||
label: "Email",
|
||||
value: "",
|
||||
},
|
||||
},
|
||||
routedToBookingUid: null,
|
||||
},
|
||||
});
|
||||
responseId = formResponse.id;
|
||||
|
||||
const denormalizedResponse = await prisma.routingFormResponseDenormalized.findUnique({
|
||||
where: { id: responseId },
|
||||
include: { fields: true },
|
||||
});
|
||||
|
||||
expect(denormalizedResponse).not.toBeNull();
|
||||
expect(denormalizedResponse?.fields).toBeDefined();
|
||||
expect(denormalizedResponse?.fields.length).toBeLessThanOrEqual(2);
|
||||
|
||||
const emailField = denormalizedResponse?.fields.find((field) => field.fieldId === "email-field-id");
|
||||
if (emailField) {
|
||||
expect(emailField.valueString).toBe("");
|
||||
}
|
||||
|
||||
const multiselectField = denormalizedResponse?.fields.find(
|
||||
(field) => field.fieldId === "multiselect-field-id"
|
||||
);
|
||||
if (multiselectField) {
|
||||
expect(multiselectField.valueStringArray).toEqual([]);
|
||||
}
|
||||
});
|
||||
|
||||
it("should handle invalid data types", async () => {
|
||||
const formResponse = await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-invalid-types",
|
||||
formId: formId,
|
||||
response: {
|
||||
"text-field-id": {
|
||||
label: "Name",
|
||||
value: 123, // Number instead of string
|
||||
},
|
||||
"number-field-id": {
|
||||
label: "Rating",
|
||||
value: "five", // String instead of number
|
||||
},
|
||||
"multiselect-field-id": {
|
||||
label: "Skills",
|
||||
value: "skill-1", // String instead of array
|
||||
},
|
||||
},
|
||||
routedToBookingUid: null,
|
||||
},
|
||||
});
|
||||
responseId = formResponse.id;
|
||||
|
||||
const denormalizedResponse = await prisma.routingFormResponseDenormalized.findUnique({
|
||||
where: { id: responseId },
|
||||
include: { fields: true },
|
||||
});
|
||||
|
||||
expect(denormalizedResponse).not.toBeNull();
|
||||
expect(denormalizedResponse?.fields).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("UPDATE Trigger Tests", () => {
|
||||
it("should update field entries when form response is updated", async () => {
|
||||
const formResponse = await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-update",
|
||||
formId: formId,
|
||||
response: {
|
||||
"text-field-id": {
|
||||
label: "Name",
|
||||
value: "Original Name",
|
||||
},
|
||||
"number-field-id": {
|
||||
label: "Rating",
|
||||
value: 3,
|
||||
},
|
||||
"multiselect-field-id": {
|
||||
label: "Skills",
|
||||
value: ["skill-1"],
|
||||
},
|
||||
},
|
||||
routedToBookingUid: null,
|
||||
},
|
||||
});
|
||||
responseId = formResponse.id;
|
||||
|
||||
const initialDenormalizedResponse = await prisma.routingFormResponseDenormalized.findUnique({
|
||||
where: { id: responseId },
|
||||
include: { fields: true },
|
||||
});
|
||||
|
||||
expect(initialDenormalizedResponse).not.toBeNull();
|
||||
expect(initialDenormalizedResponse?.fields).toBeDefined();
|
||||
expect(initialDenormalizedResponse?.fields).toHaveLength(3);
|
||||
|
||||
const initialTextField = initialDenormalizedResponse?.fields.find(
|
||||
(field) => field.fieldId === "text-field-id"
|
||||
);
|
||||
expect(initialTextField?.valueString).toBe("Original Name");
|
||||
|
||||
await prisma.app_RoutingForms_FormResponse.update({
|
||||
where: { id: responseId },
|
||||
data: {
|
||||
response: {
|
||||
"text-field-id": {
|
||||
label: "Name",
|
||||
value: "Updated Name",
|
||||
},
|
||||
"number-field-id": {
|
||||
label: "Rating",
|
||||
value: 5,
|
||||
},
|
||||
"multiselect-field-id": {
|
||||
label: "Skills",
|
||||
value: ["skill-1", "skill-2"],
|
||||
},
|
||||
"email-field-id": {
|
||||
label: "Email",
|
||||
value: "new@example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const updatedDenormalizedResponse = await prisma.routingFormResponseDenormalized.findUnique({
|
||||
where: { id: responseId },
|
||||
include: { fields: true },
|
||||
});
|
||||
|
||||
expect(updatedDenormalizedResponse).not.toBeNull();
|
||||
expect(updatedDenormalizedResponse?.fields).toBeDefined();
|
||||
expect(updatedDenormalizedResponse?.fields).toHaveLength(4); // Now we have 4 fields
|
||||
|
||||
const updatedTextField = updatedDenormalizedResponse?.fields.find(
|
||||
(field) => field.fieldId === "text-field-id"
|
||||
);
|
||||
expect(updatedTextField).toBeDefined();
|
||||
expect(updatedTextField?.valueString).toBe("Updated Name");
|
||||
|
||||
const updatedNumberField = updatedDenormalizedResponse?.fields.find(
|
||||
(field) => field.fieldId === "number-field-id"
|
||||
);
|
||||
expect(updatedNumberField).toBeDefined();
|
||||
expect(updatedNumberField?.valueNumber?.equals(new Prisma.Decimal(5))).toBe(true);
|
||||
|
||||
const updatedMultiselectField = updatedDenormalizedResponse?.fields.find(
|
||||
(field) => field.fieldId === "multiselect-field-id"
|
||||
);
|
||||
expect(updatedMultiselectField).toBeDefined();
|
||||
expect(updatedMultiselectField?.valueStringArray).toContain("skill-1");
|
||||
expect(updatedMultiselectField?.valueStringArray).toContain("skill-2");
|
||||
expect(updatedMultiselectField?.valueStringArray).toHaveLength(2);
|
||||
|
||||
const newEmailField = updatedDenormalizedResponse?.fields.find(
|
||||
(field) => field.fieldId === "email-field-id"
|
||||
);
|
||||
expect(newEmailField).toBeDefined();
|
||||
expect(newEmailField?.valueString).toBe("new@example.com");
|
||||
});
|
||||
|
||||
it("should remove field entries when fields are removed from response", async () => {
|
||||
const formResponse = await prisma.app_RoutingForms_FormResponse.create({
|
||||
data: {
|
||||
formFillerId: "test-filler-remove-fields",
|
||||
formId: formId,
|
||||
response: {
|
||||
"text-field-id": {
|
||||
label: "Name",
|
||||
value: "Test Name",
|
||||
},
|
||||
"number-field-id": {
|
||||
label: "Rating",
|
||||
value: 4,
|
||||
},
|
||||
"multiselect-field-id": {
|
||||
label: "Skills",
|
||||
value: ["skill-1", "skill-2"],
|
||||
},
|
||||
"email-field-id": {
|
||||
label: "Email",
|
||||
value: "test@example.com",
|
||||
},
|
||||
},
|
||||
routedToBookingUid: null,
|
||||
},
|
||||
});
|
||||
responseId = formResponse.id;
|
||||
|
||||
const initialDenormalizedResponse = await prisma.routingFormResponseDenormalized.findUnique({
|
||||
where: { id: responseId },
|
||||
include: { fields: true },
|
||||
});
|
||||
|
||||
expect(initialDenormalizedResponse).not.toBeNull();
|
||||
expect(initialDenormalizedResponse?.fields).toBeDefined();
|
||||
expect(initialDenormalizedResponse?.fields).toHaveLength(4);
|
||||
|
||||
await prisma.app_RoutingForms_FormResponse.update({
|
||||
where: { id: responseId },
|
||||
data: {
|
||||
response: {
|
||||
"text-field-id": {
|
||||
label: "Name",
|
||||
value: "Test Name",
|
||||
},
|
||||
"email-field-id": {
|
||||
label: "Email",
|
||||
value: "test@example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const updatedDenormalizedResponse = await prisma.routingFormResponseDenormalized.findUnique({
|
||||
where: { id: responseId },
|
||||
include: { fields: true },
|
||||
});
|
||||
|
||||
expect(updatedDenormalizedResponse).not.toBeNull();
|
||||
expect(updatedDenormalizedResponse?.fields).toBeDefined();
|
||||
expect(updatedDenormalizedResponse?.fields).toHaveLength(2); // Now we have only 2 fields
|
||||
|
||||
const fieldIds = updatedDenormalizedResponse?.fields.map((field) => field.fieldId);
|
||||
expect(fieldIds).toContain("text-field-id");
|
||||
expect(fieldIds).toContain("email-field-id");
|
||||
expect(fieldIds).not.toContain("number-field-id");
|
||||
expect(fieldIds).not.toContain("multiselect-field-id");
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user