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
12 changes: 9 additions & 3 deletions app/schemas/customer.schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,15 @@ const intIdParam = z.object({
* zod issue.
*/
const createCustomerBody = z.object({
custCompanyName: z.string().max(255).optional(),
custFName: z.string().max(255).optional(),
custLName: z.string().max(255).optional(),
// custCompanyName / custFName / custLName mirror the DB columns
// (text NOT NULL on each — see setup/TimeTracker.sql). Without
// the required flag, callers omitting them passed zod and tripped
// the postgres "null value violates not-null constraint" path,
// surfacing as a 500 instead of a clean 400. Same drift class as
// #265's custState fix.
custCompanyName: z.string().max(255),
custFName: z.string().max(255),
custLName: z.string().max(255),
custAddress1: z.string().max(255).optional(),
custAddress2: z.string().max(255).optional(),
custCity: z.string().max(255).optional(),
Expand Down
4 changes: 3 additions & 1 deletion tests/api/customer-bulk.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ beforeAll(async () => {

describe('POST /v1/customer/bulk auth contract', () => {
test('returns 403 when authKey header is missing', async () => {
// Full required-field body so body-validation passes and the
// authKey check inside makeBulkCreate is reached.
const res = await request(app)
.post('/v1/customer/bulk')
.send({ customers: [{ custCompanyName: 'Acme' }] });
.send({ customers: [{ custCompanyName: 'Acme', custFName: 'Test', custLName: 'User' }] });
expect(res.status).toBe(403);
});
});
Expand Down
7 changes: 5 additions & 2 deletions tests/api/customer-create.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,12 @@ beforeAll(async () => {

describe('POST /v1/customer', () => {
test('returns 403 when authKey header is missing', async () => {
// Send a full required-field body so we exit body validation
// and reach the controller's authKey check. custCompanyName /
// custFName / custLName are required (NOT NULL in the DB).
const res = await request(app)
.post('/v1/customer')
.send({ custCompanyName: 'Acme' });
.send({ custCompanyName: 'Acme', custFName: 'Test', custLName: 'User' });
expect(res.status).toBe(403);
expect(res.body).toMatchObject({
message: expect.stringMatching(/Authorization key not sent/i),
Expand All @@ -59,7 +62,7 @@ describe('POST /v1/customer', () => {
const res = await request(app)
.post('/v1/customer')
.set('authKey', 'definitely-not-a-real-key')
.send({ custCompanyName: 'Acme', custCompId: 1 });
.send({ custCompanyName: 'Acme', custFName: 'Test', custLName: 'User', custCompId: 1 });
// With no DB, IsMaster returns false, GetCompanyId returns -1,
// and the controller emits 403 "Invalid Authorization Key."
expect(res.status).toBe(403);
Expand Down
5 changes: 4 additions & 1 deletion tests/api/idempotency.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@ describe('Idempotency middleware: mounted on POST routes', () => {
.post('/v1/customer')
.set('authKey', 'any')
.set('Idempotency-Key', '01HFTESTKEY12345')
.send({ custCompanyName: 'Acme' });
// Full required-field body so the schema validator passes
// and we exercise the idempotency middleware itself rather
// than short-circuiting on a 400 from zod.
.send({ custCompanyName: 'Acme', custFName: 'Test', custLName: 'User' });
// Whatever the controller decides (likely 403 from inline
// auth, since the mock returns []), the idempotency layer
// should NOT have short-circuited with 400/409. That's the
Expand Down
5 changes: 4 additions & 1 deletion tests/api/validation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,10 @@ describe('body validation — POST /v1/customer', () => {
const res = await request(app)
.post('/v1/customer')
.set('authKey', 'unknown-key') // will still 403 at controller
.send({ custCompanyName: 'Acme', custCompId: 1 });
// Full required-field body — custCompanyName / custFName /
// custLName are NOT NULL in the DB and required in the
// zod schema.
.send({ custCompanyName: 'Acme', custFName: 'Test', custLName: 'User', custCompId: 1 });
// After zod passes, the controller's auth check 403s on the
// unknown key — that's the expected post-validation path.
// We just need to confirm we got past the 400 validator.
Expand Down