feat: add eslint, image upload, tests, splash tagline, security hooks
- Restore CLAUDE.md with project conventions - ESLint config with vue3-recommended + typescript - Image upload endpoint (POST /api/admin/upload) with 5MB limit - Admin product form now supports image upload/preview/removal - Vitest config + 19 tests (crypto, validation, btcpay webhook, types) - Restore .claude/ security hooks (block-risky-bash, protect-files) - Logo splash now shows "EVERYTHING YOU LOVE IS A PSYOP" tagline - Add .vite/ to gitignore Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
52
tests/shared/types.test.ts
Normal file
52
tests/shared/types.test.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import type { Product, Order, CartItem, OrderStatus, SizeStock } from '@shared/types'
|
||||
|
||||
describe('shared types', () => {
|
||||
it('Product type enforces integer sats', () => {
|
||||
const product: Product = {
|
||||
id: 'test-1',
|
||||
name: 'Test Product',
|
||||
slug: 'test-product',
|
||||
description: 'A test product',
|
||||
priceSats: 100_000,
|
||||
images: ['/images/test.jpg'],
|
||||
sizes: [{ size: 'M', stock: 10 }],
|
||||
category: 'tops',
|
||||
isActive: true,
|
||||
createdAt: '2026-01-01T00:00:00Z',
|
||||
updatedAt: '2026-01-01T00:00:00Z',
|
||||
}
|
||||
expect(product.priceSats).toBe(100_000)
|
||||
expect(Number.isInteger(product.priceSats)).toBe(true)
|
||||
})
|
||||
|
||||
it('CartItem calculates correctly with integer sats', () => {
|
||||
const item: CartItem = {
|
||||
productId: 'test-1',
|
||||
slug: 'test-product',
|
||||
name: 'Test Product',
|
||||
size: 'M',
|
||||
quantity: 3,
|
||||
priceSats: 85_000,
|
||||
image: '/images/test.jpg',
|
||||
}
|
||||
const total = item.priceSats * item.quantity
|
||||
expect(total).toBe(255_000)
|
||||
expect(Number.isInteger(total)).toBe(true)
|
||||
})
|
||||
|
||||
it('OrderStatus has valid values', () => {
|
||||
const statuses: OrderStatus[] = ['pending', 'paid', 'confirmed', 'shipped', 'delivered', 'cancelled']
|
||||
expect(statuses).toHaveLength(6)
|
||||
})
|
||||
|
||||
it('SizeStock tracks integer stock levels', () => {
|
||||
const sizes: SizeStock[] = [
|
||||
{ size: 'S', stock: 10 },
|
||||
{ size: 'M', stock: 0 },
|
||||
]
|
||||
const totalStock = sizes.reduce((sum, s) => sum + s.stock, 0)
|
||||
expect(totalStock).toBe(10)
|
||||
expect(sizes[1].stock).toBe(0)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user