import request from 'supertest'; import nock from 'nock'; import { app } from '../../src/app'; import { prisma } from '../../src/db/prisma'; import { resetDatabase } from '../setup/resetDatabase'; import { bearer, mockKeycloakJwks } from '../setup/authTestHelper'; const AUTORE = { sub: 'user-movio', email: 'movio@example.com', name: 'Movio' }; const ALTRO_AUTORE = { sub: 'user-altro', email: 'altro@example.com', name: 'Altro Utente' }; const AUTH_HEADER = bearer(AUTORE); const ALTRO_AUTH_HEADER = bearer(ALTRO_AUTORE); function attivitaPayload(overrides: Record = {}) { return { nome: 'Caccia al tesoro', stato: { id: 'BO', nome: 'Bozza' }, brancaList: [{ nome: 'E/G' }], categoriaList: [{ nome: 'grande gioco' }], materialeList: [], periodoAnnoList: [], paragrafoList: [{ corpo: 'Introduzione al gioco', tipo: { id: 'PARAGRAFO' }, ordine: 1 }], ...overrides, }; } beforeAll(() => { mockKeycloakJwks(); }); afterAll(() => { nock.cleanAll(); }); beforeEach(async () => { await resetDatabase(); }); afterEach(async () => { await resetDatabase(); }); describe('attivita endpoints', () => { test('GET /health risponde 200 con { status: "ok" }', async () => { const res = await request(app).get('/health'); expect(res.status).toBe(200); expect(res.body).toEqual({ status: 'ok' }); }); test('GET /public/attivita/get/lista/home su DB vuoto restituisce []', async () => { const res = await request(app).get('/public/attivita/get/lista/home'); expect(res.status).toBe(200); expect(res.body).toEqual([]); }); test('GET /public/attivita/get/one/:id con id non numerico restituisce 400', async () => { const res = await request(app).get('/public/attivita/get/one/abc'); expect(res.status).toBe(400); }); test('GET /public/attivita/get/one/:id con id inesistente restituisce 404', async () => { const res = await request(app).get('/public/attivita/get/one/999999'); expect(res.status).toBe(404); }); test('endpoint privati senza token restituiscono 401', async () => { const saveRes = await request(app).post('/private/attivita/save').send(attivitaPayload()); expect(saveRes.status).toBe(401); const myRes = await request(app).get('/private/attivita/get/lista/my'); expect(myRes.status).toBe(401); const changeRes = await request(app).get('/private/attivita/change/stato/1/PU'); expect(changeRes.status).toBe(401); }); test('POST /private/attivita/save senza nome restituisce 400 con informazioni di validazione', async () => { const { nome, ...payloadSenzaNome } = attivitaPayload(); const res = await request(app) .post('/private/attivita/save') .set('Authorization', AUTH_HEADER) .send(payloadSenzaNome); expect(res.status).toBe(400); expect(typeof res.body.message).toBe('string'); expect(res.body.message.length).toBeGreaterThan(0); expect(res.body.message).toContain('nome'); }); test("POST /private/attivita/save con payload valido crea l'attività, visibile poi via get/lista/my", async () => { const saveRes = await request(app) .post('/private/attivita/save') .set('Authorization', AUTH_HEADER) .send(attivitaPayload()); expect([200, 204]).toContain(saveRes.status); const myRes = await request(app) .get('/private/attivita/get/lista/my') .set('Authorization', AUTH_HEADER); expect(myRes.status).toBe(200); expect(myRes.body).toHaveLength(1); expect(myRes.body[0]).toMatchObject({ nome: 'Caccia al tesoro', autore: 'Movio' }); expect(myRes.body[0].brancaList.map((b: { nome: string }) => b.nome)).toEqual(['E/G']); expect(myRes.body[0].categoriaList.map((c: { nome: string }) => c.nome)).toEqual([ 'grande gioco', ]); }); test('get/lista/my non restituisce le attività di un altro autore', async () => { await request(app).post('/private/attivita/save').set('Authorization', AUTH_HEADER).send(attivitaPayload()); const myRes = await request(app) .get('/private/attivita/get/lista/my') .set('Authorization', ALTRO_AUTH_HEADER); expect(myRes.status).toBe(200); expect(myRes.body).toEqual([]); }); test("POST /private/attivita/save su un'attività di un altro autore restituisce 403", async () => { await request(app).post('/private/attivita/save').set('Authorization', AUTH_HEADER).send(attivitaPayload()); const created = await prisma.attivita.findFirstOrThrow(); const res = await request(app) .post('/private/attivita/save') .set('Authorization', ALTRO_AUTH_HEADER) .send(attivitaPayload({ id: created.id, nome: 'Modificata da altri' })); expect(res.status).toBe(403); }); test("change/stato aggiorna lo stato e rende visibile l'attività in home", async () => { await request(app).post('/private/attivita/save').set('Authorization', AUTH_HEADER).send(attivitaPayload()); const created = await prisma.attivita.findFirstOrThrow(); const changeRes = await request(app) .get(`/private/attivita/change/stato/${created.id}/PU`) .set('Authorization', AUTH_HEADER); expect(changeRes.status).toBe(200); expect(changeRes.body).toEqual({ id: 'PU', nome: 'Pubblicato' }); const homeRes = await request(app).get('/public/attivita/get/lista/home'); expect(homeRes.status).toBe(200); expect(homeRes.body.map((a: { id: number }) => a.id)).toContain(created.id); }); test('change/stato su id inesistente restituisce 404', async () => { const res = await request(app) .get('/private/attivita/change/stato/999999/PU') .set('Authorization', AUTH_HEADER); expect(res.status).toBe(404); }); test("change/stato su un'attività di un altro autore restituisce 403", async () => { await request(app).post('/private/attivita/save').set('Authorization', AUTH_HEADER).send(attivitaPayload()); const created = await prisma.attivita.findFirstOrThrow(); const res = await request(app) .get(`/private/attivita/change/stato/${created.id}/PU`) .set('Authorization', ALTRO_AUTH_HEADER); expect(res.status).toBe(403); }); test('CORS: risponde con Access-Control-Allow-Origin per un Origin autorizzato', async () => { const res = await request(app).get('/health').set('Origin', 'http://localhost:4200'); expect(res.headers['access-control-allow-origin']).toBe('http://localhost:4200'); }); test('POST /public/attivita/get/lista/search con [] restituisce tutte le attività presenti', async () => { await request(app) .post('/private/attivita/save') .set('Authorization', AUTH_HEADER) .send(attivitaPayload({ nome: 'Prima' })); await request(app) .post('/private/attivita/save') .set('Authorization', AUTH_HEADER) .send(attivitaPayload({ nome: 'Seconda', stato: { id: 'PU', nome: 'Pubblicato' } })); const res = await request(app).post('/public/attivita/get/lista/search').send([]); expect(res.status).toBe(200); expect(res.body).toHaveLength(2); expect(res.body.map((a: { nome: string }) => a.nome).sort()).toEqual(['Prima', 'Seconda']); }); });