From 417882dc880b92799461e8e457723f49a20d92db Mon Sep 17 00:00:00 2001 From: Dan Thareja Date: Mon, 27 Apr 2026 09:29:52 -0600 Subject: [PATCH] Stop spamming Sentry on handled Splitwise 404/403 Co-Authored-By: Claude Opus 4.7 (1M context) --- services/splitwise-auth.ts | 11 +++- tests/services/splitwise-auth.test.ts | 83 +++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 tests/services/splitwise-auth.test.ts diff --git a/services/splitwise-auth.ts b/services/splitwise-auth.ts index 24ec743..17f10cd 100644 --- a/services/splitwise-auth.ts +++ b/services/splitwise-auth.ts @@ -1,7 +1,12 @@ import * as Sentry from "@sentry/nextjs"; import { AxiosError } from "axios"; import type { SplitwiseGroup, SplitwiseUser } from "../types/splitwise"; -import { createSplitwiseAxios, SplitwiseError } from "./splitwise-axios"; +import { + createSplitwiseAxios, + SplitwiseError, + SplitwiseForbiddenError, + SplitwiseNotFoundError, +} from "./splitwise-axios"; export async function validateSplitwiseApiKey(apiKey: string) { try { @@ -88,7 +93,7 @@ export async function getSplitwiseGroup(accessToken: string, groupId: string) { }; } catch (error) { // 403 means user doesn't have access to this group - if (error instanceof AxiosError && error.response?.status === 403) { + if (error instanceof SplitwiseForbiddenError) { return { success: false, error: "No access to group", @@ -97,7 +102,7 @@ export async function getSplitwiseGroup(accessToken: string, groupId: string) { } // 404 means group doesn't exist - if (error instanceof AxiosError && error.response?.status === 404) { + if (error instanceof SplitwiseNotFoundError) { return { success: false, error: "Group not found", diff --git a/tests/services/splitwise-auth.test.ts b/tests/services/splitwise-auth.test.ts new file mode 100644 index 0000000..25d4f3a --- /dev/null +++ b/tests/services/splitwise-auth.test.ts @@ -0,0 +1,83 @@ +import { describe, it, expect, beforeEach, vi } from "vitest"; +import { http, HttpResponse } from "msw"; +import * as Sentry from "@sentry/nextjs"; +import { getSplitwiseGroup } from "@/services/splitwise-auth"; +import { server } from "../setup"; + +const SPLITWISE_BASE_URL = "https://secure.splitwise.com/api/v3.0"; + +describe("getSplitwiseGroup", () => { + beforeEach(() => { + vi.mocked(Sentry.captureException).mockClear(); + }); + + it("returns { success: false, error: 'Group not found' } on 404 without reporting to Sentry", async () => { + server.use( + http.get(`${SPLITWISE_BASE_URL}/get_group/:id`, () => + HttpResponse.json( + { errors: { base: ["Invalid API Request: record not found"] } }, + { status: 404 }, + ), + ), + ); + + const result = await getSplitwiseGroup("token", "999999"); + + expect(result).toEqual({ + success: false, + error: "Group not found", + group: null, + }); + expect(Sentry.captureException).not.toHaveBeenCalled(); + }); + + it("returns { success: false, error: 'No access to group' } on 403 without reporting to Sentry", async () => { + server.use( + http.get(`${SPLITWISE_BASE_URL}/get_group/:id`, () => + HttpResponse.json( + { errors: { base: ["You do not have permission"] } }, + { status: 403 }, + ), + ), + ); + + const result = await getSplitwiseGroup("token", "123"); + + expect(result).toEqual({ + success: false, + error: "No access to group", + group: null, + }); + expect(Sentry.captureException).not.toHaveBeenCalled(); + }); + + it("returns { success: true, group } on 200", async () => { + server.use( + http.get(`${SPLITWISE_BASE_URL}/get_group/:id`, () => + HttpResponse.json({ + group: { id: 123, name: "Test", members: [] }, + }), + ), + ); + + const result = await getSplitwiseGroup("token", "123"); + + expect(result.success).toBe(true); + expect(result.group).toEqual({ id: 123, name: "Test", members: [] }); + expect(Sentry.captureException).not.toHaveBeenCalled(); + }); + + it("reports unexpected errors (5xx) to Sentry and returns failure shape", async () => { + server.use( + http.get(`${SPLITWISE_BASE_URL}/get_group/:id`, () => + HttpResponse.json({ error: "boom" }, { status: 500 }), + ), + ); + + const result = await getSplitwiseGroup("token", "123"); + + expect(result.success).toBe(false); + expect(result.group).toBeNull(); + expect(Sentry.captureException).toHaveBeenCalledTimes(1); + }); +});