Files
frontend-miniapp/tests/unit/ExplainHallSelect.spec.ts

127 lines
4.1 KiB
TypeScript

// @vitest-environment happy-dom
import { mount } from '@vue/test-utils'
import { afterEach, describe, expect, it, vi } from 'vitest'
import ExplainHallSelect from '@/components/explain/ExplainHallSelect.vue'
const hostEnvironmentMocks = vi.hoisted(() => ({
embeddedInWechatMiniProgram: false
}))
vi.mock('@/utils/hostEnvironment', () => ({
isEmbeddedInWechatMiniProgram: () => hostEnvironmentMocks.embeddedInWechatMiniProgram
}))
afterEach(() => {
hostEnvironmentMocks.embeddedInWechatMiniProgram = false
})
describe('讲解展厅选择列表', () => {
it('微信嵌入态独立页面可强制显示 H5 返回入口,且不使用宿主导航布局', async () => {
hostEnvironmentMocks.embeddedInWechatMiniProgram = true
const wrapper = mount(ExplainHallSelect, {
props: {
forceInternalHeader: true
}
})
expect(wrapper.findAll('.explain-page-header')).toHaveLength(1)
expect(wrapper.findAll('.header-back')).toHaveLength(1)
expect(wrapper.classes()).not.toContain('host-navigation')
await wrapper.get('.header-back').trigger('tap')
expect(wrapper.emitted('back')).toEqual([[]])
})
it('微信嵌入态未强制时保留宿主导航布局,保护首页讲解 Tab', () => {
hostEnvironmentMocks.embeddedInWechatMiniProgram = true
const wrapper = mount(ExplainHallSelect)
expect(wrapper.find('.explain-page-header').exists()).toBe(false)
expect(wrapper.classes()).toContain('host-navigation')
})
it('展厅卡片只显示讲解对象数量,不暴露业务单元契约', async () => {
const wrapper = mount(ExplainHallSelect, {
props: {
stage: 'hall',
halls: [
{
id: 'hall-evolution',
name: '生命演化厅',
explainCount: 6,
guideStopCount: 6,
searchText: '生命演化厅'
}
]
}
})
const cards = wrapper.findAll('.hall-card')
expect(cards).toHaveLength(1)
expect(wrapper.text()).toContain('生命演化厅')
expect(wrapper.text()).not.toContain('6 个讲解对象')
expect(wrapper.text()).not.toContain('业务单元')
await cards[0]?.trigger('tap')
expect(wrapper.emitted('hallClick')).toEqual([['hall-evolution']])
})
it('展厅阶段按主题色卡展示展厅名称和图标', () => {
const wrapper = mount(ExplainHallSelect, {
props: {
stage: 'hall',
halls: [{
id: 'hall-dinosaur',
name: '恐龙厅',
floorLabel: 'L-2',
explainCount: 35,
guideStopCount: 35,
searchText: '恐龙厅'
}]
}
})
const card = wrapper.get('.hall-overview-card')
expect(wrapper.get('.header-title').text()).toBe('展厅讲解')
expect(card.attributes('style')).toContain('--hall-card-color: #d9b06c')
expect(card.text()).toContain('恐龙厅')
expect(card.text()).not.toContain('Dinosaur Hall')
expect(card.text()).not.toContain('35 个讲解对象')
expect(card.find('.hall-go-entry').exists()).toBe(false)
})
it('READY 讲解点不显示可讲解标签,非 READY 讲解点保留图文标签和点击事件', async () => {
const readyStop = {
id: 'stop-ready',
name: '生命起源',
hallId: 'hall-evolution',
audioStatus: 'READY'
}
const textStop = {
id: 'stop-text',
name: '化石记录',
hallId: 'hall-evolution',
audioStatus: 'MISSING'
}
const wrapper = mount(ExplainHallSelect, {
props: {
stage: 'stop',
guideStops: [readyStop, textStop]
}
})
const cards = wrapper.findAll('.stop-card')
expect(cards).toHaveLength(2)
expect(wrapper.text()).toContain('生命起源')
expect(wrapper.text()).toContain('化石记录')
expect(wrapper.text()).not.toContain('可讲解')
expect(cards[0]?.find('.hall-meta-row').exists()).toBe(false)
expect(cards[1]?.find('.floor-badge').text()).toBe('图文')
await cards[0]?.trigger('tap')
await cards[1]?.trigger('tap')
expect(wrapper.emitted('guideStopClick')).toEqual([[readyStop], [textStop]])
})
})