Files
orca/src/shared/agent-session-question-answer.test.ts
T
OrcaWinandOrcaWin 70c4c55db9 test: remove duplicate coverage and strengthen boundary assertions (#33047)
* test: strengthen launch, subject identity, and release witnesses

* test: strengthen approval paths and prompt answer boundaries

* test: strengthen conversation names and mobile log persistence

* refactor: group background task stop contract with stop operations

* test: strengthen question, title, and release validation

* test: distinguish row text and generated dispatch titles

* test: verify mobile revival events and retry exclusivity

* test: reject incomplete child row output assertions

* test: verify copied modules and option selection contracts

* test: verify mobile host state and status retry boundaries

* test: observe connector refusals and real diagnostic delivery

* test: consolidate platform memory coverage and verify bounded work

* test: allow cached legacy failure reads within work bounds

* test: verify packaging boundaries with independent fixtures

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-24 00:13:25 -07:00

129 lines
4.3 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import {
decodeAgentSessionQuestionAnswers,
encodeAgentSessionQuestionAnswers,
isValidAgentSessionQuestionAnswers,
type AgentSessionQuestionAnswer
} from './agent-session-question-answer'
const GROUP_ANSWER_PREFIX = 'question-group:'
function decodeWithOriginalPercentDecoder(encoded: string): unknown {
return JSON.parse(decodeURIComponent(encoded.slice(GROUP_ANSWER_PREFIX.length)))
}
describe('agent-session grouped question answers', () => {
const answers: AgentSessionQuestionAnswer[] = [
{ questionId: 'q1', optionIds: ['target-web', 'target-mobile'] },
{ questionId: 'q2', optionIds: [], other: 'SSH host' }
]
it('round-trips grouped answers and rejects malformed wire payloads', () => {
expect(decodeAgentSessionQuestionAnswers(encodeAgentSessionQuestionAnswers(answers))).toEqual(
answers
)
const malformed = [
'not-grouped',
'question-group:%',
'question-group:not-json',
'question-group:{}',
`${GROUP_ANSWER_PREFIX}${JSON.stringify([answers[0], { questionId: 'q2', optionIds: [1] }])}`,
`${GROUP_ANSWER_PREFIX}${JSON.stringify([{ questionId: 'q1', optionIds: [], other: 1 }])}`
]
for (const value of malformed) {
expect(decodeAgentSessionQuestionAnswers(value)).toBeNull()
}
})
it('keeps compact answers readable by the original percent-decoding contract', () => {
expect(decodeWithOriginalPercentDecoder(encodeAgentSessionQuestionAnswers(answers))).toEqual(
answers
)
})
it('accepts the previous fully percent-encoded representation', () => {
const encoded = `${GROUP_ANSWER_PREFIX}${encodeURIComponent(JSON.stringify(answers))}`
expect(decodeAgentSessionQuestionAnswers(encoded)).toEqual(answers)
})
it('round-trips percent signs and Unicode through the compact representation', () => {
const unicodeAnswers: AgentSessionQuestionAnswer[] = [
{
questionId: '進捗%',
optionIds: ['100%:完了', '🚀'],
other: 'café 東京 50%'
}
]
expect(
decodeAgentSessionQuestionAnswers(encodeAgentSessionQuestionAnswers(unicodeAnswers))
).toEqual(unicodeAnswers)
expect(
decodeWithOriginalPercentDecoder(encodeAgentSessionQuestionAnswers(unicodeAnswers))
).toEqual(unicodeAnswers)
})
it("keeps Claude's maximum choice group compact without losing selections", () => {
const maximumSelections = Array.from({ length: 4 }, (_, questionIndex) => ({
questionId: `q${questionIndex + 1}`,
optionIds: Array.from(
{ length: 4 },
(_, optionIndex) => `q${questionIndex + 1}:choice-${optionIndex + 1}`
)
}))
const encoded = encodeAgentSessionQuestionAnswers(maximumSelections)
expect(encoded.length).toBeLessThanOrEqual(512)
expect(decodeAgentSessionQuestionAnswers(encoded)).toEqual(maximumSelections)
expect(decodeWithOriginalPercentDecoder(encoded)).toEqual(maximumSelections)
})
it('validates each grouped answer against its question shape', () => {
const questions = [
{
id: 'q1',
question: 'Targets',
multiSelect: true,
options: [
{ id: 'target-web', label: 'Web' },
{ id: 'target-mobile', label: 'Mobile' }
]
},
{
id: 'q2',
question: 'Host',
multiSelect: false,
options: [],
freeTextQuestionId: 'q2'
}
]
expect(isValidAgentSessionQuestionAnswers(questions, answers)).toBe(true)
expect(isValidAgentSessionQuestionAnswers(questions, answers.toReversed())).toBe(true)
const invalid = [
[],
[...answers, { questionId: 'q3', optionIds: [] }],
[answers[0]!, answers[0]!],
[{ ...answers[0]!, questionId: 'unknown' }, answers[1]!],
[{ ...answers[0]!, optionIds: [] }, answers[1]!],
[{ ...answers[0]!, other: 'not offered' }, answers[1]!]
]
for (const candidate of invalid) {
expect(isValidAgentSessionQuestionAnswers(questions, candidate)).toBe(false)
}
expect(
isValidAgentSessionQuestionAnswers(
[{ ...questions[0]!, multiSelect: false }, questions[1]!],
answers
)
).toBe(false)
expect(
isValidAgentSessionQuestionAnswers(questions, [
{ questionId: 'q1', optionIds: ['unknown'] },
answers[1]!
])
).toBe(false)
})
})