import { readFileSync } from 'node:fs'; import { resolve } from 'node:path'; import { EventState } from '../../frontend/src/app/core/services/event-status.store'; describe('ShellHeaderComponent LED styling (component-scoped)', () => { const sourcePath = resolve( __dirname, '../../frontend/src/app/features/shell/header/shell-header.component.ts', ); const source = readFileSync(sourcePath, 'utf8'); it('declares component-scoped styles with the LED base shape', () => { expect(source).toMatch(/styles:\s*\[/); expect(source).toMatch(/display:\s*inline-block/); expect(source).toMatch(/width:\s*10px/); expect(source).toMatch(/height:\s*10px/); expect(source).toMatch(/border-radius:\s*50%/); }); it.each([ ['.led-running', '--color-success'], ['.led-countdown', '--color-warning'], ['.led-stopped', '--color-danger'], ['.led-unconfigured', '--color-secondary'], ] as const)( 'scopes %s to the existing %s token', (selector, token) => { const escaped = selector.replace('.', '\\.'); const re = new RegExp(`${escaped}\\s*\\{[^}]*var\\(${token}\\)`); expect(source).toMatch(re); }, ); it('keeps the existing state class bindings and aria-label in the template', () => { expect(source).toContain('class="led"'); expect(source).toContain('[class.led-running]="eventState() === \'running\'"'); expect(source).toContain('[class.led-countdown]="eventState() === \'countdown\'"'); expect(source).toContain('[class.led-stopped]="eventState() === \'stopped\'"'); expect(source).toContain('[class.led-unconfigured]="eventState() === \'unconfigured\'"'); expect(source).toContain("data-testid=\"shell-led\""); expect(source).toContain("[attr.aria-label]=\"'Event status: ' + eventState()\""); }); }); describe('EventState union covers all four LED classes', () => { it.each(['running', 'countdown', 'stopped', 'unconfigured'] as EventState[])( 'recognises %s', (state) => { const expected = `led led-${state}`; expect(expected.startsWith('led ')).toBe(true); expect(expected.endsWith(state)).toBe(true); }, ); });