feat: API route GET /api/products/search (TDD)

Implémentation test-driven du endpoint de recherche de produits par référence.
- Tests unitaires complets validant les cas nominaux et d'erreur
- Validation du paramètre ref avec gestion des chaînes vides
- Intégration avec searchProductByRef de lib/shopify
- Gestion appropriée des erreurs HTTP (400, 500)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-08 17:15:58 +02:00
parent 53008d1d43
commit c9422be78e
2 changed files with 71 additions and 0 deletions
+53
View File
@@ -0,0 +1,53 @@
import { GET } from '@/app/api/products/search/route'
import { NextRequest } from 'next/server'
jest.mock('@/lib/shopify', () => ({
searchProductByRef: jest.fn(),
}))
import { searchProductByRef } from '@/lib/shopify'
const mockSearch = searchProductByRef as jest.Mock
describe('GET /api/products/search', () => {
beforeEach(() => jest.clearAllMocks())
it('retourne 400 si le paramètre ref est absent', async () => {
const req = new NextRequest('http://localhost/api/products/search')
const res = await GET(req)
expect(res.status).toBe(400)
const data = await res.json()
expect(data.error).toMatch(/ref/)
})
it('retourne 400 si ref est une chaîne vide', async () => {
const req = new NextRequest('http://localhost/api/products/search?ref=')
const res = await GET(req)
expect(res.status).toBe(400)
})
it('retourne { found: false } si produit introuvable', async () => {
mockSearch.mockResolvedValue({ found: false })
const req = new NextRequest('http://localhost/api/products/search?ref=REF-9999')
const res = await GET(req)
expect(res.status).toBe(200)
expect(await res.json()).toEqual({ found: false })
expect(mockSearch).toHaveBeenCalledWith('REF-9999')
})
it('retourne le produit trouvé', async () => {
mockSearch.mockResolvedValue({ found: true, shopifyId: '123456', title: 'Carrelage REF-1042' })
const req = new NextRequest('http://localhost/api/products/search?ref=REF-1042')
const res = await GET(req)
expect(res.status).toBe(200)
expect(await res.json()).toEqual({ found: true, shopifyId: '123456', title: 'Carrelage REF-1042' })
})
it('retourne 500 en cas d\'erreur Shopify', async () => {
mockSearch.mockRejectedValue(new Error('Shopify API error: 503'))
const req = new NextRequest('http://localhost/api/products/search?ref=REF-1042')
const res = await GET(req)
expect(res.status).toBe(500)
const data = await res.json()
expect(data.error).toBeTruthy()
})
})
+18
View File
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from 'next/server'
import { searchProductByRef } from '@/lib/shopify'
export async function GET(req: NextRequest) {
const ref = req.nextUrl.searchParams.get('ref')
if (!ref || ref.trim() === '') {
return NextResponse.json({ error: 'Paramètre ref requis' }, { status: 400 })
}
try {
const result = await searchProductByRef(ref.trim())
return NextResponse.json(result)
} catch (err) {
const message = err instanceof Error ? err.message : 'Erreur inconnue'
return NextResponse.json({ error: message }, { status: 500 })
}
}