同步移动端源码并修复小程序嵌入标题
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
lyf
2026-07-28 18:37:40 +08:00
parent 06ad609e1f
commit 540bb8627f
62 changed files with 4196 additions and 1410 deletions

View File

@@ -6,7 +6,6 @@ import { flushPromises, mount } from '@vue/test-utils'
const mocks = vi.hoisted(() => ({
onLoadHandler: null as null | ((options?: Record<string, unknown>) => Promise<void>),
onBackPressHandler: null as null | (() => boolean),
onHideHandler: null as null | (() => void),
onUnloadHandler: null as null | (() => void),
enterExplainDetail: vi.fn(),
@@ -18,9 +17,7 @@ const mocks = vi.hoisted(() => ({
close: vi.fn(),
seekToPercent: vi.fn(),
setPlaybackRate: vi.fn(),
toggleMute: vi.fn(),
embeddedInWechatMiniProgram: false,
returnToWechatMiniProgram: vi.fn(() => Promise.resolve({ status: 'failed' as const, reason: 'bridge-unavailable' as const }))
toggleMute: vi.fn()
}))
const audioState = vi.hoisted(() => ({
@@ -39,9 +36,6 @@ vi.mock('@dcloudio/uni-app', () => ({
onLoad: (handler: (options?: Record<string, unknown>) => Promise<void>) => {
mocks.onLoadHandler = handler
},
onBackPress: (handler: () => boolean) => {
mocks.onBackPressHandler = handler
},
onHide: (handler: () => void) => {
mocks.onHideHandler = handler
},
@@ -80,11 +74,7 @@ vi.mock('@/composables/useGlobalAudioPlayer', () => ({
}))
vi.mock('@/utils/hostEnvironment', () => ({
isEmbeddedInWechatMiniProgram: () => mocks.embeddedInWechatMiniProgram
}))
vi.mock('@/services/WechatMiniProgramBridgeService', () => ({
returnToWechatMiniProgram: () => mocks.returnToWechatMiniProgram()
isEmbeddedInWechatMiniProgram: () => false
}))
import ExhibitDetail from '@/pages/exhibit/detail.vue'
@@ -116,7 +106,6 @@ const exhibit = {
describe('讲解详情音频优先布局', () => {
beforeEach(() => {
mocks.onLoadHandler = null
mocks.onBackPressHandler = null
mocks.onHideHandler = null
mocks.onUnloadHandler = null
audioState.currentAudio.value = null
@@ -142,9 +131,6 @@ describe('讲解详情音频优先布局', () => {
playInfo: { title: exhibit.name }
})
mocks.play.mockResolvedValue(undefined)
mocks.embeddedInWechatMiniProgram = false
mocks.returnToWechatMiniProgram.mockReset()
mocks.returnToWechatMiniProgram.mockResolvedValue({ status: 'failed', reason: 'bridge-unavailable' })
vi.stubGlobal('uni', {
showToast: vi.fn(),
navigateBack: vi.fn(),
@@ -389,58 +375,6 @@ describe('讲解详情音频优先布局', () => {
expect(uni.redirectTo).not.toHaveBeenCalled()
})
it('小程序直达讲解详情时返回宿主,不进入 H5 讲解对象列表', async () => {
mocks.embeddedInWechatMiniProgram = true
mocks.returnToWechatMiniProgram.mockResolvedValue({ status: 'returned' })
const wrapper = mount(ExhibitDetail, {
global: { stubs: { GuidePageFrame: GuidePageFrameStub } }
})
await mocks.onLoadHandler?.({
id: exhibit.id,
targetType: 'STOP',
targetId: 'stop-1',
hallId: 'hall-1',
hallName: '恐龙厅'
})
expect(wrapper.find('.hero-back').exists()).toBe(false)
wrapper.getComponent(GuidePageFrameStub).vm.$emit('back')
await flushPromises()
expect(mocks.returnToWechatMiniProgram).toHaveBeenCalledTimes(1)
expect(uni.navigateBack).not.toHaveBeenCalled()
expect(uni.redirectTo).not.toHaveBeenCalled()
})
it('从讲解对象列表进入时,即使 H5 页面栈缺失也回到对象列表', async () => {
mocks.embeddedInWechatMiniProgram = true
mocks.returnToWechatMiniProgram.mockResolvedValue({ status: 'returned' })
const wrapper = mount(ExhibitDetail, {
global: { stubs: { GuidePageFrame: GuidePageFrameStub } }
})
await mocks.onLoadHandler?.({
id: exhibit.id,
targetType: 'STOP',
targetId: 'stop-1',
hallId: 'hall-1',
hallName: '恐龙厅',
returnToGuideStopList: '1',
returnToHallList: '1'
})
expect(wrapper.find('.hero-back').exists()).toBe(true)
await wrapper.get('.hero-back').trigger('tap')
await flushPromises()
const url = vi.mocked(uni.redirectTo).mock.calls[0]?.[0]?.url || ''
const params = new URLSearchParams(url.split('?')[1])
expect(url.split('?')[0]).toBe('/pages/explain/guide-stop-list')
expect(params.get('hallId')).toBe('hall-1')
expect(params.get('returnToHallList')).toBe('1')
expect(mocks.returnToWechatMiniProgram).not.toHaveBeenCalled()
expect(uni.navigateBack).not.toHaveBeenCalled()
})
it('离开详情页时立即关闭当前讲解播放器', async () => {
audioState.currentAudio.value = { id: 'audio-1', audioUrl: exhibit.audioUrl }
audioState.currentSource.value = { targetType: 'STOP', targetId: 'stop-1', lang: 'en-US' }
@@ -473,6 +407,9 @@ describe('讲解详情音频优先布局', () => {
})
await flushPromises()
vi.mocked(uni.navigateBack).mockImplementationOnce((options: any) => {
options.fail?.()
})
wrapper.getComponent(GuidePageFrameStub).vm.$emit('back')
await flushPromises()
@@ -481,6 +418,6 @@ describe('讲解详情音频优先布局', () => {
expect(url.split('?')[0]).toBe('/pages/explain/guide-stop-list')
expect(params.get('hallId')).toBe('hall-1')
expect(params.get('hallName')).toBe('恐龙厅')
expect(uni.navigateBack).not.toHaveBeenCalled()
expect(uni.navigateBack).toHaveBeenCalledWith(expect.objectContaining({ delta: 1 }))
})
})