ce0765b298
H5 新增 navigation.canGoBack hook 并在直达二级页时补齐返回锚点 路由导航保留完整原生宿主上下文并标记应用历史状态 补齐 HostBridge 返回栈消费测试、门禁和文档
122 lines
3.4 KiB
TypeScript
122 lines
3.4 KiB
TypeScript
/* @vitest-environment jsdom */
|
|
|
|
import { act, renderHook } from '@testing-library/react';
|
|
import { afterEach, expect, test, vi } from 'vitest';
|
|
|
|
import {
|
|
canUseNativeHostCapability,
|
|
subscribeHostNavigationCanGoBack,
|
|
subscribeHostRuntimeChange,
|
|
} from '../services/host-bridge/hostBridge';
|
|
import { useHostNavigationCanGoBack } from './useHostNavigationCanGoBack';
|
|
|
|
vi.mock('../services/host-bridge/hostBridge', () => ({
|
|
canUseNativeHostCapability: vi.fn(() => false),
|
|
subscribeHostNavigationCanGoBack: vi.fn(() => () => undefined),
|
|
subscribeHostRuntimeChange: vi.fn(() => () => undefined),
|
|
}));
|
|
|
|
const canUseNativeHostCapabilityMock = vi.mocked(canUseNativeHostCapability);
|
|
const subscribeHostNavigationCanGoBackMock = vi.mocked(
|
|
subscribeHostNavigationCanGoBack,
|
|
);
|
|
const subscribeHostRuntimeChangeMock = vi.mocked(subscribeHostRuntimeChange);
|
|
|
|
function setNavigationCapability(enabled: boolean) {
|
|
canUseNativeHostCapabilityMock.mockImplementation((capability) =>
|
|
enabled
|
|
? capability === 'host.events' || capability === 'navigation.canGoBack'
|
|
: false,
|
|
);
|
|
}
|
|
|
|
afterEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
test('host navigation can-go-back stays unsupported without both event capabilities', () => {
|
|
setNavigationCapability(false);
|
|
|
|
const { result } = renderHook(() => useHostNavigationCanGoBack());
|
|
|
|
expect(result.current).toEqual({
|
|
canGoBack: false,
|
|
isSupported: false,
|
|
});
|
|
expect(subscribeHostNavigationCanGoBackMock).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test('host navigation can-go-back follows native app events', () => {
|
|
setNavigationCapability(true);
|
|
const unsubscribe = vi.fn();
|
|
let navigationListener:
|
|
| Parameters<typeof subscribeHostNavigationCanGoBack>[0]
|
|
| null = null;
|
|
subscribeHostNavigationCanGoBackMock.mockImplementation((listener) => {
|
|
navigationListener = listener;
|
|
return unsubscribe;
|
|
});
|
|
|
|
const { result, unmount } = renderHook(() =>
|
|
useHostNavigationCanGoBack(),
|
|
);
|
|
|
|
expect(result.current).toEqual({
|
|
canGoBack: false,
|
|
isSupported: true,
|
|
});
|
|
|
|
act(() => {
|
|
navigationListener?.({ canGoBack: true });
|
|
});
|
|
expect(result.current).toEqual({
|
|
canGoBack: true,
|
|
isSupported: true,
|
|
});
|
|
|
|
act(() => {
|
|
navigationListener?.({ canGoBack: false });
|
|
});
|
|
expect(result.current).toEqual({
|
|
canGoBack: false,
|
|
isSupported: true,
|
|
});
|
|
|
|
unmount();
|
|
expect(unsubscribe).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
test('host navigation can-go-back subscribes after runtime refresh exposes capabilities', () => {
|
|
setNavigationCapability(false);
|
|
let runtimeListener: Parameters<typeof subscribeHostRuntimeChange>[0] | null =
|
|
null;
|
|
let navigationListener:
|
|
| Parameters<typeof subscribeHostNavigationCanGoBack>[0]
|
|
| null = null;
|
|
subscribeHostRuntimeChangeMock.mockImplementation((listener) => {
|
|
runtimeListener = listener;
|
|
return () => undefined;
|
|
});
|
|
subscribeHostNavigationCanGoBackMock.mockImplementation((listener) => {
|
|
navigationListener = listener;
|
|
return () => undefined;
|
|
});
|
|
|
|
const { result } = renderHook(() => useHostNavigationCanGoBack());
|
|
|
|
expect(result.current.isSupported).toBe(false);
|
|
|
|
setNavigationCapability(true);
|
|
act(() => {
|
|
runtimeListener?.();
|
|
});
|
|
|
|
expect(result.current.isSupported).toBe(true);
|
|
expect(subscribeHostNavigationCanGoBackMock).toHaveBeenCalledTimes(1);
|
|
|
|
act(() => {
|
|
navigationListener?.({ canGoBack: true });
|
|
});
|
|
expect(result.current.canGoBack).toBe(true);
|
|
});
|