071faa482c
纳入 AGC Cargo workspace 的统一 rustfmt 检查与格式化入口 完成项目 TypeScript/Prettier 与 Rust 全量格式化 修复 Pingora expected executable 门禁的空白敏感误报 同步开发运维文档与 AGC skill pack 格式化忽略规则
120 lines
3.4 KiB
TypeScript
120 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);
|
|
});
|