96 lines
2.8 KiB
TypeScript
96 lines
2.8 KiB
TypeScript
/** @jest-environment node */
|
||
|
||
import { GET } from '@/app/api/external/dingtalk-material-options/route'
|
||
import { prisma } from '@/lib/prisma'
|
||
import { logApiCall, validateApiKey } from '@/lib/external-api'
|
||
|
||
jest.mock('@/lib/external-api', () => {
|
||
const { NextResponse } = require('next/server')
|
||
return {
|
||
getApiKeyFromRequest: jest.fn(
|
||
(request: { headers: Headers; nextUrl: URL }, options?: { allowQuery?: boolean }) =>
|
||
request.headers.get('X-API-Key') ||
|
||
(options?.allowQuery ? request.nextUrl.searchParams.get('apiKey') : null),
|
||
),
|
||
getClientIp: jest.fn(() => '127.0.0.1'),
|
||
logApiCall: jest.fn().mockResolvedValue(undefined),
|
||
successResponse: jest.fn((data: unknown, message?: string) =>
|
||
NextResponse.json({
|
||
success: true,
|
||
...(message ? { message } : {}),
|
||
data,
|
||
}),
|
||
),
|
||
validateApiKey: jest.fn(),
|
||
}
|
||
})
|
||
|
||
jest.mock('@/lib/prisma', () => ({
|
||
prisma: {
|
||
category: {
|
||
findMany: jest.fn(),
|
||
},
|
||
scene: {
|
||
findMany: jest.fn(),
|
||
},
|
||
productCategory: {
|
||
findMany: jest.fn(),
|
||
},
|
||
},
|
||
}))
|
||
|
||
describe('external dingtalk-material-options route', () => {
|
||
beforeEach(() => {
|
||
jest.clearAllMocks()
|
||
;(validateApiKey as jest.Mock).mockResolvedValue({
|
||
id: 'api-key-1',
|
||
name: 'test-key',
|
||
isActive: true,
|
||
})
|
||
;(prisma.category.findMany as jest.Mock).mockResolvedValue([
|
||
{ name: '顾家家居' },
|
||
{ name: '林氏木业' },
|
||
])
|
||
;(prisma.scene.findMany as jest.Mock).mockResolvedValue([
|
||
{ name: '客厅' },
|
||
{ name: '卧室' },
|
||
])
|
||
;(prisma.productCategory.findMany as jest.Mock).mockResolvedValue([
|
||
{ name: '沙发' },
|
||
{ name: '床' },
|
||
])
|
||
})
|
||
|
||
function createRequest(url: string, apiKey = 'test-key') {
|
||
return {
|
||
nextUrl: new URL(url),
|
||
headers: new Headers({
|
||
...(apiKey ? { 'X-API-Key': apiKey } : {}),
|
||
'user-agent': 'jest',
|
||
}),
|
||
} as any
|
||
}
|
||
|
||
test('应返回钉钉下拉选项', async () => {
|
||
const response = await GET(createRequest('https://example.com/api/external/dingtalk-material-options'))
|
||
const body = await response.json()
|
||
|
||
expect(response.status).toBe(200)
|
||
expect(body.success).toBe(true)
|
||
expect(body.data.requirementTypes).toContain('任务-详情')
|
||
expect(body.data.brands).toEqual(['顾家家居', '林氏木业'])
|
||
expect(body.data.sceneCategories).toEqual(['客厅', '卧室'])
|
||
expect(body.data.productCategories).toEqual(['沙发', '床'])
|
||
expect(logApiCall).toHaveBeenCalled()
|
||
})
|
||
|
||
test('允许钉钉用固定 URL 参数传 apiKey,避免每次手填请求头', async () => {
|
||
const response = await GET(
|
||
createRequest('https://example.com/api/external/dingtalk-material-options?apiKey=test-key', ''),
|
||
)
|
||
|
||
expect(response.status).toBe(200)
|
||
expect(validateApiKey).toHaveBeenCalledWith('test-key')
|
||
})
|
||
})
|