Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ describe("formValidationSchemas", () => {
describe("updateExceptionsSchema", () => {
describe("serviceNowID validation", () => {
describe("valid ServiceNow case IDs", () => {
it("should accept valid ServiceNow case ID with 9 characters", () => {
it("should accept valid ServiceNow case ID with 2 letters and 7 digits", () => {
const validData = { serviceNowID: "CS1234567" };
const result = updateExceptionsSchema().safeParse(validData);

Expand All @@ -14,7 +14,7 @@ describe("formValidationSchemas", () => {
}
});

it("should accept valid ServiceNow case ID with more than 9 characters", () => {
it("should accept valid ServiceNow case ID with more than 7 digits after the two letters", () => {
const validData = { serviceNowID: "CS123456789" };
const result = updateExceptionsSchema().safeParse(validData);

Expand All @@ -24,36 +24,8 @@ describe("formValidationSchemas", () => {
}
});

it("should accept all uppercase letters", () => {
const validData = { serviceNowID: "ABCD12345" };
const result = updateExceptionsSchema().safeParse(validData);

expect(result.success).toBe(true);
});

it("should accept all lowercase letters", () => {
const validData = { serviceNowID: "abcd12345" };
const result = updateExceptionsSchema().safeParse(validData);

expect(result.success).toBe(true);
});

it("should accept mixed case letters", () => {
const validData = { serviceNowID: "AbCd12345" };
const result = updateExceptionsSchema().safeParse(validData);

expect(result.success).toBe(true);
});

it("should accept all numbers", () => {
const validData = { serviceNowID: "123456789" };
const result = updateExceptionsSchema().safeParse(validData);

expect(result.success).toBe(true);
});

it("should accept all letters", () => {
const validData = { serviceNowID: "ABCDEFGHI" };
it("should accept case-insensitive letters prefix", () => {
const validData = { serviceNowID: "cS1234567" };
const result = updateExceptionsSchema().safeParse(validData);

expect(result.success).toBe(true);
Expand Down Expand Up @@ -84,8 +56,8 @@ describe("formValidationSchemas", () => {
});
});

describe("invalid ServiceNow case IDs - minimum length", () => {
it("should reject case ID with less than 9 characters", () => {
describe("invalid ServiceNow case IDs - format and length", () => {
it("should reject case ID with fewer than 7 digits after two letters (length error first)", () => {
const invalidData = { serviceNowID: "CS12345" };
const result = updateExceptionsSchema().safeParse(invalidData);

Expand Down Expand Up @@ -247,19 +219,19 @@ describe("formValidationSchemas", () => {
}
});

it("should show length error before regex error for short invalid strings", () => {
const invalidData = { serviceNowID: "CS!" };
it("should show space error when spaces present (before other validations)", () => {
const invalidData = { serviceNowID: "CS123 4567" };
const result = updateExceptionsSchema().safeParse(invalidData);

expect(result.success).toBe(false);
if (!result.success) {
expect(result.error.issues[0].message).toBe(
"ServiceNow case ID must be nine characters or more"
"ServiceNow case ID must not contain spaces"
);
}
});

it("should show refine error before regex error", () => {
it("should show space refine error before regex error", () => {
const invalidData = { serviceNowID: "CS1234567 !" };
const result = updateExceptionsSchema().safeParse(invalidData);

Expand Down Expand Up @@ -315,6 +287,36 @@ describe("formValidationSchemas", () => {
}
});

it("should fail the final pattern when letters count is not two", () => {
// Pass earlier checks: length>=9, no spaces, alphanumeric only
const invalidData = { serviceNowID: "ABCD12345" }; // 4 letters, 5 digits
const result = updateExceptionsSchema(true).safeParse(invalidData);

expect(result.success).toBe(false);
if (!result.success) {
expect(result.error.issues).toEqual(
expect.arrayContaining([
expect.objectContaining({
message:
"ServiceNow case ID must start with two letters followed by at least seven digits (e.g. CS0619153)",
}),
])
);
}
});

it("should fail the final pattern when digits come first", () => {
const invalidData = { serviceNowID: "123456789" }; // 9 digits, no letters
const result = updateExceptionsSchema(true).safeParse(invalidData);

expect(result.success).toBe(false);
if (!result.success) {
expect(result.error.issues[0].message).toBe(
"ServiceNow case ID must start with two letters followed by at least seven digits (e.g. CS0619153)"
);
}
});

it("should accept valid ServiceNow ID in edit mode", () => {
const validData = { serviceNowID: "CS1234567" };
const result = updateExceptionsSchema(true).safeParse(validData);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { z } from "zod";

// This schema validates the ServiceNow case ID for updating exceptions status.
// In edit mode, empty input is allowed to clear the ServiceNow ID (convert raised to non-raised).
// In non-edit mode, the ID is required and must be at least 9 characters long,
// contain only alphanumeric characters, and not include spaces.
// In non-edit mode, the ID is required and must start with two letters followed by at least seven digits (e.g. CS0619153).
export const updateExceptionsSchema = (isEditMode: boolean = false) =>
z.object({
serviceNowID: z
Expand Down Expand Up @@ -36,5 +35,12 @@ export const updateExceptionsSchema = (isEditMode: boolean = false) =>
}
// Otherwise, check alphanumeric pattern
return /^[a-zA-Z0-9]+$/.test(val);
}, "ServiceNow case ID must only contain letters and numbers"),
}, "ServiceNow case ID must only contain letters and numbers")
.refine((val) => {
if (isEditMode && val === "") {
return true;
}
// Finally, enforce two letters followed by at least seven digits (e.g. CS0619153)
return /^[A-Za-z]{2}\d{7,}$/.test(val);
}, "ServiceNow case ID must start with two letters followed by at least seven digits (e.g. CS0619153)"),
});
Loading