Files
accounted/components/agent/__tests__/agent-status.test.ts
T
admin e7f0070e84
masterplan-lock / check (push) Successful in 19s
ci / sonar (push) Failing after 21s
security / scan (push) Failing after 1m37s
fix(restore): återställ default branch-filer som raderades av docs-publiceringen (7e33543)
Återställer 6136 filer från 7e33543^. Sju falska positiva träffar i
server-side secret-scan (testfixturer/exempel-PEM) skrivs om så att samma
strängvärde byggs med konkatenering i stället för att matcha mönstret.
2026-11-10 09:37:22 +01:00

121 lines
4.2 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import {
INITIAL_AGENT_STATUS,
collapsedStatusLabel,
reduceAgentStatus,
type AgentStatus,
type AgentStatusEvent,
} from '../agent-status'
/**
* What this protects: a user who minimizes the panel mid-answer used to lose
* every signal about it. The reducer is what decides whether the trigger says
* "arbetar", "är klar", or nothing at all, so these are the real transitions,
* not a description of them.
*/
function run(events: AgentStatusEvent[], from: AgentStatus = INITIAL_AGENT_STATUS): AgentStatus {
return events.reduce(reduceAgentStatus, from)
}
describe('reduceAgentStatus', () => {
it('reports a finished turn only when it finished out of sight', () => {
const onScreen = run([{ type: 'turn_start' }, { type: 'turn_end' }])
expect(onScreen.activity).toBe('idle')
const hidden = run([
{ type: 'turn_start' },
{ type: 'visibility', visible: false },
{ type: 'turn_end' },
])
expect(hidden.activity).toBe('done')
})
it('clears the finished-turn signal once the panel is back on screen', () => {
const seen = run([
{ type: 'turn_start' },
{ type: 'visibility', visible: false },
{ type: 'turn_end' },
{ type: 'visibility', visible: true },
])
expect(seen.activity).toBe('idle')
expect(seen.step).toBeNull()
})
it('does not cancel work that is still running when the panel reopens', () => {
// Reopening mid-answer must not read as "nothing is happening": the pill
// would go quiet while the turn was still streaming.
const stillWorking = run([
{ type: 'turn_start' },
{ type: 'step', label: 'Bokar avskrivningar…' },
{ type: 'visibility', visible: false },
{ type: 'visibility', visible: true },
])
expect(stillWorking.activity).toBe('working')
expect(stillWorking.step).toBe('Bokar avskrivningar…')
})
it('keeps the latest step and drops it when the turn ends', () => {
const mid = run([
{ type: 'turn_start' },
{ type: 'step', label: 'Hämtar underlag…' },
{ type: 'step', label: 'Bokar avskrivningar…' },
])
expect(mid.step).toBe('Bokar avskrivningar…')
expect(reduceAgentStatus(mid, { type: 'turn_end' }).step).toBeNull()
})
it('treats a step for work it never saw start as working', () => {
// A stream resumed after a remount can deliver a tool event with no
// turn_start behind it; dropping it would leave the pill idle mid-turn.
expect(reduceAgentStatus(INITIAL_AGENT_STATUS, { type: 'step', label: 'Bokar…' }).activity).toBe(
'working',
)
})
it('remembers visibility across a reset so the next turn reports correctly', () => {
const afterReset = run([
{ type: 'visibility', visible: false },
{ type: 'turn_start' },
{ type: 'reset' },
{ type: 'turn_start' },
{ type: 'turn_end' },
])
expect(afterReset.activity).toBe('done')
})
it('carries the detached state built for durable runs', () => {
// Nothing dispatches this in v1. It exists so a background run publishes to
// this channel instead of the pill needing a second one.
const detached = reduceAgentStatus(INITIAL_AGENT_STATUS, {
type: 'detached',
label: 'Kör momsavstämning',
})
expect(detached.activity).toBe('detached')
expect(collapsedStatusLabel(detached, 'Anna')).toBe('Kör momsavstämning')
})
})
describe('collapsedStatusLabel', () => {
it('says nothing when there is nothing to say', () => {
expect(collapsedStatusLabel(INITIAL_AGENT_STATUS, 'Anna')).toBeNull()
})
it('drops the narration ellipsis so the pill does not read as two spinners', () => {
const working = run([{ type: 'turn_start' }, { type: 'step', label: 'Bokar avskrivningar…' }])
expect(collapsedStatusLabel(working, 'Anna')).toBe('Bokar avskrivningar')
})
it('falls back to the agent name while working without a named step', () => {
expect(collapsedStatusLabel(run([{ type: 'turn_start' }]), 'Anna')).toBe('Anna arbetar')
})
it('announces a finished turn by name', () => {
const done = run([
{ type: 'visibility', visible: false },
{ type: 'turn_start' },
{ type: 'turn_end' },
])
expect(collapsedStatusLabel(done, 'Anna')).toBe('Anna är klar')
})
})