From b148ada1d07a3bef153d6fffac66cb8b2c87efc1 Mon Sep 17 00:00:00 2001 From: murashit Date: Wed, 24 Jun 2026 11:38:47 +0900 Subject: [PATCH] Parameterize repeated test cases --- tests/app-server/thread-settings.test.ts | 32 +++-- .../composer/composer-keys.test.ts | 28 +++-- .../composer/composer-suggestions.test.ts | 34 +++--- .../turns/slash-command-execution.test.ts | 12 +- .../chat/protocol/inbound/routing.test.ts | 115 +++++++++--------- .../protocol/server-requests/approval.test.ts | 91 +++++++------- tests/runtime/service-tier-state.test.ts | 14 ++- 7 files changed, 164 insertions(+), 162 deletions(-) diff --git a/tests/app-server/thread-settings.test.ts b/tests/app-server/thread-settings.test.ts index 88a7227c..ef697133 100644 --- a/tests/app-server/thread-settings.test.ts +++ b/tests/app-server/thread-settings.test.ts @@ -19,11 +19,13 @@ describe("app-server thread settings", () => { expect(update).toEqual({ model: "gpt-5.5", effort: null }); }); - it("parses supported approvals reviewer values", () => { - expect(approvalsReviewerOrNull("user")).toBe("user"); - expect(approvalsReviewerOrNull("auto_review")).toBe("auto_review"); - expect(approvalsReviewerOrNull("guardian_subagent")).toBe("guardian_subagent"); - expect(approvalsReviewerOrNull("unknown")).toBeNull(); + it.each([ + ["user", "user"], + ["auto_review", "auto_review"], + ["guardian_subagent", "guardian_subagent"], + ["unknown", null], + ] as const)("parses approvals reviewer value %s", (value, expected) => { + expect(approvalsReviewerOrNull(value)).toBe(expected); }); it("builds collaboration mode payloads with built-in instructions", () => { @@ -54,18 +56,14 @@ describe("app-server thread settings", () => { }); }); - it("accepts non-empty service tier ids from config and app-server reports", () => { - expect(parseServiceTier("fast")).toBe("fast"); - expect(parseServiceTier("standard")).toBe("standard"); - expect(parseServiceTier("priority")).toBe("priority"); - expect(parseServiceTier("default")).toBe("default"); - expect(parseServiceTier("flex")).toBe("flex"); - expect(parseServiceTier("auto")).toBe("auto"); - expect(parseServiceTier("catalog-tier")).toBe("catalog-tier"); - }); + it.each(["fast", "standard", "priority", "default", "flex", "auto", "catalog-tier"])( + "accepts non-empty service tier id %s from config and app-server reports", + (serviceTier) => { + expect(parseServiceTier(serviceTier)).toBe(serviceTier); + }, + ); - it("ignores absent service tier values", () => { - expect(parseServiceTier("")).toBeNull(); - expect(parseServiceTier(null)).toBeNull(); + it.each(["", null])("ignores absent service tier value %s", (serviceTier) => { + expect(parseServiceTier(serviceTier)).toBeNull(); }); }); diff --git a/tests/features/chat/conversation/composer/composer-keys.test.ts b/tests/features/chat/conversation/composer/composer-keys.test.ts index c7aa4723..e2e17965 100644 --- a/tests/features/chat/conversation/composer/composer-keys.test.ts +++ b/tests/features/chat/conversation/composer/composer-keys.test.ts @@ -12,20 +12,26 @@ const baseEvent: ComposerSendKeyEvent = { }; describe("composer send keys", () => { - it("sends on plain Enter in Enter mode", () => { - expect(isComposerSendKey(baseEvent, "enter")).toBe(true); - expect(isComposerSendKey({ ...baseEvent, shiftKey: true }, "enter")).toBe(false); - expect(isComposerSendKey({ ...baseEvent, metaKey: true }, "enter")).toBe(false); + it.each([ + { name: "plain Enter", event: baseEvent, shortcut: "enter", expected: true }, + { name: "Shift+Enter", event: { ...baseEvent, shiftKey: true }, shortcut: "enter", expected: false }, + { name: "Meta+Enter", event: { ...baseEvent, metaKey: true }, shortcut: "enter", expected: false }, + ] as const)("checks $name in Enter mode", ({ event, shortcut, expected }) => { + expect(isComposerSendKey(event, shortcut)).toBe(expected); }); - it("sends on Cmd/Ctrl+Enter in mod-enter mode", () => { - expect(isComposerSendKey({ ...baseEvent, metaKey: true }, "mod-enter")).toBe(true); - expect(isComposerSendKey({ ...baseEvent, ctrlKey: true }, "mod-enter")).toBe(true); - expect(isComposerSendKey(baseEvent, "mod-enter")).toBe(false); + it.each([ + { name: "Meta+Enter", event: { ...baseEvent, metaKey: true }, shortcut: "mod-enter", expected: true }, + { name: "Ctrl+Enter", event: { ...baseEvent, ctrlKey: true }, shortcut: "mod-enter", expected: true }, + { name: "plain Enter", event: baseEvent, shortcut: "mod-enter", expected: false }, + ] as const)("checks $name in Cmd/Ctrl+Enter mode", ({ event, shortcut, expected }) => { + expect(isComposerSendKey(event, shortcut)).toBe(expected); }); - it("does not send during composition", () => { - expect(isComposerSendKey({ ...baseEvent, isComposing: true }, "enter")).toBe(false); - expect(isComposerSendKey({ ...baseEvent, metaKey: true, isComposing: true }, "mod-enter")).toBe(false); + it.each([ + { name: "Enter mode", event: { ...baseEvent, isComposing: true }, shortcut: "enter" }, + { name: "Cmd/Ctrl+Enter mode", event: { ...baseEvent, metaKey: true, isComposing: true }, shortcut: "mod-enter" }, + ] as const)("does not send during composition in $name", ({ event, shortcut }) => { + expect(isComposerSendKey(event, shortcut)).toBe(false); }); }); diff --git a/tests/features/chat/conversation/composer/composer-suggestions.test.ts b/tests/features/chat/conversation/composer/composer-suggestions.test.ts index 86b746c4..bff6d938 100644 --- a/tests/features/chat/conversation/composer/composer-suggestions.test.ts +++ b/tests/features/chat/conversation/composer/composer-suggestions.test.ts @@ -112,22 +112,24 @@ describe("composer suggestions", () => { }, ]; - it("parses supported slash commands only", () => { - expect(parseSlashCommand("/status")).toEqual({ command: "status", args: "" }); - expect(parseSlashCommand("/clear")).toEqual({ command: "clear", args: "" }); - expect(parseSlashCommand("/resume thread-1")).toEqual({ command: "resume", args: "thread-1" }); - expect(parseSlashCommand("/refer thread-1 続きです")).toEqual({ command: "refer", args: "thread-1 続きです" }); - expect(parseSlashCommand("/fork")).toEqual({ command: "fork", args: "" }); - expect(parseSlashCommand("/archive thread-1")).toEqual({ command: "archive", args: "thread-1" }); - expect(parseSlashCommand("/rename thread-1 New name")).toEqual({ command: "rename", args: "thread-1 New name" }); - expect(parseSlashCommand("/doctor")).toEqual({ command: "doctor", args: "" }); - expect(parseSlashCommand("/fast now")).toEqual({ command: "fast", args: "now" }); - expect(parseSlashCommand("/plan")).toEqual({ command: "plan", args: "" }); - expect(parseSlashCommand("/plan OK、実装してください")).toEqual({ command: "plan", args: "OK、実装してください" }); - expect(parseSlashCommand("/model gpt-5.5")).toEqual({ command: "model", args: "gpt-5.5" }); - expect(parseSlashCommand("/reasoning high")).toEqual({ command: "reasoning", args: "high" }); - expect(parseSlashCommand("/new")).toBeNull(); - expect(parseSlashCommand("/unknown")).toBeNull(); + it.each([ + { input: "/status", expected: { command: "status", args: "" } }, + { input: "/clear", expected: { command: "clear", args: "" } }, + { input: "/resume thread-1", expected: { command: "resume", args: "thread-1" } }, + { input: "/refer thread-1 続きです", expected: { command: "refer", args: "thread-1 続きです" } }, + { input: "/fork", expected: { command: "fork", args: "" } }, + { input: "/archive thread-1", expected: { command: "archive", args: "thread-1" } }, + { input: "/rename thread-1 New name", expected: { command: "rename", args: "thread-1 New name" } }, + { input: "/doctor", expected: { command: "doctor", args: "" } }, + { input: "/fast now", expected: { command: "fast", args: "now" } }, + { input: "/plan", expected: { command: "plan", args: "" } }, + { input: "/plan OK、実装してください", expected: { command: "plan", args: "OK、実装してください" } }, + { input: "/model gpt-5.5", expected: { command: "model", args: "gpt-5.5" } }, + { input: "/reasoning high", expected: { command: "reasoning", args: "high" } }, + { input: "/new", expected: null }, + { input: "/unknown", expected: null }, + ])("parses slash command input $input", ({ input, expected }) => { + expect(parseSlashCommand(input)).toEqual(expected); }); it("ranks wikilinks with Obsidian fuzzy search and uses Obsidian linktext", () => { diff --git a/tests/features/chat/conversation/turns/slash-command-execution.test.ts b/tests/features/chat/conversation/turns/slash-command-execution.test.ts index 98821d97..3e1e3e8f 100644 --- a/tests/features/chat/conversation/turns/slash-command-execution.test.ts +++ b/tests/features/chat/conversation/turns/slash-command-execution.test.ts @@ -651,16 +651,14 @@ describe("slash commands", () => { expect(ctx.addSystemMessage).toHaveBeenCalledWith("Reasoning effort reset to default for subsequent turns."); }); - it("routes runtime reset aliases through reset commands", async () => { + it.each(["reset", "clear", "off"])("routes runtime reset alias %s through reset commands", async (alias) => { const ctx = context(); - for (const alias of ["reset", "clear", "off"]) { - await executeSlashCommand("model", alias, ctx); - await executeSlashCommand("reasoning", alias, ctx); - } + await executeSlashCommand("model", alias, ctx); + await executeSlashCommand("reasoning", alias, ctx); - expect(ctx.runtimeSettings.resetModelToConfig).toHaveBeenCalledTimes(3); - expect(ctx.runtimeSettings.resetReasoningEffortToConfig).toHaveBeenCalledTimes(3); + expect(ctx.runtimeSettings.resetModelToConfig).toHaveBeenCalledOnce(); + expect(ctx.runtimeSettings.resetReasoningEffortToConfig).toHaveBeenCalledOnce(); expect(ctx.runtimeSettings.requestModel).not.toHaveBeenCalled(); expect(ctx.runtimeSettings.requestReasoningEffort).not.toHaveBeenCalled(); }); diff --git a/tests/features/chat/protocol/inbound/routing.test.ts b/tests/features/chat/protocol/inbound/routing.test.ts index 1242fc1b..b994aff0 100644 --- a/tests/features/chat/protocol/inbound/routing.test.ts +++ b/tests/features/chat/protocol/inbound/routing.test.ts @@ -56,28 +56,24 @@ describe("chat inbound routing", () => { ); }); - it("classifies every active-thread server request method and extracts its scope", () => { - const requests = [ - { request: commandApprovalRequest(), kind: "approval" }, - { request: fileChangeApprovalRequest(), kind: "approval" }, - { request: permissionsApprovalRequest(), kind: "approval" }, - { request: userInputRequest({ threadId: "thread-active" }), kind: "userInput" }, - { request: mcpElicitationRequest(), kind: "mcpElicitation" }, - { request: currentTimeRequest("thread-active"), kind: "currentTime" }, - { request: dynamicToolCallRequest(), kind: "unsupported" }, - ] as const; - - for (const { request, kind } of requests) { - expect(routeServerRequest(request, activeScope).kind).toBe(kind); - if ("turnId" in request.params) { - expect( - routeServerRequest({ ...request, params: { ...request.params, turnId: "turn-other" } } as ServerRequest, activeScope).kind, - ).toBe("inactive"); - } + it.each([ + { name: "command approval", request: commandApprovalRequest(), kind: "approval" }, + { name: "file change approval", request: fileChangeApprovalRequest(), kind: "approval" }, + { name: "permissions approval", request: permissionsApprovalRequest(), kind: "approval" }, + { name: "user input", request: userInputRequest({ threadId: "thread-active" }), kind: "userInput" }, + { name: "MCP elicitation", request: mcpElicitationRequest(), kind: "mcpElicitation" }, + { name: "current time", request: currentTimeRequest("thread-active"), kind: "currentTime" }, + { name: "dynamic tool call", request: dynamicToolCallRequest(), kind: "unsupported" }, + ])("classifies $name server requests and extracts scope", ({ request, kind }) => { + expect(routeServerRequest(request, activeScope).kind).toBe(kind); + if ("turnId" in request.params) { expect( - routeServerRequest({ ...request, params: { ...request.params, threadId: "thread-other" } } as ServerRequest, activeScope).kind, + routeServerRequest({ ...request, params: { ...request.params, turnId: "turn-other" } } as ServerRequest, activeScope).kind, ).toBe("inactive"); } + expect( + routeServerRequest({ ...request, params: { ...request.params, threadId: "thread-other" } } as ServerRequest, activeScope).kind, + ).toBe("inactive"); }); it("marks scoped messages inactive when the thread or turn does not match", () => { @@ -149,11 +145,13 @@ describe("chat inbound routing", () => { ).toBe("inactive"); }); - it("classifies supported server request families before unsupported requests", () => { - expect(routeServerRequest(commandApprovalRequest(), { activeThreadId: null, activeTurnId: null }).kind).toBe("approval"); - expect(routeServerRequest(userInputRequest(), { activeThreadId: null, activeTurnId: null }).kind).toBe("userInput"); - expect(routeServerRequest(mcpElicitationRequest(), { activeThreadId: null, activeTurnId: null }).kind).toBe("mcpElicitation"); - expect(routeServerRequest(currentTimeRequest("thread-active"), { activeThreadId: null, activeTurnId: null }).kind).toBe("currentTime"); + it.each([ + { name: "command approval", request: commandApprovalRequest(), kind: "approval" }, + { name: "user input", request: userInputRequest(), kind: "userInput" }, + { name: "MCP elicitation", request: mcpElicitationRequest(), kind: "mcpElicitation" }, + { name: "current time", request: currentTimeRequest("thread-active"), kind: "currentTime" }, + ])("classifies $name before unsupported requests", ({ request, kind }) => { + expect(routeServerRequest(request, { activeThreadId: null, activeTurnId: null }).kind).toBe(kind); }); it("classifies inactive requests before request-family handling", () => { @@ -162,10 +160,13 @@ describe("chat inbound routing", () => { expect(route.kind).toBe("inactive"); }); - it("keeps unscoped unsupported requests out of active-turn routing", () => { - for (const request of unscopedUnsupportedRequests()) { - expect(routeServerRequest(request, activeScope).kind).toBe("unsupported"); - } + it.each( + unscopedUnsupportedRequests().map((request) => ({ + name: request.method, + request, + })), + )("keeps unscoped unsupported request $name out of active-turn routing", ({ request }) => { + expect(routeServerRequest(request, activeScope).kind).toBe("unsupported"); }); it("routes unknown runtime server requests to the unknown fallback", () => { @@ -187,15 +188,17 @@ describe("chat inbound routing", () => { ).toBe("inactive"); }); - it("classifies notification categories without mutating state", () => { - expect(routeServerNotification(agentDeltaNotification(), activeScope).kind).toBe("streamUpdate"); - expect(routeServerNotification(turnStartedNotification(), activeScope).kind).toBe("turnLifecycle"); - expect(routeServerNotification(threadArchivedNotification(), activeScope).kind).toBe("threadLifecycle"); - expect(routeServerNotification(threadSettingsUpdatedNotification(), activeScope).kind).toBe("threadLifecycle"); - expect(routeServerNotification(threadGoalUpdatedNotification(), activeScope).kind).toBe("threadLifecycle"); - expect(routeServerNotification(serverRequestResolvedNotification(), activeScope).kind).toBe("requestResolved"); - expect(routeServerNotification(mcpStartupStatusNotification(), activeScope).kind).toBe("diagnosticStatus"); - expect(routeServerNotification(warningNotification(), activeScope).kind).toBe("userVisibleNotice"); + it.each([ + { name: "agent delta", notification: agentDeltaNotification(), kind: "streamUpdate" }, + { name: "turn started", notification: turnStartedNotification(), kind: "turnLifecycle" }, + { name: "thread archived", notification: threadArchivedNotification(), kind: "threadLifecycle" }, + { name: "thread settings updated", notification: threadSettingsUpdatedNotification(), kind: "threadLifecycle" }, + { name: "thread goal updated", notification: threadGoalUpdatedNotification(), kind: "threadLifecycle" }, + { name: "server request resolved", notification: serverRequestResolvedNotification(), kind: "requestResolved" }, + { name: "MCP startup status", notification: mcpStartupStatusNotification(), kind: "diagnosticStatus" }, + { name: "warning", notification: warningNotification(), kind: "userVisibleNotice" }, + ])("classifies $name notifications without mutating state", ({ notification, kind }) => { + expect(routeServerNotification(notification, activeScope).kind).toBe(kind); }); it("leaves unhandled app-server notifications explicit", () => { @@ -240,31 +243,23 @@ describe("chat inbound routing", () => { expect(planChatNotification(state, notification, (prefix) => `${prefix}-1`)).toEqual({ actions: [], effects: [] }); }); - it("still scopes app-server notifications that Codex Panel does not handle", () => { - expect(routeServerNotification(rawResponseItemCompletedNotification("thread-active", "turn-active"), activeScope).kind).toBe( - "unhandled", - ); - expect(routeServerNotification(rawResponseItemCompletedNotification("thread-other", "turn-active"), activeScope).kind).toBe("inactive"); - expect(routeServerNotification(rawResponseItemCompletedNotification("thread-active", "turn-other"), activeScope).kind).toBe("inactive"); - - expect(routeServerNotification(turnModerationMetadataNotification("thread-active", "turn-active"), activeScope).kind).toBe("unhandled"); - expect(routeServerNotification(turnModerationMetadataNotification("thread-other", "turn-active"), activeScope).kind).toBe("inactive"); - expect(routeServerNotification(turnModerationMetadataNotification("thread-active", "turn-other"), activeScope).kind).toBe("inactive"); - - expect(routeServerNotification(terminalInteractionNotification("thread-active", "turn-active"), activeScope).kind).toBe("unhandled"); - expect(routeServerNotification(terminalInteractionNotification("thread-other", "turn-active"), activeScope).kind).toBe("inactive"); - expect(routeServerNotification(terminalInteractionNotification("thread-active", "turn-other"), activeScope).kind).toBe("inactive"); - - expect(routeServerNotification(modelVerificationNotification("thread-active", "turn-active"), activeScope).kind).toBe("unhandled"); - expect(routeServerNotification(modelVerificationNotification("thread-other", "turn-active"), activeScope).kind).toBe("inactive"); - expect(routeServerNotification(modelVerificationNotification("thread-active", "turn-other"), activeScope).kind).toBe("inactive"); + it.each([ + { name: "raw response item completed", notification: rawResponseItemCompletedNotification }, + { name: "turn moderation metadata", notification: turnModerationMetadataNotification }, + { name: "terminal interaction", notification: terminalInteractionNotification }, + { name: "model verification", notification: modelVerificationNotification }, + ])("still scopes unhandled turn notification $name", ({ notification }) => { + expect(routeServerNotification(notification("thread-active", "turn-active"), activeScope).kind).toBe("unhandled"); + expect(routeServerNotification(notification("thread-other", "turn-active"), activeScope).kind).toBe("inactive"); + expect(routeServerNotification(notification("thread-active", "turn-other"), activeScope).kind).toBe("inactive"); }); - it("still scopes unhandled thread lifecycle notifications", () => { - expect(routeServerNotification(threadStatusChangedNotification("thread-active"), activeScope).kind).toBe("unhandled"); - expect(routeServerNotification(threadStatusChangedNotification("thread-other"), activeScope).kind).toBe("inactive"); - expect(routeServerNotification(threadClosedNotification("thread-active"), activeScope).kind).toBe("unhandled"); - expect(routeServerNotification(threadClosedNotification("thread-other"), activeScope).kind).toBe("inactive"); + it.each([ + { name: "thread status changed", notification: threadStatusChangedNotification }, + { name: "thread closed", notification: threadClosedNotification }, + ])("still scopes unhandled thread lifecycle notification $name", ({ notification }) => { + expect(routeServerNotification(notification("thread-active"), activeScope).kind).toBe("unhandled"); + expect(routeServerNotification(notification("thread-other"), activeScope).kind).toBe("inactive"); }); it("scopes MCP startup status notifications when app-server provides a thread id", () => { diff --git a/tests/features/chat/protocol/server-requests/approval.test.ts b/tests/features/chat/protocol/server-requests/approval.test.ts index 0f14f14e..42c245c6 100644 --- a/tests/features/chat/protocol/server-requests/approval.test.ts +++ b/tests/features/chat/protocol/server-requests/approval.test.ts @@ -385,60 +385,61 @@ describe("approval model", () => { ]); }); - it("builds action responses for current approval families", () => { - const requests: { request: ServerRequest; acceptSession: unknown; cancel: unknown }[] = [ - { - request: { - id: 3, - method: "item/commandExecution/requestApproval", - params: { - command: "npm test", - cwd: "/tmp/project", - threadId: "thread", - turnId: "turn", - itemId: "command", - environmentId: null, - startedAtMs: 1, - reason: null, - commandActions: [], - proposedExecpolicyAmendment: null, - proposedNetworkPolicyAmendments: [], - availableDecisions: ["acceptForSession", "cancel", "decline"], - }, + it.each([ + { + name: "command approval", + request: { + id: 3, + method: "item/commandExecution/requestApproval", + params: { + command: "npm test", + cwd: "/tmp/project", + threadId: "thread", + turnId: "turn", + itemId: "command", + environmentId: null, + startedAtMs: 1, + reason: null, + commandActions: [], + proposedExecpolicyAmendment: null, + proposedNetworkPolicyAmendments: [], + availableDecisions: ["acceptForSession", "cancel", "decline"], }, - acceptSession: { decision: "acceptForSession" }, - cancel: { decision: "cancel" }, }, - { - request: { - id: 4, - method: "item/fileChange/requestApproval", - params: { - threadId: "thread", - turnId: "turn", - itemId: "file", - startedAtMs: 1, - reason: "write", - grantRoot: "/tmp/project", - }, + acceptSession: { decision: "acceptForSession" }, + cancel: { decision: "cancel" }, + }, + { + name: "file change approval", + request: { + id: 4, + method: "item/fileChange/requestApproval", + params: { + threadId: "thread", + turnId: "turn", + itemId: "file", + startedAtMs: 1, + reason: "write", + grantRoot: "/tmp/project", }, - acceptSession: { decision: "acceptForSession" }, - cancel: { decision: "cancel" }, }, - ]; - - for (const { request, acceptSession, cancel } of requests) { + acceptSession: { decision: "acceptForSession" }, + cancel: { decision: "cancel" }, + }, + ] satisfies { name: string; request: ServerRequest; acceptSession: unknown; cancel: unknown }[])( + "builds action responses for $name", + ({ request, acceptSession, cancel }) => { const approval = expectPresent(toPendingApproval(request)); if (approval.kind === "command") { const options = approvalActionOptions(approval); expect(approvalResponse(approval, expectPresent(options[0]).action)).toEqual(acceptSession); expect(approvalResponse(approval, expectPresent(options[1]).action)).toEqual(cancel); expect(approvalResponse(approval, expectPresent(options[2]).action)).toEqual({ decision: "decline" }); - } else { - expect(approvalResponse(approval, "accept-session")).toEqual(acceptSession); - expect(approvalResponse(approval, "cancel")).toEqual(cancel); - expect(approvalResponse(approval, "decline")).toEqual({ decision: "decline" }); + return; } - } - }); + expect(approvalResponse(approval, "accept-session")).toEqual(acceptSession); + expect(approvalResponse(approval, "cancel")).toEqual(cancel); + expect(approvalResponse(approval, "decline")).toEqual({ decision: "decline" }); + }, + ); }); diff --git a/tests/runtime/service-tier-state.test.ts b/tests/runtime/service-tier-state.test.ts index 2d72468b..850de81b 100644 --- a/tests/runtime/service-tier-state.test.ts +++ b/tests/runtime/service-tier-state.test.ts @@ -6,12 +6,14 @@ import { fastModeActive } from "../../src/features/chat/domain/runtime/effective import type { RuntimeSnapshot } from "../../src/features/chat/domain/runtime/snapshot"; describe("service tier runtime state", () => { - it("recognizes Codex fast tier aliases without rejecting other tier ids", () => { - expect(fastMode("fast")).toBe(true); - expect(fastMode("priority")).toBe(true); - expect(fastMode("catalog-fast", [{ id: "catalog-fast", name: "Fast" }])).toBe(true); - expect(fastMode("priority", [{ id: "priority", name: "Priority" }])).toBe(false); - expect(fastMode("flex", [{ id: "flex", name: "Flex" }])).toBe(false); + it.each([ + { name: "built-in fast", serviceTier: "fast", serviceTiers: [], expected: true }, + { name: "built-in priority", serviceTier: "priority", serviceTiers: [], expected: true }, + { name: "catalog Fast tier", serviceTier: "catalog-fast", serviceTiers: [{ id: "catalog-fast", name: "Fast" }], expected: true }, + { name: "catalog Priority tier", serviceTier: "priority", serviceTiers: [{ id: "priority", name: "Priority" }], expected: false }, + { name: "catalog Flex tier", serviceTier: "flex", serviceTiers: [{ id: "flex", name: "Flex" }], expected: false }, + ])("recognizes $name without rejecting other tier ids", ({ serviceTier, serviceTiers, expected }) => { + expect(fastMode(serviceTier, serviceTiers)).toBe(expected); }); });