test: add vitest test infrastructure and configuration
- Add vitest.config.ts with coverage thresholds - Add test/setup.ts with testing-library setup - Add test/helpers.ts with test utilities
This commit is contained in:
157
admin-web/test/helpers.ts
Normal file
157
admin-web/test/helpers.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL
|
||||
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
|
||||
|
||||
// Create test client with service role for admin access (only if credentials exist)
|
||||
export const testSupabase = supabaseUrl && supabaseKey
|
||||
? createClient(
|
||||
supabaseUrl,
|
||||
supabaseKey,
|
||||
{
|
||||
auth: {
|
||||
autoRefreshToken: false,
|
||||
persistSession: false,
|
||||
},
|
||||
}
|
||||
)
|
||||
: null
|
||||
|
||||
// Test data generators
|
||||
export function generateTestTrainer(overrides = {}) {
|
||||
return {
|
||||
name: `Test Trainer ${Date.now()}`,
|
||||
specialty: 'Test Specialty',
|
||||
color: '#FF6B35',
|
||||
...overrides,
|
||||
}
|
||||
}
|
||||
|
||||
export function generateTestWorkout(overrides = {}) {
|
||||
return {
|
||||
title: `Test Workout ${Date.now()}`,
|
||||
category: 'full-body' as const,
|
||||
level: 'Beginner' as const,
|
||||
duration: 4,
|
||||
calories: 45,
|
||||
rounds: 8,
|
||||
prep_time: 10,
|
||||
work_time: 20,
|
||||
rest_time: 10,
|
||||
equipment: [],
|
||||
music_vibe: 'electronic' as const,
|
||||
exercises: [{ name: 'Test Exercise', duration: 20 }],
|
||||
is_featured: false,
|
||||
...overrides,
|
||||
}
|
||||
}
|
||||
|
||||
// Database cleanup helpers
|
||||
export async function cleanupTestData() {
|
||||
if (!testSupabase) {
|
||||
console.warn('⚠️ No test database configured, skipping cleanup')
|
||||
return
|
||||
}
|
||||
|
||||
// Delete test workouts (with timestamps to avoid deleting real data)
|
||||
const { error: workoutsError } = await testSupabase
|
||||
.from('workouts')
|
||||
.delete()
|
||||
.ilike('title', 'Test Workout%')
|
||||
|
||||
if (workoutsError) {
|
||||
console.error('Failed to cleanup test workouts:', workoutsError)
|
||||
}
|
||||
|
||||
// Delete test trainers
|
||||
const { error: trainersError } = await testSupabase
|
||||
.from('trainers')
|
||||
.delete()
|
||||
.ilike('name', 'Test Trainer%')
|
||||
|
||||
if (trainersError) {
|
||||
console.error('Failed to cleanup test trainers:', trainersError)
|
||||
}
|
||||
|
||||
// Delete test collections
|
||||
const { error: collectionsError } = await testSupabase
|
||||
.from('collections')
|
||||
.delete()
|
||||
.ilike('title', 'Test Collection%')
|
||||
|
||||
if (collectionsError) {
|
||||
console.error('Failed to cleanup test collections:', collectionsError)
|
||||
}
|
||||
}
|
||||
|
||||
// Setup test trainer
|
||||
export async function createTestTrainer(overrides = {}) {
|
||||
if (!testSupabase) {
|
||||
throw new Error('Test database not configured')
|
||||
}
|
||||
|
||||
const trainer = generateTestTrainer(overrides)
|
||||
const { data, error } = await testSupabase
|
||||
.from('trainers')
|
||||
.insert(trainer)
|
||||
.select()
|
||||
.single()
|
||||
|
||||
if (error) {
|
||||
throw new Error(`Failed to create test trainer: ${error.message}`)
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// Setup test workout
|
||||
export async function createTestWorkout(trainerId: string, overrides = {}) {
|
||||
if (!testSupabase) {
|
||||
throw new Error('Test database not configured')
|
||||
}
|
||||
|
||||
const workout = generateTestWorkout(overrides)
|
||||
const { data, error } = await testSupabase
|
||||
.from('workouts')
|
||||
.insert({ ...workout, trainer_id: trainerId })
|
||||
.select()
|
||||
.single()
|
||||
|
||||
if (error) {
|
||||
throw new Error(`Failed to create test workout: ${error.message}`)
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// Delete specific workout
|
||||
export async function deleteWorkout(id: string) {
|
||||
if (!testSupabase) {
|
||||
throw new Error('Test database not configured')
|
||||
}
|
||||
|
||||
const { error } = await testSupabase
|
||||
.from('workouts')
|
||||
.delete()
|
||||
.eq('id', id)
|
||||
|
||||
if (error) {
|
||||
throw new Error(`Failed to delete workout: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
// Delete specific trainer
|
||||
export async function deleteTrainer(id: string) {
|
||||
if (!testSupabase) {
|
||||
throw new Error('Test database not configured')
|
||||
}
|
||||
|
||||
const { error } = await testSupabase
|
||||
.from('trainers')
|
||||
.delete()
|
||||
.eq('id', id)
|
||||
|
||||
if (error) {
|
||||
throw new Error(`Failed to delete trainer: ${error.message}`)
|
||||
}
|
||||
}
|
||||
59
admin-web/test/setup.ts
Normal file
59
admin-web/test/setup.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import '@testing-library/jest-dom'
|
||||
import { vi, beforeAll, afterAll, beforeEach } from 'vitest'
|
||||
|
||||
// Check if we have test database credentials
|
||||
const hasTestDb = process.env.NEXT_PUBLIC_SUPABASE_URL &&
|
||||
(process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY)
|
||||
|
||||
// Global test setup
|
||||
beforeAll(async () => {
|
||||
if (hasTestDb) {
|
||||
console.log('🧪 Setting up test environment with real database...')
|
||||
const testUrl = process.env.NEXT_PUBLIC_SUPABASE_URL
|
||||
if (!testUrl?.includes('test') && !testUrl?.includes('localhost')) {
|
||||
console.warn('⚠️ WARNING: Not using a test database!')
|
||||
console.warn('Current URL:', testUrl)
|
||||
}
|
||||
} else {
|
||||
console.log('🧪 Running tests with mocked database...')
|
||||
}
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
// Cleanup before each test to ensure isolation (only if we have real DB)
|
||||
if (hasTestDb) {
|
||||
try {
|
||||
const { cleanupTestData } = await import('./helpers')
|
||||
await cleanupTestData()
|
||||
} catch (e) {
|
||||
// Silently ignore if helpers not available
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
if (hasTestDb) {
|
||||
console.log('🧹 Cleaning up test environment...')
|
||||
try {
|
||||
const { cleanupTestData } = await import('./helpers')
|
||||
await cleanupTestData()
|
||||
} catch (e) {
|
||||
// Silently ignore if helpers not available
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Mock Supabase client for component tests that don't need real DB
|
||||
vi.mock('@/lib/supabase', () => ({
|
||||
supabase: {
|
||||
storage: {
|
||||
from: vi.fn(() => ({
|
||||
upload: vi.fn(),
|
||||
remove: vi.fn(),
|
||||
move: vi.fn(),
|
||||
list: vi.fn(),
|
||||
getPublicUrl: vi.fn(() => ({ data: { publicUrl: 'https://example.com/test.jpg' } })),
|
||||
})),
|
||||
},
|
||||
},
|
||||
}))
|
||||
Reference in New Issue
Block a user