246 lines
8.0 KiB
TypeScript
246 lines
8.0 KiB
TypeScript
/** @jest-environment node */
|
|
|
|
import { GET } from '@/app/api/taobao-detail-plus/route'
|
|
import { getServerSession } from 'next-auth'
|
|
|
|
jest.mock('next-auth', () => ({
|
|
getServerSession: jest.fn(),
|
|
}))
|
|
|
|
jest.mock('@/lib/auth', () => ({
|
|
authOptions: {},
|
|
}))
|
|
|
|
describe('taobao-detail-plus route', () => {
|
|
const originalApiKey = process.env.TAOBAO_DETAIL_PLUS_API_KEY
|
|
const originalBaseUrl = process.env.TAOBAO_DETAIL_PLUS_API_BASE_URL
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks()
|
|
;(getServerSession as jest.Mock).mockResolvedValue({
|
|
user: { id: 'user-1', name: 'tester' },
|
|
})
|
|
process.env.TAOBAO_DETAIL_PLUS_API_KEY = 'test-api-key'
|
|
process.env.TAOBAO_DETAIL_PLUS_API_BASE_URL = 'http://mocked.example.com'
|
|
global.fetch = jest.fn() as jest.Mock
|
|
})
|
|
|
|
afterAll(() => {
|
|
if (originalApiKey === undefined) {
|
|
delete process.env.TAOBAO_DETAIL_PLUS_API_KEY
|
|
} else {
|
|
process.env.TAOBAO_DETAIL_PLUS_API_KEY = originalApiKey
|
|
}
|
|
|
|
if (originalBaseUrl === undefined) {
|
|
delete process.env.TAOBAO_DETAIL_PLUS_API_BASE_URL
|
|
} else {
|
|
process.env.TAOBAO_DETAIL_PLUS_API_BASE_URL = originalBaseUrl
|
|
}
|
|
})
|
|
|
|
function createRequest(url: string) {
|
|
return {
|
|
nextUrl: new URL(url),
|
|
} as any
|
|
}
|
|
|
|
test('未登录时应返回 401', async () => {
|
|
;(getServerSession as jest.Mock).mockResolvedValue(null)
|
|
|
|
const response = await GET(createRequest('https://example.com/api/taobao-detail-plus?itemId=867081550619'))
|
|
const body = await response.json()
|
|
|
|
expect(response.status).toBe(401)
|
|
expect(body.error.code).toBe('UNAUTHORIZED')
|
|
})
|
|
|
|
test('商品ID 非法时应返回 400', async () => {
|
|
const response = await GET(createRequest('https://example.com/api/taobao-detail-plus?itemId=abc'))
|
|
const body = await response.json()
|
|
|
|
expect(response.status).toBe(400)
|
|
expect(body.error.code).toBe('INVALID_ITEM_ID')
|
|
})
|
|
|
|
test('未配置第三方密钥时应返回 500', async () => {
|
|
delete process.env.TAOBAO_DETAIL_PLUS_API_KEY
|
|
|
|
const response = await GET(createRequest('https://example.com/api/taobao-detail-plus?itemId=867081550619'))
|
|
const body = await response.json()
|
|
|
|
expect(response.status).toBe(500)
|
|
expect(body.error.code).toBe('SERVICE_NOT_CONFIGURED')
|
|
})
|
|
|
|
test('上游返回 404 时应转成商品不存在的人话提示', async () => {
|
|
;(global.fetch as jest.Mock).mockResolvedValue({
|
|
ok: false,
|
|
status: 404,
|
|
json: async () => ({
|
|
success: false,
|
|
error: '未找到该商品数据',
|
|
}),
|
|
})
|
|
|
|
const response = await GET(createRequest('https://example.com/api/taobao-detail-plus?itemId=930071432357'))
|
|
const body = await response.json()
|
|
|
|
expect(response.status).toBe(404)
|
|
expect(body.error.code).toBe('ITEM_NOT_FOUND')
|
|
expect(body.error.message).toBe('未找到该商品数据')
|
|
})
|
|
|
|
test('查询成功时应返回精简后的商品摘要', async () => {
|
|
;(global.fetch as jest.Mock).mockResolvedValue({
|
|
ok: true,
|
|
json: async () => ({
|
|
success: true,
|
|
data: {
|
|
item_id: '867081550619',
|
|
title: '床边桌可移动升降折叠桌子',
|
|
shop_name: '耐家官方旗舰店',
|
|
price: '59.50',
|
|
location: '江苏常州',
|
|
seller_type: '天猫',
|
|
detail_url: 'https://item.taobao.com/item.htm?id=867081550619',
|
|
video_url: 'https://cloud.video.taobao.com/video.mp4',
|
|
item_imgs_count: 5,
|
|
skus_count: 25,
|
|
attributes_count: 17,
|
|
total_count: '900+',
|
|
item_imgs_json: [
|
|
{ url: 'https://img.example.com/1.jpg' },
|
|
{ url: 'https://img.example.com/2.jpg' },
|
|
],
|
|
skus_json: [
|
|
{ img: 'https://img.example.com/sku-1.jpg' },
|
|
{ image: 'https://img.example.com/sku-2.jpg' },
|
|
],
|
|
desc_imgs_json: [
|
|
{ url: 'https://img.example.com/desc-1.jpg' },
|
|
],
|
|
},
|
|
}),
|
|
})
|
|
|
|
const response = await GET(createRequest('https://example.com/api/taobao-detail-plus?itemId=867081550619'))
|
|
const body = await response.json()
|
|
|
|
expect(response.status).toBe(200)
|
|
expect(body.success).toBe(true)
|
|
expect(body.data).toEqual({
|
|
itemId: '867081550619',
|
|
title: '床边桌可移动升降折叠桌子',
|
|
shopName: '耐家官方旗舰店',
|
|
price: '59.50',
|
|
location: '江苏常州',
|
|
sellerType: '天猫',
|
|
detailUrl: 'https://item.taobao.com/item.htm?id=867081550619',
|
|
videoUrl: 'https://cloud.video.taobao.com/video.mp4',
|
|
mainImageUrl: 'https://img.example.com/1.jpg',
|
|
itemImages: ['https://img.example.com/1.jpg', 'https://img.example.com/2.jpg'],
|
|
allItemImages: ['https://img.example.com/1.jpg', 'https://img.example.com/2.jpg'],
|
|
skuImages: ['https://img.example.com/sku-1.jpg', 'https://img.example.com/sku-2.jpg'],
|
|
descImages: ['https://img.example.com/desc-1.jpg'],
|
|
itemImageCount: 5,
|
|
skuCount: 25,
|
|
attributeCount: 17,
|
|
totalCount: '900+',
|
|
})
|
|
expect(global.fetch).toHaveBeenCalledWith(
|
|
'http://mocked.example.com/api/public/taobao-detail-plus?itemId=867081550619',
|
|
expect.objectContaining({
|
|
headers: {
|
|
'x-api-key': 'test-api-key',
|
|
},
|
|
method: 'GET',
|
|
}),
|
|
)
|
|
})
|
|
|
|
test('应兼容从 skuBase 和详情 HTML 中提取图片', async () => {
|
|
;(global.fetch as jest.Mock).mockResolvedValue({
|
|
ok: true,
|
|
json: async () => ({
|
|
success: true,
|
|
data: {
|
|
item_id: '867081550619',
|
|
title: '测试商品',
|
|
shop_name: '测试店铺',
|
|
item_imgs_json: [
|
|
{ url: 'https://img.example.com/main-1.jpg' },
|
|
],
|
|
raw_data_json: {
|
|
skuBase: {
|
|
props: [
|
|
{
|
|
values: [
|
|
{ image: '//img.example.com/sku-a.png' },
|
|
{ imgUrl: 'https://img.example.com/sku-b.png' },
|
|
],
|
|
},
|
|
],
|
|
},
|
|
descHtml:
|
|
'<div><img src="https://img.example.com/desc-a.jpg" /><img src="//img.example.com/desc-b.webp" /></div>',
|
|
},
|
|
},
|
|
}),
|
|
})
|
|
|
|
const response = await GET(createRequest('https://example.com/api/taobao-detail-plus?itemId=867081550619'))
|
|
const body = await response.json()
|
|
|
|
expect(response.status).toBe(200)
|
|
expect(body.data.skuImages).toEqual([
|
|
'https://img.example.com/sku-a.png',
|
|
'https://img.example.com/sku-b.png',
|
|
])
|
|
expect(body.data.descImages).toEqual([
|
|
'https://img.example.com/desc-a.jpg',
|
|
'https://img.example.com/desc-b.webp',
|
|
])
|
|
})
|
|
|
|
test('应兼容从 specs_json 和字符串化 JSON 字段中提取 SKU 图与详情图', async () => {
|
|
;(global.fetch as jest.Mock).mockResolvedValue({
|
|
ok: true,
|
|
json: async () => ({
|
|
success: true,
|
|
data: {
|
|
item_id: '867081550619',
|
|
title: '测试商品 2',
|
|
shop_name: '测试店铺 2',
|
|
item_imgs_json: JSON.stringify([
|
|
{ url: 'https://img.example.com/main-1.jpg' },
|
|
]),
|
|
specs_json: JSON.stringify({
|
|
颜色分类: {
|
|
a: ['胡桃色', 'http://img.example.com/spec-1.jpg'],
|
|
b: ['纯白色', 'https://img.example.com/spec-2.png'],
|
|
},
|
|
}),
|
|
raw_data_json: JSON.stringify({
|
|
desc:
|
|
'<div><img src="https://img.example.com/desc-from-raw.jpg" /></div>',
|
|
}),
|
|
},
|
|
}),
|
|
})
|
|
|
|
const response = await GET(createRequest('https://example.com/api/taobao-detail-plus?itemId=867081550619'))
|
|
const body = await response.json()
|
|
|
|
expect(response.status).toBe(200)
|
|
expect(body.data.itemImages).toEqual(['https://img.example.com/main-1.jpg'])
|
|
expect(body.data.skuImages).toEqual([
|
|
'http://img.example.com/spec-1.jpg',
|
|
'https://img.example.com/spec-2.png',
|
|
])
|
|
expect(body.data.descImages).toEqual([
|
|
'https://img.example.com/desc-from-raw.jpg',
|
|
])
|
|
})
|
|
})
|