From 98790339ef7643d74f4b15b1e2a186d43fe0a0d8 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 21 Feb 2026 23:21:35 +0000 Subject: [PATCH] test: dedupe repeated validation and throw assertions --- src/config/includes.test.ts | 4 +-- src/config/sessions/sessions.test.ts | 8 ++--- src/gateway/call.test.ts | 13 ++++++-- src/slack/blocks-input.test.ts | 50 ++++++++++++++++++---------- 4 files changed, 49 insertions(+), 26 deletions(-) diff --git a/src/config/includes.test.ts b/src/config/includes.test.ts index 8c7e4ff46b3..a36fcb8f90f 100644 --- a/src/config/includes.test.ts +++ b/src/config/includes.test.ts @@ -142,8 +142,8 @@ describe("resolveConfigIncludes", () => { for (const testCase of cases) { const files = { [configPath(testCase.includeFile)]: testCase.included }; const obj = { $include: `./${testCase.includeFile}`, extra: true }; - expect(() => resolve(obj, files), testCase.includeFile).toThrow(ConfigIncludeError); - expect(() => resolve(obj, files), testCase.includeFile).toThrow( + expectResolveIncludeError( + () => resolve(obj, files), /Sibling keys require included content to be an object/, ); } diff --git a/src/config/sessions/sessions.test.ts b/src/config/sessions/sessions.test.ts index 99d415d315f..8924a3f1054 100644 --- a/src/config/sessions/sessions.test.ts +++ b/src/config/sessions/sessions.test.ts @@ -21,10 +21,10 @@ import type { SessionEntry } from "./types.js"; describe("session path safety", () => { it("rejects unsafe session IDs", () => { - expect(() => validateSessionId("../etc/passwd")).toThrow(/Invalid session ID/); - expect(() => validateSessionId("a/b")).toThrow(/Invalid session ID/); - expect(() => validateSessionId("a\\b")).toThrow(/Invalid session ID/); - expect(() => validateSessionId("/abs")).toThrow(/Invalid session ID/); + const unsafeSessionIds = ["../etc/passwd", "a/b", "a\\b", "/abs"]; + for (const sessionId of unsafeSessionIds) { + expect(() => validateSessionId(sessionId), sessionId).toThrow(/Invalid session ID/); + } }); it("resolves transcript path inside an explicit sessions dir", () => { diff --git a/src/gateway/call.test.ts b/src/gateway/call.test.ts index aa18d6fd5d6..f716e39d60c 100644 --- a/src/gateway/call.test.ts +++ b/src/gateway/call.test.ts @@ -333,9 +333,16 @@ describe("buildGatewayConnectionDetails", () => { resolveGatewayPort.mockReturnValue(18789); pickPrimaryTailnetIPv4.mockReturnValue(undefined); - expect(() => buildGatewayConnectionDetails()).toThrow("SECURITY ERROR"); - expect(() => buildGatewayConnectionDetails()).toThrow("plaintext ws://"); - expect(() => buildGatewayConnectionDetails()).toThrow("wss://"); + let thrown: unknown; + try { + buildGatewayConnectionDetails(); + } catch (error) { + thrown = error; + } + expect(thrown).toBeInstanceOf(Error); + expect((thrown as Error).message).toContain("SECURITY ERROR"); + expect((thrown as Error).message).toContain("plaintext ws://"); + expect((thrown as Error).message).toContain("wss://"); }); it("allows ws:// for loopback addresses in local mode", () => { diff --git a/src/slack/blocks-input.test.ts b/src/slack/blocks-input.test.ts index 72b851ce27f..dba05e8103f 100644 --- a/src/slack/blocks-input.test.ts +++ b/src/slack/blocks-input.test.ts @@ -19,23 +19,39 @@ describe("parseSlackBlocksInput", () => { expect(parsed).toEqual([{ type: "section", text: { type: "mrkdwn", text: "hi" } }]); }); - it("rejects invalid JSON", () => { - expect(() => parseSlackBlocksInput("{bad-json")).toThrow(/valid JSON/i); - }); + it("rejects invalid block payloads", () => { + const cases = [ + { + name: "invalid JSON", + input: "{bad-json", + expectedMessage: /valid JSON/i, + }, + { + name: "non-array payload", + input: { type: "divider" }, + expectedMessage: /must be an array/i, + }, + { + name: "empty array", + input: [], + expectedMessage: /at least one block/i, + }, + { + name: "non-object block", + input: ["not-a-block"], + expectedMessage: /must be an object/i, + }, + { + name: "missing block type", + input: [{}], + expectedMessage: /non-empty string type/i, + }, + ] as const; - it("rejects non-array payloads", () => { - expect(() => parseSlackBlocksInput({ type: "divider" })).toThrow(/must be an array/i); - }); - - it("rejects empty arrays", () => { - expect(() => parseSlackBlocksInput([])).toThrow(/at least one block/i); - }); - - it("rejects non-object blocks", () => { - expect(() => parseSlackBlocksInput(["not-a-block"])).toThrow(/must be an object/i); - }); - - it("rejects blocks without type", () => { - expect(() => parseSlackBlocksInput([{}])).toThrow(/non-empty string type/i); + for (const testCase of cases) { + expect(() => parseSlackBlocksInput(testCase.input), testCase.name).toThrow( + testCase.expectedMessage, + ); + } }); });