@@ -36,11 +36,13 @@ import type {
|
|||||||
} from '@/domain/museum'
|
} from '@/domain/museum'
|
||||||
import {
|
import {
|
||||||
guideTopTabUrl,
|
guideTopTabUrl,
|
||||||
|
isGuideTopTab,
|
||||||
navigateToGuideTopTab,
|
navigateToGuideTopTab,
|
||||||
type GuideTopTab
|
type GuideTopTab
|
||||||
} from '@/utils/guideTopTabs'
|
} from '@/utils/guideTopTabs'
|
||||||
import { isEmbeddedInWechatMiniProgram } from '@/utils/hostEnvironment'
|
import { isEmbeddedInWechatMiniProgram } from '@/utils/hostEnvironment'
|
||||||
import { explainGuideStopListUrl } from '@/utils/explainNavigation'
|
import { explainGuideStopListUrl } from '@/utils/explainNavigation'
|
||||||
|
import { returnToWechatMiniProgram } from '@/services/WechatMiniProgramBridgeService'
|
||||||
|
|
||||||
const explainHallItems = ref<ExplainHallSelectItem[]>([])
|
const explainHallItems = ref<ExplainHallSelectItem[]>([])
|
||||||
const explainLoading = ref(false)
|
const explainLoading = ref(false)
|
||||||
@@ -71,8 +73,6 @@ const buildExplainHallItems = (
|
|||||||
|
|
||||||
const shouldUseHostNavigation = computed(() => isEmbeddedInWechatMiniProgram())
|
const shouldUseHostNavigation = computed(() => isEmbeddedInWechatMiniProgram())
|
||||||
|
|
||||||
const GUIDE_HOME_URL = '/pages/index/index?tab=guide'
|
|
||||||
|
|
||||||
type ExplainListHistoryState = {
|
type ExplainListHistoryState = {
|
||||||
museumGuidePage?: 'explain-list'
|
museumGuidePage?: 'explain-list'
|
||||||
[key: string]: unknown
|
[key: string]: unknown
|
||||||
@@ -93,9 +93,7 @@ const getPageStack = () => (
|
|||||||
typeof getCurrentPages === 'function' ? getCurrentPages() as PageStackEntry[] : []
|
typeof getCurrentPages === 'function' ? getCurrentPages() as PageStackEntry[] : []
|
||||||
)
|
)
|
||||||
|
|
||||||
const guideHomeUrl = () => (
|
const guideHomeUrl = (tab: GuideTopTab = 'guide') => guideTopTabUrl(tab)
|
||||||
shouldUseHostNavigation.value ? guideTopTabUrl('guide') : GUIDE_HOME_URL
|
|
||||||
)
|
|
||||||
|
|
||||||
const isExplainListHistoryState = (state: unknown): state is ExplainListHistoryState => (
|
const isExplainListHistoryState = (state: unknown): state is ExplainListHistoryState => (
|
||||||
Boolean(
|
Boolean(
|
||||||
@@ -120,6 +118,25 @@ const reLaunchGuideHome = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const reLaunchPreviousGuideHome = (tab: GuideTopTab) => {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: guideHomeUrl(tab),
|
||||||
|
fail: showGuideHomeReturnError
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const returnToHostMiniProgram = async () => {
|
||||||
|
isReturningToGuideHome = true
|
||||||
|
const result = await returnToWechatMiniProgram()
|
||||||
|
if (result.status === 'returned') return
|
||||||
|
|
||||||
|
isReturningToGuideHome = false
|
||||||
|
uni.showToast({
|
||||||
|
title: '返回小程序失败,请重试',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const consumeExplainListHistory = () => {
|
const consumeExplainListHistory = () => {
|
||||||
if (
|
if (
|
||||||
typeof window === 'undefined'
|
typeof window === 'undefined'
|
||||||
@@ -144,25 +161,27 @@ const returnToGuideHome = () => {
|
|||||||
const previousTab = Array.isArray(previousPage?.options?.tab)
|
const previousTab = Array.isArray(previousPage?.options?.tab)
|
||||||
? previousPage.options.tab[0]
|
? previousPage.options.tab[0]
|
||||||
: previousPage?.options?.tab
|
: previousPage?.options?.tab
|
||||||
const canNavigateBackToGuideHome = (
|
const canNavigateBackToGuideHome = previousRoute === 'pages/index/index'
|
||||||
!shouldUseHostNavigation.value
|
const previousGuideHomeTab = isGuideTopTab(previousTab) ? previousTab : 'guide'
|
||||||
&& previousRoute === 'pages/index/index'
|
|
||||||
&& (!previousTab || previousTab === 'guide')
|
|
||||||
)
|
|
||||||
|
|
||||||
if (canNavigateBackToGuideHome) {
|
if (canNavigateBackToGuideHome) {
|
||||||
uni.navigateBack({
|
uni.navigateBack({
|
||||||
delta: 1,
|
delta: 1,
|
||||||
fail: reLaunchGuideHome
|
fail: () => reLaunchPreviousGuideHome(previousGuideHomeTab)
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shouldUseHostNavigation.value) {
|
||||||
|
void returnToHostMiniProgram()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
reLaunchGuideHome()
|
reLaunchGuideHome()
|
||||||
}
|
}
|
||||||
|
|
||||||
const pushExplainListHistory = () => {
|
const pushExplainListHistory = () => {
|
||||||
if (typeof window === 'undefined' || getPageStack().length > 1) return
|
if (typeof window === 'undefined' || shouldUseHostNavigation.value || getPageStack().length > 1) return
|
||||||
if (explainListHistoryPushed) return
|
if (explainListHistoryPushed) return
|
||||||
|
|
||||||
if (isExplainListHistoryState(window.history.state)) {
|
if (isExplainListHistoryState(window.history.state)) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
interface MiniProgramBridge {
|
interface MiniProgramBridge {
|
||||||
getEnv?: (callback: (result: { miniprogram?: boolean }) => void) => void
|
getEnv?: (callback: (result: { miniprogram?: boolean }) => void) => void
|
||||||
navigateTo?: (options: { url: string; success?: () => void; fail?: (error: { errMsg?: string }) => void }) => void
|
navigateTo?: (options: { url: string; success?: () => void; fail?: (error: { errMsg?: string }) => void }) => void
|
||||||
|
navigateBack?: (options: { delta?: number; success?: () => void; fail?: (error: { errMsg?: string }) => void }) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WechatMiniProgramBridgeResult =
|
export type WechatMiniProgramBridgeResult =
|
||||||
@@ -15,6 +16,11 @@ export type WechatMiniProgramBridgeResult =
|
|||||||
| { status: 'not-embedded' }
|
| { status: 'not-embedded' }
|
||||||
| { status: 'failed'; reason: 'invalid-target' | 'bridge-unavailable' | 'not-in-mini-program' | 'navigation-failed' | 'page-not-found' | 'timeout' }
|
| { status: 'failed'; reason: 'invalid-target' | 'bridge-unavailable' | 'not-in-mini-program' | 'navigation-failed' | 'page-not-found' | 'timeout' }
|
||||||
|
|
||||||
|
export type WechatMiniProgramReturnResult =
|
||||||
|
| { status: 'returned' }
|
||||||
|
| { status: 'not-embedded' }
|
||||||
|
| { status: 'failed'; reason: 'bridge-unavailable' | 'not-in-mini-program' | 'navigation-failed' | 'timeout' }
|
||||||
|
|
||||||
const SDK_URL = 'https://res.wx.qq.com/open/js/jweixin-1.3.2.js'
|
const SDK_URL = 'https://res.wx.qq.com/open/js/jweixin-1.3.2.js'
|
||||||
const BRIDGE_WAIT_TIMEOUT = 2500
|
const BRIDGE_WAIT_TIMEOUT = 2500
|
||||||
const BRIDGE_POLL_INTERVAL = 50
|
const BRIDGE_POLL_INTERVAL = 50
|
||||||
@@ -22,6 +28,7 @@ const GET_ENV_TIMEOUT = 1500
|
|||||||
const NAVIGATION_TIMEOUT = 3000
|
const NAVIGATION_TIMEOUT = 3000
|
||||||
|
|
||||||
let pendingNavigation: Promise<WechatMiniProgramBridgeResult> | null = null
|
let pendingNavigation: Promise<WechatMiniProgramBridgeResult> | null = null
|
||||||
|
let pendingReturn: Promise<WechatMiniProgramReturnResult> | null = null
|
||||||
let sdkLoadPromise: Promise<void> | null = null
|
let sdkLoadPromise: Promise<void> | null = null
|
||||||
|
|
||||||
const getBridge = (): MiniProgramBridge | null => {
|
const getBridge = (): MiniProgramBridge | null => {
|
||||||
@@ -108,6 +115,31 @@ const navigateToHostLocationPage = (bridge: MiniProgramBridge, target: WechatOpe
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const navigateBackToHostPage = (bridge: MiniProgramBridge) => new Promise<WechatMiniProgramReturnResult>((resolve) => {
|
||||||
|
if (!bridge.navigateBack) return resolve({ status: 'failed', reason: 'bridge-unavailable' })
|
||||||
|
let settled = false
|
||||||
|
const finish = (result: WechatMiniProgramReturnResult) => {
|
||||||
|
if (settled) return
|
||||||
|
settled = true
|
||||||
|
clearTimeout(timeout)
|
||||||
|
resolve(result)
|
||||||
|
}
|
||||||
|
const timeout = setTimeout(() => finish({ status: 'failed', reason: 'timeout' }), NAVIGATION_TIMEOUT)
|
||||||
|
try {
|
||||||
|
bridge.navigateBack({
|
||||||
|
delta: 1,
|
||||||
|
success: () => finish({ status: 'returned' }),
|
||||||
|
fail: (error) => {
|
||||||
|
console.error('返回微信小程序失败:', error)
|
||||||
|
finish({ status: 'failed', reason: 'navigation-failed' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error('调用微信小程序返回桥接失败:', error)
|
||||||
|
finish({ status: 'failed', reason: 'navigation-failed' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const openOnce = async (target: WechatOpenLocationTarget): Promise<WechatMiniProgramBridgeResult> => {
|
const openOnce = async (target: WechatOpenLocationTarget): Promise<WechatMiniProgramBridgeResult> => {
|
||||||
const validation = validateWechatOpenLocationTarget(target)
|
const validation = validateWechatOpenLocationTarget(target)
|
||||||
if (!validation.ok) return { status: 'failed', reason: 'invalid-target' }
|
if (!validation.ok) return { status: 'failed', reason: 'invalid-target' }
|
||||||
@@ -118,8 +150,22 @@ const openOnce = async (target: WechatOpenLocationTarget): Promise<WechatMiniPro
|
|||||||
return navigateToHostLocationPage(bridge, validation.value)
|
return navigateToHostLocationPage(bridge, validation.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const returnOnce = async (): Promise<WechatMiniProgramReturnResult> => {
|
||||||
|
if (!isEmbeddedInWechatMiniProgram()) return { status: 'not-embedded' }
|
||||||
|
const bridge = await waitForBridge()
|
||||||
|
if (!bridge) return { status: 'failed', reason: 'bridge-unavailable' }
|
||||||
|
if (!await isMiniProgramWebView(bridge)) return { status: 'failed', reason: 'not-in-mini-program' }
|
||||||
|
return navigateBackToHostPage(bridge)
|
||||||
|
}
|
||||||
|
|
||||||
export const openWechatMiniProgramLocation = (target: WechatOpenLocationTarget) => {
|
export const openWechatMiniProgramLocation = (target: WechatOpenLocationTarget) => {
|
||||||
if (pendingNavigation) return pendingNavigation
|
if (pendingNavigation) return pendingNavigation
|
||||||
pendingNavigation = openOnce(target).finally(() => { pendingNavigation = null })
|
pendingNavigation = openOnce(target).finally(() => { pendingNavigation = null })
|
||||||
return pendingNavigation
|
return pendingNavigation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const returnToWechatMiniProgram = () => {
|
||||||
|
if (pendingReturn) return pendingReturn
|
||||||
|
pendingReturn = returnOnce().finally(() => { pendingReturn = null })
|
||||||
|
return pendingReturn
|
||||||
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ test('hall goes directly to paged guide objects without outline requests', async
|
|||||||
expect(requests.filter((url) => url.includes('/stops/page')).map((url) => new URL(url).searchParams.get('pageNo'))).toEqual(['1', '2'])
|
expect(requests.filter((url) => url.includes('/stops/page')).map((url) => new URL(url).searchParams.get('pageNo'))).toEqual(['1', '2'])
|
||||||
})
|
})
|
||||||
|
|
||||||
test('embedded hall list exposes an H5 return control that keeps host markers', async ({ page }) => {
|
test('embedded hall list leaves title and return navigation to the host mini-program', async ({ page }) => {
|
||||||
await page.route('**/app-api/gis/guide/catalog/**', async (route) => {
|
await page.route('**/app-api/gis/guide/catalog/**', async (route) => {
|
||||||
const url = route.request().url()
|
const url = route.request().url()
|
||||||
if (url.includes('/catalog/halls?')) {
|
if (url.includes('/catalog/halls?')) {
|
||||||
@@ -78,29 +78,24 @@ test('embedded hall list exposes an H5 return control that keeps host markers',
|
|||||||
|
|
||||||
await page.goto('/#/pages/explain/list?embedded=wechat-mini-program&weapp=1')
|
await page.goto('/#/pages/explain/list?embedded=wechat-mini-program&weapp=1')
|
||||||
const back = page.locator('.header-back')
|
const back = page.locator('.header-back')
|
||||||
await expect(back).toHaveCount(1)
|
await expect(back).toHaveCount(0)
|
||||||
await expect(back).toBeVisible()
|
|
||||||
await expect(page.locator('.hall-overview-card')).toHaveCount(1)
|
await expect(page.locator('.hall-overview-card')).toHaveCount(1)
|
||||||
for (const width of [375, 390, 430]) {
|
for (const width of [375, 390, 430]) {
|
||||||
await page.setViewportSize({ width, height: 844 })
|
await page.setViewportSize({ width, height: 844 })
|
||||||
const layout = await page.locator('.explain-hall-select').evaluate((container) => {
|
const layout = await page.locator('.explain-hall-select').evaluate((container) => {
|
||||||
const header = container.querySelector<HTMLElement>('.explain-page-header')
|
|
||||||
const card = container.querySelector<HTMLElement>('.hall-overview-card')
|
const card = container.querySelector<HTMLElement>('.hall-overview-card')
|
||||||
if (!header || !card) throw new Error('missing header or hall card')
|
if (!card) throw new Error('missing hall card')
|
||||||
const headerRect = header.getBoundingClientRect()
|
|
||||||
const cardRect = card.getBoundingClientRect()
|
const cardRect = card.getBoundingClientRect()
|
||||||
return {
|
return {
|
||||||
clientWidth: container.clientWidth,
|
clientWidth: container.clientWidth,
|
||||||
scrollWidth: container.scrollWidth,
|
scrollWidth: container.scrollWidth,
|
||||||
headerBottom: headerRect.bottom,
|
|
||||||
cardTop: cardRect.top
|
cardTop: cardRect.top
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
expect(layout.scrollWidth).toBeLessThanOrEqual(layout.clientWidth)
|
expect(layout.scrollWidth).toBeLessThanOrEqual(layout.clientWidth)
|
||||||
expect(layout.cardTop).toBeGreaterThanOrEqual(layout.headerBottom)
|
expect(layout.cardTop).toBeGreaterThanOrEqual(0)
|
||||||
}
|
}
|
||||||
await back.click()
|
await expect(page.locator('.explain-page-header')).toHaveCount(0)
|
||||||
await expect(page).toHaveURL(/#\/\?tab=guide&embedded=wechat-mini-program&weapp=1$/)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('ordinary H5 hall list return reaches the guide home', async ({ page }) => {
|
test('ordinary H5 hall list return reaches the guide home', async ({ page }) => {
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ const hostEnvironmentMocks = vi.hoisted(() => ({
|
|||||||
embeddedInWechatMiniProgram: false
|
embeddedInWechatMiniProgram: false
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
const miniProgramBridgeMocks = vi.hoisted(() => ({
|
||||||
|
returnToWechatMiniProgram: vi.fn()
|
||||||
|
}))
|
||||||
|
|
||||||
const testState = vi.hoisted(() => ({
|
const testState = vi.hoisted(() => ({
|
||||||
onLoadHandler: null as null | (() => void),
|
onLoadHandler: null as null | (() => void),
|
||||||
onBackPressHandler: null as null | (() => boolean)
|
onBackPressHandler: null as null | (() => boolean)
|
||||||
@@ -27,6 +31,10 @@ vi.mock('@/utils/hostEnvironment', () => ({
|
|||||||
isEmbeddedInWechatMiniProgram: () => hostEnvironmentMocks.embeddedInWechatMiniProgram
|
isEmbeddedInWechatMiniProgram: () => hostEnvironmentMocks.embeddedInWechatMiniProgram
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
vi.mock('@/services/WechatMiniProgramBridgeService', () => ({
|
||||||
|
returnToWechatMiniProgram: miniProgramBridgeMocks.returnToWechatMiniProgram
|
||||||
|
}))
|
||||||
|
|
||||||
vi.mock('@/usecases/explainUseCase', () => ({
|
vi.mock('@/usecases/explainUseCase', () => ({
|
||||||
explainUseCase: {
|
explainUseCase: {
|
||||||
loadExplainHalls: async () => [],
|
loadExplainHalls: async () => [],
|
||||||
@@ -60,6 +68,7 @@ const mountExplainList = () => mount(ExplainListPage, {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
hostEnvironmentMocks.embeddedInWechatMiniProgram = false
|
hostEnvironmentMocks.embeddedInWechatMiniProgram = false
|
||||||
|
miniProgramBridgeMocks.returnToWechatMiniProgram.mockResolvedValue({ status: 'not-embedded' })
|
||||||
testState.onLoadHandler = null
|
testState.onLoadHandler = null
|
||||||
testState.onBackPressHandler = null
|
testState.onBackPressHandler = null
|
||||||
window.location.hash = '#/pages/explain/list'
|
window.location.hash = '#/pages/explain/list'
|
||||||
@@ -78,9 +87,9 @@ afterEach(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('讲解展厅列表返回', () => {
|
describe('讲解展厅列表返回', () => {
|
||||||
it('首页通过内部页面栈进入时,顶部返回使用 navigateBack 回到导览首页', async () => {
|
it('首页讲解 Tab 进入时,顶部返回使用 navigateBack 保留讲解 Tab', async () => {
|
||||||
vi.stubGlobal('getCurrentPages', vi.fn(() => [
|
vi.stubGlobal('getCurrentPages', vi.fn(() => [
|
||||||
{ route: 'pages/index/index', options: { tab: 'guide' } },
|
{ route: 'pages/index/index', options: { tab: 'explain' } },
|
||||||
{ route: 'pages/explain/list', options: {} }
|
{ route: 'pages/explain/list', options: {} }
|
||||||
]))
|
]))
|
||||||
const wrapper = mountExplainList()
|
const wrapper = mountExplainList()
|
||||||
@@ -91,6 +100,7 @@ describe('讲解展厅列表返回', () => {
|
|||||||
|
|
||||||
expect(uni.navigateBack).toHaveBeenCalledWith(expect.objectContaining({ delta: 1 }))
|
expect(uni.navigateBack).toHaveBeenCalledWith(expect.objectContaining({ delta: 1 }))
|
||||||
expect(uni.reLaunch).not.toHaveBeenCalled()
|
expect(uni.reLaunch).not.toHaveBeenCalled()
|
||||||
|
expect(miniProgramBridgeMocks.returnToWechatMiniProgram).not.toHaveBeenCalled()
|
||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -106,38 +116,38 @@ describe('讲解展厅列表返回', () => {
|
|||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('微信嵌入态由宿主导航提供标题与返回,不渲染重复的 H5 页头', async () => {
|
it('微信嵌入态直达页面由宿主提供标题与返回,并返回小程序', async () => {
|
||||||
hostEnvironmentMocks.embeddedInWechatMiniProgram = true
|
hostEnvironmentMocks.embeddedInWechatMiniProgram = true
|
||||||
|
miniProgramBridgeMocks.returnToWechatMiniProgram.mockResolvedValue({ status: 'returned' })
|
||||||
window.location.hash = '#/pages/explain/list?embedded=wechat-mini-program&weapp=1'
|
window.location.hash = '#/pages/explain/list?embedded=wechat-mini-program&weapp=1'
|
||||||
window.history.replaceState({}, '', window.location.href)
|
window.history.replaceState({}, '', window.location.href)
|
||||||
const wrapper = mountExplainList()
|
const wrapper = mountExplainList()
|
||||||
|
|
||||||
expect(wrapper.getComponent(ExplainHallSelectStub).props('forceInternalHeader')).toBe(false)
|
expect(wrapper.getComponent(ExplainHallSelectStub).props('forceInternalHeader')).toBe(false)
|
||||||
await wrapper.get('[data-testid="explain-list-back"]').trigger('click')
|
await wrapper.get('[data-testid="explain-list-back"]').trigger('click')
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
expect(uni.navigateBack).not.toHaveBeenCalled()
|
expect(uni.navigateBack).not.toHaveBeenCalled()
|
||||||
expect(uni.reLaunch).toHaveBeenCalledWith(expect.objectContaining({
|
expect(uni.reLaunch).not.toHaveBeenCalled()
|
||||||
url: '/pages/index/index?tab=guide&embedded=wechat-mini-program&weapp=1'
|
expect(miniProgramBridgeMocks.returnToWechatMiniProgram).toHaveBeenCalledTimes(1)
|
||||||
}))
|
|
||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('微信嵌入态即使前置页是导览首页也不调用宿主返回', async () => {
|
it('微信嵌入态从本项目首页进入时仍返回本项目首页', async () => {
|
||||||
hostEnvironmentMocks.embeddedInWechatMiniProgram = true
|
hostEnvironmentMocks.embeddedInWechatMiniProgram = true
|
||||||
window.location.hash = '#/pages/explain/list?embedded=wechat-mini-program'
|
window.location.hash = '#/pages/explain/list?embedded=wechat-mini-program'
|
||||||
window.history.replaceState({}, '', window.location.href)
|
window.history.replaceState({}, '', window.location.href)
|
||||||
vi.stubGlobal('getCurrentPages', vi.fn(() => [
|
vi.stubGlobal('getCurrentPages', vi.fn(() => [
|
||||||
{ route: 'pages/index/index', options: { tab: 'guide' } },
|
{ route: 'pages/index/index', options: { tab: 'explain' } },
|
||||||
{ route: 'pages/explain/list', options: {} }
|
{ route: 'pages/explain/list', options: {} }
|
||||||
]))
|
]))
|
||||||
const wrapper = mountExplainList()
|
const wrapper = mountExplainList()
|
||||||
|
|
||||||
await wrapper.get('[data-testid="explain-list-back"]').trigger('click')
|
await wrapper.get('[data-testid="explain-list-back"]').trigger('click')
|
||||||
|
|
||||||
expect(uni.navigateBack).not.toHaveBeenCalled()
|
expect(uni.navigateBack).toHaveBeenCalledWith(expect.objectContaining({ delta: 1 }))
|
||||||
expect(uni.reLaunch).toHaveBeenCalledWith(expect.objectContaining({
|
expect(uni.reLaunch).not.toHaveBeenCalled()
|
||||||
url: '/pages/index/index?tab=guide&embedded=wechat-mini-program'
|
expect(miniProgramBridgeMocks.returnToWechatMiniProgram).not.toHaveBeenCalled()
|
||||||
}))
|
|
||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -157,23 +167,27 @@ describe('讲解展厅列表返回', () => {
|
|||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('上一页是首页但不是导览 Tab 时重启到导览首页', async () => {
|
it('首页返回失败时重启到原讲解 Tab', async () => {
|
||||||
vi.stubGlobal('getCurrentPages', vi.fn(() => [
|
vi.stubGlobal('getCurrentPages', vi.fn(() => [
|
||||||
{ route: 'pages/index/index', options: { tab: 'explain' } },
|
{ route: 'pages/index/index', options: { tab: 'explain' } },
|
||||||
{ route: 'pages/explain/list', options: {} }
|
{ route: 'pages/explain/list', options: {} }
|
||||||
]))
|
]))
|
||||||
|
vi.stubGlobal('uni', {
|
||||||
|
navigateBack: vi.fn((options: { fail?: () => void }) => options.fail?.()),
|
||||||
|
reLaunch: vi.fn(),
|
||||||
|
showToast: vi.fn()
|
||||||
|
})
|
||||||
const wrapper = mountExplainList()
|
const wrapper = mountExplainList()
|
||||||
|
|
||||||
await wrapper.get('[data-testid="explain-list-back"]').trigger('click')
|
await wrapper.get('[data-testid="explain-list-back"]').trigger('click')
|
||||||
|
|
||||||
expect(uni.navigateBack).not.toHaveBeenCalled()
|
|
||||||
expect(uni.reLaunch).toHaveBeenCalledWith(expect.objectContaining({
|
expect(uni.reLaunch).toHaveBeenCalledWith(expect.objectContaining({
|
||||||
url: '/pages/index/index?tab=guide'
|
url: '/pages/index/index?tab=explain'
|
||||||
}))
|
}))
|
||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('navigateBack 失败后重启到导览首页', async () => {
|
it('导览首页返回失败后重启到原导览 Tab', async () => {
|
||||||
vi.stubGlobal('getCurrentPages', vi.fn(() => [
|
vi.stubGlobal('getCurrentPages', vi.fn(() => [
|
||||||
{ route: 'pages/index/index', options: { tab: 'guide' } },
|
{ route: 'pages/index/index', options: { tab: 'guide' } },
|
||||||
{ route: 'pages/explain/list', options: {} }
|
{ route: 'pages/explain/list', options: {} }
|
||||||
@@ -210,8 +224,9 @@ describe('讲解展厅列表返回', () => {
|
|||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('根栈只创建一条历史标记,浏览器返回会回到导览首页', async () => {
|
it('微信嵌入态根栈不创建 H5 history 标记,平台返回交给宿主', async () => {
|
||||||
hostEnvironmentMocks.embeddedInWechatMiniProgram = true
|
hostEnvironmentMocks.embeddedInWechatMiniProgram = true
|
||||||
|
miniProgramBridgeMocks.returnToWechatMiniProgram.mockResolvedValue({ status: 'returned' })
|
||||||
window.location.hash = '#/pages/explain/list?embedded=wechat-mini-program&weapp=1'
|
window.location.hash = '#/pages/explain/list?embedded=wechat-mini-program&weapp=1'
|
||||||
window.history.replaceState({}, '', window.location.href)
|
window.history.replaceState({}, '', window.location.href)
|
||||||
const wrapper = mountExplainList()
|
const wrapper = mountExplainList()
|
||||||
@@ -220,17 +235,13 @@ describe('讲解展厅列表返回', () => {
|
|||||||
testState.onLoadHandler?.()
|
testState.onLoadHandler?.()
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
window.dispatchEvent(new PopStateEvent('popstate', { state: {} }))
|
expect(pushState).not.toHaveBeenCalled()
|
||||||
await flushPromises()
|
|
||||||
|
|
||||||
expect(uni.navigateBack).not.toHaveBeenCalled()
|
expect(uni.navigateBack).not.toHaveBeenCalled()
|
||||||
expect(pushState).toHaveBeenCalledTimes(1)
|
expect(uni.reLaunch).not.toHaveBeenCalled()
|
||||||
const url = vi.mocked(uni.reLaunch).mock.calls[0]?.[0]?.url || ''
|
expect(testState.onBackPressHandler?.()).toBe(true)
|
||||||
const query = new URLSearchParams(url.split('?')[1])
|
await flushPromises()
|
||||||
expect(url.split('?')[0]).toBe('/pages/index/index')
|
expect(miniProgramBridgeMocks.returnToWechatMiniProgram).toHaveBeenCalledTimes(1)
|
||||||
expect(query.get('tab')).toBe('guide')
|
|
||||||
expect(query.get('embedded')).toBe('wechat-mini-program')
|
|
||||||
expect(query.get('weapp')).toBe('1')
|
|
||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,27 @@ describe('微信小程序 web-view 桥接', () => {
|
|||||||
expect(document.querySelector('[data-wechat-js-sdk="true"]')).toBeNull()
|
expect(document.querySelector('[data-wechat-js-sdk="true"]')).toBeNull()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('嵌入小程序时通过 navigateBack 返回宿主页', async () => {
|
||||||
|
setEmbeddedRuntime()
|
||||||
|
const { returnToWechatMiniProgram } = await loadService()
|
||||||
|
const navigateBack = vi.fn(({ success }) => success())
|
||||||
|
Object.assign(window, {
|
||||||
|
wx: {
|
||||||
|
miniProgram: {
|
||||||
|
getEnv: (done: (value: { miniprogram: boolean }) => void) => done({ miniprogram: true }),
|
||||||
|
navigateBack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await expect(returnToWechatMiniProgram()).resolves.toEqual({ status: 'returned' })
|
||||||
|
expect(navigateBack).toHaveBeenCalledWith({
|
||||||
|
delta: 1,
|
||||||
|
success: expect.any(Function),
|
||||||
|
fail: expect.any(Function)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it('等待延迟注入的 bridge 后导航到编码后的宿主页', async () => {
|
it('等待延迟注入的 bridge 后导航到编码后的宿主页', async () => {
|
||||||
setEmbeddedRuntime()
|
setEmbeddedRuntime()
|
||||||
const { openWechatMiniProgramLocation } = await loadService()
|
const { openWechatMiniProgramLocation } = await loadService()
|
||||||
|
|||||||
Reference in New Issue
Block a user