From 015833150a6b16cfaea7d5a33c23f9a63c4c79ee Mon Sep 17 00:00:00 2001 From: Mathieu Date: Tue, 9 Jun 2026 09:58:14 +0200 Subject: [PATCH] feat(plan5): API GET /api/creation/metafields (TDD) --- src/app/api/creation/metafields/route.test.ts | 37 +++++++++++++++++++ src/app/api/creation/metafields/route.ts | 20 ++++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/app/api/creation/metafields/route.test.ts create mode 100644 src/app/api/creation/metafields/route.ts diff --git a/src/app/api/creation/metafields/route.test.ts b/src/app/api/creation/metafields/route.test.ts new file mode 100644 index 0000000..63c4f92 --- /dev/null +++ b/src/app/api/creation/metafields/route.test.ts @@ -0,0 +1,37 @@ +import { GET } from './route' +import * as shopifyMetafields from '@/lib/shopifyMetafields' +import { getServerSession } from 'next-auth' + +jest.mock('next-auth') +jest.mock('@/lib/shopifyMetafields') + +const mockSession = getServerSession as jest.MockedFunction +const mockFetchDefs = shopifyMetafields.fetchMetafieldDefinitions as jest.MockedFunction +const mockMatch = shopifyMetafields.matchMetafields as jest.MockedFunction + +describe('GET /api/creation/metafields', () => { + beforeEach(() => { + mockSession.mockResolvedValue({ user: { id: 'u1', role: 'admin' } } as never) + mockFetchDefs.mockResolvedValue([ + { id: '1', namespace: 'custom', key: 'puissance', name: 'Puissance', type: 'single_line_text_field' }, + ]) + mockMatch.mockReturnValue({ + matched: { 'Puissance (AN)': { columnHeader: 'Puissance (AN)', action: 'map', namespace: 'custom', key: 'puissance', existingDefinitionId: '1' } }, + unmatched: ['Batterie (AP)'], + }) + }) + + it('retourne 401 sans session', async () => { + mockSession.mockResolvedValue(null) + const res = await GET(new Request('http://localhost/api/creation/metafields?columns=Puissance') as never) + expect(res.status).toBe(401) + }) + + it('retourne définitions + matching', async () => { + const res = await GET(new Request('http://localhost/api/creation/metafields?columns=Puissance+%28AN%29%2CBatterie+%28AP%29') as never) + const body = await res.json() + expect(body.definitions).toHaveLength(1) + expect(body.matched['Puissance (AN)'].key).toBe('puissance') + expect(body.unmatched).toContain('Batterie (AP)') + }) +}) diff --git a/src/app/api/creation/metafields/route.ts b/src/app/api/creation/metafields/route.ts new file mode 100644 index 0000000..6fbcb3f --- /dev/null +++ b/src/app/api/creation/metafields/route.ts @@ -0,0 +1,20 @@ +import { NextRequest, NextResponse } from 'next/server' +import { getServerSession } from 'next-auth' +import { authOptions } from '@/lib/auth' +import { fetchMetafieldDefinitions, matchMetafields } from '@/lib/shopifyMetafields' + +export async function GET(req: NextRequest) { + const session = await getServerSession(authOptions) + if (!session) return NextResponse.json({ error: 'Non authentifié' }, { status: 401 }) + try { + const { searchParams } = new URL(req.url) + const columnsParam = searchParams.get('columns') ?? '' + const columns = columnsParam ? columnsParam.split(',').map(c => c.trim()).filter(Boolean) : [] + const definitions = await fetchMetafieldDefinitions() + const { matched, unmatched } = matchMetafields(columns, definitions) + return NextResponse.json({ definitions, matched, unmatched }) + } catch (err) { + const message = err instanceof Error ? err.message : 'Erreur inconnue' + return NextResponse.json({ error: message }, { status: 500 }) + } +}