test: add structured output fallback and non-retryable error tests

Cover the two key paths in requestJsonBodyWithStructuredFallback:
1. 400 with response_format mention → retry without structured output
2. 500 server error → no retry, error propagated

Change-Id: If8d0fc484e49238699444131cbadcf1b18bf992f
This commit is contained in:
wujunchen 2026-04-27 12:44:42 +08:00
parent 67a9ccdafb
commit 538d7bcedd

View file

@ -804,10 +804,81 @@ async function testRunCliEdgeCases() {
}
// Wrap the tail in an async runner so module-level tests can include async cases.
async function testStructuredOutputFallback() {
const previousRequestUrlMock = requestUrlMock;
let callCount = 0;
requestUrlMock = async (params) => {
callCount++;
if (callCount === 1) {
// First call: structured output rejected with 400
return {
status: 400,
json: { error: 'response_format is not supported' },
text: JSON.stringify({ error: 'response_format is not supported' }),
};
}
// Second call: fallback succeeds
return openAiCardsResponse([
{ title: 'Fallback', anchor: 'fallback anchor', gist: 'G', bullets: ['B'] },
]);
};
try {
const sections = await t.summarizeDocument(
'intro\nfallback anchor\nend',
{
...baseSettings,
streaming: false,
promptLanguage: 'en',
minCards: 1,
maxCards: 3,
maxDocChars: 10000,
},
{ phase: 'queued', onCancel: () => {}, throwIfCancelled: () => {}, setPhase: () => {} },
);
assert.strictEqual(callCount, 2, 'structured output fallback made two requests');
assert.strictEqual(sections[0].title, 'Fallback', 'fallback response parsed correctly');
} finally {
requestUrlMock = previousRequestUrlMock;
}
}
async function testStructuredOutputNonRetryableError() {
const previousRequestUrlMock = requestUrlMock;
requestUrlMock = async () => ({
status: 500,
json: { error: 'Internal server error' },
text: JSON.stringify({ error: 'Internal server error' }),
});
try {
await assert.rejects(
() => t.summarizeDocument(
'test content',
{
...baseSettings,
streaming: false,
promptLanguage: 'en',
minCards: 1,
maxCards: 3,
maxDocChars: 10000,
},
{ phase: 'queued', onCancel: () => {}, throwIfCancelled: () => {}, setPhase: () => {} },
),
/500/,
'non-retryable error (500) is not caught by structured fallback',
);
} finally {
requestUrlMock = previousRequestUrlMock;
}
}
(async () => {
await testRunCliEdgeCases();
await testCacheManagerMove();
await testSummarizeDocumentAnchorSorting();
await testStructuredOutputFallback();
await testStructuredOutputNonRetryableError();
console.log('modules tests passed');
})().catch((e) => {
console.error(e);