diff --git a/src/openclaw/__tests__/config.test.ts b/src/openclaw/__tests__/config.test.ts index 62972f45a..9255b7464 100644 --- a/src/openclaw/__tests__/config.test.ts +++ b/src/openclaw/__tests__/config.test.ts @@ -5,7 +5,7 @@ import { OpenClawConfigSchema } from "../../config/schema/openclaw" describe("OpenClaw Config", () => { test("resolveGateway resolves HTTP gateway", () => { - const config: OpenClawConfig = { + const config: OpenClawConfig = testCoerce({ enabled: true, gateways: { discord: { @@ -20,7 +20,7 @@ describe("OpenClaw Config", () => { instruction: "Started session {{sessionId}}", }, }, - } as any + }) const resolved = resolveGateway(config, "session-start") expect(resolved).not.toBeNull() @@ -30,31 +30,31 @@ describe("OpenClaw Config", () => { }) test("resolveGateway returns null for disabled config", () => { - const config: OpenClawConfig = { + const config: OpenClawConfig = testCoerce({ enabled: false, gateways: {}, hooks: {}, - } as any + }) expect(resolveGateway(config, "session-start")).toBeNull() }) test("resolveGateway returns null for unknown hook", () => { - const config: OpenClawConfig = { + const config: OpenClawConfig = testCoerce({ enabled: true, gateways: {}, hooks: {}, - } as any + }) expect(resolveGateway(config, "unknown")).toBeNull() }) test("resolveGateway returns null for disabled hook", () => { - const config: OpenClawConfig = { + const config: OpenClawConfig = testCoerce({ enabled: true, gateways: { g: { type: "http", url: "https://example.com" } }, hooks: { event: { enabled: false, gateway: "g", instruction: "i" }, }, - } as any + }) expect(resolveGateway(config, "event")).toBeNull() }) diff --git a/src/openclaw/__tests__/reply-listener-discord.test.ts b/src/openclaw/__tests__/reply-listener-discord.test.ts index 8fcc77c03..d84a99d81 100644 --- a/src/openclaw/__tests__/reply-listener-discord.test.ts +++ b/src/openclaw/__tests__/reply-listener-discord.test.ts @@ -75,7 +75,7 @@ describe("pollDiscordReplies", () => { status: 401, }), )) - globalThis.fetch = fetchMock as unknown as typeof fetch + globalThis.fetch = testCoerce(fetchMock) const state = createState() @@ -109,7 +109,7 @@ describe("pollDiscordReplies", () => { ), ) .mockResolvedValueOnce(new Response(null, { status: 204 })) - globalThis.fetch = fetchMock as unknown as typeof fetch + globalThis.fetch = testCoerce(fetchMock) const lookupSpy = spyOn(sessionRegistryModule, "lookupByMessageId").mockReturnValue({ sessionId: "ses-1", tmuxSession: "session-1", diff --git a/src/shared/frontmatter.test.ts b/src/shared/frontmatter.test.ts index a4e7e4750..19225086b 100644 --- a/src/shared/frontmatter.test.ts +++ b/src/shared/frontmatter.test.ts @@ -216,20 +216,23 @@ Body content` agent: string } + interface FrontmatterWithExtras extends MinimalMeta { + extra_field: string + another_extra: { nested: string; array: string[] } + custom_boolean: boolean + custom_number: number + } + // when - const result = parseFrontmatter(content) + const result = parseFrontmatter(content) // then expect(result.data.description).toBe("Test command") expect(result.data.agent).toBe("build") expect(result.body).toBe("Body content") - // @ts-expect-error - accessing extra field not in MinimalMeta expect(result.data.extra_field).toBe("should not fail") - // @ts-expect-error - accessing extra field not in MinimalMeta expect(result.data.another_extra).toEqual({ nested: "value", array: ["item1", "item2"] }) - // @ts-expect-error - accessing extra field not in MinimalMeta expect(result.data.custom_boolean).toBe(true) - // @ts-expect-error - accessing extra field not in MinimalMeta expect(result.data.custom_number).toBe(42) }) diff --git a/src/shared/git-worktree/collect-git-diff-stats.test.ts b/src/shared/git-worktree/collect-git-diff-stats.test.ts index e74148bf2..080bec382 100644 --- a/src/shared/git-worktree/collect-git-diff-stats.test.ts +++ b/src/shared/git-worktree/collect-git-diff-stats.test.ts @@ -52,7 +52,7 @@ describe("collectGitDiffStats", () => { expect(execSyncSpy).not.toHaveBeenCalled() expect(execFileSyncSpy.mock.calls.length).toBeGreaterThanOrEqual(3) - const calls = execFileSyncSpy.mock.calls as unknown as Array<[string, string[], { cwd?: string }]> + const calls = testCoerce>(execFileSyncSpy.mock.calls) const diffCall = calls.find(([, args]) => args[0] === "diff") const statusCall = calls.find(([, args]) => args[0] === "status") const untrackedCall = calls.find(([, args]) => args[0] === "ls-files") diff --git a/src/shared/migration/migrations-sidecar.ts b/src/shared/migration/migrations-sidecar.ts index 0cbac7db1..9491b3f8a 100644 --- a/src/shared/migration/migrations-sidecar.ts +++ b/src/shared/migration/migrations-sidecar.ts @@ -1,6 +1,7 @@ import * as fs from "node:fs" import * as path from "node:path" import { log } from "../logger" +import { isRecord } from "../record-type-guard" import { writeFileAtomically } from "../write-file-atomically" /** @@ -48,14 +49,9 @@ export function readAppliedMigrations(configPath: string): Set { return new Set() } const content = fs.readFileSync(sidecarPath, "utf-8") - const parsed = JSON.parse(content) as unknown - if ( - parsed && - typeof parsed === "object" && - !Array.isArray(parsed) && - Array.isArray((parsed as MigrationsSidecar).appliedMigrations) - ) { - return new Set((parsed as MigrationsSidecar).appliedMigrations.filter((m): m is string => typeof m === "string")) + const parsed: unknown = JSON.parse(content) + if (isRecord(parsed) && Array.isArray(parsed.appliedMigrations)) { + return new Set(parsed.appliedMigrations.filter((migration): migration is string => typeof migration === "string")) } return new Set() } catch (err) { diff --git a/src/shared/model-suggestion-retry.test.ts b/src/shared/model-suggestion-retry.test.ts index 698419a67..35f9bb4dc 100644 --- a/src/shared/model-suggestion-retry.test.ts +++ b/src/shared/model-suggestion-retry.test.ts @@ -217,7 +217,7 @@ describe("promptWithModelSuggestionRetry", () => { const client = { session: { promptAsync: promptMock } } // when calling promptWithModelSuggestionRetry - await promptWithModelSuggestionRetry(client as any, { + await promptWithModelSuggestionRetry(testCoerce(client), { path: { id: "session-1" }, body: { parts: [{ type: "text", text: "hello" }], @@ -244,7 +244,7 @@ describe("promptWithModelSuggestionRetry", () => { // when calling promptWithModelSuggestionRetry // then should throw the error without retrying await expect( - promptWithModelSuggestionRetry(client as any, { + promptWithModelSuggestionRetry(testCoerce(client), { path: { id: "session-1" }, body: { agent: "explore", @@ -267,7 +267,7 @@ describe("promptWithModelSuggestionRetry", () => { // when calling promptWithModelSuggestionRetry // then should throw the original error await expect( - promptWithModelSuggestionRetry(client as any, { + promptWithModelSuggestionRetry(testCoerce(client), { path: { id: "session-1" }, body: { parts: [{ type: "text", text: "hello" }], @@ -288,7 +288,7 @@ describe("promptWithModelSuggestionRetry", () => { // when calling promptWithModelSuggestionRetry // then should throw the error await expect( - promptWithModelSuggestionRetry(client as any, { + promptWithModelSuggestionRetry(testCoerce(client), { path: { id: "session-1" }, body: { parts: [{ type: "text", text: "hello" }], @@ -307,7 +307,7 @@ describe("promptWithModelSuggestionRetry", () => { const client = { session: { promptAsync: promptMock } } // when calling with additional body fields - await promptWithModelSuggestionRetry(client as any, { + await promptWithModelSuggestionRetry(testCoerce(client), { path: { id: "session-1" }, body: { agent: "explore", @@ -341,7 +341,7 @@ describe("promptWithModelSuggestionRetry", () => { // when calling promptWithModelSuggestionRetry // then should throw the error await expect( - promptWithModelSuggestionRetry(client as any, { + promptWithModelSuggestionRetry(testCoerce(client), { path: { id: "session-1" }, body: { parts: [{ type: "text", text: "hello" }], @@ -365,7 +365,7 @@ describe("promptWithModelSuggestionRetry", () => { // when calling without model in body // then should throw the error await expect( - promptWithModelSuggestionRetry(client as any, { + promptWithModelSuggestionRetry(testCoerce(client), { path: { id: "session-1" }, body: { parts: [{ type: "text", text: "hello" }], @@ -386,7 +386,7 @@ describe("promptSyncWithModelSuggestionRetry", () => { const client = { session: { prompt: promptMock, promptAsync: promptAsyncMock } } // when calling promptSyncWithModelSuggestionRetry - await promptSyncWithModelSuggestionRetry(client as any, { + await promptSyncWithModelSuggestionRetry(testCoerce(client), { path: { id: "session-1" }, body: { parts: [{ type: "text", text: "hello" }], @@ -424,7 +424,7 @@ describe("promptSyncWithModelSuggestionRetry", () => { // when calling with short timeout // then should abort the request and throw timeout error await expect( - promptSyncWithModelSuggestionRetry(client as any, { + promptSyncWithModelSuggestionRetry(testCoerce(client), { path: { id: "session-1" }, body: { parts: [{ type: "text", text: "hello" }], @@ -451,7 +451,7 @@ describe("promptSyncWithModelSuggestionRetry", () => { const client = { session: { prompt: promptMock } } // when calling promptSyncWithModelSuggestionRetry - await promptSyncWithModelSuggestionRetry(client as any, { + await promptSyncWithModelSuggestionRetry(testCoerce(client), { path: { id: "session-1" }, body: { parts: [{ type: "text", text: "hello" }], @@ -477,7 +477,7 @@ describe("promptSyncWithModelSuggestionRetry", () => { // when calling promptSyncWithModelSuggestionRetry // then should throw the original error await expect( - promptSyncWithModelSuggestionRetry(client as any, { + promptSyncWithModelSuggestionRetry(testCoerce(client), { path: { id: "session-1" }, body: { parts: [{ type: "text", text: "hello" }], @@ -504,7 +504,7 @@ describe("promptSyncWithModelSuggestionRetry", () => { // when calling without model in body // then should throw (cannot retry without original model) await expect( - promptSyncWithModelSuggestionRetry(client as any, { + promptSyncWithModelSuggestionRetry(testCoerce(client), { path: { id: "session-1" }, body: { parts: [{ type: "text", text: "hello" }], @@ -521,7 +521,7 @@ describe("promptSyncWithModelSuggestionRetry", () => { const client = { session: { prompt: promptMock } } // when calling with additional body fields - await promptSyncWithModelSuggestionRetry(client as any, { + await promptSyncWithModelSuggestionRetry(testCoerce(client), { path: { id: "session-1" }, body: { agent: "multimodal-looker",