146 lines
4.6 KiB
TypeScript
146 lines
4.6 KiB
TypeScript
/** @jest-environment node */
|
|
|
|
import { GET as getSchemaRoute } from '@/app/api/external/material-import/schema/route'
|
|
import { POST as postJobsRoute } from '@/app/api/external/material-import/jobs/route'
|
|
import { GET as getJobStatusRoute } from '@/app/api/external/material-import/jobs/[jobId]/route'
|
|
import { getExternalMaterialImportJobStatus, getExternalMaterialImportSchema, createExternalMaterialImportJob, triggerExternalMaterialImportJob } from '@/lib/external-material-import'
|
|
import { logApiCall, validateApiKey } from '@/lib/external-api'
|
|
|
|
jest.mock('@/lib/external-api', () => {
|
|
const { NextResponse } = require('next/server')
|
|
return {
|
|
getApiKeyFromRequest: jest.fn((request: { headers: Headers }) => request.headers.get('X-API-Key')),
|
|
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/external-material-import', () => ({
|
|
ExternalMaterialImportError: class ExternalMaterialImportError extends Error {
|
|
status: number
|
|
code: string
|
|
|
|
constructor(status: number, code: string, message: string) {
|
|
super(message)
|
|
this.status = status
|
|
this.code = code
|
|
}
|
|
},
|
|
getExternalMaterialImportSchema: jest.fn(),
|
|
createExternalMaterialImportJob: jest.fn(),
|
|
getExternalMaterialImportJobStatus: jest.fn(),
|
|
triggerExternalMaterialImportJob: jest.fn(),
|
|
}))
|
|
|
|
function createRequest(url: string, body?: unknown) {
|
|
return {
|
|
nextUrl: new URL(url),
|
|
headers: new Headers({
|
|
'X-API-Key': 'test-key',
|
|
'user-agent': 'jest',
|
|
}),
|
|
json: jest.fn().mockResolvedValue(body),
|
|
} as any
|
|
}
|
|
|
|
describe('external material import routes', () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks()
|
|
;(validateApiKey as jest.Mock).mockResolvedValue({
|
|
id: 'api-1',
|
|
name: 'test-key',
|
|
isActive: true,
|
|
})
|
|
})
|
|
|
|
test('schema 路由应返回服务层 schema 结果', async () => {
|
|
;(getExternalMaterialImportSchema as jest.Mock).mockResolvedValue({
|
|
materialType: '任务-详情',
|
|
open: true,
|
|
fields: [],
|
|
imageGroups: {
|
|
allowedKeys: ['main', 'sku', 'detail'],
|
|
minTotalImages: 1,
|
|
},
|
|
})
|
|
|
|
const response = await getSchemaRoute(
|
|
createRequest('https://example.com/api/external/material-import/schema?materialType=任务-详情'),
|
|
)
|
|
const body = await response.json()
|
|
|
|
expect(response.status).toBe(200)
|
|
expect(body.success).toBe(true)
|
|
expect(body.data.materialType).toBe('任务-详情')
|
|
expect(getExternalMaterialImportSchema).toHaveBeenCalledWith('任务-详情')
|
|
expect(logApiCall).toHaveBeenCalled()
|
|
})
|
|
|
|
test('jobs 路由创建新任务时应触发后台处理', async () => {
|
|
;(createExternalMaterialImportJob as jest.Mock).mockResolvedValue({
|
|
created: true,
|
|
job: {
|
|
jobId: 'job-1',
|
|
materialType: '任务-详情',
|
|
taskNo: 'TASK202603240001',
|
|
status: 'processing',
|
|
success: false,
|
|
resultMaterialId: null,
|
|
errorCode: null,
|
|
errorMessage: null,
|
|
completedAt: null,
|
|
},
|
|
})
|
|
|
|
const response = await postJobsRoute(
|
|
createRequest('https://example.com/api/external/material-import/jobs', {
|
|
formData: {
|
|
taskNo: 'TASK202603240001',
|
|
},
|
|
}),
|
|
)
|
|
const body = await response.json()
|
|
|
|
expect(response.status).toBe(200)
|
|
expect(body.success).toBe(true)
|
|
expect(body.data.created).toBe(true)
|
|
expect(triggerExternalMaterialImportJob).toHaveBeenCalledWith('job-1')
|
|
})
|
|
|
|
test('job status 路由应透传 jobId 和 apiKey 范围查询', async () => {
|
|
;(getExternalMaterialImportJobStatus as jest.Mock).mockResolvedValue({
|
|
jobId: 'job-1',
|
|
materialType: '任务-详情',
|
|
taskNo: 'TASK202603240001',
|
|
status: 'succeeded',
|
|
success: true,
|
|
resultMaterialId: 'material-1',
|
|
errorCode: null,
|
|
errorMessage: null,
|
|
completedAt: '2026-03-24T09:02:00.000Z',
|
|
})
|
|
|
|
const response = await getJobStatusRoute(
|
|
createRequest('https://example.com/api/external/material-import/jobs/job-1'),
|
|
{ params: { jobId: 'job-1' } },
|
|
)
|
|
const body = await response.json()
|
|
|
|
expect(response.status).toBe(200)
|
|
expect(body.success).toBe(true)
|
|
expect(body.data.success).toBe(true)
|
|
expect(getExternalMaterialImportJobStatus).toHaveBeenCalledWith({
|
|
apiKeyId: 'api-1',
|
|
jobId: 'job-1',
|
|
})
|
|
})
|
|
})
|