test(next-story): add unit tests for GET /api/products/:id/next-story
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
eafdef4d5a
commit
5903881580
1 changed files with 66 additions and 12 deletions
|
|
@ -5,6 +5,9 @@ vi.mock('@/lib/prisma', () => ({
|
|||
sprint: {
|
||||
findFirst: vi.fn(),
|
||||
},
|
||||
story: {
|
||||
findFirst: vi.fn(),
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
|
|
@ -18,10 +21,23 @@ import { GET as getNextStory } from '@/app/api/products/[id]/next-story/route'
|
|||
|
||||
const mockPrisma = prisma as unknown as {
|
||||
sprint: { findFirst: ReturnType<typeof vi.fn> }
|
||||
story: { findFirst: ReturnType<typeof vi.fn> }
|
||||
}
|
||||
const mockAuth = authenticateApiRequest as ReturnType<typeof vi.fn>
|
||||
|
||||
function makeRequest(productId = 'product-1'): [Request, { params: Promise<{ id: string }> }] {
|
||||
const SPRINT = { id: 'sprint-1', product_id: 'prod-1', status: 'ACTIVE' }
|
||||
const STORY = {
|
||||
id: 'story-1',
|
||||
title: 'Account aanmaken',
|
||||
description: 'Als bezoeker wil ik een account aanmaken.',
|
||||
acceptance_criteria: '- Gebruikersnaam verplicht',
|
||||
tasks: [
|
||||
{ id: 'task-1', title: 'Formulier bouwen', description: null, priority: 1, sort_order: 1, status: 'TO_DO' },
|
||||
{ id: 'task-2', title: 'Validatie toevoegen', description: null, priority: 2, sort_order: 2, status: 'TO_DO' },
|
||||
],
|
||||
}
|
||||
|
||||
function makeRequest(productId = 'prod-1'): [Request, { params: Promise<{ id: string }> }] {
|
||||
return [
|
||||
new Request(`http://localhost/api/products/${productId}/next-story`, {
|
||||
method: 'GET',
|
||||
|
|
@ -34,23 +50,61 @@ function makeRequest(productId = 'product-1'): [Request, { params: Promise<{ id:
|
|||
describe('GET /api/products/:id/next-story', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockAuth.mockResolvedValue({ userId: 'user-1', isDemo: false })
|
||||
})
|
||||
|
||||
// TC-NS-01
|
||||
it.todo('returns 401 when no token provided')
|
||||
|
||||
// TC-NS-03
|
||||
it.todo('returns 404 when product is not accessible')
|
||||
|
||||
// TC-NS-04
|
||||
it.todo('returns 404 when product has no active sprint')
|
||||
it('returns 404 when product has no active sprint', async () => {
|
||||
mockPrisma.sprint.findFirst.mockResolvedValue(null)
|
||||
|
||||
const res = await getNextStory(...makeRequest())
|
||||
const data = await res.json()
|
||||
|
||||
expect(res.status).toBe(404)
|
||||
expect(data.error).toBeTruthy()
|
||||
})
|
||||
|
||||
// TC-NS-05
|
||||
it.todo('returns 404 when active sprint has no IN_SPRINT stories')
|
||||
it('returns 404 when active sprint has no IN_SPRINT stories', async () => {
|
||||
mockPrisma.sprint.findFirst.mockResolvedValue(SPRINT)
|
||||
mockPrisma.story.findFirst.mockResolvedValue(null)
|
||||
|
||||
const res = await getNextStory(...makeRequest())
|
||||
const data = await res.json()
|
||||
|
||||
expect(res.status).toBe(404)
|
||||
expect(data.error).toBeTruthy()
|
||||
})
|
||||
|
||||
// TC-NS-06
|
||||
it.todo('returns the highest-priority story with its tasks')
|
||||
it('returns the highest-priority story with its tasks', async () => {
|
||||
mockPrisma.sprint.findFirst.mockResolvedValue(SPRINT)
|
||||
mockPrisma.story.findFirst.mockResolvedValue(STORY)
|
||||
|
||||
// TC-NS-07
|
||||
it.todo('returns 404 for another user\'s product')
|
||||
const res = await getNextStory(...makeRequest())
|
||||
const data = await res.json()
|
||||
|
||||
expect(res.status).toBe(200)
|
||||
expect(data).toMatchObject({
|
||||
id: 'story-1',
|
||||
title: 'Account aanmaken',
|
||||
description: 'Als bezoeker wil ik een account aanmaken.',
|
||||
acceptance_criteria: '- Gebruikersnaam verplicht',
|
||||
})
|
||||
expect(data.tasks).toHaveLength(2)
|
||||
expect(data.tasks[0]).toMatchObject({ id: 'task-1', status: 'TO_DO' })
|
||||
})
|
||||
|
||||
it('queries story ordered by priority then sort_order', async () => {
|
||||
mockPrisma.sprint.findFirst.mockResolvedValue(SPRINT)
|
||||
mockPrisma.story.findFirst.mockResolvedValue(STORY)
|
||||
|
||||
await getNextStory(...makeRequest())
|
||||
|
||||
expect(mockPrisma.story.findFirst).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
orderBy: [{ priority: 'asc' }, { sort_order: 'asc' }],
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue