Skip to content

Commit 530033c

Browse files
test(requesty): pin the late-completion discard and the empty-content fallback
Rerunning the unit mutation preflight after the completePrompt fix left three mutants on lines the rewrite touches, none of them reachable by the previous tests: - ConditionalExpression at requesty.ts:333 (the post-completion abort check, replaced by false) survived because the new race settles at the abort, so no test still reached that check. "discards a completion that resolves in the same turn the caller aborts" makes the SDK win the race outright - it returns an already-resolved response and aborts from a handler queued one step ahead of the provider's continuation - and asserts the value is still discarded. Control: deleting the check fails exactly that test with "promise resolved \"'late'\" instead of rejecting". - StringLiteral at requesty.ts:337 (the || "" fallback) was NoCoverage. - OptionalChaining at requesty.ts:337 (choices[0]?.message) survived. "returns an empty string when the completion carries an empty message content / no choices at all" covers both: the string mutant fails both cases with "expected 'Stryker was here!' to be ''", the optional-chain mutant fails the no-choices case with "Cannot read properties of undefined (reading 'message')". requesty.spec.ts 46/46 green; eslint --max-warnings=0, prettier --check and src tsc --noEmit clean; no suppression and no Stryker directive added.
1 parent 311f6b7 commit 530033c

1 file changed

Lines changed: 36 additions & 0 deletions

File tree

‎src/api/providers/__tests__/requesty.spec.ts‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,42 @@ describe("RequestyHandler", () => {
10071007
})
10081008
})
10091009

1010+
it("discards a completion that resolves in the same turn the caller aborts", async () => {
1011+
// The race above settles at the abort, so the post-completion check is reached only when the
1012+
// SDK wins the race outright: the response promise resolves, the abort lands before the
1013+
// provider continues with the value, and the value must still be discarded. Aborting from a
1014+
// handler on the response promise - queued one step ahead of the provider's race handler -
1015+
// pins that interleaving without timing it.
1016+
const handler = new RequestyHandler(mockOptions)
1017+
const controller = new AbortController()
1018+
mockCreate.mockImplementationOnce(() => {
1019+
const response = Promise.resolve({ choices: [{ message: { content: "late" } }] })
1020+
void response.then(() => {
1021+
queueMicrotask(() => controller.abort())
1022+
})
1023+
return response
1024+
})
1025+
1026+
await expect(
1027+
handler.completePrompt("test prompt", { abortSignal: controller.signal }),
1028+
).rejects.toMatchObject({
1029+
name: "AbortError",
1030+
message: "The Requesty request was aborted",
1031+
})
1032+
})
1033+
1034+
it.each([
1035+
["an empty message content", { choices: [{ message: { content: "" } }] }],
1036+
["no choices at all", { choices: [] }],
1037+
])("returns an empty string when the completion carries %s", async (_label: string, response: unknown) => {
1038+
// The fallback is what makes completePrompt return "" rather than an empty value or a
1039+
// TypeError, and callers render the result directly.
1040+
const handler = new RequestyHandler(mockOptions)
1041+
mockCreate.mockResolvedValueOnce(response)
1042+
1043+
await expect(handler.completePrompt("test prompt")).resolves.toBe("")
1044+
})
1045+
10101046
it("does not forward a non-positive timeout to the client", async () => {
10111047
const handler = new RequestyHandler(mockOptions)
10121048
mockCreate.mockResolvedValueOnce({ choices: [{ message: { content: "response" } }] })

0 commit comments

Comments
 (0)