diff --git a/src/commands/doctor-session-transcripts.test.ts b/src/commands/doctor-session-transcripts.test.ts index 1d9b22ba9a2..7ef9c8e7d8f 100644 --- a/src/commands/doctor-session-transcripts.test.ts +++ b/src/commands/doctor-session-transcripts.test.ts @@ -14,6 +14,16 @@ import { repairBrokenSessionTranscriptFile, } from "./doctor-session-transcripts.js"; +function countNonEmptyLines(value: string): number { + let count = 0; + for (const line of value.split(/\r?\n/)) { + if (line) { + count += 1; + } + } + return count; +} + describe("doctor session transcript repair", () => { let root: string; @@ -129,7 +139,7 @@ describe("doctor session transcript repair", () => { expect(title).toBe("Session transcripts"); expect(message).toContain("duplicated prompt-rewrite branches"); expect(message).toContain('Run "openclaw doctor --fix"'); - expect((await fs.readFile(filePath, "utf-8")).split(/\r?\n/).filter(Boolean)).toHaveLength(3); + expect(countNonEmptyLines(await fs.readFile(filePath, "utf-8"))).toBe(3); }); it("ignores ordinary branch history without internal runtime context", async () => { @@ -152,6 +162,6 @@ describe("doctor session transcript repair", () => { const result = await repairBrokenSessionTranscriptFile({ filePath, shouldRepair: true }); expect(result.broken).toBe(false); - expect((await fs.readFile(filePath, "utf-8")).split(/\r?\n/).filter(Boolean)).toHaveLength(3); + expect(countNonEmptyLines(await fs.readFile(filePath, "utf-8"))).toBe(3); }); }); diff --git a/src/gateway/server-methods/server-methods.test.ts b/src/gateway/server-methods/server-methods.test.ts index c49dede5266..9fa3b49f2db 100644 --- a/src/gateway/server-methods/server-methods.test.ts +++ b/src/gateway/server-methods/server-methods.test.ts @@ -31,6 +31,16 @@ vi.mock("../../commands/status.js", () => ({ getStatusSummary: vi.fn().mockResolvedValue({ ok: true }), })); +function countMatching(items: readonly T[], predicate: (item: T) => boolean): number { + let count = 0; + for (const item of items) { + if (predicate(item)) { + count += 1; + } + } + return count; +} + describe("waitForAgentJob", () => { async function runLifecycleScenario(params: { runIdPrefix: string; @@ -1212,7 +1222,7 @@ describe("exec approval handlers", () => { expect(firstResolveRespond).toHaveBeenCalledWith(true, { ok: true }, undefined); expect(repeatResolveRespond).toHaveBeenCalledWith(true, { ok: true }, undefined); - expect(broadcasts.filter((entry) => entry.event === "exec.approval.resolved")).toHaveLength( + expect(countMatching(broadcasts, (entry) => entry.event === "exec.approval.resolved")).toBe( resolvedBroadcastCount, ); expect(conflictingResolveRespond).toHaveBeenCalledWith( diff --git a/src/plugins/loader.test.ts b/src/plugins/loader.test.ts index 08bad34ba37..d39dfa2f0ad 100644 --- a/src/plugins/loader.test.ts +++ b/src/plugins/loader.test.ts @@ -4282,7 +4282,7 @@ module.exports = { id: "throws-after-import", register() {} };`, }, }); - expect(registry.services.filter((entry) => entry.service.id === "shared-service")).toHaveLength( + expect(countMatching(registry.services, (entry) => entry.service.id === "shared-service")).toBe( 1, ); expectNoDiagnosticContaining({ diff --git a/src/secrets/audit.test.ts b/src/secrets/audit.test.ts index 43564a141fa..b2b69b0cffa 100644 --- a/src/secrets/audit.test.ts +++ b/src/secrets/audit.test.ts @@ -18,6 +18,16 @@ type AuditFixture = { const OPENAI_API_KEY_MARKER = "OPENAI_API_KEY"; // pragma: allowlist secret const MAX_AUDIT_MODELS_JSON_BYTES = 5 * 1024 * 1024; +function countNonEmptyLines(value: string): number { + let count = 0; + for (const line of value.split("\n")) { + if (line.trim().length > 0) { + count += 1; + } + } + return count; +} + async function writeJsonFile(filePath: string, value: unknown): Promise { await fs.writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8"); } @@ -334,7 +344,7 @@ describe("secrets audit", () => { expect(report.summary.unresolvedRefCount).toBe(0); const callLog = await fs.readFile(execLogPath, "utf8"); - const callCount = callLog.split("\n").filter((line) => line.trim().length > 0).length; + const callCount = countNonEmptyLines(callLog); expect(callCount).toBe(1); }); @@ -398,7 +408,7 @@ describe("secrets audit", () => { expect(report.summary.unresolvedRefCount).toBeGreaterThanOrEqual(2); const callLog = await fs.readFile(execLogPath, "utf8"); - const callCount = callLog.split("\n").filter((line) => line.trim().length > 0).length; + const callCount = countNonEmptyLines(callLog); expect(callCount).toBe(1); }); diff --git a/test/scripts/parallels-smoke-model.test.ts b/test/scripts/parallels-smoke-model.test.ts index eb4c8bc821e..d538f1d22da 100644 --- a/test/scripts/parallels-smoke-model.test.ts +++ b/test/scripts/parallels-smoke-model.test.ts @@ -35,6 +35,16 @@ const TS_PATHS = { const OS_TS_PATHS = [TS_PATHS.linux, TS_PATHS.macos, TS_PATHS.windows]; +function countNonEmptyLines(value: string): number { + let count = 0; + for (const line of value.split("\n")) { + if (line) { + count += 1; + } + } + return count; +} + function runTsEval(source: string, env: Record = {}) { return execFileSync("node", ["--import", "tsx", "--input-type=module", "--eval", source], { encoding: "utf8", @@ -79,7 +89,7 @@ describe("Parallels smoke model selection", () => { } else { expect(wrapper, wrapperPath).toContain(TS_PATHS[platform as "linux" | "macos" | "windows"]); } - expect(wrapper.split("\n").filter(Boolean).length).toBeLessThanOrEqual(5); + expect(countNonEmptyLines(wrapper)).toBeLessThanOrEqual(5); } }); diff --git a/test/vitest-unit-fast-config.test.ts b/test/vitest-unit-fast-config.test.ts index b6c64b8532e..5c62b7bb9fc 100644 --- a/test/vitest-unit-fast-config.test.ts +++ b/test/vitest-unit-fast-config.test.ts @@ -20,6 +20,16 @@ function requireTestConfig(config: T): NonNullable return config.test as NonNullable; } +function countMatching(items: readonly T[], predicate: (item: T) => boolean): number { + let count = 0; + for (const item of items) { + if (predicate(item)) { + count += 1; + } + } + return count; +} + describe("unit-fast vitest lane", () => { it("runs cache-friendly tests without the reset-heavy runner or runtime setup", () => { const config = createUnitFastVitestConfig({}); @@ -122,7 +132,7 @@ describe("unit-fast vitest lane", () => { expect(currentCandidates.length).toBeGreaterThanOrEqual(unitFastTestFiles.length); expect(broadCandidates.length).toBeGreaterThan(currentCandidates.length); - expect(broadAnalysis.filter((entry) => entry.unitFast).length).toBeGreaterThan( + expect(countMatching(broadAnalysis, (entry) => entry.unitFast)).toBeGreaterThan( unitFastTestFiles.length, ); });