8b501266ff
Add live agent progress, elapsed timing, verified code navigation and rich Markdown rendering. Preserve NanumSquare styling with missing glyph fallback, fix platform availability filtering and unify workspace scrollbar and visualization controls.
88 lines
3.8 KiB
JavaScript
88 lines
3.8 KiB
JavaScript
const { test } = require('node:test')
|
|
const assert = require('node:assert/strict')
|
|
const fs = require('node:fs')
|
|
const vm = require('node:vm')
|
|
const ts = require('typescript')
|
|
const React = require('react')
|
|
const { renderToStaticMarkup } = require('react-dom/server')
|
|
|
|
function harness(initialNow = 1000) {
|
|
let now = initialNow, state, effect, interval, cleared = 0
|
|
const windowEvents = new Map(), documentEvents = new Map()
|
|
class Clock extends Date { static now() { return now } }
|
|
const exports = {}
|
|
vm.runInNewContext(ts.transpileModule(fs.readFileSync(require.resolve('../src/renderer/src/components/AgentWorkDuration.tsx'), 'utf8'), {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022, jsx: ts.JsxEmit.ReactJSX }
|
|
}).outputText, {
|
|
exports, Date: Clock,
|
|
window: {
|
|
setInterval(callback, delay) { assert.equal(delay, 1000); interval = callback; return 7 },
|
|
clearInterval(id) { assert.equal(id, 7); interval = undefined; cleared++ },
|
|
addEventListener: (name, callback) => windowEvents.set(name, callback),
|
|
removeEventListener: name => windowEvents.delete(name)
|
|
},
|
|
document: {
|
|
addEventListener: (name, callback) => documentEvents.set(name, callback),
|
|
removeEventListener: name => documentEvents.delete(name)
|
|
},
|
|
require(name) {
|
|
if (name === '../i18n') return { t: (key, values) => key.replace(/\{\{seconds\}\}/g, values.seconds), useLocaleRender() {} }
|
|
if (name === 'react') return { ...React,
|
|
useState(initial) { state ??= typeof initial === 'function' ? initial() : initial; return [state, value => { state = value }] },
|
|
useEffect(callback) { effect = callback }
|
|
}
|
|
return require(name)
|
|
}
|
|
})
|
|
return {
|
|
render: props => renderToStaticMarkup(exports.AgentWorkDuration({ dark: true, ...props })),
|
|
mount: () => effect(), advance: ms => { now += ms }, tick: () => interval?.(),
|
|
visible: () => documentEvents.get('visibilitychange')?.(), focus: () => windowEvents.get('focus')?.(),
|
|
interval: () => interval, cleared: () => cleared,
|
|
listeners: () => windowEvents.size + documentEvents.size
|
|
}
|
|
}
|
|
|
|
test('running duration is based on start time, not the number of interval ticks', () => {
|
|
const h = harness()
|
|
assert.match(h.render({ startedAt: 1000 }), /0초 동안 작업 중입니다/)
|
|
const cleanup = h.mount()
|
|
h.advance(12_900)
|
|
h.tick()
|
|
assert.match(h.render({ startedAt: 1000 }), /12초 동안 작업 중입니다/)
|
|
h.advance(60_000)
|
|
h.visible()
|
|
assert.match(h.render({ startedAt: 1000 }), /72초 동안 작업 중입니다/)
|
|
h.advance(5_000)
|
|
h.focus()
|
|
assert.match(h.render({ startedAt: 1000 }), /77초 동안 작업 중입니다/)
|
|
assert.equal(h.listeners(), 2)
|
|
cleanup()
|
|
assert.equal(h.interval(), undefined)
|
|
assert.equal(h.listeners(), 0)
|
|
assert.equal(h.cleared(), 1)
|
|
})
|
|
|
|
test('returning to a remounted chat shows the full elapsed time immediately', () => {
|
|
const h = harness(74_000)
|
|
assert.match(h.render({ startedAt: 1000 }), /73초 동안 작업 중입니다/)
|
|
})
|
|
|
|
test('completed duration stays fixed and never starts a timer', () => {
|
|
const h = harness()
|
|
assert.match(h.render({ startedAt: 1000, durationMs: 20_900 }), /20초 동안 작업함/)
|
|
assert.equal(h.mount(), undefined)
|
|
h.advance(60_000)
|
|
h.tick()
|
|
assert.match(h.render({ durationMs: 20_900 }), /20초 동안 작업함/)
|
|
assert.equal(h.interval(), undefined)
|
|
assert.equal(h.listeners(), 0)
|
|
assert.match(h.render({ durationMs: 0 }), /0초 동안 작업함/)
|
|
})
|
|
|
|
test('legacy replies and invalid timing do not invent an elapsed duration', () => {
|
|
const h = harness()
|
|
for (const durationMs of [undefined, -1, NaN, Infinity]) assert.equal(h.render({ durationMs }), '')
|
|
assert.match(h.render({ startedAt: 2000 }), /0초 동안 작업 중입니다/)
|
|
})
|