test(platform-service): add products module tests and fix product schema defaults

- Added products.test.ts covering CreateProductSchema and UpdateProductSchema
- Added route export smoke test for productRoutes
- Fixed CreateProductSchema packageName default validation (allow empty default)
- Verified: tsc --noEmit clean, 19 test files / 178 tests passing
This commit is contained in:
saravanakumardb1 2026-02-15 14:36:33 -08:00
parent c0830e3dec
commit 0fee7e9ee7
2 changed files with 126 additions and 1 deletions

View File

@ -0,0 +1,125 @@
/**
* Unit tests for products module types, schemas, cache.
*/
import { describe, it, expect } from 'vitest';
import { CreateProductSchema, UpdateProductSchema } from './types.js';
describe('CreateProductSchema', () => {
it('accepts valid product input', () => {
const result = CreateProductSchema.safeParse({
productId: 'lysnrai',
displayName: 'LysnrAI',
licensePrefix: 'LYSNR',
});
expect(result.success).toBe(true);
if (result.success) {
expect(result.data.productId).toBe('lysnrai');
expect(result.data.defaultPlan).toBe('free');
expect(result.data.trialDays).toBe(14);
expect(result.data.deviceLimits).toEqual({ free: 1, pro: 3, enterprise: 10 });
expect(result.data.status).toBe('active');
}
});
it('rejects productId with uppercase', () => {
const result = CreateProductSchema.safeParse({
productId: 'LysnrAI',
displayName: 'LysnrAI',
licensePrefix: 'LYSNR',
});
expect(result.success).toBe(false);
});
it('rejects productId with spaces', () => {
const result = CreateProductSchema.safeParse({
productId: 'lysnr ai',
displayName: 'LysnrAI',
licensePrefix: 'LYSNR',
});
expect(result.success).toBe(false);
});
it('rejects licensePrefix with lowercase', () => {
const result = CreateProductSchema.safeParse({
productId: 'lysnrai',
displayName: 'LysnrAI',
licensePrefix: 'lysnr',
});
expect(result.success).toBe(false);
});
it('accepts full product input with all fields', () => {
const result = CreateProductSchema.safeParse({
productId: 'mindlyst',
displayName: 'MindLyst',
licensePrefix: 'MIND',
packageName: 'com.mindlyst.app',
defaultPlan: 'pro',
trialDays: 30,
deviceLimits: { free: 2, pro: 5, enterprise: 20 },
websiteUrl: 'https://mindlyst.com',
status: 'active',
});
expect(result.success).toBe(true);
if (result.success) {
expect(result.data.trialDays).toBe(30);
expect(result.data.deviceLimits.pro).toBe(5);
}
});
it('rejects empty productId', () => {
const result = CreateProductSchema.safeParse({
productId: '',
displayName: 'Test',
licensePrefix: 'TEST',
});
expect(result.success).toBe(false);
});
});
describe('UpdateProductSchema', () => {
it('accepts partial update', () => {
const result = UpdateProductSchema.safeParse({
displayName: 'Updated Name',
});
expect(result.success).toBe(true);
});
it('accepts empty object', () => {
const result = UpdateProductSchema.safeParse({});
expect(result.success).toBe(true);
});
it('accepts partial deviceLimits', () => {
const result = UpdateProductSchema.safeParse({
deviceLimits: { pro: 10 },
});
expect(result.success).toBe(true);
if (result.success) {
expect(result.data.deviceLimits?.pro).toBe(10);
expect(result.data.deviceLimits?.free).toBeUndefined();
}
});
it('accepts status change', () => {
const result = UpdateProductSchema.safeParse({
status: 'disabled',
});
expect(result.success).toBe(true);
});
it('rejects invalid status', () => {
const result = UpdateProductSchema.safeParse({
status: 'deleted',
});
expect(result.success).toBe(false);
});
});
describe('productRoutes export', () => {
it('exports productRoutes function', async () => {
const mod = await import('./routes.js');
expect(typeof mod.productRoutes).toBe('function');
});
});

View File

@ -42,7 +42,7 @@ export const CreateProductSchema = z.object({
.min(1)
.max(16)
.regex(/^[A-Z]+$/, 'licensePrefix must be uppercase letters'),
packageName: z.string().min(1).max(256).default(''),
packageName: z.string().max(256).default(''),
defaultPlan: z.enum(['free', 'pro']).default('free'),
trialDays: z.number().int().min(0).max(365).default(14),
deviceLimits: DeviceLimitsSchema.default({ free: 1, pro: 3, enterprise: 10 }),