feat(plan5): API GET /api/creation/preview (TDD)

This commit is contained in:
2026-06-09 09:57:29 +02:00
parent 072110e655
commit 04833b490c
2 changed files with 78 additions and 0 deletions
@@ -0,0 +1,50 @@
import { GET } from './route'
import * as creationSheets from '@/lib/creationSheets'
import { getServerSession } from 'next-auth'
jest.mock('next-auth')
jest.mock('@/lib/creationSheets')
jest.mock('@/lib/prisma', () => ({
prisma: { productCreation: { findMany: jest.fn().mockResolvedValue([]) } },
}))
const mockSession = getServerSession as jest.MockedFunction<typeof getServerSession>
const mockFetch = creationSheets.fetchPendingProducts as jest.MockedFunction<typeof creationSheets.fetchPendingProducts>
const makePending = (tab: string, row: number, specific: Record<string, string> = {}) => ({
tab, rowNumber: row, sku: `SKU-${row}`, title: `Produit ${row}`,
priceMarket: '99', priceActual: '79', stock: 5, weightKg: 2,
vendor: 'BOSCH', famille: tab, sousFamille: '', comment: '',
collectionId: '10', subCollectionId: '', hasPhoto: false,
specificFields: specific,
})
describe('GET /api/creation/preview', () => {
beforeEach(() => {
mockSession.mockResolvedValue({ user: { id: 'u1', role: 'admin' } } as never)
mockFetch.mockResolvedValue([
makePending('OUTILLAGE', 2, { 'Puissance (AN)': '1500W' }),
makePending('CARRELAGE', 3),
])
})
it('retourne 401 sans session', async () => {
mockSession.mockResolvedValue(null)
const res = await GET(new Request('http://localhost') as never)
expect(res.status).toBe(401)
})
it('retourne les produits groupés par onglet', async () => {
const res = await GET(new Request('http://localhost') as never)
const body = await res.json()
expect(body.byTab['OUTILLAGE']).toHaveLength(1)
expect(body.byTab['CARRELAGE']).toHaveLength(1)
expect(body.total).toBe(2)
})
it('liste les colonnes spécifiques uniques', async () => {
const res = await GET(new Request('http://localhost') as never)
const body = await res.json()
expect(body.specificColumns).toContain('Puissance (AN)')
})
})
+28
View File
@@ -0,0 +1,28 @@
import { NextRequest, NextResponse } from 'next/server'
import { getServerSession } from 'next-auth'
import { authOptions } from '@/lib/auth'
import { fetchPendingProducts } from '@/lib/creationSheets'
import { prisma } from '@/lib/prisma'
import type { PendingProduct } from '@/types/creation'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export async function GET(_req: NextRequest) {
const session = await getServerSession(authOptions)
if (!session) return NextResponse.json({ error: 'Non authentifié' }, { status: 401 })
try {
const existing = await prisma.productCreation.findMany({ select: { sheetTab: true, sheetRow: true } })
const alreadyCreated = new Set(existing.map(e => `${e.sheetTab}:${e.sheetRow}`))
const pending = await fetchPendingProducts(alreadyCreated)
const byTab: Record<string, PendingProduct[]> = {}
const specificColumns = new Set<string>()
for (const p of pending) {
if (!byTab[p.tab]) byTab[p.tab] = []
byTab[p.tab].push(p)
Object.keys(p.specificFields).forEach(k => specificColumns.add(k))
}
return NextResponse.json({ byTab, total: pending.length, specificColumns: Array.from(specificColumns).sort() })
} catch (err) {
const message = err instanceof Error ? err.message : 'Erreur inconnue'
return NextResponse.json({ error: message }, { status: 500 })
}
}