Files
orca/src/main/ipc/dashboard-payload-validation.test.ts
T
Brennan Benson f3473f2b79 feat(dashboard): tint agent cards by state, show the project as an icon, name the chat
Three glanceability changes to the agent board:

- The "Needs You" signal moves from the column border onto the cards
  themselves, and done agents get the same treatment in green. Idle cards
  that simply aren't running stay neutral, so a tint always means "this one
  wants you".
- The repo is now its own icon with the name in a tooltip, instead of a
  mono label that truncated and competed with the worktree name. Icons ride
  the snapshot keyed by repoId — image icons are data URLs, and the
  snapshot republishes several times a second.
- The user-message line is labelled with the tab's conversation name rather
  than "You", resolved through the same getAgentRowConversationName the
  sidebar's agent rows use. Status-only titles still fall back to "You".
2026-07-27 16:14:23 -07:00

117 lines
3.3 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import type { DashboardSnapshot } from '../../shared/dashboard-snapshot'
import { isDashboardRevealAgentArgs, isDashboardSnapshot } from './dashboard-payload-validation'
const SNAPSHOT = {
generatedAt: 1_700_000_000_000,
cards: [
{
paneKey: 'tab-1:leaf-1',
ptyId: 'pty-1',
agentType: 'codex',
bucket: 'attention',
dotState: 'waiting',
task: 'Review the dashboard',
lastUserMessage: 'Please review this',
lastAgentMessage: 'I need a decision.',
repoId: 'repo-1',
worktreeId: 'worktree-1',
tabId: 'tab-1',
leafId: 'leaf-1',
repoName: 'Orca',
worktreeName: 'Dashboard',
startedAt: 1_699_999_000_000,
finishedAt: null,
stateChangedAt: 1_699_999_500_000,
unseen: true,
askSummary: '{"question":"Proceed?"}'
}
]
} satisfies DashboardSnapshot
describe('dashboard payload validation', () => {
it('accepts a complete dashboard snapshot', () => {
expect(isDashboardSnapshot(SNAPSHOT)).toBe(true)
})
it('rejects malformed or unbounded snapshot fields', () => {
expect(isDashboardSnapshot({ ...SNAPSHOT, generatedAt: Number.NaN })).toBe(false)
expect(
isDashboardSnapshot({
...SNAPSHOT,
cards: [{ ...SNAPSHOT.cards[0], bucket: 'unexpected' }]
})
).toBe(false)
expect(
isDashboardSnapshot({
...SNAPSHOT,
cards: [{ ...SNAPSHOT.cards[0], lastAgentMessage: 'x'.repeat(8_001) }]
})
).toBe(false)
})
it('accepts repo icons a pop-out can safely render, and rejects the rest', () => {
expect(
isDashboardSnapshot({
...SNAPSHOT,
repoIconsByRepoId: {
'repo-1': { type: 'lucide', name: 'Rocket' },
'repo-2': null,
'repo-3': {
type: 'image',
src: 'https://github.com/anthropics.png?size=64',
source: 'github'
}
}
})
).toBe(true)
// Absent entirely: a pop-out on older code still gets its snapshot.
expect(isDashboardSnapshot({ ...SNAPSHOT, repoIconsByRepoId: undefined })).toBe(true)
expect(
isDashboardSnapshot({
...SNAPSHOT,
repoIconsByRepoId: {
'repo-1': { type: 'image', src: 'javascript:alert(1)', source: 'file' }
}
})
).toBe(false)
expect(
isDashboardSnapshot({
...SNAPSHOT,
repoIconsByRepoId: { 'repo-1': { type: 'nonsense' } }
})
).toBe(false)
expect(isDashboardSnapshot({ ...SNAPSHOT, repoIconsByRepoId: [] })).toBe(false)
})
it('bounds the conversation name', () => {
expect(
isDashboardSnapshot({
...SNAPSHOT,
cards: [{ ...SNAPSHOT.cards[0], conversationName: 'Sparse-checkout parser' }]
})
).toBe(true)
expect(
isDashboardSnapshot({
...SNAPSHOT,
cards: [{ ...SNAPSHOT.cards[0], conversationName: 'x'.repeat(1_025) }]
})
).toBe(false)
})
it('requires complete bounded reveal routing', () => {
expect(
isDashboardRevealAgentArgs({
repoId: 'repo-1',
worktreeId: 'worktree-1',
tabId: 'tab-1',
leafId: null
})
).toBe(true)
expect(
isDashboardRevealAgentArgs({ repoId: 'repo-1', worktreeId: 'worktree-1', tabId: '' })
).toBe(false)
})
})