// @vitest-environment happy-dom import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' const target = { latitude: 22.604321, longitude: 114.058765, name: '停车场 A&B', address: '龙华区 #1' } const setEmbeddedRuntime = () => Object.assign(window, { __wxjs_environment: 'miniprogram' }) const loadService = async () => { vi.resetModules() return import('@/services/WechatMiniProgramBridgeService') } beforeEach(() => { vi.useFakeTimers() vi.stubGlobal('uni', { showToast: vi.fn() }) delete (window as Window & { wx?: unknown }).wx delete (window as Window & { __wxjs_environment?: string }).__wxjs_environment window.history.replaceState({}, '', '/') }) afterEach(() => { vi.useRealTimers() vi.unstubAllGlobals() document.querySelectorAll('script[data-wechat-js-sdk="true"]').forEach((node) => node.remove()) }) describe('微信小程序 web-view 桥接', () => { it('普通浏览器立即返回 not-embedded,不加载 SDK', async () => { const { openWechatMiniProgramLocation } = await loadService() await expect(openWechatMiniProgramLocation(target)).resolves.toEqual({ status: 'not-embedded' }) expect(document.querySelector('[data-wechat-js-sdk="true"]')).toBeNull() }) it('等待延迟注入的 bridge 后导航到编码后的宿主页', async () => { setEmbeddedRuntime() const { openWechatMiniProgramLocation } = await loadService() const result = openWechatMiniProgramLocation(target) await vi.advanceTimersByTimeAsync(100) const navigateTo = vi.fn(({ success }) => success()) Object.assign(window, { wx: { miniProgram: { getEnv: (done: (value: { miniprogram: boolean }) => void) => done({ miniprogram: true }), navigateTo } } }) await vi.advanceTimersByTimeAsync(100) await expect(result).resolves.toEqual({ status: 'opened' }) expect(navigateTo).toHaveBeenCalledWith(expect.objectContaining({ url: expect.stringContaining('/pages/open-location/index?latitude=22.604321&longitude=114.058765&name=%E5%81%9C%E8%BD%A6%E5%9C%BA%20A%26B') })) }) it('handles getEnv false, navigate fail, page not found, and callback timeout', async () => { setEmbeddedRuntime() const { openWechatMiniProgramLocation } = await loadService() Object.assign(window, { wx: { miniProgram: { getEnv: (done: (value: { miniprogram: boolean }) => void) => done({ miniprogram: false }), navigateTo: vi.fn() } } }) await expect(openWechatMiniProgramLocation(target)).resolves.toEqual({ status: 'failed', reason: 'not-in-mini-program' }) Object.assign(window, { wx: { miniProgram: { getEnv: (done: (value: { miniprogram: boolean }) => void) => done({ miniprogram: true }) } } }) await expect(openWechatMiniProgramLocation(target)).resolves.toEqual({ status: 'failed', reason: 'bridge-unavailable' }) Object.assign(window, { wx: { miniProgram: { getEnv: (done: (value: { miniprogram: boolean }) => void) => done({ miniprogram: true }), navigateTo: vi.fn(({ fail }) => fail({ errMsg: 'navigateTo:fail permission denied' })) } } }) await expect(openWechatMiniProgramLocation(target)).resolves.toEqual({ status: 'failed', reason: 'navigation-failed' }) const navigateTo = vi.fn(({ fail }) => fail({ errMsg: 'navigateTo:fail page not found' })) Object.assign(window, { wx: { miniProgram: { getEnv: (done: (value: { miniprogram: boolean }) => void) => done({ miniprogram: true }), navigateTo } } }) await expect(openWechatMiniProgramLocation(target)).resolves.toEqual({ status: 'failed', reason: 'page-not-found' }) Object.assign(window, { wx: { miniProgram: { getEnv: (done: (value: { miniprogram: boolean }) => void) => done({ miniprogram: true }), navigateTo: vi.fn() } } }) const timeoutResult = openWechatMiniProgramLocation(target) await vi.advanceTimersByTimeAsync(3001) await expect(timeoutResult).resolves.toEqual({ status: 'failed', reason: 'timeout' }) }) it('deduplicates rapid calls while navigation is in flight', async () => { setEmbeddedRuntime() const { openWechatMiniProgramLocation } = await loadService() let succeed: (() => void) | undefined const navigateTo = vi.fn(({ success }) => { succeed = success }) Object.assign(window, { wx: { miniProgram: { getEnv: (done: (value: { miniprogram: boolean }) => void) => done({ miniprogram: true }), navigateTo } } }) const first = openWechatMiniProgramLocation(target) expect(openWechatMiniProgramLocation(target)).toBe(first) await Promise.resolve() await Promise.resolve() await Promise.resolve() expect(navigateTo).toHaveBeenCalledTimes(1) succeed?.() await expect(first).resolves.toEqual({ status: 'opened' }) expect(navigateTo).toHaveBeenCalledTimes(1) }) })