76 lines
2.3 KiB
JavaScript
76 lines
2.3 KiB
JavaScript
|
|
import { test } from 'node:test'
|
||
|
|
import assert from 'node:assert/strict'
|
||
|
|
|
||
|
|
import { formatCost, formatNumber, formatDuration, progressBar, renderConsoleReport, renderMarkdownReport, contextState } from '../src/reports.mjs'
|
||
|
|
|
||
|
|
test('formatNumber uses en-US grouping', () => {
|
||
|
|
assert.equal(formatNumber(1234567), '1,234,567')
|
||
|
|
})
|
||
|
|
|
||
|
|
test('formatCost keeps precision for tiny values', () => {
|
||
|
|
assert.equal(formatCost(0), '$0.0000')
|
||
|
|
assert.match(formatCost(0.002106102), /^\$0\.00211$/)
|
||
|
|
assert.match(formatCost(1.5), /^\$1\.5000$/)
|
||
|
|
})
|
||
|
|
|
||
|
|
test('formatDuration renders mm:ss and hours', () => {
|
||
|
|
assert.equal(formatDuration(65_000), '01:05')
|
||
|
|
assert.equal(formatDuration(3_725_000), '1h 02m')
|
||
|
|
})
|
||
|
|
|
||
|
|
test('progressBar clamps', () => {
|
||
|
|
assert.equal(progressBar(0, 4), '░░░░')
|
||
|
|
assert.equal(progressBar(100, 4), '████')
|
||
|
|
assert.equal(progressBar(50, 4), '██░░')
|
||
|
|
assert.equal(progressBar(999, 4), '████')
|
||
|
|
})
|
||
|
|
|
||
|
|
test('contextState classifies thresholds', () => {
|
||
|
|
assert.equal(contextState(10, 100), 'ok')
|
||
|
|
assert.equal(contextState(80, 100), 'warn')
|
||
|
|
assert.equal(contextState(120, 100), 'over')
|
||
|
|
})
|
||
|
|
|
||
|
|
const report = {
|
||
|
|
runId: 'run',
|
||
|
|
iteration: 2,
|
||
|
|
total: 5,
|
||
|
|
status: 'completed',
|
||
|
|
topic: 'Refactor settings',
|
||
|
|
stageTitle: 'Stage 2',
|
||
|
|
stageId: 's2',
|
||
|
|
stageStatus: 'in_progress',
|
||
|
|
percent: 42,
|
||
|
|
nextStage: 'Stage 3',
|
||
|
|
summary: 'Changed things and verified.',
|
||
|
|
questions: [],
|
||
|
|
tokens: { input: 1000, output: 200, reasoning: 10, cacheRead: 500, total: 1200 },
|
||
|
|
cost: 0.05,
|
||
|
|
contextSize: 1200,
|
||
|
|
contextState: 'ok',
|
||
|
|
contextWarnTokens: 150000,
|
||
|
|
durationMs: 65_000,
|
||
|
|
filesChanged: ['a.ts', 'b.vue'],
|
||
|
|
sessionID: 'ses_1',
|
||
|
|
error: null,
|
||
|
|
}
|
||
|
|
|
||
|
|
test('renderConsoleReport contains the key report fields', async () => {
|
||
|
|
const { setColorEnabled } = await import('../src/ansi.mjs')
|
||
|
|
setColorEnabled(false)
|
||
|
|
const text = renderConsoleReport(report, { cost: 0.2 })
|
||
|
|
assert.match(text, /Iteration 2\/5/)
|
||
|
|
assert.match(text, /Refactor settings/)
|
||
|
|
assert.match(text, /42%/)
|
||
|
|
assert.match(text, /Stage 3/)
|
||
|
|
assert.match(text, /1,200/)
|
||
|
|
})
|
||
|
|
|
||
|
|
test('renderMarkdownReport emits a structured document', () => {
|
||
|
|
const md = renderMarkdownReport(report)
|
||
|
|
assert.match(md, /# Iteration 2\/5/)
|
||
|
|
assert.match(md, /## Files changed/)
|
||
|
|
assert.match(md, /`a\.ts`/)
|
||
|
|
assert.match(md, /## Summary/)
|
||
|
|
})
|