import React from 'react';
import { render, screen, fireEvent, within } from '@testing-library/react';
jest.mock('lucide-react', () =>
new Proxy(
{},
{
get: (_t, prop) =>
prop === '__esModule' ? true : (props) => ,
}
)
);
import Agents from '@/pages/doormile/agents/Agents';
/**
* The Agents page.
*
* It renders a hand-maintained table (lib/agentNetwork.js) rather than a live
* feed, so the risk here is not stale data — agentNetwork.test.js guards the
* table — it is that the page silently drops something. A detail panel that
* renders an empty string, or a card whose status has no colour, looks like a
* quiet page rather than a broken one.
*/
describe('the Agents page', () => {
it('lists all nine agents', () => {
render();
['JARVIS', 'Dispatch', 'Exception', 'Express Dispatch', 'Order', 'Route Optimizer', 'Hub', 'Fleet', 'Customer'].forEach(
(name) => {
expect(screen.getAllByText(name).length).toBeGreaterThan(0);
}
);
});
it('opens on Dispatch rather than an empty panel', () => {
// It is the only agent with anything to show. Landing on a blank detail
// panel reads as a broken page.
render();
expect(screen.getByText('DISPATCH_AGENT')).toBeInTheDocument();
expect(screen.getByText(/only agent doing real work/i)).toBeInTheDocument();
});
it('swaps the whole detail panel when another agent is picked', () => {
render();
fireEvent.click(screen.getByRole('button', { name: /Exception/ }));
expect(screen.getByText('EXCEPTION_AGENT')).toBeInTheDocument();
expect(screen.getByText(/17,188 of the 18,146 lines/)).toBeInTheDocument();
// and the previous agent's record is gone, not merely scrolled away
expect(screen.queryByText('DISPATCH_AGENT')).not.toBeInTheDocument();
});
it('marks the selected card for a screen reader, not just with a colour', () => {
render();
const exception = screen.getByRole('button', { name: /Exception/ });
expect(exception).toHaveAttribute('aria-pressed', 'false');
fireEvent.click(exception);
expect(exception).toHaveAttribute('aria-pressed', 'true');
});
it('says a task-driven agent listens to nothing, rather than leaving a blank', () => {
render();
fireEvent.click(screen.getByRole('button', { name: /Fleet/ }));
expect(screen.getByText(/runs only when JARVIS hands it a task/i)).toBeInTheDocument();
});
it('shows the pipeline, both halves of it', () => {
render();
expect(screen.getByText('doormile_backend')).toBeInTheDocument();
expect(screen.getByText('NATS JetStream')).toBeInTheDocument();
expect(screen.getByText('Event-driven')).toBeInTheDocument();
expect(screen.getByText('Task-driven')).toBeInTheDocument();
expect(screen.getByText('Alert, never act')).toBeInTheDocument();
});
it('states that nothing is switched on, in the KPI row', () => {
// The page's central claim: the swarm observes and alerts, and does not
// write to the system.
render();
expect(screen.getByText(/Gates on/)).toBeInTheDocument();
expect(screen.getByText(/All autonomy gates OFF/)).toBeInTheDocument();
});
it('admits the figures are a snapshot, not a feed', () => {
// A status board that looks live and is four days old is worse than one
// that says how old it is.
render();
expect(screen.getAllByText(/Last run · 16–20 Sep 2026/).length).toBeGreaterThan(0);
});
it('shows the repeated-error count on the log rows', () => {
render();
const errs = screen.getAllByText('×8,594');
expect(errs).toHaveLength(2);
});
it('every card carries a real trigger label, not undefined', () => {
const { container } = render();
const cards = container.querySelectorAll('button[aria-pressed]');
expect(cards).toHaveLength(9);
cards.forEach((card) => {
const text = within(card).getByText(/NATS event|NATS pull|JARVIS task|In-process/);
expect(text).toBeInTheDocument();
});
});
});