Files
app/src/__tests__/customers.schema.test.ts
BOHA 519edce373 fix: 2026-06-09 full-codebase audit hardening
Validation: shared NaN-guarded Zod coercion helpers in schemas/common.ts replace
the raw number|string transform idiom across every schema (the root-cause NaN bug
class); emailOrEmpty + lenient isoDateString/timeString.

Security: roles privilege-escalation closed; refresh-token family revocation on
reuse; TOTP uses config params; read endpoints permission-guarded; received-invoices
gross VAT on all paths; orders-pdf custom-items authz.

Concurrency: $queryRaw SELECT...FOR UPDATE locks in ascending-id order (warehouse
confirm/cancel, attendance lockUserRow); uniqueness checks moved into create
transactions (TOCTOU -> 409); deterministic id tiebreak on second-precision
timestamp ordering (plan resolveCell/resolveGrid, warehouse FIFO).

Frontend: Rules-of-Hooks fixed across ~14 pages + PlanCellModal; UTC-date persisted
fields; dashboard invalidation gaps; stale-closure confirm bugs.

Tooling/tests: ESLint flat config (react-hooks/rules-of-hooks = error) + Prettier;
tsconfig.test.json so tsc -b type-checks the tests; removed 3 dead deps; npm audit
fix (8 -> 3). Suite 195 -> 247 (happy-path auth, FIFO oldest-first, flakiness fixes),
isolated on app_test via .env.test with a hard-throw setup guard.

Gates: tsc 0 | build 0 | vitest 247/247 | eslint 0 errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 06:45:26 +02:00

106 lines
3.0 KiB
TypeScript

import { describe, it, expect } from "vitest";
import {
CreateCustomerSchema,
UpdateCustomerSchema,
} from "../schemas/customers.schema";
describe("UpdateCustomerSchema", () => {
it("rejects empty name", () => {
const result = UpdateCustomerSchema.safeParse({ name: "" });
expect(result.success).toBe(false);
});
it("accepts valid name", () => {
const result = UpdateCustomerSchema.safeParse({ name: "Acme Corp" });
expect(result.success).toBe(true);
});
it("accepts partial updates without name", () => {
const result = UpdateCustomerSchema.safeParse({ street: "Main St" });
expect(result.success).toBe(true);
});
it("rejects a name longer than 255 chars", () => {
const result = UpdateCustomerSchema.safeParse({ name: "x".repeat(256) });
expect(result.success).toBe(false);
});
it("accepts nullable address/identity fields set to null", () => {
const result = UpdateCustomerSchema.safeParse({
street: null,
city: null,
postal_code: null,
country: null,
company_id: null,
vat_id: null,
});
expect(result.success).toBe(true);
});
});
describe("CreateCustomerSchema", () => {
it("requires a name", () => {
const result = CreateCustomerSchema.safeParse({ street: "Main St" });
expect(result.success).toBe(false);
});
it("accepts a full valid payload with all optional fields", () => {
const result = CreateCustomerSchema.safeParse({
name: "Acme Corp",
street: "Main St 1",
city: "Praha",
postal_code: "11000",
country: "CZ",
company_id: "12345678",
vat_id: "CZ12345678",
custom_fields: [{ label: "Note", value: "VIP" }],
customer_field_order: ["name", "street"],
});
expect(result.success).toBe(true);
});
it("accepts custom_fields as an array of arbitrary objects", () => {
const result = CreateCustomerSchema.safeParse({
name: "Acme Corp",
custom_fields: [
{ label: "a", value: 1 },
{ nested: { deep: true } },
"raw string",
],
});
expect(result.success).toBe(true);
});
it("rejects custom_fields that is not an array", () => {
const result = CreateCustomerSchema.safeParse({
name: "Acme Corp",
custom_fields: { not: "an array" },
});
expect(result.success).toBe(false);
});
it("rejects custom_fields longer than the 100-item cap", () => {
const result = CreateCustomerSchema.safeParse({
name: "Acme Corp",
custom_fields: Array.from({ length: 101 }, (_, i) => ({ i })),
});
expect(result.success).toBe(false);
});
it("rejects customer_field_order entries that are not strings", () => {
const result = CreateCustomerSchema.safeParse({
name: "Acme Corp",
customer_field_order: ["name", 5],
});
expect(result.success).toBe(false);
});
it("rejects an over-length nullable field (vat_id > 255)", () => {
const result = CreateCustomerSchema.safeParse({
name: "Acme Corp",
vat_id: "x".repeat(256),
});
expect(result.success).toBe(false);
});
});