补齐移动壳深链失败观测
移动壳 Deep Link 解析返回状态并记录拒绝路径 ShellApp 记录初始链接读取失败且保留安全入口 移动壳配置检查和文档同步深链失败边界
This commit is contained in:
@@ -17,6 +17,7 @@ const shellHarness = vi.hoisted(() => {
|
||||
const cameraViewProps = { current: null as Record<string, unknown> | null };
|
||||
const injectJavaScriptError = { current: null as Error | null };
|
||||
const injectedScripts = [] as string[];
|
||||
const linkingUrlListeners = [] as Array<(event: { url: string }) => void>;
|
||||
const networkListeners = [] as Array<(state: Record<string, unknown>) => void>;
|
||||
|
||||
return {
|
||||
@@ -31,8 +32,10 @@ const shellHarness = vi.hoisted(() => {
|
||||
cameraViewProps.current = null;
|
||||
injectJavaScriptError.current = null;
|
||||
injectedScripts.length = 0;
|
||||
linkingUrlListeners.length = 0;
|
||||
networkListeners.length = 0;
|
||||
},
|
||||
linkingUrlListeners,
|
||||
webViewProps,
|
||||
};
|
||||
});
|
||||
@@ -184,7 +187,10 @@ vi.mock('react-native', () => ({
|
||||
addEventListener: vi.fn(() => ({ remove: vi.fn() })),
|
||||
},
|
||||
Linking: {
|
||||
addEventListener: vi.fn(() => ({ remove: vi.fn() })),
|
||||
addEventListener: vi.fn((_event, listener) => {
|
||||
shellHarness.linkingUrlListeners.push(listener);
|
||||
return { remove: vi.fn() };
|
||||
}),
|
||||
canOpenURL: vi.fn(async () => true),
|
||||
getInitialURL: vi.fn(async () => null),
|
||||
openURL: vi.fn(async () => undefined),
|
||||
@@ -613,4 +619,58 @@ describe('ShellApp HostBridge event injection', () => {
|
||||
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
|
||||
test('initial deep link read failures are logged without replacing the current WebView URL', async () => {
|
||||
const { Linking } = await import('react-native');
|
||||
const initialUrlError = new Error('initial URL unavailable');
|
||||
vi.mocked(Linking.getInitialURL).mockRejectedValueOnce(initialUrlError);
|
||||
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
|
||||
const ShellApp = await importShellApp();
|
||||
|
||||
render(<ShellApp />);
|
||||
|
||||
const webViewProps = shellHarness.webViewProps.current as {
|
||||
source?: { uri?: string };
|
||||
};
|
||||
const initialWebUrl = webViewProps.source?.uri;
|
||||
|
||||
await waitFor(() => {
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
'mobile shell deep link failed for initial_url.read',
|
||||
initialUrlError,
|
||||
);
|
||||
});
|
||||
expect(shellHarness.webViewProps.current?.source).toEqual({
|
||||
uri: initialWebUrl,
|
||||
});
|
||||
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
|
||||
test('runtime deep link rejections are logged and fall back to a safe WebView URL', async () => {
|
||||
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
|
||||
const ShellApp = await importShellApp();
|
||||
|
||||
render(<ShellApp />);
|
||||
const webViewProps = shellHarness.webViewProps.current as {
|
||||
source?: { uri?: string };
|
||||
};
|
||||
const initialWebUrl = webViewProps.source?.uri;
|
||||
|
||||
shellHarness.linkingUrlListeners[0]?.({
|
||||
url: 'https://outside.example/works/detail?work=PZ-1',
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
'mobile shell deep link failed for runtime_url.rejected',
|
||||
'https://outside.example/works/detail?work=PZ-1',
|
||||
);
|
||||
});
|
||||
expect(shellHarness.webViewProps.current?.source).toEqual({
|
||||
uri: initialWebUrl,
|
||||
});
|
||||
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user