From 337feb297dca085655e9691cdf9448e09e6a78bc Mon Sep 17 00:00:00 2001 From: can1357 Date: Sat, 11 Jul 2026 11:31:08 +0200 Subject: [PATCH] test: improved test null safety and type assertions - Added explicit existence checks for objects prior to property access across various test suites. - Replaced optional chaining with non-null assertions to satisfy TypeScript strictness requirements in test assertions. --- packages/ai/test/anthropic-alignment.test.ts | 11 ++++++++--- .../ai/test/openai-codex-responses-lite.test.ts | 14 ++++++++------ .../test/openai-responses-history-payload.test.ts | 5 +++-- packages/ai/test/openai-responses-stateful.test.ts | 7 ++++--- packages/ai/test/pre-response-timeout.test.ts | 7 ++++--- packages/ai/test/stream-auth-retry.test.ts | 6 ++++-- .../sdk-custom-tools-per-session-binding.test.ts | 12 ++++++++---- .../coding-agent/test/session-messages.test.ts | 3 ++- .../tools/browser-cmux-release-mid-run.test.ts | 7 ++++--- packages/coding-agent/test/tools/irc.test.ts | 3 ++- .../test/web/search/perplexity.test.ts | 8 +++++--- 11 files changed, 52 insertions(+), 31 deletions(-) diff --git a/packages/ai/test/anthropic-alignment.test.ts b/packages/ai/test/anthropic-alignment.test.ts index 837bf7b21..1ed9d20fc 100644 --- a/packages/ai/test/anthropic-alignment.test.ts +++ b/packages/ai/test/anthropic-alignment.test.ts @@ -382,12 +382,17 @@ describe("Anthropic request fingerprint alignment", () => { // cache window (the Continue. pad is appended after it) but must not get // a breakpoint — Anthropic rejects cache_control on thinking blocks. const assistant = payload.messages?.find(message => message.role === "assistant"); - expect(Array.isArray(assistant?.content)).toBe(true); - for (const block of assistant?.content as Array<{ type: string; cache_control?: unknown }>) { + expect(assistant).toBeDefined(); + const assistantContent = assistant?.content; + expect(Array.isArray(assistantContent)).toBe(true); + for (const block of (assistantContent ?? []) as Array<{ type: string; cache_control?: unknown }>) { expect(block.cache_control).toBeUndefined(); } const last = payload.messages?.at(-1); - expect((last?.content as Array<{ cache_control?: unknown }>)[0]?.cache_control).toBeDefined(); + expect(last).toBeDefined(); + const lastContent = last?.content; + expect(Array.isArray(lastContent)).toBe(true); + expect((lastContent as Array<{ cache_control?: unknown }>)[0]?.cache_control).toBeDefined(); }); it("adds effort and mid-conversation betas to API-key requests that use those features", async () => { diff --git a/packages/ai/test/openai-codex-responses-lite.test.ts b/packages/ai/test/openai-codex-responses-lite.test.ts index a57e515dd..8ef2319bb 100644 --- a/packages/ai/test/openai-codex-responses-lite.test.ts +++ b/packages/ai/test/openai-codex-responses-lite.test.ts @@ -665,12 +665,14 @@ describe("openai-codex Responses Lite and client metadata wire format", () => { }).result(); expect(result.stopReason).toBe("stop"); - expect(captured?.headers.get("x-openai-internal-codex-responses-lite")).toBe("true"); - expect(captured?.headers.get("version")).toBe("0.144.1"); - expect(captured?.body.reasoning).toEqual({ context: "all_turns" }); - expect(captured?.body.instructions).toBeUndefined(); - expect(captured?.body.tools).toBeUndefined(); - expect((captured?.body.input as Array>)[0]?.type).toBe("additional_tools"); + expect(captured).toBeDefined(); + expect(captured!.headers.get("x-openai-internal-codex-responses-lite")).toBe("true"); + expect(captured!.headers.get("version")).toBe("0.144.1"); + const body = captured!.body; + expect(body.reasoning).toEqual({ context: "all_turns" }); + expect(body.instructions).toBeUndefined(); + expect(body.tools).toBeUndefined(); + expect((body.input as Array>)[0]?.type).toBe("additional_tools"); }); it("omits the lite marker while retaining canonical client_metadata", async () => { diff --git a/packages/ai/test/openai-responses-history-payload.test.ts b/packages/ai/test/openai-responses-history-payload.test.ts index a1a4dc84e..78886cc84 100644 --- a/packages/ai/test/openai-responses-history-payload.test.ts +++ b/packages/ai/test/openai-responses-history-payload.test.ts @@ -1181,9 +1181,10 @@ describe("OpenAI responses history payload", () => { ), ).toBe(false); expect(reasoningItem?.encrypted_content).toBe("enc_opaque"); - expect(functionCallItem?.call_id).toBe(expectedCallId); + expect(functionCallItem).toBeDefined(); + expect(functionCallItem!.call_id).toBe(expectedCallId); expect(functionCallOutputItem?.call_id).toBe(expectedCallId); - expect((functionCallItem?.call_id as string).length).toBeLessThanOrEqual(64); + expect((functionCallItem!.call_id as string).length).toBeLessThanOrEqual(64); expect(containsAssistantOutputText(payload.input, "Sanitized assistant answer")).toBe(true); expect(replayHistoryItems[0]?.id).toBe(opaqueReasoningId); expect(replayHistoryItems[1]?.id).toBe(opaqueMessageId); diff --git a/packages/ai/test/openai-responses-stateful.test.ts b/packages/ai/test/openai-responses-stateful.test.ts index 98c37ff03..8f6fb1b1a 100644 --- a/packages/ai/test/openai-responses-stateful.test.ts +++ b/packages/ai/test/openai-responses-stateful.test.ts @@ -396,8 +396,9 @@ describe("openai-responses stateful chaining", () => { expect(sentRequests).toHaveLength(2); expect(sentRequests[0]?.store).toBe(false); - expect(sentRequests[1]?.store).toBe(false); - expect(sentRequests[1]?.previous_response_id).toBeUndefined(); - expect((sentRequests[1]?.input as unknown[]).length).toBeGreaterThan(1); + expect(sentRequests[1]).toBeDefined(); + expect(sentRequests[1]!.store).toBe(false); + expect(sentRequests[1]!.previous_response_id).toBeUndefined(); + expect((sentRequests[1]!.input as unknown[]).length).toBeGreaterThan(1); }); }); diff --git a/packages/ai/test/pre-response-timeout.test.ts b/packages/ai/test/pre-response-timeout.test.ts index 12a22dee9..a72fdb90a 100644 --- a/packages/ai/test/pre-response-timeout.test.ts +++ b/packages/ai/test/pre-response-timeout.test.ts @@ -54,9 +54,10 @@ describe("armPreResponseTimeout", () => { const caller = new AbortController(); const { signal, clear } = armPreResponseTimeout(caller.signal, 60_000); clear(); - expect(signal?.aborted).toBe(false); + expect(signal).toBeDefined(); + expect(signal!.aborted).toBe(false); caller.abort(new Error("caller cancelled")); - expect(signal?.aborted).toBe(true); - expect((signal?.reason as Error).message).toBe("caller cancelled"); + expect(signal!.aborted).toBe(true); + expect((signal!.reason as Error).message).toBe("caller cancelled"); }); }); diff --git a/packages/ai/test/stream-auth-retry.test.ts b/packages/ai/test/stream-auth-retry.test.ts index 856fb08ae..a3e7e5bee 100644 --- a/packages/ai/test/stream-auth-retry.test.ts +++ b/packages/ai/test/stream-auth-retry.test.ts @@ -114,7 +114,8 @@ describe("streamSimple resolver auth retry", () => { { lastChance: false, hasError: false }, { lastChance: false, hasError: true }, ]); - expect((contexts[1]?.error as { status?: number }).status).toBe(401); + expect(contexts[1]).toBeDefined(); + expect((contexts[1]!.error as { status?: number }).status).toBe(401); }); it("buffers the start event and retries on a 401 error event before content", async () => { @@ -503,7 +504,8 @@ describe("streamSimple resolver auth retry", () => { expect(retryContexts.map(ctx => ({ lastChance: ctx.lastChance, hasError: ctx.error !== undefined }))).toEqual([ { lastChance: true, hasError: true }, ]); - expect((retryContexts[0]?.error as Error).message).toContain("Resource exhausted"); + expect(retryContexts[0]).toBeDefined(); + expect((retryContexts[0]!.error as Error).message).toContain("Resource exhausted"); }); it("surfaces the original error when the resolver declines every retry", async () => { diff --git a/packages/coding-agent/test/sdk-custom-tools-per-session-binding.test.ts b/packages/coding-agent/test/sdk-custom-tools-per-session-binding.test.ts index a0bd07a9b..712886993 100644 --- a/packages/coding-agent/test/sdk-custom-tools-per-session-binding.test.ts +++ b/packages/coding-agent/test/sdk-custom-tools-per-session-binding.test.ts @@ -61,8 +61,10 @@ describe("loadCustomTools per-session binding (#2190 review fix)", () => { expect(parentResult.tools).toHaveLength(1); expect(subagentResult.tools).toHaveLength(1); - const parentApi = (parentResult.tools[0]?.tool as unknown as { __boundApi: CustomToolAPI }).__boundApi; - const subagentApi = (subagentResult.tools[0]?.tool as unknown as { __boundApi: CustomToolAPI }).__boundApi; + expect(parentResult.tools[0]).toBeDefined(); + expect(subagentResult.tools[0]).toBeDefined(); + const parentApi = (parentResult.tools[0]!.tool as unknown as { __boundApi: CustomToolAPI }).__boundApi; + const subagentApi = (subagentResult.tools[0]!.tool as unknown as { __boundApi: CustomToolAPI }).__boundApi; expect(parentApi.cwd).toBe("/tmp/parent-cwd"); expect(subagentApi.cwd).toBe("/tmp/subagent-cwd"); @@ -82,8 +84,10 @@ describe("loadCustomTools per-session binding (#2190 review fix)", () => { subagentLog.push(`subagent:${action.label}`), ); - const parentApi = (parentResult.tools[0]?.tool as unknown as { __boundApi: CustomToolAPI }).__boundApi; - const subagentApi = (subagentResult.tools[0]?.tool as unknown as { __boundApi: CustomToolAPI }).__boundApi; + expect(parentResult.tools[0]).toBeDefined(); + expect(subagentResult.tools[0]).toBeDefined(); + const parentApi = (parentResult.tools[0]!.tool as unknown as { __boundApi: CustomToolAPI }).__boundApi; + const subagentApi = (subagentResult.tools[0]!.tool as unknown as { __boundApi: CustomToolAPI }).__boundApi; // Cast: the test fixture exposes the runtime API verbatim. parentApi.pushPendingAction({ diff --git a/packages/coding-agent/test/session-messages.test.ts b/packages/coding-agent/test/session-messages.test.ts index f2ad3f361..a80e9825f 100644 --- a/packages/coding-agent/test/session-messages.test.ts +++ b/packages/coding-agent/test/session-messages.test.ts @@ -54,7 +54,8 @@ describe("convertToLlm compaction summary", () => { { role: "compactionSummary", summary: "plain summary", tokensBefore: 1000, timestamp: Date.now() }, ]; const converted = convertToLlm(messages); - expect((converted[0]?.content as unknown[]).length).toBe(1); + expect(converted[0]).toBeDefined(); + expect((converted[0]!.content as unknown[]).length).toBe(1); }); }); diff --git a/packages/coding-agent/test/tools/browser-cmux-release-mid-run.test.ts b/packages/coding-agent/test/tools/browser-cmux-release-mid-run.test.ts index 1845e527f..dbecc8f30 100644 --- a/packages/coding-agent/test/tools/browser-cmux-release-mid-run.test.ts +++ b/packages/coding-agent/test/tools/browser-cmux-release-mid-run.test.ts @@ -267,9 +267,10 @@ describe("browser tab-supervisor — cmux tab close mid-run (#4499)", () => { // the composed `runSignal` in `runInTabWithSnapshot` transitions // to aborted. Without this line, the reviewer's failure mode // stands: the run body keeps executing until its own timeout. - expect(capturedCloseAc?.signal.aborted).toBe(true); - expect(capturedCloseAc?.signal.reason).toBeInstanceOf(Error); - expect((capturedCloseAc?.signal.reason as Error).message).toMatch(/Tab "docfinal" was closed/); + expect(capturedCloseAc).toBeDefined(); + expect(capturedCloseAc!.signal.aborted).toBe(true); + expect(capturedCloseAc!.signal.reason).toBeInstanceOf(Error); + expect((capturedCloseAc!.signal.reason as Error).message).toMatch(/Tab "docfinal" was closed/); // Caller-facing contract: `runInTab` rejects with the tab-close // error immediately, not after the run's 60_000ms timeout. diff --git a/packages/coding-agent/test/tools/irc.test.ts b/packages/coding-agent/test/tools/irc.test.ts index 8953510a7..ca51e346c 100644 --- a/packages/coding-agent/test/tools/irc.test.ts +++ b/packages/coding-agent/test/tools/irc.test.ts @@ -735,7 +735,8 @@ describe("IRC", () => { expect(promptSpy).toHaveBeenCalledTimes(1); // The idle wake routes through #wakeForIrc, which batches records into one prompt — // even a lone incoming message is delivered as a one-element array. - const prompted = (promptSpy.mock.calls[0]?.[0] as unknown as CustomMessage[])[0]; + expect(promptSpy.mock.calls[0]).toBeDefined(); + const prompted = (promptSpy.mock.calls[0]![0] as unknown as CustomMessage[])[0]; expect(prompted).toMatchObject({ role: "custom", customType: "irc:incoming" }); expect(prompted.details).toMatchObject({ id: "msg-1", from: "0-Peer", message: "wake up" }); diff --git a/packages/coding-agent/test/web/search/perplexity.test.ts b/packages/coding-agent/test/web/search/perplexity.test.ts index 6153b9394..30c4f9949 100644 --- a/packages/coding-agent/test/web/search/perplexity.test.ts +++ b/packages/coding-agent/test/web/search/perplexity.test.ts @@ -356,9 +356,11 @@ describe("Perplexity OAuth request shape", () => { // The consumer ask endpoint has no system slot; prepending the prompt makes // the model refuse ("I don't have web-search tools in this turn"). - expect(body?.query_str).toBe("quic vs tcp"); - expect((body?.params as Record).query_str).toBe("quic vs tcp"); - expect((body?.params as Record).model_preference).toBe("experimental"); + expect(body).toBeDefined(); + expect(body!.query_str).toBe("quic vs tcp"); + const params = body!.params as Record; + expect(params.query_str).toBe("quic vs tcp"); + expect(params.model_preference).toBe("experimental"); // The ask endpoint authenticates via the next-auth session cookie; a bearer // header is ignored and silently downgrades to the anonymous `turbo` model. expect(headers?.get("cookie")).toBe("__Secure-next-auth.session-token=test-oauth-token");