124 lines
3.6 KiB
TypeScript
124 lines
3.6 KiB
TypeScript
/**
|
|
* Example unit tests with automatic Zod validation
|
|
* Uses hypermodern approach where validation happens automatically
|
|
*/
|
|
|
|
import { describe, it, expect } from 'vitest'
|
|
import { mount } from '@vue/test-utils'
|
|
import App from '@/App.vue'
|
|
import { AutoValidator, type Playlist, type User } from '@/validation'
|
|
|
|
/**
|
|
* Creates a playlist - validation happens automatically in development/test mode
|
|
* @param name - Playlist name
|
|
* @param description - Optional description
|
|
* @returns Playlist object (automatically validated)
|
|
*/
|
|
function createPlaylist(name: string, description?: string): Playlist {
|
|
const rawData = {
|
|
id: crypto.randomUUID(),
|
|
name,
|
|
description,
|
|
tracks: []
|
|
}
|
|
|
|
// In hypermodern setup, this would be handled by build-time transform
|
|
// For now, we use our auto-validator
|
|
return AutoValidator.validate<Playlist>('Playlist', rawData)
|
|
}
|
|
|
|
/**
|
|
* Simulates API response handling with automatic validation
|
|
* @param apiResponse - Raw API data
|
|
* @returns Validated user object
|
|
*/
|
|
function handleUserApiResponse(apiResponse: unknown): User {
|
|
// Validation happens automatically - no explicit .parse() needed
|
|
return AutoValidator.validate<User>('User', apiResponse)
|
|
}
|
|
|
|
describe('App.vue', () => {
|
|
it('renders properly', () => {
|
|
const wrapper = mount(App)
|
|
expect(wrapper.text()).toContain('Plex Playlist')
|
|
})
|
|
})
|
|
|
|
describe('Automatic Zod validation (hypermodern approach)', () => {
|
|
it('validates playlist creation automatically', () => {
|
|
const playlist = createPlaylist('Test Playlist', 'Test description')
|
|
|
|
expect(playlist.name).toBe('Test Playlist')
|
|
expect(playlist.description).toBe('Test description')
|
|
expect(playlist.tracks).toEqual([])
|
|
expect(playlist.id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)
|
|
})
|
|
|
|
it('creates playlist without description automatically', () => {
|
|
const playlist = createPlaylist('Simple Playlist')
|
|
|
|
expect(playlist.name).toBe('Simple Playlist')
|
|
expect(playlist.description).toBeUndefined()
|
|
expect(playlist.tracks).toEqual([])
|
|
})
|
|
|
|
it('automatically validates API responses', () => {
|
|
const apiResponse = {
|
|
id: 123,
|
|
username: 'testuser',
|
|
email: 'test@example.com',
|
|
preferences: {
|
|
theme: 'dark',
|
|
notifications: false
|
|
}
|
|
}
|
|
|
|
const user = handleUserApiResponse(apiResponse)
|
|
expect(user.username).toBe('testuser')
|
|
expect(user.preferences.theme).toBe('dark')
|
|
})
|
|
|
|
it('automatically catches validation errors', () => {
|
|
const invalidPlaylistData = {
|
|
id: 'not-a-uuid', // Invalid UUID
|
|
name: '', // Empty name
|
|
tracks: 'invalid' // Should be array
|
|
}
|
|
|
|
expect(() => {
|
|
AutoValidator.validate<Playlist>('Playlist', invalidPlaylistData)
|
|
}).toThrow()
|
|
})
|
|
|
|
it('provides safe validation with error handling', () => {
|
|
const malformedData = {
|
|
id: 'not-a-uuid',
|
|
description: 'Missing name field'
|
|
}
|
|
|
|
const result = AutoValidator.safeValidate<Playlist>('Playlist', malformedData)
|
|
|
|
expect(result.success).toBe(false)
|
|
if (!result.success) {
|
|
expect(result.error.issues).toBeDefined()
|
|
expect(result.error.issues.length).toBeGreaterThan(0)
|
|
}
|
|
})
|
|
|
|
it('handles successful safe validation', () => {
|
|
const validData = {
|
|
id: crypto.randomUUID(),
|
|
name: 'Valid Playlist',
|
|
tracks: ['track1', 'track2']
|
|
}
|
|
|
|
const result = AutoValidator.safeValidate<Playlist>('Playlist', validData)
|
|
|
|
expect(result.success).toBe(true)
|
|
if (result.success) {
|
|
expect(result.data.name).toBe('Valid Playlist')
|
|
expect(result.data.tracks).toEqual(['track1', 'track2'])
|
|
}
|
|
})
|
|
})
|