import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { RouterTestingModule } from '@angular/router/testing'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { MatDialogModule } from '@angular/material/dialog'; import { TranslateModule } from '@ngx-translate/core'; import { SidebarComponent } from './sidebar.component'; import { AuthService, UserCategory } from '@services/auth.service'; // ───────────────────────────────────────────────────────────────────────────── // Rutas con condiciones de visibilidad (según sidebar.component.html) // ───────────────────────────────────────────────────────────────────────────── /** Siempre visibles para todos los roles autenticados */ const ALWAYS_VISIBLE = ['/groups']; /** Solo visibles para super-admin y ou-admin (ocultos para operator y minimal) */ const ADMIN_ONLY_ROUTES = [ '/dhcp-servers', '/boot-servers', '/calendars', '/repositories', '/menus', ]; // ───────────────────────────────────────────────────────────────────────────── // Helper: cuenta mat-list-item visibles en el DOM // ───────────────────────────────────────────────────────────────────────────── function countVisibleListItems(fixture: ComponentFixture): number { return fixture.debugElement.queryAll(By.css('mat-list-item')).length; } /** Devuelve true si existe algún mat-list-item con [routerLink] apuntando a la ruta dada */ function hasRouteLink(fixture: ComponentFixture, route: string): boolean { const items = fixture.debugElement.queryAll(By.css(`[routerLink="${route}"]`)); return items.length > 0; } // ───────────────────────────────────────────────────────────────────────────── // Mock de AuthService // ───────────────────────────────────────────────────────────────────────────── function mockAuthService(category: UserCategory) { return { userCategory: category, username: 'test-user', isSuperAdmin: category === 'super-admin', isOUAdmin: category === 'ou-admin', isOUOperator: category === 'ou-operator', isOUMinimal: category === 'ou-minimal', getCurrentRole: () => category, }; } // ───────────────────────────────────────────────────────────────────────────── // Suite principal // ───────────────────────────────────────────────────────────────────────────── describe('SidebarComponent — visibilidad de elementos por rol', () => { let fixture: ComponentFixture; let component: SidebarComponent; async function createComponent(category: UserCategory) { await TestBed.configureTestingModule({ declarations: [SidebarComponent], imports: [ RouterTestingModule, MatDialogModule, TranslateModule.forRoot(), ], providers: [ { provide: AuthService, useValue: mockAuthService(category) }, ], schemas: [CUSTOM_ELEMENTS_SCHEMA], // ignora mat-* desconocidos }).compileComponents(); fixture = TestBed.createComponent(SidebarComponent); component = fixture.componentInstance; fixture.detectChanges(); } // ── Grupos — siempre visible ─────────────────────────────────────────────── describe('/groups — siempre visible para cualquier rol', () => { (['super-admin', 'ou-admin', 'ou-operator', 'ou-minimal'] as UserCategory[]).forEach(role => { it(`${role} ve el enlace a /groups`, async () => { await createComponent(role); expect(hasRouteLink(fixture, '/groups')).toBeTrue(); }); }); }); // ── Super-admin ve todo ──────────────────────────────────────────────────── describe('super-admin — ve todos los elementos del sidebar', () => { beforeEach(async () => createComponent('super-admin')); ADMIN_ONLY_ROUTES.forEach(route => { it(`ve el enlace a ${route}`, () => { expect(hasRouteLink(fixture, route)).toBeTrue(); }); }); it('ve el menú de acciones (commands)', () => { // El parent de commands es un mat-list-item sin routerLink pero con el ngIf const items = fixture.debugElement.queryAll(By.css('mat-list-item')); expect(items.length).toBeGreaterThan(1); }); }); // ── Ou-admin ve todo ─────────────────────────────────────────────────────── describe('ou-admin — ve todos los elementos del sidebar', () => { beforeEach(async () => createComponent('ou-admin')); ADMIN_ONLY_ROUTES.forEach(route => { it(`ve el enlace a ${route}`, () => { expect(hasRouteLink(fixture, route)).toBeTrue(); }); }); }); // ── Ou-operator: /groups y las trazas de sus acciones ────────────────────── describe('ou-operator — ve /groups y /commands-logs', () => { beforeEach(async () => createComponent('ou-operator')); it('ve /groups', () => { expect(hasRouteLink(fixture, '/groups')).toBeTrue(); }); ADMIN_ONLY_ROUTES.forEach(route => { it(`NO ve el enlace a ${route}`, () => { expect(hasRouteLink(fixture, route)).toBeFalse(); }); }); it('ve el menú de acciones (commands) para acceder a las trazas', () => { // /groups + el desplegable de acciones expect(countVisibleListItems(fixture)).toBe(2); }); it('ve el enlace a /commands-logs al desplegar el menú de acciones', () => { component.toggleCommandSub(); fixture.detectChanges(); expect(hasRouteLink(fixture, '/commands-logs')).toBeTrue(); }); it('NO ve los enlaces de gestión de comandos ni tareas', () => { component.toggleCommandSub(); fixture.detectChanges(); expect(hasRouteLink(fixture, '/commands')).toBeFalse(); expect(hasRouteLink(fixture, '/commands-task')).toBeFalse(); }); }); // ── Ou-minimal: solo /groups ─────────────────────────────────────────────── describe('ou-minimal — solo ve /groups', () => { beforeEach(async () => createComponent('ou-minimal')); it('ve /groups', () => { expect(hasRouteLink(fixture, '/groups')).toBeTrue(); }); ADMIN_ONLY_ROUTES.forEach(route => { it(`NO ve el enlace a ${route}`, () => { expect(hasRouteLink(fixture, route)).toBeFalse(); }); }); it('NO ve el menú de acciones (commands)', () => { expect(countVisibleListItems(fixture)).toBe(1); }); }); // ── Comparativa admin vs operator ───────────────────────────────────────── describe('comparativa: ou-admin ve más items que ou-operator', () => { it('ou-admin tiene más mat-list-items visibles que ou-operator', async () => { await createComponent('ou-admin'); const adminCount = countVisibleListItems(fixture); TestBed.resetTestingModule(); await createComponent('ou-operator'); const operatorCount = countVisibleListItems(fixture); expect(adminCount).toBeGreaterThan(operatorCount); }); }); });