Files
ecommerce-platform/test/unit/lib/validate.test.ts
T

330 lines
11 KiB
TypeScript
Raw Normal View History

import { describe, it, expect } from 'vitest'
import {
loginSchema,
registerSchema,
changePasswordSchema,
productTypeSchema,
productSchema,
categorySchema,
reviewSchema,
cartItemSchema,
checkoutSchema,
settingSchema,
} from '@/lib/validate'
// ─── loginSchema ────────────────────────────────────────────────────────────
describe('loginSchema', () => {
it('accepts valid email and password', () => {
const result = loginSchema.safeParse({ email: 'user@example.com', password: 'anypass' })
expect(result.success).toBe(true)
})
it('rejects invalid email', () => {
const result = loginSchema.safeParse({ email: 'not-an-email', password: 'pass' })
expect(result.success).toBe(false)
expect(result.error?.errors[0].message).toBe('Invalid email address')
})
it('rejects empty password', () => {
const result = loginSchema.safeParse({ email: 'user@example.com', password: '' })
expect(result.success).toBe(false)
})
it('rejects missing fields', () => {
expect(loginSchema.safeParse({}).success).toBe(false)
})
})
// ─── registerSchema ──────────────────────────────────────────────────────────
describe('registerSchema', () => {
const valid = {
email: 'user@example.com',
password: 'ValidPass123!',
name: 'Mario Rossi',
}
it('accepts valid registration data', () => {
expect(registerSchema.safeParse(valid).success).toBe(true)
})
it('rejects password shorter than 12 chars', () => {
const r = registerSchema.safeParse({ ...valid, password: 'Short1!' })
expect(r.success).toBe(false)
expect(r.error?.errors[0].message).toMatch(/12 characters/)
})
it('rejects password without uppercase', () => {
const r = registerSchema.safeParse({ ...valid, password: 'nouppercase1!' })
expect(r.success).toBe(false)
expect(r.error?.errors[0].message).toMatch(/uppercase/)
})
it('rejects password without lowercase', () => {
const r = registerSchema.safeParse({ ...valid, password: 'NOLOWERCASE1!' })
expect(r.success).toBe(false)
expect(r.error?.errors[0].message).toMatch(/lowercase/)
})
it('rejects password without number', () => {
const r = registerSchema.safeParse({ ...valid, password: 'NoNumberHere!' })
expect(r.success).toBe(false)
expect(r.error?.errors[0].message).toMatch(/number/)
})
it('rejects password without symbol', () => {
const r = registerSchema.safeParse({ ...valid, password: 'NoSymbolHere1' })
expect(r.success).toBe(false)
expect(r.error?.errors[0].message).toMatch(/symbol/)
})
it('rejects empty name', () => {
const r = registerSchema.safeParse({ ...valid, name: '' })
expect(r.success).toBe(false)
})
it('rejects name longer than 100 chars', () => {
const r = registerSchema.safeParse({ ...valid, name: 'a'.repeat(101) })
expect(r.success).toBe(false)
})
})
// ─── changePasswordSchema ────────────────────────────────────────────────────
describe('changePasswordSchema', () => {
it('accepts valid passwords', () => {
const r = changePasswordSchema.safeParse({
currentPassword: 'OldPass1!',
newPassword: 'NewStrongPass1!',
})
expect(r.success).toBe(true)
})
it('rejects empty currentPassword', () => {
const r = changePasswordSchema.safeParse({
currentPassword: '',
newPassword: 'NewStrongPass1!',
})
expect(r.success).toBe(false)
})
it('rejects weak newPassword', () => {
const r = changePasswordSchema.safeParse({
currentPassword: 'OldPass1!',
newPassword: 'weak',
})
expect(r.success).toBe(false)
})
})
// ─── productTypeSchema ───────────────────────────────────────────────────────
describe('productTypeSchema', () => {
const valid = { name: 'Abbigliamento', slug: 'abbigliamento', schema: { color: 'string' } }
it('accepts valid product type', () => {
expect(productTypeSchema.safeParse(valid).success).toBe(true)
})
it('rejects slug with uppercase', () => {
const r = productTypeSchema.safeParse({ ...valid, slug: 'Abbigliamento' })
expect(r.success).toBe(false)
})
it('rejects slug with spaces', () => {
const r = productTypeSchema.safeParse({ ...valid, slug: 'con spazio' })
expect(r.success).toBe(false)
})
it('accepts slug with hyphens and numbers', () => {
const r = productTypeSchema.safeParse({ ...valid, slug: 'tipo-123' })
expect(r.success).toBe(true)
})
it('rejects empty name', () => {
expect(productTypeSchema.safeParse({ ...valid, name: '' }).success).toBe(false)
})
})
// ─── productSchema ───────────────────────────────────────────────────────────
describe('productSchema', () => {
const valid = {
typeId: 'type-1',
title: 'Maglietta',
slug: 'maglietta',
description: 'Una bella maglietta',
basePrice: 1999,
currency: 'EUR',
status: 'DRAFT' as const,
attributes: {},
}
it('accepts valid product', () => {
expect(productSchema.safeParse(valid).success).toBe(true)
})
it('rejects negative price', () => {
const r = productSchema.safeParse({ ...valid, basePrice: -1 })
expect(r.success).toBe(false)
})
it('accepts price = 0', () => {
const r = productSchema.safeParse({ ...valid, basePrice: 0 })
expect(r.success).toBe(true)
})
it('rejects currency not 3 chars', () => {
const r = productSchema.safeParse({ ...valid, currency: 'EU' })
expect(r.success).toBe(false)
})
it('rejects invalid status', () => {
const r = productSchema.safeParse({ ...valid, status: 'INVALID' })
expect(r.success).toBe(false)
})
it('accepts all valid statuses', () => {
for (const status of ['DRAFT', 'PUBLISHED', 'ARCHIVED'] as const) {
expect(productSchema.safeParse({ ...valid, status }).success).toBe(true)
}
})
it('accepts optional categoryIds', () => {
const r = productSchema.safeParse({ ...valid, categoryIds: ['cat-1', 'cat-2'] })
expect(r.success).toBe(true)
})
it('rejects non-integer price', () => {
const r = productSchema.safeParse({ ...valid, basePrice: 19.99 })
expect(r.success).toBe(false)
})
})
// ─── categorySchema ──────────────────────────────────────────────────────────
describe('categorySchema', () => {
const valid = { name: 'Uomo', slug: 'uomo' }
it('accepts valid category', () => {
expect(categorySchema.safeParse(valid).success).toBe(true)
})
it('accepts category with parentId', () => {
expect(categorySchema.safeParse({ ...valid, parentId: 'parent-1' }).success).toBe(true)
})
it('accepts parentId = null', () => {
expect(categorySchema.safeParse({ ...valid, parentId: null }).success).toBe(true)
})
it('rejects slug with special chars', () => {
const r = categorySchema.safeParse({ ...valid, slug: 'cat@home' })
expect(r.success).toBe(false)
})
})
// ─── reviewSchema ────────────────────────────────────────────────────────────
describe('reviewSchema', () => {
const valid = { productId: 'prod-1', rating: 4 }
it('accepts valid review', () => {
expect(reviewSchema.safeParse(valid).success).toBe(true)
})
it('rejects rating 0', () => {
expect(reviewSchema.safeParse({ ...valid, rating: 0 }).success).toBe(false)
})
it('rejects rating 6', () => {
expect(reviewSchema.safeParse({ ...valid, rating: 6 }).success).toBe(false)
})
it('accepts all valid ratings 1-5', () => {
for (const rating of [1, 2, 3, 4, 5]) {
expect(reviewSchema.safeParse({ ...valid, rating }).success).toBe(true)
}
})
it('rejects comment longer than 2000 chars', () => {
const r = reviewSchema.safeParse({ ...valid, comment: 'a'.repeat(2001) })
expect(r.success).toBe(false)
})
it('accepts title up to 200 chars', () => {
expect(reviewSchema.safeParse({ ...valid, title: 'a'.repeat(200) }).success).toBe(true)
})
})
// ─── cartItemSchema ──────────────────────────────────────────────────────────
describe('cartItemSchema', () => {
const valid = { productId: 'prod-1', quantity: 2 }
it('accepts valid cart item', () => {
expect(cartItemSchema.safeParse(valid).success).toBe(true)
})
it('rejects quantity 0', () => {
expect(cartItemSchema.safeParse({ ...valid, quantity: 0 }).success).toBe(false)
})
it('rejects quantity over 100', () => {
expect(cartItemSchema.safeParse({ ...valid, quantity: 101 }).success).toBe(false)
})
it('accepts quantity = 100', () => {
expect(cartItemSchema.safeParse({ ...valid, quantity: 100 }).success).toBe(true)
})
it('accepts optional variantId', () => {
expect(cartItemSchema.safeParse({ ...valid, variantId: 'var-1' }).success).toBe(true)
})
})
// ─── checkoutSchema ──────────────────────────────────────────────────────────
describe('checkoutSchema', () => {
const valid = { items: [{ productId: 'prod-1', quantity: 1 }] }
it('accepts valid checkout', () => {
expect(checkoutSchema.safeParse(valid).success).toBe(true)
})
it('rejects empty items array', () => {
const r = checkoutSchema.safeParse({ items: [] })
expect(r.success).toBe(false)
expect(r.error?.errors[0].message).toBe('Cart is empty')
})
it('accepts multiple items', () => {
const r = checkoutSchema.safeParse({
items: [
{ productId: 'prod-1', quantity: 2 },
{ productId: 'prod-2', quantity: 1 },
],
})
expect(r.success).toBe(true)
})
})
// ─── settingSchema ───────────────────────────────────────────────────────────
describe('settingSchema', () => {
it('accepts valid setting', () => {
expect(settingSchema.safeParse({ key: 'site_name', value: 'My Shop' }).success).toBe(true)
})
it('rejects empty key', () => {
expect(settingSchema.safeParse({ key: '', value: 'anything' }).success).toBe(false)
})
it('accepts any value type', () => {
for (const value of ['string', 42, true, null, { nested: true }]) {
expect(settingSchema.safeParse({ key: 'k', value }).success).toBe(true)
}
})
})