/** * DC-105: Wizard endpoint tests */ const express = require('express'); const request = require('supertest'); function createApp(templates) { const app = express(); app.use(express.json()); const wizardRoutes = require('../../routes/wizard'); const wrap = (fn) => (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next); app.use('/api/v1', wizardRoutes({ APP_TEMPLATES: templates || [], asyncHandler: wrap })); return app; } describe('DC-105: Smart Defaults Wizard', () => { it('GET /categories returns 6 categories', async () => { const app = createApp(); const res = await request(app).get('/api/v1/wizard/categories'); expect(res.status).toBe(200); expect(res.body.success).toBe(true); expect(res.body.categories).toHaveLength(6); expect(res.body.categories[0]).toHaveProperty('id'); expect(res.body.categories[0]).toHaveProperty('label'); expect(res.body.categories[0]).toHaveProperty('icon'); }); it('POST /recommend returns services for media-streaming', async () => { const app = createApp([ { id: 'plex', name: 'Plex', image: 'plexinc/pms-docker', ports: [32400] }, { id: 'sonarr', name: 'Sonarr', image: 'lscr.io/linuxserver/sonarr', ports: [8989] }, ]); const res = await request(app) .post('/api/v1/wizard/recommend') .send({ categories: ['media-streaming'], hardwareProfile: 'medium' }); expect(res.status).toBe(200); expect(res.body.totalRecommended).toBeGreaterThan(0); expect(res.body.services[0].template).toBe('plex'); expect(res.body.services[0].available).toBe(true); }); it('POST /recommend returns 400 without categories', async () => { const app = createApp(); const res = await request(app) .post('/api/v1/wizard/recommend') .send({ categories: [] }); expect(res.status).toBe(400); }); it('POST /recommend limits services by hardware profile', async () => { const app = createApp(); const res = await request(app) .post('/api/v1/wizard/recommend') .send({ categories: ['media-streaming', 'development', 'monitoring'], hardwareProfile: 'minimal' }); expect(res.status).toBe(200); expect(res.body.totalRecommended).toBeLessThanOrEqual(3); }); it('POST /apply returns deployment plan', async () => { const app = createApp(); const res = await request(app) .post('/api/v1/wizard/apply') .send({ services: ['plex', 'sonarr'], subdomainPrefix: 'sami-' }); expect(res.status).toBe(200); expect(res.body.totalSteps).toBe(2); expect(res.body.plan[0].subdomain).toBe('sami-plex'); }); it('POST /apply returns 400 without services', async () => { const app = createApp(); const res = await request(app) .post('/api/v1/wizard/apply') .send({ services: [] }); expect(res.status).toBe(400); }); });