diff --git a/app/api/streak/route.test.ts b/app/api/streak/route.test.ts index c81ca19b..17a8174e 100644 --- a/app/api/streak/route.test.ts +++ b/app/api/streak/route.test.ts @@ -136,7 +136,21 @@ describe('GET /api/streak', () => { expect(response.status).toBe(400); const body = await response.json(); expect(body.error).toBe('Invalid parameters'); - expect(body.details).not.toBeNull(); + }); + + it('returns 400 Bad Request when ?layout= is set to an unsupported format (Variation 4)', async () => { + const response = await GET( + makeRequest({ + user: 'octocat', + layout: 'unsupported_layout', + }) + ); + + expect(response.status).toBe(400); + const body = await response.json(); + expect(body.details.fieldErrors.layout[0]).toContain( + 'Invalid layout format. Supported values: default, compact, full.' + ); }); it('returns 400 when the user parameter is missing', async () => { diff --git a/lib/validations.test.ts b/lib/validations.test.ts index 6cf61a05..b3b0a05e 100644 --- a/lib/validations.test.ts +++ b/lib/validations.test.ts @@ -1061,3 +1061,71 @@ describe('streakParamsSchema user maxLength validation boundaries (Variation 3)' expect(parseResult.success).toBe(true); }); }); + +/* ========================================================================== + * LAYOUT PARAMETER — QUERY VALIDATION BOUNDARIES (VARIATION 4) + * ========================================================================== */ + +describe('streakParamsSchema — layout query validation boundaries (Variation 4)', () => { + it('rejects unsupported_layout and marks the parse as failed', () => { + const result = streakParamsSchema.safeParse({ + user: 'octocat', + layout: 'unsupported_layout', + }); + + expect(result.success).toBe(false); + }); + + it('surfaces a meaningful error message for unsupported_layout', () => { + const result = streakParamsSchema.safeParse({ + user: 'octocat', + layout: 'unsupported_layout', + }); + + expect(result.success).toBe(false); + if (!result.success) { + const messages = result.error.issues.map((i) => i.message).join(' '); + expect(messages).toContain( + 'Invalid layout format. Supported values: default, compact, full.' + ); + } + }); + + it('accepts "default" as a valid layout value', () => { + const result = streakParamsSchema.safeParse({ + user: 'octocat', + layout: 'default', + }); + + expect(result.success).toBe(true); + }); + + it('accepts "compact" as a valid layout value', () => { + const result = streakParamsSchema.safeParse({ + user: 'octocat', + layout: 'compact', + }); + + expect(result.success).toBe(true); + }); + + it('accepts "full" as a valid layout value', () => { + const result = streakParamsSchema.safeParse({ + user: 'octocat', + layout: 'full', + }); + + expect(result.success).toBe(true); + }); + + it('treats omitted layout as undefined (no validation error)', () => { + const result = streakParamsSchema.safeParse({ + user: 'octocat', + }); + + expect(result.success).toBe(true); + if (result.success) { + expect(result.data.layout).toBeUndefined(); + } + }); +});