From 20ded4916cdec0768b94da41b8aec35324edf3ba Mon Sep 17 00:00:00 2001 From: mathuraditya724 Date: Tue, 31 Mar 2026 21:31:47 +0530 Subject: [PATCH] fix(test): adapt tests for buildCommand auth guard (#611) The auth guard added in #611 calls getAuthConfig() before every command, which broke ~200 tests that had no auth token in the test environment. - Set a fake SENTRY_AUTH_TOKEN in test preload so the auth guard passes globally (real API calls are blocked by the global fetch mock) - Add auth: false to command.test.ts test commands (they test framework behavior, not authentication) - Clear the env token in tests that specifically verify unauthenticated or SENTRY_TOKEN-priority behavior (logout, refresh, whoami, project list) --- test/commands/auth/logout.test.ts | 6 +++++ test/commands/auth/refresh.test.ts | 6 +++++ test/commands/auth/whoami.test.ts | 20 ++++++++++++++++ test/commands/project/list.test.ts | 38 ++++++++++++++++++++++-------- test/lib/command.test.ts | 29 +++++++++++++++++++++++ test/preload.ts | 6 +++++ 6 files changed, 95 insertions(+), 10 deletions(-) diff --git a/test/commands/auth/logout.test.ts b/test/commands/auth/logout.test.ts index 8953cb4480..8bf8282a96 100644 --- a/test/commands/auth/logout.test.ts +++ b/test/commands/auth/logout.test.ts @@ -126,6 +126,9 @@ describe("logoutCommand.func", () => { isAuthenticatedSpy.mockReturnValue(true); isEnvTokenActiveSpy.mockReturnValue(true); // Set env var directly — getActiveEnvVarName() reads env vars via getEnvToken() + // Clear SENTRY_AUTH_TOKEN so SENTRY_TOKEN takes priority + const savedAuthToken = process.env.SENTRY_AUTH_TOKEN; + delete process.env.SENTRY_AUTH_TOKEN; process.env.SENTRY_TOKEN = "sntrys_token_456"; const { context } = createContext(); @@ -138,6 +141,9 @@ describe("logoutCommand.func", () => { expect(msg).toContain("SENTRY_TOKEN"); } finally { delete process.env.SENTRY_TOKEN; + if (savedAuthToken !== undefined) { + process.env.SENTRY_AUTH_TOKEN = savedAuthToken; + } } expect(clearAuthSpy).not.toHaveBeenCalled(); }); diff --git a/test/commands/auth/refresh.test.ts b/test/commands/auth/refresh.test.ts index 94c786a267..9a744ef4ef 100644 --- a/test/commands/auth/refresh.test.ts +++ b/test/commands/auth/refresh.test.ts @@ -85,6 +85,9 @@ describe("refreshCommand.func", () => { test("env token (SENTRY_TOKEN): throws AuthError with SENTRY_TOKEN in message", async () => { isEnvTokenActiveSpy.mockReturnValue(true); // Set env var directly — getActiveEnvVarName() reads env vars via getEnvToken() + // Clear SENTRY_AUTH_TOKEN so SENTRY_TOKEN takes priority + const savedAuthToken = process.env.SENTRY_AUTH_TOKEN; + delete process.env.SENTRY_AUTH_TOKEN; process.env.SENTRY_TOKEN = "sntrys_token_456"; const { context } = createContext(); @@ -99,6 +102,9 @@ describe("refreshCommand.func", () => { expect((err as AuthError).message).not.toContain("SENTRY_AUTH_TOKEN"); } finally { delete process.env.SENTRY_TOKEN; + if (savedAuthToken !== undefined) { + process.env.SENTRY_AUTH_TOKEN = savedAuthToken; + } } expect(refreshTokenSpy).not.toHaveBeenCalled(); diff --git a/test/commands/auth/whoami.test.ts b/test/commands/auth/whoami.test.ts index dd44e52dc7..0ed717736e 100644 --- a/test/commands/auth/whoami.test.ts +++ b/test/commands/auth/whoami.test.ts @@ -84,6 +84,26 @@ describe("whoamiCommand.func", () => { }); describe("unauthenticated", () => { + let getAuthConfigSpy: ReturnType; + let savedAuthToken: string | undefined; + + beforeEach(() => { + // Clear env token and mock getAuthConfig so buildCommand's auth guard + // sees no credentials — this tests the unauthenticated path end-to-end. + savedAuthToken = process.env.SENTRY_AUTH_TOKEN; + delete process.env.SENTRY_AUTH_TOKEN; + getAuthConfigSpy = spyOn(dbAuth, "getAuthConfig").mockReturnValue( + undefined + ); + }); + + afterEach(() => { + getAuthConfigSpy.mockRestore(); + if (savedAuthToken !== undefined) { + process.env.SENTRY_AUTH_TOKEN = savedAuthToken; + } + }); + test("throws AuthError(not_authenticated) when no token stored", async () => { isAuthenticatedSpy.mockReturnValue(false); diff --git a/test/commands/project/list.test.ts b/test/commands/project/list.test.ts index 870f45ae90..dbc7b99763 100644 --- a/test/commands/project/list.test.ts +++ b/test/commands/project/list.test.ts @@ -969,8 +969,17 @@ describe("fetchOrgProjectsSafe", () => { test("propagates AuthError when not authenticated", async () => { // Clear auth token so the API client throws AuthError before making any request await clearAuth(); - - await expect(fetchOrgProjectsSafe("myorg")).rejects.toThrow(AuthError); + // Also clear env token — preload sets a fake one for the auth guard + const savedAuthToken = process.env.SENTRY_AUTH_TOKEN; + delete process.env.SENTRY_AUTH_TOKEN; + + try { + await expect(fetchOrgProjectsSafe("myorg")).rejects.toThrow(AuthError); + } finally { + if (savedAuthToken !== undefined) { + process.env.SENTRY_AUTH_TOKEN = savedAuthToken; + } + } }); }); @@ -1233,14 +1242,23 @@ describe("handleAutoDetect", () => { setDefaults("test-org"); // Clear auth so getAuthToken() throws AuthError before any fetch await clearAuth(); - - await expect( - handleAutoDetect("/tmp/test-project", { - limit: 30, - json: true, - fresh: false, - }) - ).rejects.toThrow(AuthError); + // Also clear env token — preload sets a fake one for the auth guard + const savedAuthToken = process.env.SENTRY_AUTH_TOKEN; + delete process.env.SENTRY_AUTH_TOKEN; + + try { + await expect( + handleAutoDetect("/tmp/test-project", { + limit: 30, + json: true, + fresh: false, + }) + ).rejects.toThrow(AuthError); + } finally { + if (savedAuthToken !== undefined) { + process.env.SENTRY_AUTH_TOKEN = savedAuthToken; + } + } }); test("slow path: uses full fetch when platform filter is active", async () => { diff --git a/test/lib/command.test.ts b/test/lib/command.test.ts index e0883d3800..2495186c3f 100644 --- a/test/lib/command.test.ts +++ b/test/lib/command.test.ts @@ -76,6 +76,7 @@ describe("buildCommand", () => { test("builds a valid command object", () => { const command = buildCommand({ docs: { brief: "Test command" }, + auth: false, parameters: { flags: { verbose: { kind: "boolean", brief: "Verbose", default: false }, @@ -91,6 +92,7 @@ describe("buildCommand", () => { test("handles commands with empty parameters", () => { const command = buildCommand({ docs: { brief: "Simple command" }, + auth: false, parameters: {}, async *func() { // no-op @@ -128,6 +130,7 @@ describe("buildCommand telemetry integration", () => { TestContext >({ docs: { brief: "Test" }, + auth: false, parameters: { flags: { verbose: { kind: "boolean", brief: "Verbose", default: false }, @@ -168,6 +171,7 @@ describe("buildCommand telemetry integration", () => { test("skips false boolean flags in telemetry", async () => { const command = buildCommand<{ json: boolean }, [], TestContext>({ docs: { brief: "Test" }, + auth: false, parameters: { flags: { json: { kind: "boolean", brief: "JSON output", default: false }, @@ -199,6 +203,7 @@ describe("buildCommand telemetry integration", () => { const command = buildCommand, [string], TestContext>({ docs: { brief: "Test" }, + auth: false, parameters: { positional: { kind: "tuple", @@ -236,6 +241,7 @@ describe("buildCommand telemetry integration", () => { const command = buildCommand, [], TestContext>({ docs: { brief: "Test" }, + auth: false, parameters: {}, // biome-ignore lint/correctness/useYield: test command — no output to yield async *func(this: TestContext) { @@ -261,6 +267,7 @@ describe("buildCommand telemetry integration", () => { const command = buildCommand<{ delay: number }, [], TestContext>({ docs: { brief: "Test" }, + auth: false, parameters: { flags: { delay: { @@ -371,6 +378,7 @@ describe("buildCommand", () => { test("builds a valid command object", () => { const command = buildCommand({ docs: { brief: "Test command" }, + auth: false, parameters: { flags: { json: { kind: "boolean", brief: "JSON output", default: false }, @@ -388,6 +396,7 @@ describe("buildCommand", () => { const command = buildCommand<{ json: boolean }, [], TestContext>({ docs: { brief: "Test" }, + auth: false, parameters: { flags: { json: { kind: "boolean", brief: "JSON output", default: false }, @@ -499,6 +508,7 @@ describe("buildCommand", () => { const command = buildCommand<{ limit: number }, [], TestContext>({ docs: { brief: "Test" }, + auth: false, parameters: { flags: { limit: { @@ -547,6 +557,7 @@ describe("buildCommand", () => { TestContext >({ docs: { brief: "Test" }, + auth: false, parameters: { flags: { verbose: { @@ -603,6 +614,7 @@ describe("buildCommand", () => { try { const command = buildCommand<{ verbose: boolean }, [], TestContext>({ docs: { brief: "Test" }, + auth: false, parameters: { flags: { verbose: { @@ -674,6 +686,7 @@ describe("buildCommand output config", () => { TestContext >({ docs: { brief: "Test" }, + auth: false, output: { human: () => "unused" }, parameters: { flags: { @@ -717,6 +730,7 @@ describe("buildCommand output config", () => { TestContext >({ docs: { brief: "Test" }, + auth: false, output: { human: () => "unused" }, parameters: {}, // biome-ignore lint/correctness/useYield: test command — no output to yield @@ -756,6 +770,7 @@ describe("buildCommand output config", () => { TestContext >({ docs: { brief: "Test" }, + auth: false, output: { human: () => "unused" }, parameters: {}, // biome-ignore lint/correctness/useYield: test command — no output to yield @@ -794,6 +809,7 @@ describe("buildCommand output config", () => { TestContext >({ docs: { brief: "Test" }, + auth: false, output: { human: () => "unused" }, parameters: {}, // biome-ignore lint/correctness/useYield: test command — no output to yield @@ -858,6 +874,7 @@ describe("buildCommand output config", () => { TestContext >({ docs: { brief: "Test" }, + auth: false, output: { human: () => "unused" }, parameters: { flags: { @@ -901,6 +918,7 @@ describe("buildCommand output config", () => { TestContext >({ docs: { brief: "Test" }, + auth: false, output: { human: () => "unused" }, parameters: {}, // biome-ignore lint/correctness/useYield: test command — no output to yield @@ -942,6 +960,7 @@ describe("buildCommand output config", () => { TestContext >({ docs: { brief: "Test" }, + auth: false, output: { human: () => "unused" }, parameters: { flags: { @@ -996,6 +1015,7 @@ describe("buildCommand return-based output", () => { TestContext >({ docs: { brief: "Test" }, + auth: false, output: { human: (d: { name: string; role: string }) => `${d.name} (${d.role})`, }, @@ -1024,6 +1044,7 @@ describe("buildCommand return-based output", () => { TestContext >({ docs: { brief: "Test" }, + auth: false, output: { human: (d: { name: string; role: string }) => `${d.name} (${d.role})`, }, @@ -1053,6 +1074,7 @@ describe("buildCommand return-based output", () => { TestContext >({ docs: { brief: "Test" }, + auth: false, output: { human: (d: { id: number; name: string; role: string }) => `${d.name}`, }, @@ -1084,6 +1106,7 @@ describe("buildCommand return-based output", () => { const makeCommand = () => buildCommand<{ json: boolean; fields?: string[] }, [], TestContext>({ docs: { brief: "Test" }, + auth: false, output: { human: (d: { value: number }) => `Value: ${d.value}`, }, @@ -1131,6 +1154,7 @@ describe("buildCommand return-based output", () => { TestContext >({ docs: { brief: "Test" }, + auth: false, output: { human: () => "unused", }, @@ -1188,6 +1212,7 @@ describe("buildCommand return-based output", () => { TestContext >({ docs: { brief: "Test" }, + auth: false, output: { human: (d: { name: string }) => `Hello, ${d.name}!`, }, @@ -1218,6 +1243,7 @@ describe("buildCommand return-based output", () => { TestContext >({ docs: { brief: "Test" }, + auth: false, output: { human: (d: Array<{ id: number }>) => d.map(((x) => x.id).join(", ")), }, @@ -1247,6 +1273,7 @@ describe("buildCommand return-based output", () => { const makeCommand = () => buildCommand<{ json: boolean; fields?: string[] }, [], TestContext>({ docs: { brief: "Test" }, + auth: false, output: { human: (d: { org: string }) => `Org: ${d.org}`, }, @@ -1285,6 +1312,7 @@ describe("buildCommand return-based output", () => { TestContext >({ docs: { brief: "Test" }, + auth: false, output: { human: (d: { error: string }) => `Error: ${d.error}`, }, @@ -1333,6 +1361,7 @@ describe("buildCommand return-based output", () => { TestContext >({ docs: { brief: "Test" }, + auth: false, output: { human: (d: { error: string }) => `Error: ${d.error}`, }, diff --git a/test/preload.ts b/test/preload.ts index e9aaa9dcaa..7d77e7d86a 100644 --- a/test/preload.ts +++ b/test/preload.ts @@ -93,6 +93,12 @@ delete process.env.SENTRY_HOST; delete process.env.SENTRY_ORG; delete process.env.SENTRY_PROJECT; +// Set a fake auth token so buildCommand's auth guard passes in tests. +// Real API calls are blocked by the global fetch mock below. +// Tests that specifically verify unauthenticated behavior (e.g., auth status) +// mock getAuthConfig to return undefined. +process.env.SENTRY_AUTH_TOKEN = "sntrys_test-token-for-unit-tests_000000"; + // Disable telemetry and background update checks in tests // This prevents Sentry SDK from keeping the process alive and making external calls process.env.SENTRY_CLI_NO_TELEMETRY = "1";