fix: Prefill issue when name isn't present and add unit tests (#11418)

* Fix yarn.lock

* Add tests for getBookingResponsesSchema

* Fix prefill failing if name isnt provided

* More tests and another fix
pull/11529/head^2
Hariom Balhara 2023-09-26 16:16:31 +05:30 committed by GitHub
parent a0642598ab
commit 4acfb4b28c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 1048 additions and 12 deletions

File diff suppressed because it is too large Load Diff

View File

@ -79,7 +79,7 @@ function preprocess<T extends z.ZodType>({
isPartialSchema, isPartialSchema,
field, field,
}); });
return newResponses; return;
} }
if (field.type === "boolean") { if (field.type === "boolean") {
// Turn a boolean in string to a real boolean // Turn a boolean in string to a real boolean
@ -103,7 +103,11 @@ function preprocess<T extends z.ZodType>({
newResponses[field.name] = value; newResponses[field.name] = value;
} }
}); });
return newResponses;
return {
...parsedResponses,
...newResponses,
};
}, },
schema.superRefine(async (responses, ctx) => { schema.superRefine(async (responses, ctx) => {
if (!eventType.bookingFields) { if (!eventType.bookingFields) {
@ -137,8 +141,10 @@ function preprocess<T extends z.ZodType>({
continue; continue;
} }
if (isRequired && !isPartialSchema && !value) if (isRequired && !isPartialSchema && !value) {
ctx.addIssue({ code: z.ZodIssueCode.custom, message: m(`error_required_field`) }); ctx.addIssue({ code: z.ZodIssueCode.custom, message: m(`error_required_field`) });
return;
}
if (bookingField.type === "email") { if (bookingField.type === "email") {
// Email RegExp to validate if the input is a valid email // Email RegExp to validate if the input is a valid email
@ -224,6 +230,7 @@ function preprocess<T extends z.ZodType>({
!optionValue !optionValue
) { ) {
ctx.addIssue({ code: z.ZodIssueCode.custom, message: m("error_required_field") }); ctx.addIssue({ code: z.ZodIssueCode.custom, message: m("error_required_field") });
return;
} }
if (optionValue) { if (optionValue) {
@ -248,14 +255,17 @@ function preprocess<T extends z.ZodType>({
continue; continue;
} }
throw new Error(`Can't parse unknown booking field type: ${bookingField.type}`); ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Can't parse unknown booking field type: ${bookingField.type}`,
});
} }
}) })
); );
if (isPartialSchema) { if (isPartialSchema) {
// Query Params can be completely invalid, try to preprocess as much of it in correct format but in worst case simply don't prefill instead of crashing // Query Params can be completely invalid, try to preprocess as much of it in correct format but in worst case simply don't prefill instead of crashing
return preprocessed.catch(() => { return preprocessed.catch(function (res?: { error?: unknown[] }) {
console.error("Failed to preprocess query params, prefilling will be skipped"); console.error("Failed to preprocess query params, prefilling will be skipped", res?.error);
return {}; return {};
}); });
} }

View File

@ -5,6 +5,8 @@ import { getValidRhfFieldName } from "@calcom/lib/getValidRhfFieldName";
import { fieldTypesConfigMap } from "./fieldTypes"; import { fieldTypesConfigMap } from "./fieldTypes";
import { getVariantsConfig, preprocessNameFieldDataWithVariant } from "./utils"; import { getVariantsConfig, preprocessNameFieldDataWithVariant } from "./utils";
const nonEmptyString = () => z.string().refine((value: string) => value.trim().length > 0);
const fieldTypeEnum = z.enum([ const fieldTypeEnum = z.enum([
"name", "name",
"text", "text",
@ -289,7 +291,7 @@ export const fieldTypesSchemaMap: Partial<
if (fields.length === 1) { if (fields.length === 1) {
const field = fields[0]; const field = fields[0];
if (variantSupportedFields.includes(field.type)) { if (variantSupportedFields.includes(field.type)) {
const schema = stringSchema; const schema = field.required && !isPartialSchema ? nonEmptyString() : stringSchema;
if (!schema.safeParse(response).success) { if (!schema.safeParse(response).success) {
ctx.addIssue({ code: z.ZodIssueCode.custom, message: m("Invalid string") }); ctx.addIssue({ code: z.ZodIssueCode.custom, message: m("Invalid string") });
} }
@ -299,7 +301,7 @@ export const fieldTypesSchemaMap: Partial<
} }
} }
fields.forEach((subField) => { fields.forEach((subField) => {
const schema = stringSchema; const schema = subField.required && !isPartialSchema ? nonEmptyString() : stringSchema;
if (!variantSupportedFields.includes(subField.type)) { if (!variantSupportedFields.includes(subField.type)) {
throw new Error(`Unsupported field.type with variants: ${subField.type}`); throw new Error(`Unsupported field.type with variants: ${subField.type}`);
} }

View File

@ -22,8 +22,6 @@ import { isSupportedTimeZone } from "@calcom/lib/date-fns";
import { slugify } from "@calcom/lib/slugify"; import { slugify } from "@calcom/lib/slugify";
import { EventTypeCustomInputType } from "@calcom/prisma/enums"; import { EventTypeCustomInputType } from "@calcom/prisma/enums";
export const nonEmptyString = () => z.string().refine((value: string) => value.trim().length > 0);
// Let's not import 118kb just to get an enum // Let's not import 118kb just to get an enum
export enum Frequency { export enum Frequency {
YEARLY = 0, YEARLY = 0,
@ -115,14 +113,15 @@ export type BookingFieldType = FormBuilderFieldType;
// Validation of user added bookingFields' responses happen using `getBookingResponsesSchema` which requires `eventType`. // Validation of user added bookingFields' responses happen using `getBookingResponsesSchema` which requires `eventType`.
// So it is a dynamic validation and thus entire validation can't exist here // So it is a dynamic validation and thus entire validation can't exist here
// Note that this validation runs to validate prefill params as well, so it should consider that partial values can be there. e.g. `name` might be empty string
export const bookingResponses = z export const bookingResponses = z
.object({ .object({
email: z.string(), email: z.string(),
//TODO: Why don't we move name out of bookingResponses and let it be handled like user fields? //TODO: Why don't we move name out of bookingResponses and let it be handled like user fields?
name: z.union([ name: z.union([
nonEmptyString(), z.string(),
z.object({ z.object({
firstName: nonEmptyString(), firstName: z.string(),
lastName: z.string().optional(), lastName: z.string().optional(),
}), }),
]), ]),