// @vitest-environment happy-dom import { defineComponent } from 'vue' import { flushPromises, mount } from '@vue/test-utils' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import ExplainListPage from '@/pages/explain/list.vue' const hostEnvironmentMocks = vi.hoisted(() => ({ embeddedInWechatMiniProgram: false })) const testState = vi.hoisted(() => ({ onLoadHandler: null as null | (() => void) })) vi.mock('@dcloudio/uni-app', () => ({ onLoad: (handler: () => void) => { testState.onLoadHandler = handler } })) vi.mock('@/utils/hostEnvironment', () => ({ isEmbeddedInWechatMiniProgram: () => hostEnvironmentMocks.embeddedInWechatMiniProgram })) vi.mock('@/usecases/explainUseCase', () => ({ explainUseCase: { loadExplainHalls: async () => [], loadExplainHallSummaries: async () => ({}) } })) const GuidePageFrameStub = defineComponent({ name: 'GuidePageFrame', template: '
' }) const ExplainHallSelectStub = defineComponent({ name: 'ExplainHallSelect', emits: ['back'], template: '' }) const mountExplainList = () => mount(ExplainListPage, { global: { stubs: { GuidePageFrame: GuidePageFrameStub, ExplainHallSelect: ExplainHallSelectStub } } }) beforeEach(() => { hostEnvironmentMocks.embeddedInWechatMiniProgram = false testState.onLoadHandler = null window.location.hash = '#/pages/explain/list' window.history.replaceState({}, '', window.location.href) vi.stubGlobal('uni', { navigateBack: vi.fn(), redirectTo: vi.fn(), reLaunch: vi.fn() }) }) afterEach(() => { vi.restoreAllMocks() vi.unstubAllGlobals() }) describe('讲解展厅列表返回', () => { it('微信内嵌时不调用 navigateBack,并保留宿主标识返回首页讲解 Tab', async () => { hostEnvironmentMocks.embeddedInWechatMiniProgram = true window.location.hash = '#/pages/explain/list?embedded=wechat-mini-program&weapp=1&mini-program=1' window.history.replaceState({}, '', window.location.href) const wrapper = mountExplainList() const pushState = vi.spyOn(window.history, 'pushState') testState.onLoadHandler?.() await flushPromises() await wrapper.get('[data-testid="explain-list-back"]').trigger('click') expect(pushState).toHaveBeenCalledWith( expect.objectContaining({ museumGuidePage: 'explain-list' }), '', window.location.href ) expect(uni.navigateBack).not.toHaveBeenCalled() expect(uni.reLaunch).toHaveBeenCalledTimes(1) const url = vi.mocked(uni.reLaunch).mock.calls[0]?.[0]?.url || '' const query = new URLSearchParams(url.split('?')[1]) expect(url.split('?')[0]).toBe('/pages/index/index') expect(query.get('tab')).toBe('explain') expect(query.get('embedded')).toBe('wechat-mini-program') expect(query.get('weapp')).toBe('1') expect(query.get('mini-program')).toBe('1') wrapper.unmount() }) it('微信内嵌浏览器返回时回到首页讲解 Tab', async () => { hostEnvironmentMocks.embeddedInWechatMiniProgram = true window.location.hash = '#/pages/explain/list?embedded=wechat-mini-program&weapp=1' window.history.replaceState({}, '', window.location.href) const wrapper = mountExplainList() testState.onLoadHandler?.() await flushPromises() window.dispatchEvent(new PopStateEvent('popstate', { state: {} })) await flushPromises() expect(uni.navigateBack).not.toHaveBeenCalled() const url = vi.mocked(uni.reLaunch).mock.calls[0]?.[0]?.url || '' const query = new URLSearchParams(url.split('?')[1]) expect(url.split('?')[0]).toBe('/pages/index/index') expect(query.get('tab')).toBe('explain') expect(query.get('embedded')).toBe('wechat-mini-program') expect(query.get('weapp')).toBe('1') wrapper.unmount() }) it('普通 H5 保持原有 navigateBack 行为', async () => { const wrapper = mountExplainList() await wrapper.get('[data-testid="explain-list-back"]').trigger('click') expect(uni.navigateBack).toHaveBeenCalledWith(expect.objectContaining({ delta: 1 })) expect(uni.reLaunch).not.toHaveBeenCalled() wrapper.unmount() }) })