import { provideHttpClient } from '@angular/common/http'; import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing'; import { type ComponentFixture, TestBed } from '@angular/core/testing'; import { beforeEach, describe, expect, it } from 'vitest'; import { SessionStore } from '../../core/auth/session.store'; import { PermissionsPage } from './permissions.page'; describe('PermissionsPage', () => { let fixture: ComponentFixture; let ctrl: HttpTestingController; const el = () => fixture.nativeElement as HTMLElement; const tick = async () => { fixture.detectChanges(); await new Promise((r) => setTimeout(r)); fixture.detectChanges(); }; const click = async (selector: string, index = 0) => { (el().querySelectorAll(selector)[index] as HTMLElement).click(); await tick(); }; const byText = (selector: string, text: string) => [...el().querySelectorAll(selector)].find((e) => e.textContent?.trim().startsWith(text))!; beforeEach(async () => { await TestBed.configureTestingModule({ imports: [PermissionsPage], providers: [provideHttpClient(), provideHttpClientTesting()], }).compileComponents(); TestBed.inject(SessionStore); // sin sesión: solo necesitamos que exista ctrl = TestBed.inject(HttpTestingController); fixture = TestBed.createComponent(PermissionsPage); await tick(); ctrl.expectOne('/api/permissions').flush([ { webUser: 'ana', paths: ['/ventas/*', '/socios/clientes'] }, { webUser: 'luis', paths: ['*'] }, ]); await tick(); }); it('lista los usuarios con permisos', () => { expect([...el().querySelectorAll('.users li button')].map((b) => b.textContent?.trim())).toEqual(['ana', 'luis']); }); it('al elegir un usuario marca sus pantallas (el módulo completo por /ventas/*)', async () => { await click('.users li button', 0); const checked = [...el().querySelectorAll('fieldset .items input')].filter((i) => i.checked); expect(checked.length).toBe(10); // 9 de ventas + Clientes expect(el().querySelector('.actions .main')!.disabled).toBe(true); // sin cambios }); it('el acceso total oculta las casillas y no ofrece Administración como casilla', async () => { await click('.users li button', 1); expect(el().querySelector('fieldset')).toBeNull(); await click('.users li button', 0); expect(byText('legend label', 'Administración')).toBeUndefined(); }); it('guarda los patrones resultantes con PUT', async () => { await click('.users li button', 0); const inv = byText('legend label', 'Inventario').querySelector('input')!; inv.click(); await tick(); expect(el().querySelector('.actions .main')!.disabled).toBe(false); await click('.actions .main'); const req = ctrl.expectOne((r) => r.method === 'PUT'); expect(req.request.url).toBe('/api/permissions/ana'); expect(req.request.body).toEqual({ paths: ['/ventas/*', '/inventario/*', '/socios/clientes'] }); req.flush({ webUser: 'ana', paths: [] }); await tick(); ctrl.expectOne('/api/permissions').flush([{ webUser: 'ana', paths: ['/ventas/*', '/inventario/*', '/socios/clientes'] }]); await tick(); expect(el().querySelector('.msg')?.textContent).toContain('Permisos de ana guardados'); }); it('muestra el error del servidor, por ejemplo al quitar el último administrador', async () => { await click('.users li button', 1); await click('.actions .danger'); ctrl.expectOne((r) => r.method === 'DELETE' && r.url === '/api/permissions/luis').flush( { message: 'No se puede quitar al último administrador' }, { status: 409, statusText: 'Conflict' }, ); await tick(); expect(el().querySelector('.msg.err')?.textContent).toContain('último administrador'); }); it('agregar un usuario lo selecciona sin guardar hasta pulsar Guardar', async () => { const input = el().querySelector('.add input')!; input.value = 'marta'; input.dispatchEvent(new Event('input')); await tick(); await click('.add .btn'); expect([...el().querySelectorAll('.users li button')].map((b) => b.textContent?.trim())).toContain('marta'); expect(el().querySelector('.detail h2')?.textContent).toBe('marta'); ctrl.expectNone((r) => r.method === 'PUT'); }); });