From e928f5553755bde2805a83a06db818c2281ca1d6 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 13 Mar 2026 19:01:16 +0000 Subject: [PATCH] test: tighten warning and npm integrity coverage --- src/infra/npm-integrity.test.ts | 82 ++++++++++++++++++++++++++------ src/infra/warning-filter.test.ts | 60 ++++++++++++++++------- 2 files changed, 110 insertions(+), 32 deletions(-) diff --git a/src/infra/npm-integrity.test.ts b/src/infra/npm-integrity.test.ts index e7e40b46413..aa96da76fab 100644 --- a/src/infra/npm-integrity.test.ts +++ b/src/infra/npm-integrity.test.ts @@ -6,23 +6,34 @@ import { describe("resolveNpmIntegrityDrift", () => { it("returns proceed=true when integrity is missing or unchanged", async () => { - await expect( - resolveNpmIntegrityDrift({ - spec: "@openclaw/test@1.0.0", - expectedIntegrity: "sha512-same", + const createPayload = vi.fn(() => "unused"); + const cases = [ + { + expectedIntegrity: undefined, resolution: { integrity: "sha512-same", resolvedAt: "2026-01-01T00:00:00.000Z" }, - createPayload: () => "unused", - }), - ).resolves.toEqual({ proceed: true }); - - await expect( - resolveNpmIntegrityDrift({ - spec: "@openclaw/test@1.0.0", + }, + { expectedIntegrity: "sha512-same", resolution: { resolvedAt: "2026-01-01T00:00:00.000Z" }, - createPayload: () => "unused", - }), - ).resolves.toEqual({ proceed: true }); + }, + { + expectedIntegrity: "sha512-same", + resolution: { integrity: "sha512-same", resolvedAt: "2026-01-01T00:00:00.000Z" }, + }, + ]; + + for (const testCase of cases) { + await expect( + resolveNpmIntegrityDrift({ + spec: "@openclaw/test@1.0.0", + expectedIntegrity: testCase.expectedIntegrity, + resolution: testCase.resolution, + createPayload, + }), + ).resolves.toEqual({ proceed: true }); + } + + expect(createPayload).not.toHaveBeenCalled(); }); it("uses callback on integrity drift", async () => { @@ -52,6 +63,31 @@ describe("resolveNpmIntegrityDrift", () => { }); }); + it("returns payload when the drift callback allows continuing", async () => { + const result = await resolveNpmIntegrityDrift({ + spec: "@openclaw/test@1.0.0", + expectedIntegrity: "sha512-old", + resolution: { + integrity: "sha512-new", + resolvedAt: "2026-01-01T00:00:00.000Z", + }, + createPayload: ({ spec, actualIntegrity }) => ({ spec, actualIntegrity }), + onIntegrityDrift: async () => true, + }); + + expect(result).toEqual({ + integrityDrift: { + expectedIntegrity: "sha512-old", + actualIntegrity: "sha512-new", + }, + payload: { + spec: "@openclaw/test@1.0.0", + actualIntegrity: "sha512-new", + }, + proceed: true, + }); + }); + it("warns by default when no callback is provided", async () => { const warn = vi.fn(); const result = await resolveNpmIntegrityDrift({ @@ -100,4 +136,22 @@ describe("resolveNpmIntegrityDrift", () => { "aborted: npm package integrity drift detected for @openclaw/test@1.0.0", ); }); + + it("falls back to the original spec when resolvedSpec is missing", async () => { + const warn = vi.fn(); + + await resolveNpmIntegrityDriftWithDefaultMessage({ + spec: "@openclaw/test@1.0.0", + expectedIntegrity: "sha512-old", + resolution: { + integrity: "sha512-new", + resolvedAt: "2026-01-01T00:00:00.000Z", + }, + warn, + }); + + expect(warn).toHaveBeenCalledWith( + "Integrity drift detected for @openclaw/test@1.0.0: expected sha512-old, got sha512-new", + ); + }); }); diff --git a/src/infra/warning-filter.test.ts b/src/infra/warning-filter.test.ts index 9333d23da0c..1eb3b1372b5 100644 --- a/src/infra/warning-filter.test.ts +++ b/src/infra/warning-filter.test.ts @@ -12,6 +12,10 @@ function resetWarningFilterInstallState(): void { process.emitWarning = baseEmitWarning; } +async function flushWarnings(): Promise { + await new Promise((resolve) => setImmediate(resolve)); +} + describe("warning filter", () => { beforeEach(() => { resetWarningFilterInstallState(); @@ -23,36 +27,49 @@ describe("warning filter", () => { }); it("suppresses known deprecation and experimental warning signatures", () => { - expect( - shouldIgnoreWarning({ + const ignoredWarnings = [ + { name: "DeprecationWarning", code: "DEP0040", message: "The punycode module is deprecated.", - }), - ).toBe(true); - expect( - shouldIgnoreWarning({ + }, + { name: "DeprecationWarning", code: "DEP0060", message: "The `util._extend` API is deprecated.", - }), - ).toBe(true); - expect( - shouldIgnoreWarning({ + }, + { name: "ExperimentalWarning", message: "SQLite is an experimental feature and might change at any time", - }), - ).toBe(true); + }, + ]; + + for (const warning of ignoredWarnings) { + expect(shouldIgnoreWarning(warning)).toBe(true); + } }); it("keeps unknown warnings visible", () => { - expect( - shouldIgnoreWarning({ + const visibleWarnings = [ + { name: "DeprecationWarning", code: "DEP9999", message: "Totally new warning", - }), - ).toBe(false); + }, + { + name: "ExperimentalWarning", + message: "Different experimental warning", + }, + { + name: "DeprecationWarning", + code: "DEP0040", + message: "Different deprecated module", + }, + ]; + + for (const warning of visibleWarnings) { + expect(shouldIgnoreWarning(warning)).toBe(false); + } }); it("installs once and suppresses known warnings at emit time", async () => { @@ -82,11 +99,18 @@ describe("warning filter", () => { type: "DeprecationWarning", code: "DEP0060", }); - await new Promise((resolve) => setImmediate(resolve)); + emitWarning( + Object.assign(new Error("The punycode module is deprecated."), { + name: "DeprecationWarning", + code: "DEP0040", + }), + ); + await flushWarnings(); expect(seenWarnings.find((warning) => warning.code === "DEP0060")).toBeUndefined(); + expect(seenWarnings.find((warning) => warning.code === "DEP0040")).toBeUndefined(); emitWarning("Visible warning", { type: "Warning", code: "OPENCLAW_TEST_WARNING" }); - await new Promise((resolve) => setImmediate(resolve)); + await flushWarnings(); expect( seenWarnings.find((warning) => warning.code === "OPENCLAW_TEST_WARNING"), ).toBeDefined();