fix: break Vite refresh loop by ignoring __tests__ in route generation
TanStack Router plugin was picking up test files under routes/__tests__/, causing routeTree.gen.ts to regenerate in a loop. Added routeFileIgnorePattern and removed stale radar.test.tsx.
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
|
||||
import { Route as rootRouteImport } from './routes/__root'
|
||||
import { Route as SettingsRouteImport } from './routes/settings'
|
||||
import { Route as RadarRouteImport } from './routes/radar'
|
||||
import { Route as InboxRouteImport } from './routes/inbox'
|
||||
import { Route as HqRouteImport } from './routes/hq'
|
||||
import { Route as AgentsRouteImport } from './routes/agents'
|
||||
@@ -25,6 +26,11 @@ const SettingsRoute = SettingsRouteImport.update({
|
||||
path: '/settings',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const RadarRoute = RadarRouteImport.update({
|
||||
id: '/radar',
|
||||
path: '/radar',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const InboxRoute = InboxRouteImport.update({
|
||||
id: '/inbox',
|
||||
path: '/inbox',
|
||||
@@ -76,6 +82,7 @@ export interface FileRoutesByFullPath {
|
||||
'/agents': typeof AgentsRoute
|
||||
'/hq': typeof HqRoute
|
||||
'/inbox': typeof InboxRoute
|
||||
'/radar': typeof RadarRoute
|
||||
'/settings': typeof SettingsRouteWithChildren
|
||||
'/initiatives/$id': typeof InitiativesIdRoute
|
||||
'/settings/health': typeof SettingsHealthRoute
|
||||
@@ -88,6 +95,7 @@ export interface FileRoutesByTo {
|
||||
'/agents': typeof AgentsRoute
|
||||
'/hq': typeof HqRoute
|
||||
'/inbox': typeof InboxRoute
|
||||
'/radar': typeof RadarRoute
|
||||
'/initiatives/$id': typeof InitiativesIdRoute
|
||||
'/settings/health': typeof SettingsHealthRoute
|
||||
'/settings/projects': typeof SettingsProjectsRoute
|
||||
@@ -100,6 +108,7 @@ export interface FileRoutesById {
|
||||
'/agents': typeof AgentsRoute
|
||||
'/hq': typeof HqRoute
|
||||
'/inbox': typeof InboxRoute
|
||||
'/radar': typeof RadarRoute
|
||||
'/settings': typeof SettingsRouteWithChildren
|
||||
'/initiatives/$id': typeof InitiativesIdRoute
|
||||
'/settings/health': typeof SettingsHealthRoute
|
||||
@@ -114,6 +123,7 @@ export interface FileRouteTypes {
|
||||
| '/agents'
|
||||
| '/hq'
|
||||
| '/inbox'
|
||||
| '/radar'
|
||||
| '/settings'
|
||||
| '/initiatives/$id'
|
||||
| '/settings/health'
|
||||
@@ -126,6 +136,7 @@ export interface FileRouteTypes {
|
||||
| '/agents'
|
||||
| '/hq'
|
||||
| '/inbox'
|
||||
| '/radar'
|
||||
| '/initiatives/$id'
|
||||
| '/settings/health'
|
||||
| '/settings/projects'
|
||||
@@ -137,6 +148,7 @@ export interface FileRouteTypes {
|
||||
| '/agents'
|
||||
| '/hq'
|
||||
| '/inbox'
|
||||
| '/radar'
|
||||
| '/settings'
|
||||
| '/initiatives/$id'
|
||||
| '/settings/health'
|
||||
@@ -150,6 +162,7 @@ export interface RootRouteChildren {
|
||||
AgentsRoute: typeof AgentsRoute
|
||||
HqRoute: typeof HqRoute
|
||||
InboxRoute: typeof InboxRoute
|
||||
RadarRoute: typeof RadarRoute
|
||||
SettingsRoute: typeof SettingsRouteWithChildren
|
||||
InitiativesIdRoute: typeof InitiativesIdRoute
|
||||
InitiativesIndexRoute: typeof InitiativesIndexRoute
|
||||
@@ -164,6 +177,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof SettingsRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/radar': {
|
||||
id: '/radar'
|
||||
path: '/radar'
|
||||
fullPath: '/radar'
|
||||
preLoaderRoute: typeof RadarRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/inbox': {
|
||||
id: '/inbox'
|
||||
path: '/inbox'
|
||||
@@ -251,6 +271,7 @@ const rootRouteChildren: RootRouteChildren = {
|
||||
AgentsRoute: AgentsRoute,
|
||||
HqRoute: HqRoute,
|
||||
InboxRoute: InboxRoute,
|
||||
RadarRoute: RadarRoute,
|
||||
SettingsRoute: SettingsRouteWithChildren,
|
||||
InitiativesIdRoute: InitiativesIdRoute,
|
||||
InitiativesIndexRoute: InitiativesIndexRoute,
|
||||
|
||||
@@ -1,451 +0,0 @@
|
||||
// @vitest-environment happy-dom
|
||||
import '@testing-library/jest-dom/vitest'
|
||||
import { render, screen, fireEvent, within } from '@testing-library/react'
|
||||
import { vi, describe, it, expect, beforeEach } from 'vitest'
|
||||
|
||||
vi.mock('@/components/radar/CompactionEventsDialog', () => ({
|
||||
CompactionEventsDialog: ({ open, agentId, agentName, isAgentRunning, onOpenChange }: any) =>
|
||||
open ? (
|
||||
<div data-testid="compaction-dialog" data-agent-id={agentId} data-agent-name={agentName} data-is-running={String(isAgentRunning)}>
|
||||
<button onClick={() => onOpenChange(false)}>close</button>
|
||||
</div>
|
||||
) : null,
|
||||
}))
|
||||
vi.mock('@/components/radar/SubagentSpawnsDialog', () => ({
|
||||
SubagentSpawnsDialog: ({ open, agentId, agentName, isAgentRunning, onOpenChange }: any) =>
|
||||
open ? (
|
||||
<div data-testid="subagents-dialog" data-agent-id={agentId} data-agent-name={agentName} data-is-running={String(isAgentRunning)}>
|
||||
<button onClick={() => onOpenChange(false)}>close</button>
|
||||
</div>
|
||||
) : null,
|
||||
}))
|
||||
vi.mock('@/components/radar/QuestionsAskedDialog', () => ({
|
||||
QuestionsAskedDialog: ({ open, agentId, agentName, isAgentRunning, onOpenChange }: any) =>
|
||||
open ? (
|
||||
<div data-testid="questions-dialog" data-agent-id={agentId} data-agent-name={agentName} data-is-running={String(isAgentRunning)}>
|
||||
<button onClick={() => onOpenChange(false)}>close</button>
|
||||
</div>
|
||||
) : null,
|
||||
}))
|
||||
vi.mock('@/components/radar/InterAgentMessagesDialog', () => ({
|
||||
InterAgentMessagesDialog: ({ open, agentId, agentName, isAgentRunning, onOpenChange }: any) =>
|
||||
open ? (
|
||||
<div data-testid="messages-dialog" data-agent-id={agentId} data-agent-name={agentName} data-is-running={String(isAgentRunning)}>
|
||||
<button onClick={() => onOpenChange(false)}>close</button>
|
||||
</div>
|
||||
) : null,
|
||||
}))
|
||||
|
||||
type AgentRadarRow = {
|
||||
id: string
|
||||
name: string
|
||||
mode: string
|
||||
status: string
|
||||
initiativeId: string | null
|
||||
initiativeName: string | null
|
||||
taskId: string | null
|
||||
taskName: string | null
|
||||
createdAt: string
|
||||
questionsCount: number
|
||||
messagesCount: number
|
||||
subagentsCount: number
|
||||
compactionsCount: number
|
||||
}
|
||||
|
||||
// --- Hoisted mocks ---
|
||||
const mockListForRadarUseQuery = vi.hoisted(() => vi.fn())
|
||||
const mockListInitiativesUseQuery = vi.hoisted(() => vi.fn())
|
||||
const mockListAgentsUseQuery = vi.hoisted(() => vi.fn())
|
||||
const mockNavigate = vi.hoisted(() => vi.fn())
|
||||
const mockUseSearch = vi.hoisted(() =>
|
||||
vi.fn().mockReturnValue({
|
||||
timeRange: '24h',
|
||||
status: 'all',
|
||||
initiativeId: undefined,
|
||||
mode: 'all',
|
||||
})
|
||||
)
|
||||
|
||||
vi.mock('@/lib/trpc', () => ({
|
||||
trpc: {
|
||||
agent: {
|
||||
listForRadar: { useQuery: mockListForRadarUseQuery },
|
||||
},
|
||||
listInitiatives: { useQuery: mockListInitiativesUseQuery },
|
||||
listAgents: { useQuery: mockListAgentsUseQuery },
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/hooks', () => ({
|
||||
useLiveUpdates: vi.fn(),
|
||||
LiveUpdateRule: undefined,
|
||||
}))
|
||||
|
||||
vi.mock('@/components/ThemeToggle', () => ({
|
||||
ThemeToggle: () => null,
|
||||
}))
|
||||
|
||||
vi.mock('@/components/HealthDot', () => ({
|
||||
HealthDot: () => null,
|
||||
}))
|
||||
|
||||
vi.mock('@/components/NavBadge', () => ({
|
||||
NavBadge: () => null,
|
||||
}))
|
||||
|
||||
vi.mock('@tanstack/react-router', () => ({
|
||||
createFileRoute: () => () => ({ component: null }),
|
||||
useNavigate: () => mockNavigate,
|
||||
useSearch: mockUseSearch,
|
||||
Link: ({
|
||||
to,
|
||||
search,
|
||||
children,
|
||||
}: {
|
||||
to: string
|
||||
search?: Record<string, string>
|
||||
children: React.ReactNode | ((props: { isActive: boolean }) => React.ReactNode)
|
||||
}) => {
|
||||
const params = search ? new URLSearchParams(search).toString() : ''
|
||||
const href = params ? `${to}?${params}` : to
|
||||
const content = typeof children === 'function' ? children({ isActive: false }) : children
|
||||
return <a href={href}>{content}</a>
|
||||
},
|
||||
}))
|
||||
|
||||
// Import after mocks
|
||||
import { RadarPage } from '../radar'
|
||||
import { AppLayout } from '../../layouts/AppLayout'
|
||||
|
||||
function makeAgent(overrides?: Partial<AgentRadarRow>): AgentRadarRow {
|
||||
return {
|
||||
id: 'agent-1',
|
||||
name: 'jolly-penguin',
|
||||
mode: 'execute',
|
||||
status: 'running',
|
||||
initiativeId: null,
|
||||
initiativeName: null,
|
||||
taskId: null,
|
||||
taskName: null,
|
||||
createdAt: new Date(Date.now() - 3600_000).toISOString(),
|
||||
questionsCount: 0,
|
||||
messagesCount: 0,
|
||||
subagentsCount: 0,
|
||||
compactionsCount: 0,
|
||||
...overrides,
|
||||
}
|
||||
}
|
||||
|
||||
describe('RadarPage', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockListInitiativesUseQuery.mockReturnValue({ data: [], isLoading: false })
|
||||
mockUseSearch.mockReturnValue({
|
||||
timeRange: '24h',
|
||||
status: 'all',
|
||||
initiativeId: undefined,
|
||||
mode: 'all',
|
||||
})
|
||||
})
|
||||
|
||||
it('renders "Radar" heading', () => {
|
||||
mockListForRadarUseQuery.mockReturnValue({ data: [], isLoading: false })
|
||||
render(<RadarPage />)
|
||||
expect(screen.getByRole('heading', { name: /radar/i })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders 4 summary stat cards with correct aggregated values', () => {
|
||||
// Use distinct totals; scope number checks to stat card containers to avoid table collisions
|
||||
const agents = [
|
||||
makeAgent({ id: 'a1', questionsCount: 3, messagesCount: 10, subagentsCount: 2, compactionsCount: 1 }),
|
||||
makeAgent({ id: 'a2', questionsCount: 4, messagesCount: 5, subagentsCount: 1, compactionsCount: 3 }),
|
||||
]
|
||||
mockListForRadarUseQuery.mockReturnValue({ data: agents, isLoading: false })
|
||||
render(<RadarPage />)
|
||||
|
||||
// Verify labels exist
|
||||
expect(screen.getByText('Total Questions Asked')).toBeInTheDocument()
|
||||
expect(screen.getByText('Total Inter-Agent Messages')).toBeInTheDocument()
|
||||
expect(screen.getByText('Total Subagent Spawns')).toBeInTheDocument()
|
||||
expect(screen.getByText('Total Compaction Events')).toBeInTheDocument()
|
||||
|
||||
// Verify aggregated totals by scoping to the stat card's container
|
||||
// Total Questions: 3+4=7
|
||||
const questionsContainer = screen.getByText('Total Questions Asked').parentElement!
|
||||
expect(questionsContainer.querySelector('.text-3xl')).toHaveTextContent('7')
|
||||
// Total Messages: 10+5=15
|
||||
const messagesContainer = screen.getByText('Total Inter-Agent Messages').parentElement!
|
||||
expect(messagesContainer.querySelector('.text-3xl')).toHaveTextContent('15')
|
||||
})
|
||||
|
||||
it('table renders one row per agent', () => {
|
||||
const agents = [
|
||||
makeAgent({ id: 'a1', name: 'agent-one' }),
|
||||
makeAgent({ id: 'a2', name: 'agent-two' }),
|
||||
makeAgent({ id: 'a3', name: 'agent-three' }),
|
||||
]
|
||||
mockListForRadarUseQuery.mockReturnValue({ data: agents, isLoading: false })
|
||||
render(<RadarPage />)
|
||||
|
||||
const tbody = document.querySelector('tbody')!
|
||||
const rows = within(tbody).getAllByRole('row')
|
||||
expect(rows).toHaveLength(3)
|
||||
})
|
||||
|
||||
it('default sort: newest first', () => {
|
||||
const older = makeAgent({ id: 'a1', name: 'older-agent', createdAt: new Date(Date.now() - 7200_000).toISOString() })
|
||||
const newer = makeAgent({ id: 'a2', name: 'newer-agent', createdAt: new Date(Date.now() - 1800_000).toISOString() })
|
||||
mockListForRadarUseQuery.mockReturnValue({ data: [older, newer], isLoading: false })
|
||||
render(<RadarPage />)
|
||||
|
||||
const tbody = document.querySelector('tbody')!
|
||||
const rows = within(tbody).getAllByRole('row')
|
||||
expect(rows[0]).toHaveTextContent('newer-agent')
|
||||
expect(rows[1]).toHaveTextContent('older-agent')
|
||||
})
|
||||
|
||||
it('clicking "Started" column header sorts ascending, clicking again sorts descending', () => {
|
||||
const older = makeAgent({ id: 'a1', name: 'older-agent', createdAt: new Date(Date.now() - 7200_000).toISOString() })
|
||||
const newer = makeAgent({ id: 'a2', name: 'newer-agent', createdAt: new Date(Date.now() - 1800_000).toISOString() })
|
||||
mockListForRadarUseQuery.mockReturnValue({ data: [older, newer], isLoading: false })
|
||||
render(<RadarPage />)
|
||||
|
||||
// First click: default is desc (newest first), clicking toggles to asc (oldest first)
|
||||
fireEvent.click(screen.getByRole('columnheader', { name: /started/i }))
|
||||
const rowsAsc = within(document.querySelector('tbody')!).getAllByRole('row')
|
||||
expect(rowsAsc[0]).toHaveTextContent('older-agent')
|
||||
expect(rowsAsc[1]).toHaveTextContent('newer-agent')
|
||||
|
||||
// Second click: re-query header (text content changed to '▲'), toggle back to desc
|
||||
fireEvent.click(screen.getByRole('columnheader', { name: /started/i }))
|
||||
const rowsDesc = within(document.querySelector('tbody')!).getAllByRole('row')
|
||||
expect(rowsDesc[0]).toHaveTextContent('newer-agent')
|
||||
expect(rowsDesc[1]).toHaveTextContent('older-agent')
|
||||
})
|
||||
|
||||
it('agent name cell renders a Link to /agents with selected param', () => {
|
||||
const agent = makeAgent({ id: 'agent-xyz', name: 'test-agent' })
|
||||
mockListForRadarUseQuery.mockReturnValue({ data: [agent], isLoading: false })
|
||||
render(<RadarPage />)
|
||||
|
||||
const link = screen.getByRole('link', { name: 'test-agent' })
|
||||
expect(link).toBeInTheDocument()
|
||||
expect(link).toHaveAttribute('href', expect.stringContaining('/agents'))
|
||||
expect(link).toHaveAttribute('href', expect.stringContaining('agent-xyz'))
|
||||
})
|
||||
|
||||
it('non-zero metric cell has cursor-pointer class; zero cell does not', () => {
|
||||
mockListForRadarUseQuery.mockReturnValue({
|
||||
data: [makeAgent({ id: 'a1', questionsCount: 5 })],
|
||||
isLoading: false,
|
||||
})
|
||||
render(<RadarPage />)
|
||||
|
||||
// Find all cells with text "5" — the non-zero questions cell
|
||||
const tbody = document.querySelector('tbody')!
|
||||
const cells = tbody.querySelectorAll('td')
|
||||
|
||||
// Find the cell containing "5" (questionsCount)
|
||||
const nonZeroCell = Array.from(cells).find(cell => cell.textContent === '5')
|
||||
expect(nonZeroCell).toBeTruthy()
|
||||
expect(nonZeroCell!.className).toContain('cursor-pointer')
|
||||
|
||||
// Find a zero cell (messagesCount=0)
|
||||
const zeroCell = Array.from(cells).find(cell => cell.textContent === '0' && !cell.className.includes('cursor-pointer'))
|
||||
expect(zeroCell).toBeTruthy()
|
||||
})
|
||||
|
||||
it('selecting mode filter calls navigate with mode param', () => {
|
||||
mockListForRadarUseQuery.mockReturnValue({ data: [], isLoading: false })
|
||||
render(<RadarPage />)
|
||||
|
||||
const selects = screen.getAllByRole('combobox')
|
||||
// Mode select is the 4th select (timeRange, status, initiative, mode)
|
||||
const modeSelect = selects[3]
|
||||
fireEvent.change(modeSelect, { target: { value: 'execute' } })
|
||||
|
||||
expect(mockNavigate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
search: expect.any(Function),
|
||||
})
|
||||
)
|
||||
|
||||
// Call the search function to verify the result
|
||||
const call = mockNavigate.mock.calls[0][0]
|
||||
const result = call.search({ timeRange: '24h', status: 'all', initiativeId: undefined, mode: 'all' })
|
||||
expect(result).toMatchObject({ mode: 'execute' })
|
||||
})
|
||||
|
||||
it('selecting status filter calls navigate with status param', () => {
|
||||
mockListForRadarUseQuery.mockReturnValue({ data: [], isLoading: false })
|
||||
render(<RadarPage />)
|
||||
|
||||
const selects = screen.getAllByRole('combobox')
|
||||
// Status select is the 2nd select
|
||||
const statusSelect = selects[1]
|
||||
fireEvent.change(statusSelect, { target: { value: 'running' } })
|
||||
|
||||
expect(mockNavigate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
search: expect.any(Function),
|
||||
})
|
||||
)
|
||||
|
||||
const call = mockNavigate.mock.calls[0][0]
|
||||
const result = call.search({ timeRange: '24h', status: 'all', initiativeId: undefined, mode: 'all' })
|
||||
expect(result).toMatchObject({ status: 'running' })
|
||||
})
|
||||
|
||||
it('empty state shown when agents returns []', () => {
|
||||
mockListForRadarUseQuery.mockReturnValue({ data: [], isLoading: false })
|
||||
render(<RadarPage />)
|
||||
|
||||
expect(screen.getByText('No agent activity in this time period')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('loading skeleton shown when isLoading is true', () => {
|
||||
mockListForRadarUseQuery.mockReturnValue({ data: undefined, isLoading: true })
|
||||
render(<RadarPage />)
|
||||
|
||||
const skeletons = document.querySelectorAll('.animate-pulse')
|
||||
expect(skeletons.length).toBeGreaterThanOrEqual(5)
|
||||
})
|
||||
|
||||
describe('dialog integration', () => {
|
||||
const alphaAgent = {
|
||||
id: 'agent-alpha-id',
|
||||
name: 'agent-alpha',
|
||||
mode: 'execute',
|
||||
status: 'running',
|
||||
initiativeId: null,
|
||||
initiativeName: null,
|
||||
taskId: null,
|
||||
taskName: null,
|
||||
createdAt: new Date(Date.now() - 3600_000).toISOString(),
|
||||
questionsCount: 3,
|
||||
messagesCount: 2,
|
||||
subagentsCount: 1,
|
||||
compactionsCount: 4,
|
||||
}
|
||||
const betaAgent = {
|
||||
id: 'agent-beta-id',
|
||||
name: 'agent-beta',
|
||||
mode: 'execute',
|
||||
status: 'stopped',
|
||||
initiativeId: null,
|
||||
initiativeName: null,
|
||||
taskId: null,
|
||||
taskName: null,
|
||||
createdAt: new Date(Date.now() - 7200_000).toISOString(),
|
||||
questionsCount: 0,
|
||||
messagesCount: 0,
|
||||
subagentsCount: 0,
|
||||
compactionsCount: 0,
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
mockListForRadarUseQuery.mockReturnValue({ data: [alphaAgent, betaAgent], isLoading: false })
|
||||
})
|
||||
|
||||
it('clicking a non-zero Compactions cell opens CompactionEventsDialog with correct agentId and agentName', async () => {
|
||||
render(<RadarPage />)
|
||||
const cell = screen.getByTestId(`cell-compactions-agent-alpha-id`)
|
||||
fireEvent.click(cell)
|
||||
const dialog = await screen.findByTestId('compaction-dialog')
|
||||
expect(dialog).toBeInTheDocument()
|
||||
expect(dialog).toHaveAttribute('data-agent-name', 'agent-alpha')
|
||||
expect(dialog).toHaveAttribute('data-agent-id', 'agent-alpha-id')
|
||||
})
|
||||
|
||||
it('clicking a non-zero Subagents cell opens SubagentSpawnsDialog', async () => {
|
||||
render(<RadarPage />)
|
||||
const cell = screen.getByTestId(`cell-subagents-agent-alpha-id`)
|
||||
fireEvent.click(cell)
|
||||
const dialog = await screen.findByTestId('subagents-dialog')
|
||||
expect(dialog).toBeInTheDocument()
|
||||
expect(dialog).toHaveAttribute('data-agent-name', 'agent-alpha')
|
||||
expect(dialog).toHaveAttribute('data-agent-id', 'agent-alpha-id')
|
||||
})
|
||||
|
||||
it('clicking a non-zero Questions cell opens QuestionsAskedDialog', async () => {
|
||||
render(<RadarPage />)
|
||||
const cell = screen.getByTestId(`cell-questions-agent-alpha-id`)
|
||||
fireEvent.click(cell)
|
||||
const dialog = await screen.findByTestId('questions-dialog')
|
||||
expect(dialog).toBeInTheDocument()
|
||||
expect(dialog).toHaveAttribute('data-agent-name', 'agent-alpha')
|
||||
expect(dialog).toHaveAttribute('data-agent-id', 'agent-alpha-id')
|
||||
})
|
||||
|
||||
it('clicking a non-zero Messages cell opens InterAgentMessagesDialog', async () => {
|
||||
render(<RadarPage />)
|
||||
const cell = screen.getByTestId(`cell-messages-agent-alpha-id`)
|
||||
fireEvent.click(cell)
|
||||
const dialog = await screen.findByTestId('messages-dialog')
|
||||
expect(dialog).toBeInTheDocument()
|
||||
expect(dialog).toHaveAttribute('data-agent-name', 'agent-alpha')
|
||||
expect(dialog).toHaveAttribute('data-agent-id', 'agent-alpha-id')
|
||||
})
|
||||
|
||||
it('dialog closes when onOpenChange(false) fires', async () => {
|
||||
render(<RadarPage />)
|
||||
const cell = screen.getByTestId(`cell-compactions-agent-alpha-id`)
|
||||
fireEvent.click(cell)
|
||||
const dialog = await screen.findByTestId('compaction-dialog')
|
||||
expect(dialog).toBeInTheDocument()
|
||||
fireEvent.click(screen.getByRole('button', { name: 'close' }))
|
||||
expect(screen.queryByTestId('compaction-dialog')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('zero metric cells do not open any dialog when clicked', () => {
|
||||
render(<RadarPage />)
|
||||
// agent-beta has all zeros — click each zero metric cell
|
||||
fireEvent.click(screen.getByTestId('cell-compactions-agent-beta-id'))
|
||||
fireEvent.click(screen.getByTestId('cell-subagents-agent-beta-id'))
|
||||
fireEvent.click(screen.getByTestId('cell-questions-agent-beta-id'))
|
||||
fireEvent.click(screen.getByTestId('cell-messages-agent-beta-id'))
|
||||
expect(screen.queryByTestId('compaction-dialog')).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('subagents-dialog')).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('questions-dialog')).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('messages-dialog')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('passes isAgentRunning=true when the agent status is "running"', async () => {
|
||||
render(<RadarPage />)
|
||||
const cell = screen.getByTestId(`cell-compactions-agent-alpha-id`)
|
||||
fireEvent.click(cell)
|
||||
const dialog = await screen.findByTestId('compaction-dialog')
|
||||
expect(dialog).toHaveAttribute('data-is-running', 'true')
|
||||
})
|
||||
|
||||
it('passes isAgentRunning=false when the agent status is "stopped"', async () => {
|
||||
// Use a stopped agent with non-zero compactions
|
||||
const stoppedAgent = { ...betaAgent, id: 'stopped-agent-id', name: 'stopped-agent', compactionsCount: 2, status: 'stopped' }
|
||||
mockListForRadarUseQuery.mockReturnValue({ data: [stoppedAgent], isLoading: false })
|
||||
render(<RadarPage />)
|
||||
const cell = screen.getByTestId('cell-compactions-stopped-agent-id')
|
||||
fireEvent.click(cell)
|
||||
const dialog = await screen.findByTestId('compaction-dialog')
|
||||
expect(dialog).toHaveAttribute('data-is-running', 'false')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('AppLayout - Radar nav item', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('"Radar" appears in AppLayout nav', () => {
|
||||
mockListAgentsUseQuery.mockReturnValue({ data: [], isLoading: false })
|
||||
render(
|
||||
<AppLayout connectionState="connected">
|
||||
<div>content</div>
|
||||
</AppLayout>
|
||||
)
|
||||
|
||||
const radarLink = screen.getByRole('link', { name: 'Radar' })
|
||||
expect(radarLink).toBeInTheDocument()
|
||||
expect(radarLink).toHaveAttribute('href', expect.stringContaining('/radar'))
|
||||
})
|
||||
})
|
||||
@@ -4,7 +4,13 @@ import { TanStackRouterVite } from "@tanstack/router-plugin/vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [TanStackRouterVite({ autoCodeSplitting: true }), react()],
|
||||
plugins: [
|
||||
TanStackRouterVite({
|
||||
autoCodeSplitting: true,
|
||||
routeFileIgnorePattern: '__tests__',
|
||||
}),
|
||||
react(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
|
||||
Reference in New Issue
Block a user