103 lines
3.8 KiB
TypeScript
103 lines
3.8 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest'
|
|
import type { GuideStopInfo } from '@/data/adapters/guideStopInfoAdapter'
|
|
import type { AudioPlayInfoRepository } from '@/repositories/AudioPlayInfoRepository'
|
|
import type { ExplainRepository } from '@/repositories/ExplainRepository'
|
|
import { ExplainUseCase } from '@/usecases/explainUseCase'
|
|
import { dataSourceConfig } from '@/config/dataSource'
|
|
|
|
const createStopInfo = (overrides: Partial<GuideStopInfo> = {}): GuideStopInfo => ({
|
|
available: true,
|
|
targetType: 'STOP',
|
|
targetId: 'stop-1',
|
|
lang: 'zh-CN',
|
|
title: 'Guide stop',
|
|
galleryUrls: [],
|
|
imageStatus: 'MISSING',
|
|
linkedExhibits: [
|
|
{
|
|
id: 'exhibit-1',
|
|
name: 'Linked exhibit',
|
|
coverImageUrl: '/linked-exhibit.jpg'
|
|
}
|
|
],
|
|
playTargetType: 'STOP',
|
|
playTargetId: 'stop-1',
|
|
hasAudio: false,
|
|
hasText: false,
|
|
supportedLanguages: [],
|
|
audioStatus: 'MISSING',
|
|
...overrides
|
|
})
|
|
|
|
const createUseCase = (stopInfo: GuideStopInfo) => {
|
|
const explain = {
|
|
getExhibitById: vi.fn().mockResolvedValue(null),
|
|
listExplainExhibits: vi.fn().mockResolvedValue([])
|
|
} as unknown as ExplainRepository
|
|
const audioPlayInfo = {
|
|
getStopInfo: vi.fn().mockResolvedValue(stopInfo)
|
|
} as unknown as AudioPlayInfoRepository
|
|
|
|
return new ExplainUseCase(explain, audioPlayInfo)
|
|
}
|
|
|
|
describe('ExplainUseCase stop image policy', () => {
|
|
it('uses stop-info first in remote mode without requesting a catalog fallback', async () => {
|
|
const originalMode = dataSourceConfig.explainContentMode
|
|
Object.assign(dataSourceConfig, { explainContentMode: 'remote' })
|
|
const explain = {
|
|
getExhibitById: vi.fn(),
|
|
listExplainExhibits: vi.fn(),
|
|
listExplainExhibitsByHall: vi.fn()
|
|
} as unknown as ExplainRepository
|
|
const audio = { getStopInfo: vi.fn().mockResolvedValue(createStopInfo()) } as unknown as AudioPlayInfoRepository
|
|
|
|
await new ExplainUseCase(explain, audio).enterExplainDetail({
|
|
exhibitId: 'stop-1', targetType: 'STOP', targetId: 'stop-1', hallName: '宇宙厅'
|
|
})
|
|
|
|
expect(audio.getStopInfo).toHaveBeenCalledTimes(1)
|
|
expect(explain.getExhibitById).not.toHaveBeenCalled()
|
|
expect(explain.listExplainExhibits).not.toHaveBeenCalled()
|
|
Object.assign(dataSourceConfig, { explainContentMode: originalMode })
|
|
})
|
|
|
|
it('delegates hall exhibits and business-unit stops without loading full exhibits', async () => {
|
|
const explain = {
|
|
listExplainExhibitsByHall: vi.fn().mockResolvedValue([]),
|
|
listGuideStopsByBusinessUnit: vi.fn().mockResolvedValue([])
|
|
} as unknown as ExplainRepository
|
|
const useCase = new ExplainUseCase(explain, {} as AudioPlayInfoRepository)
|
|
await useCase.listExhibitsByHallId('hall-1')
|
|
await useCase.listGuideStopsByBusinessUnit('hall-1', 'outline-1')
|
|
expect(explain.listExplainExhibitsByHall).toHaveBeenCalledWith('hall-1')
|
|
expect(explain.listGuideStopsByBusinessUnit).toHaveBeenCalledWith('hall-1', 'outline-1')
|
|
})
|
|
it('does not use linked exhibit images when stop-info reports MISSING', async () => {
|
|
const detail = await createUseCase(createStopInfo()).enterExplainDetail({
|
|
exhibitId: 'stop-1',
|
|
targetType: 'STOP',
|
|
targetId: 'stop-1'
|
|
})
|
|
|
|
expect(detail.image).toBeUndefined()
|
|
expect(detail.galleryUrls).toEqual([])
|
|
expect(detail.linkedExhibits?.[0]?.coverImageUrl).toBe('/linked-exhibit.jpg')
|
|
})
|
|
|
|
it('uses the stop image when stop-info reports READY', async () => {
|
|
const detail = await createUseCase(createStopInfo({
|
|
imageStatus: 'READY',
|
|
coverImageUrl: '/guide-stop.jpg',
|
|
galleryUrls: ['/guide-stop-gallery.jpg']
|
|
})).enterExplainDetail({
|
|
exhibitId: 'stop-1',
|
|
targetType: 'STOP',
|
|
targetId: 'stop-1'
|
|
})
|
|
|
|
expect(detail.image).toBe('/guide-stop.jpg')
|
|
expect(detail.galleryUrls).toEqual(['/guide-stop-gallery.jpg'])
|
|
})
|
|
})
|