diff --git a/apps/sim/app/api/users/me/settings/route.test.ts b/apps/sim/app/api/users/me/settings/route.test.ts new file mode 100644 index 00000000000..f11f71ff96f --- /dev/null +++ b/apps/sim/app/api/users/me/settings/route.test.ts @@ -0,0 +1,48 @@ +/** + * @vitest-environment node + */ +import { createMockRequest, dbChainMockFns, resetDbChainMock } from '@sim/testing' +import { beforeEach, describe, expect, it, vi } from 'vitest' + +const { mockGetSession } = vi.hoisted(() => ({ + mockGetSession: vi.fn(), +})) + +vi.mock('@/lib/auth', () => ({ + auth: { api: { getSession: vi.fn() } }, + getSession: mockGetSession, +})) + +import { PATCH } from '@/app/api/users/me/settings/route' + +describe('PATCH /api/users/me/settings', () => { + beforeEach(() => { + vi.clearAllMocks() + resetDbChainMock() + mockGetSession.mockResolvedValue({ user: { id: 'user-1' } }) + }) + + it('reports success when the write lands', async () => { + const response = await PATCH(createMockRequest('PATCH', { theme: 'dark' })) + + expect(response.status).toBe(200) + expect(await response.json()).toEqual({ success: true }) + }) + + /** + * The regression this guards: the catch answered `{ success: true }` with 200, so + * `useUpdateGeneralSetting`'s optimistic rollback in `onError` could never run — + * a failed write showed as applied until the next refetch, including for + * consent-shaped settings the user believes they changed. + */ + it('reports failure when the write throws', async () => { + dbChainMockFns.insert.mockImplementationOnce(() => { + throw new Error('connection terminated unexpectedly') + }) + + const response = await PATCH(createMockRequest('PATCH', { theme: 'dark' })) + + expect(response.status).toBe(500) + expect(await response.json()).not.toMatchObject({ success: true }) + }) +}) diff --git a/apps/sim/app/api/users/me/settings/route.ts b/apps/sim/app/api/users/me/settings/route.ts index 24ccacceb62..69e06dd689c 100644 --- a/apps/sim/app/api/users/me/settings/route.ts +++ b/apps/sim/app/api/users/me/settings/route.ts @@ -74,6 +74,10 @@ export const PATCH = withRouteHandler(async (request: NextRequest) => { return NextResponse.json({ success: true }, { status: 200 }) } catch (error: any) { logger.error(`[${requestId}] Settings update error`, error) - return NextResponse.json({ success: true }, { status: 200 }) + /* The client mutation is optimistic: it writes the new value into the cache in + `onMutate` and restores it in `onError`. Answering 200 here left that rollback + unreachable, so a failed write showed as applied until the next refetch — + including for consent-shaped settings the user believes they changed. */ + return NextResponse.json({ error: 'Failed to update settings' }, { status: 500 }) } })