/** * @vitest-environment happy-dom */ import { afterEach, describe, expect, it } from 'vitest'; import { cleanup, render, screen, fireEvent } from '@testing-library/react'; import LotlTierTimeline from './LotlTierTimeline'; import { buildLotlTimelineModel, resolveLotlTierOrder } from '../../help/lotlTimeline'; import { mockAgent } from '../../test/fixtures'; describe('LotlTierTimeline', () => { afterEach(() => cleanup()); it('renders 14 tiers from fixture attempts', () => { const order = resolveLotlTierOrder(); expect(order).toHaveLength(14); const agent = mockAgent({ status: 'online', lotl_tier: 'wsl', lotl_attempts: [ { tier: 'vuln_recon', ok: true, duration_ms: 800, phase: 'recon' }, { tier: 'docker', ok: false, error: 'no daemon', duration_ms: 1200, phase: 'deploy' }, { tier: 'wsl', ok: false, error: 'distro missing', duration_ms: 900, phase: 'deploy' }, ], }); const model = buildLotlTimelineModel(agent, order, agent.lotl_attempts ?? []); expect(model.tiers).toHaveLength(14); expect(model.succeeded).toBe(1); expect(model.tiers[0].state).toBe('success'); expect(model.tiers[1].state).toBe('failed'); expect(model.tiers[2].state).toBe('trying'); render(); expect(screen.getByText('ONION TIER CHAIN')).toBeInTheDocument(); expect(screen.getByText('1/14 tiers succeeded')).toBeInTheDocument(); expect(screen.getAllByRole('listitem')).toHaveLength(14); expect(screen.getByText('Vuln Recon')).toBeInTheDocument(); expect(screen.getByText('GPO')).toBeInTheDocument(); }); it('shows cloned-from badge when inherited phenotype present', () => { const order = resolveLotlTierOrder(); const agent = mockAgent({ inherited_phenotype: { source_agent_name: 'worker-07', tier_order: ['container', 'wsl'], spread_lane: 'winrm', }, }); const model = buildLotlTimelineModel(agent, order, []); render(); expect(screen.getByText('Cloned from worker-07')).toBeInTheDocument(); }); it('expands attempt detail on tier click', () => { const order = resolveLotlTierOrder(); const agent = mockAgent({ lotl_attempts: [ { tier: 'docker', ok: false, error: 'AV blocked', duration_ms: 500, phase: 'deploy' }, ], }); const model = buildLotlTimelineModel(agent, order, agent.lotl_attempts ?? []); render(); fireEvent.click(screen.getByText('Docker')); expect(screen.getByText('AV blocked')).toBeInTheDocument(); expect(screen.getByText('deploy')).toBeInTheDocument(); expect(screen.getByText('500ms')).toBeInTheDocument(); }); });