Files
frontend-miniapp/tests/unit/BackendExplainContentProvider.spec.ts
lyf 9ea1bfab71
Some checks failed
CI / verify (push) Has been cancelled
同步 sgs-frontend-mobile 源码
2026-07-27 11:26:01 +08:00

83 lines
3.8 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from 'vitest'
import { BackendExplainContentProvider } from '@/data/providers/backendExplainContentProvider'
const installRequest = (handler: (url: string) => unknown) => {
vi.stubGlobal('uni', {
request: ({ url, success }: { url: string, success: (response: unknown) => void }) => {
success({ statusCode: 200, data: handler(url) })
}
})
}
describe('BackendExplainContentProvider hall stop paging', () => {
afterEach(() => vi.unstubAllGlobals())
it('uses the paged hall endpoint and maps independent pages without outlines', async () => {
const requests: string[] = []
installRequest((url) => {
requests.push(url)
if (url.includes('/catalog/halls?')) return { code: 0, data: [{ id: 'hall-1', name: '恐龙厅', floorId: 'f1' }] }
const pageNo = new URL(url, 'http://localhost').searchParams.get('pageNo')
return {
code: 0,
data: {
total: 30,
list: pageNo === '1'
? [{ stopId: 'stop-1', name: '对象一', imageStatus: 'READY', coverImageUrl: '/one.jpg', playTargetType: 'STOP', playTargetId: 'target-1' }]
: [{ stopId: 'stop-2', name: '对象二', imageStatus: 'MISSING', playTargetType: 'STOP', playTargetId: 'target-2' }]
}
}
})
const provider = new BackendExplainContentProvider()
const [first, second] = await Promise.all([
provider.listGuideStopsPageByHall('hall-1', 1, 20),
provider.listGuideStopsPageByHall('hall-1', 2, 20)
])
expect(first).toMatchObject({ total: 30, pageNo: 1, pageSize: 20, hasMore: true })
expect(first.items[0]).toMatchObject({ id: 'stop-1', hallName: '恐龙厅', playTargetId: 'target-1' })
expect(second.items.map((item) => item.id)).toEqual(['stop-2'])
expect(requests.filter((url) => url.includes('/stops/page'))).toHaveLength(2)
expect(requests.some((url) => url.includes('/outlines'))).toBe(false)
expect(requests.find((url) => url.includes('pageNo=1') && url.includes('pageSize=20') && url.includes('lang=zh-CN'))).toBeTruthy()
})
it('clears failed inflight requests so the page can be retried', async () => {
let attempts = 0
installRequest((url) => {
if (url.includes('/catalog/halls?')) return { code: 0, data: [{ id: 'hall-1', name: '恐龙厅' }] }
attempts += 1
return attempts === 1 ? { code: 500, msg: 'temporary failure' } : { code: 0, data: { list: [], total: 0 } }
})
const provider = new BackendExplainContentProvider()
await expect(provider.listGuideStopsPageByHall('hall-1', 1, 20)).rejects.toThrow('temporary failure')
await expect(provider.listGuideStopsPageByHall('hall-1', 1, 20)).resolves.toMatchObject({ items: [], total: 0, hasMore: false })
expect(attempts).toBe(2)
})
it('reuses the short-lived persistent catalog cache across provider instances', async () => {
const values = new Map<string, string>()
vi.stubGlobal('window', {
localStorage: {
getItem: (key: string) => values.get(key) || null,
setItem: (key: string, value: string) => values.set(key, value),
removeItem: (key: string) => values.delete(key)
}
})
const requests: string[] = []
installRequest((url) => {
requests.push(url)
if (url.includes('/catalog/halls?')) return { code: 0, data: [{ id: 'hall-1', name: '恐龙厅' }] }
return { code: 0, data: { list: [{ stopId: 'stop-1', name: '对象一' }], total: 1 } }
})
const firstProvider = new BackendExplainContentProvider()
const secondProvider = new BackendExplainContentProvider()
await firstProvider.listGuideStopsPageByHall('hall-1', 1, 20)
await secondProvider.listGuideStopsPageByHall('hall-1', 1, 20)
expect(requests.filter((url) => url.includes('/catalog/halls?'))).toHaveLength(1)
expect(requests.filter((url) => url.includes('/stops/page'))).toHaveLength(1)
})
})