import type { INestApplication } from '@nestjs/common'; import request from 'supertest'; import { createTestApp, employee } from './support/create-test-app.js'; describe('Permisos de menú (e2e)', () => { let app: INestApplication; let admin: { Authorization: string }; let luis: { Authorization: string }; const loginAs = async (username: string) => { const res = await request(app.getHttpServer()).post('/api/auth/login').send({ username, password: 'secreto' }).expect(200); return { Authorization: `Bearer ${res.body.token}` }; }; beforeEach(async () => { app = await createTestApp([employee('ana', 1), employee('luis', 2)], 'ana'); admin = await loginAs('ana'); }); afterEach(async () => { await app.close(); }); it('el administrador del .env obtiene "*" al arrancar', async () => { const res = await request(app.getHttpServer()).get('/api/user/menu').set(admin).expect(200); expect(res.body).toEqual({ allowedPaths: ['*'] }); }); it('un usuario sin permisos recibe menú vacío', async () => { luis = await loginAs('luis'); const res = await request(app.getHttpServer()).get('/api/user/menu').set(luis).expect(200); expect(res.body.allowedPaths).toEqual([]); }); it('el admin asigna permisos y el usuario los ve; un no-admin no puede administrar', async () => { await request(app.getHttpServer()) .put('/api/permissions/luis') .set(admin) .send({ paths: ['/ventas/*', '/inventario/articulos', '/ventas/*'] }) .expect(200) .expect({ webUser: 'luis', paths: ['/inventario/articulos', '/ventas/*'] }); luis = await loginAs('luis'); const menu = await request(app.getHttpServer()).get('/api/user/menu').set(luis).expect(200); expect(menu.body.allowedPaths).toEqual(['/inventario/articulos', '/ventas/*']); await request(app.getHttpServer()).get('/api/permissions').set(luis).expect(403); await request(app.getHttpServer()).put('/api/permissions/luis').set(luis).send({ paths: ['*'] }).expect(403); }); it('PUT reemplaza, GET lista y DELETE elimina', async () => { await request(app.getHttpServer()).put('/api/permissions/luis').set(admin).send({ paths: ['/ventas/*'] }).expect(200); await request(app.getHttpServer()).put('/api/permissions/luis').set(admin).send({ paths: ['/compras/*'] }).expect(200); const list = await request(app.getHttpServer()).get('/api/permissions').set(admin).expect(200); expect(list.body).toEqual([ { webUser: 'ana', paths: ['*'] }, { webUser: 'luis', paths: ['/compras/*'] }, ]); await request(app.getHttpServer()).delete('/api/permissions/luis').set(admin).expect(204); const one = await request(app.getHttpServer()).get('/api/permissions/luis').set(admin).expect(200); expect(one.body.paths).toEqual([]); }); it('rechaza patrones inválidos', async () => { for (const bad of ['ventas', '/ventas/', '/ventas/*/x', '/a b', '**', '']) { await request(app.getHttpServer()).put('/api/permissions/luis').set(admin).send({ paths: [bad] }).expect(400); } await request(app.getHttpServer()).put('/api/permissions/luis').set(admin).send({}).expect(400); }); it('no permite quitar el acceso total al último administrador', async () => { await request(app.getHttpServer()).put('/api/permissions/ana').set(admin).send({ paths: ['/ventas/*'] }).expect(409); await request(app.getHttpServer()).delete('/api/permissions/ana').set(admin).expect(409); // con un segundo administrador, ana sí puede dejar de serlo await request(app.getHttpServer()).put('/api/permissions/luis').set(admin).send({ paths: ['*'] }).expect(200); await request(app.getHttpServer()).put('/api/permissions/ana').set(admin).send({ paths: ['/ventas/*'] }).expect(200); }); it('sin sesión no se accede al menú ni a la administración', async () => { await request(app.getHttpServer()).get('/api/user/menu').expect(401); await request(app.getHttpServer()).get('/api/permissions').expect(401); }); });