/**
* @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();
});
});