Files
bowenliang123 87a2893190 refactor(comments): clean up the test-suite comments to the guideline
Apply the AGENTS.md comments guideline to every .ts under tests/: remove
what the code already expresses, keep only what it cannot.

Removed: spec-header coverage inventories the describe/test tree already
names; comments restating the next line's assertion or its message; helper
JSDoc whose body already says it; within-file duplicates; five stale
claims (trendChart's "six aggregated turns" against agg.length === 8,
agentGraph's "six categories" against CATS' seven, fold-timing's "cheapest
call LAST" against a loop that feeds it first, fold-surface's unreachable
plain-JSON note, contextView's "two turns" for a one-turn fixture).

Kept and condensed: the projection-freeze class, strict wire/state-schema
hazards, retention and pricing windows, pairing rules, hostile-input
rationale, fixture and expectation-array ground truth, jsdom mechanics,
and issue-numbered regressions.

Comment lines 2604 -> 2014 (-22%); 85 module headers kept, 30 coverage
inventories dropped; every surviving comment line is within the 140-column
limit, with 36 wrapped lines joined onto fuller ones.

No logic, string, identifier, import or directive changed: a comment-strip
gate proves each file's comment-free code is byte-identical to HEAD, and a
line-level proof pairs all 845 changed lines with an unchanged code part.
pnpm run lint && pnpm run test (106 files / 2061 tests, per-file 100%
coverage) && pnpm run build all pass.
2026-10-10 00:50:55 +08:00

142 lines
5.7 KiB
TypeScript

// The /context slash command (src/client/command.ts) over a faithful harness ctx. Session ids are unique per test
// so the module-level modal/consume state never leaks between cases.
import assert from 'node:assert/strict'
import { describe, test } from 'vitest'
import { registerContextCommand } from '../../src/client/command'
import { DICT_EN } from '../../src/client/i18n'
import { ContextIcon } from '../../src/client/icon'
import { modalStoreOf, takePendingConsume } from '../../src/client/modalStore'
import type { InputTriggersFace } from '../../src/client/services'
import { asClientCtx, TestClientCtx } from './helpers/harness'
import { makeKit } from './helpers/kit'
type Source = Parameters<InputTriggersFace['registerSource']>[0]
class TestInputTriggers {
readonly sources: Source[] = []
registerSource(src: Source): () => void {
this.sources.push(src)
return () => {
const i = this.sources.indexOf(src)
if (i >= 0) this.sources.splice(i, 1)
}
}
}
const SIGNAL = new AbortController().signal
function setup(): { ctx: TestClientCtx; inputTriggers: TestInputTriggers; source: Source } {
const inputTriggers = new TestInputTriggers()
const ctx = new TestClientCtx({ services: { inputTriggers } })
registerContextCommand(asClientCtx(ctx), makeKit())
assert.equal(inputTriggers.sources.length, 1)
return { ctx, inputTriggers, source: inputTriggers.sources[0] }
}
describe('registerContextCommand', () => {
test('without the input-triggers service nothing registers and disposal is safe', () => {
const ctx = new TestClientCtx()
registerContextCommand(asClientCtx(ctx), makeKit())
ctx.dispose()
})
test('a service provided with a foreign shape registers nothing', () => {
// The inject callback fires on the service NAME; a value that is not a
// trigger face (a half-composed module, a producer drift) must degrade
// to the no-command state instead of throwing at apply.
const ctx = new TestClientCtx({ services: { inputTriggers: { registerSource: 42 } } })
registerContextCommand(asClientCtx(ctx), makeKit())
ctx.dispose()
})
test('with the service it registers one "/" source named context at order 1', () => {
const { ctx, inputTriggers, source } = setup()
assert.equal(source.trigger, '/')
assert.equal(source.name, 'context')
assert.equal(source.order, 1)
ctx.dispose()
assert.equal(inputTriggers.sources.length, 0)
})
})
describe('candidates', () => {
test('a non-leading position yields no candidates', async () => {
const { source } = setup()
assert.deepEqual(await source.candidates({ sessionId: 'cmd-pos' }, { query: '', position: 'trailing', signal: SIGNAL }), [])
})
test('an empty query yields the context candidate', async () => {
const { source } = setup()
const candidates = await source.candidates({ sessionId: 'cmd-empty' }, { query: '', position: 'leading', signal: SIGNAL })
// The localized section replaces the menu's raw source-name title row;
// the localized label and glyph are display-only (older harness builds render the bare name).
assert.deepEqual(candidates, [{
name: 'context',
label: DICT_EN['cmd.label'],
icon: ContextIcon,
section: DICT_EN['cmd.section'],
description: DICT_EN['cmd.desc'],
}])
})
test('a matching prefix yields the candidate; a mismatch yields none', async () => {
const { source } = setup()
const session = { sessionId: 'cmd-prefix' }
const hit = await source.candidates(session, { query: 'con', position: 'leading', signal: SIGNAL })
assert.equal(hit.length, 1)
assert.equal(hit[0].name, 'context')
assert.deepEqual(await source.candidates(session, { query: 'xyz', position: 'leading', signal: SIGNAL }), [])
})
test('the query match is case- and whitespace-insensitive', async () => {
const { source } = setup()
const candidates = await source.candidates({ sessionId: 'cmd-case' }, { query: ' CONTEXT ', position: 'leading', signal: SIGNAL })
assert.equal(candidates.length, 1)
})
})
describe('onPick', () => {
test('records the span guard, opens the modal, and answers handled', () => {
const { source } = setup()
const span = { start: 0, end: 8, draftRev: 3 }
const outcome = source.onPick({
candidate: { name: 'context' },
session: { sessionId: 'cmd-pick' },
position: 'leading',
via: 'menu',
span,
})
assert.equal(outcome, 'handled')
assert.equal(modalStoreOf('cmd-pick').getSnapshot(), true)
assert.deepEqual(takePendingConsume('cmd-pick'), { kind: 'span', span })
})
})
describe('matchEnter', () => {
// The contract marks matchEnter optional; registerContextCommand always
// provides it, and the spec asserts that registration shape once.
test('the bare /context line arms the bare-token guard, opens the modal, and answers handled', async () => {
const { source } = setup()
assert.ok(source.matchEnter, 'the /context source registers matchEnter')
const outcome = await source.matchEnter({ sessionId: 'cmd-enter' }, '/context', SIGNAL)
assert.equal(outcome, 'handled')
assert.equal(modalStoreOf('cmd-enter').getSnapshot(), true)
assert.deepEqual(takePendingConsume('cmd-enter'), { kind: 'bare-token', token: '/context' })
})
test('a /context line with trailing text is not matched', async () => {
const { source } = setup()
assert.ok(source.matchEnter)
assert.equal(await source.matchEnter({ sessionId: 'cmd-extra' }, '/context extra', SIGNAL), undefined)
assert.equal(takePendingConsume('cmd-extra'), undefined)
})
test('any other line is not matched', async () => {
const { source } = setup()
assert.ok(source.matchEnter)
assert.equal(await source.matchEnter({ sessionId: 'cmd-other' }, 'hello', SIGNAL), undefined)
})
})