Implement stores and refills, improve testing
This commit is contained in:
parent
9f416903ef
commit
5536acd67d
137 changed files with 21218 additions and 221 deletions
120
packages/shared/src/validation/purchase.schemas.test.ts
Normal file
120
packages/shared/src/validation/purchase.schemas.test.ts
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import {
|
||||
CreatePurchaseItemSchema,
|
||||
CreatePurchaseSchema,
|
||||
UpdatePurchaseSchema,
|
||||
PurchaseQuerySchema,
|
||||
} from './purchase.schemas.js';
|
||||
|
||||
describe('CreatePurchaseItemSchema', () => {
|
||||
it('accepts minimal valid item', () => {
|
||||
const result = CreatePurchaseItemSchema.safeParse({ name: 'Tylenol 30ct', quantity: 30, unit: 'tablet' });
|
||||
expect(result.success).toBe(true);
|
||||
if (result.success) expect(result.data.addedToCabinet).toBeUndefined();
|
||||
});
|
||||
|
||||
it('accepts item with all fields', () => {
|
||||
const result = CreatePurchaseItemSchema.safeParse({
|
||||
medicineProductId: 'mp-1',
|
||||
name: 'Tylenol 30ct',
|
||||
quantity: 30,
|
||||
unit: 'tablet',
|
||||
actualPrice: 9.99,
|
||||
currency: 'USD',
|
||||
priceRecordId: 'pr-1',
|
||||
});
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects empty name', () => {
|
||||
expect(CreatePurchaseItemSchema.safeParse({ name: '', quantity: 1, unit: 'tablet' }).success).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects non-positive quantity', () => {
|
||||
expect(CreatePurchaseItemSchema.safeParse({ name: 'X', quantity: 0, unit: 'tablet' }).success).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects empty unit', () => {
|
||||
expect(CreatePurchaseItemSchema.safeParse({ name: 'X', quantity: 1, unit: '' }).success).toBe(false);
|
||||
});
|
||||
|
||||
it('trims name whitespace', () => {
|
||||
const result = CreatePurchaseItemSchema.parse({ name: ' Tylenol ', quantity: 1, unit: 'tablet' });
|
||||
expect(result.name).toBe('Tylenol');
|
||||
});
|
||||
});
|
||||
|
||||
describe('CreatePurchaseSchema', () => {
|
||||
const validItem = { name: 'Tylenol', quantity: 30, unit: 'tablet' };
|
||||
|
||||
it('defaults status to in_cabinet', () => {
|
||||
const result = CreatePurchaseSchema.parse({ storeId: 'st-1', items: [validItem] });
|
||||
expect(result.status).toBe('in_cabinet');
|
||||
});
|
||||
|
||||
it('accepts ordered status', () => {
|
||||
const result = CreatePurchaseSchema.safeParse({ storeId: 'st-1', status: 'ordered', items: [validItem] });
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects empty storeId', () => {
|
||||
expect(CreatePurchaseSchema.safeParse({ storeId: '', items: [validItem] }).success).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects empty items array', () => {
|
||||
expect(CreatePurchaseSchema.safeParse({ storeId: 'st-1', items: [] }).success).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects invalid status', () => {
|
||||
expect(CreatePurchaseSchema.safeParse({ storeId: 'st-1', status: 'pending', items: [validItem] }).success).toBe(false);
|
||||
});
|
||||
|
||||
it('accepts optional purchasedAt datetime', () => {
|
||||
const result = CreatePurchaseSchema.safeParse({
|
||||
storeId: 'st-1',
|
||||
items: [validItem],
|
||||
purchasedAt: '2026-01-15T00:00:00.000Z',
|
||||
});
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects invalid purchasedAt', () => {
|
||||
expect(CreatePurchaseSchema.safeParse({ storeId: 'st-1', items: [validItem], purchasedAt: 'not-a-date' }).success).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('UpdatePurchaseSchema', () => {
|
||||
it('accepts empty object', () => {
|
||||
expect(UpdatePurchaseSchema.safeParse({}).success).toBe(true);
|
||||
});
|
||||
|
||||
it('accepts notes only', () => {
|
||||
expect(UpdatePurchaseSchema.safeParse({ notes: 'updated' }).success).toBe(true);
|
||||
});
|
||||
|
||||
it('trims notes whitespace', () => {
|
||||
const result = UpdatePurchaseSchema.parse({ notes: ' hello ' });
|
||||
expect(result.notes).toBe('hello');
|
||||
});
|
||||
});
|
||||
|
||||
describe('PurchaseQuerySchema', () => {
|
||||
it('defaults limit to 20', () => {
|
||||
const result = PurchaseQuerySchema.parse({});
|
||||
expect(result.limit).toBe(20);
|
||||
});
|
||||
|
||||
it('accepts status filter', () => {
|
||||
expect(PurchaseQuerySchema.safeParse({ status: 'ordered' }).success).toBe(true);
|
||||
expect(PurchaseQuerySchema.safeParse({ status: 'in_cabinet' }).success).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects invalid status', () => {
|
||||
expect(PurchaseQuerySchema.safeParse({ status: 'unknown' }).success).toBe(false);
|
||||
});
|
||||
|
||||
it('coerces string limit', () => {
|
||||
const result = PurchaseQuerySchema.parse({ limit: '50' });
|
||||
expect(result.limit).toBe(50);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue