108 lines
4.1 KiB
JavaScript
108 lines
4.1 KiB
JavaScript
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) => <span data-testid={`icon-${String(prop)}`} {...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(<Agents />);
|
||
['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(<Agents />);
|
||
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(<Agents />);
|
||
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(<Agents />);
|
||
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(<Agents />);
|
||
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(<Agents />);
|
||
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(<Agents />);
|
||
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(<Agents />);
|
||
expect(screen.getAllByText(/Last run · 16–20 Sep 2026/).length).toBeGreaterThan(0);
|
||
});
|
||
|
||
it('shows the repeated-error count on the log rows', () => {
|
||
render(<Agents />);
|
||
const errs = screen.getAllByText('×8,594');
|
||
expect(errs).toHaveLength(2);
|
||
});
|
||
|
||
it('every card carries a real trigger label, not undefined', () => {
|
||
const { container } = render(<Agents />);
|
||
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();
|
||
});
|
||
});
|
||
});
|