import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import request from 'supertest'; import express from 'express'; import cors from 'cors'; import knex from 'knex'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; import { Router } from 'express'; import { registerToken, authMiddleware } from '../middleware/auth.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); let app; let db; const TEST_TOKEN = 'test-token-12345'; function createCVRoutes(db) { const router = Router(); router.get('/', async (req, res) => { try { const row = await db('cv_data').where({ id: 1 }).first(); if (!row) { return res.status(404).json({ error: 'CV data not found' }); } res.json(JSON.parse(row.data)); } catch (error) { console.error('Error fetching CV:', error); res.status(500).json({ error: 'Failed to fetch CV data' }); } }); router.put('/', authMiddleware, async (req, res) => { try { const data = req.body; if (!data || typeof data !== 'object') { return res.status(400).json({ error: 'Invalid CV data' }); } if (!data.personal?.name) { return res.status(400).json({ error: 'personal.name is required' }); } await db('cv_data').where({ id: 1 }).update({ data: JSON.stringify(data), updated_at: db.fn.now() }); res.json({ success: true, message: 'CV data updated' }); } catch (error) { console.error('Error updating CV:', error); res.status(500).json({ error: 'Failed to update CV data' }); } }); router.get('/export', async (req, res) => { try { const row = await db('cv_data').where({ id: 1 }).first(); if (!row) { return res.status(404).json({ error: 'CV data not found' }); } res.setHeader('Content-Type', 'application/json'); res.setHeader('Content-Disposition', 'attachment; filename="cv.json"'); res.send(row.data); } catch (error) { console.error('Error exporting CV:', error); res.status(500).json({ error: 'Failed to export CV data' }); } }); return router; } beforeAll(async () => { const testDbPath = join(__dirname, 'test.db'); db = knex({ client: 'better-sqlite3', connection: { filename: testDbPath }, useNullAsDefault: true }); await db.schema.dropTableIfExists('cv_data'); await db.schema.createTable('cv_data', (table) => { table.increments('id').primary(); table.text('data').notNullable(); table.datetime('updated_at').defaultTo(db.fn.now()); }); const defaultData = { personal: { name: 'Test User', title: 'Developer', email: 'test@test.com' }, experience: [], skills: {}, education: [], projects: [] }; await db('cv_data').insert({ id: 1, data: JSON.stringify(defaultData) }); registerToken(TEST_TOKEN); app = express(); app.use(cors()); app.use(express.json()); app.use('/api/cv', createCVRoutes(db)); }); afterAll(async () => { if (db) { await db.destroy(); } }); describe('CV API', () => { it('GET /api/cv returns CV data', async () => { const response = await request(app).get('/api/cv'); expect(response.status).toBe(200); expect(response.body.personal.name).toBe('Test User'); }); it('PUT /api/cv updates CV data', async () => { const response = await request(app) .put('/api/cv') .set('Authorization', `Bearer ${TEST_TOKEN}`) .send({ personal: { name: 'Updated Name', title: 'Dev', email: 'test@test.com' }, experience: [], skills: {}, education: [], projects: [] }); expect(response.status).toBe(200); expect(response.body.success).toBe(true); const getResponse = await request(app).get('/api/cv'); expect(getResponse.body.personal.name).toBe('Updated Name'); }); it('PUT /api/cv validates required fields', async () => { const response = await request(app) .put('/api/cv') .set('Authorization', `Bearer ${TEST_TOKEN}`) .send({ personal: {} }); expect(response.status).toBe(400); expect(response.body.error).toContain('name is required'); }); it('PUT /api/cv requires authentication', async () => { const response = await request(app) .put('/api/cv') .send({ personal: { name: 'Test', title: 'Dev', email: 'test@test.com' }, experience: [], skills: {}, education: [], projects: [] }); expect(response.status).toBe(401); }); it('GET /api/cv/export returns JSON file', async () => { const response = await request(app).get('/api/cv/export'); expect(response.status).toBe(200); expect(response.headers['content-type']).toContain('application/json'); const data = JSON.parse(response.text); expect(data.personal).toBeDefined(); }); });