united-tattoo/__tests__/lib/data-migration.test.ts

145 lines
4.2 KiB
TypeScript

import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'
// Mock the database using proper Vitest patterns
const mockStmt = {
bind: vi.fn().mockReturnThis(),
run: vi.fn().mockResolvedValue({ success: true, changes: 1 }),
get: vi.fn(),
all: vi.fn().mockResolvedValue({ results: [] }),
first: vi.fn().mockResolvedValue(null),
}
const mockDB = {
prepare: vi.fn().mockReturnValue(mockStmt),
exec: vi.fn(),
}
// Mock the entire lib/db module
vi.mock('@/lib/db', () => ({
getDB: vi.fn(() => mockDB),
}))
// Mock the artists data with proper structure
vi.mock('@/data/artists', () => ({
artists: [
{
id: '1',
name: 'Test Artist',
bio: 'Test bio',
styles: ['Traditional', 'Realism'],
instagram: 'https://instagram.com/testartist',
experience: '5 years',
workImages: ['/test-image.jpg'],
faceImage: '/test-face.jpg',
},
{
id: '2',
name: 'Another Artist',
bio: 'Another bio',
styles: ['Japanese', 'Blackwork'],
instagram: 'https://instagram.com/anotherartist',
experience: '8 years',
workImages: [],
faceImage: '/another-face.jpg',
},
],
}))
describe('DataMigrator', () => {
let DataMigrator: any
let migrator: any
beforeEach(async () => {
vi.clearAllMocks()
// Reset mock implementations
mockDB.prepare.mockReturnValue(mockStmt)
mockStmt.first.mockResolvedValue(null)
mockStmt.run.mockResolvedValue({ success: true, changes: 1 })
// Import the DataMigrator class after mocks are set up
const module = await import('@/lib/data-migration')
DataMigrator = module.DataMigrator
migrator = new DataMigrator()
})
afterEach(() => {
vi.resetAllMocks()
})
describe('isMigrationCompleted', () => {
it('should return false when no artists exist', async () => {
mockStmt.first.mockResolvedValueOnce({ count: 0 })
const isCompleted = await migrator.isMigrationCompleted()
expect(isCompleted).toBe(false)
})
it('should return true when artists exist', async () => {
mockStmt.first.mockResolvedValueOnce({ count: 2 })
const isCompleted = await migrator.isMigrationCompleted()
expect(isCompleted).toBe(true)
})
})
describe('migrateArtistData', () => {
it('should migrate all artists successfully', async () => {
await migrator.migrateArtistData()
// Verify user creation calls
expect(mockDB.prepare).toHaveBeenCalledWith(
expect.stringContaining('INSERT OR IGNORE INTO users')
)
// Verify artist creation calls
expect(mockDB.prepare).toHaveBeenCalledWith(
expect.stringContaining('INSERT OR IGNORE INTO artists')
)
// Verify portfolio image creation calls
expect(mockDB.prepare).toHaveBeenCalledWith(
expect.stringContaining('INSERT OR IGNORE INTO portfolio_images')
)
})
it('should handle errors gracefully', async () => {
mockStmt.run.mockRejectedValueOnce(new Error('Database error'))
await expect(migrator.migrateArtistData()).rejects.toThrow('Database error')
})
})
describe('clearMigratedData', () => {
it('should clear all data successfully', async () => {
await migrator.clearMigratedData()
expect(mockDB.prepare).toHaveBeenCalledWith('DELETE FROM portfolio_images')
expect(mockDB.prepare).toHaveBeenCalledWith('DELETE FROM artists')
expect(mockDB.prepare).toHaveBeenCalledWith('DELETE FROM users WHERE role = "ARTIST"')
})
it('should handle clear data errors', async () => {
mockStmt.run.mockRejectedValueOnce(new Error('Clear error'))
await expect(migrator.clearMigratedData()).rejects.toThrow('Clear error')
})
})
describe('getMigrationStats', () => {
it('should return correct migration statistics', async () => {
mockStmt.first
.mockResolvedValueOnce({ count: 3 }) // total users
.mockResolvedValueOnce({ count: 2 }) // total artists
.mockResolvedValueOnce({ count: 1 }) // total portfolio images
const stats = await migrator.getMigrationStats()
expect(stats.totalUsers).toBe(3)
expect(stats.totalArtists).toBe(2)
expect(stats.totalPortfolioImages).toBe(1)
})
})
})