补齐移动壳网络单测
移动壳 network.status helper 增加独立单测覆盖 原生壳结构门禁登记移动网络测试 宿主壳文档和共享决策同步网络测试边界
This commit is contained in:
@@ -49,6 +49,14 @@ const hostBridgeNetworkSource = fs.readFileSync(
|
||||
hostBridgeNetworkPath,
|
||||
'utf8',
|
||||
);
|
||||
const hostBridgeNetworkTestPath = new URL(
|
||||
'../src/host-bridge/network.test.ts',
|
||||
import.meta.url,
|
||||
);
|
||||
const hostBridgeNetworkTestSource = fs.readFileSync(
|
||||
hostBridgeNetworkTestPath,
|
||||
'utf8',
|
||||
);
|
||||
const notificationsPath = new URL('../src/host-bridge/notifications.ts', import.meta.url);
|
||||
const notificationsSource = fs.readFileSync(notificationsPath, 'utf8');
|
||||
const protocolPath = new URL('../src/host-bridge/protocol.ts', import.meta.url);
|
||||
@@ -2294,6 +2302,18 @@ for (const snippet of [
|
||||
throw new Error(`mobile shell network module is missing ${snippet}`);
|
||||
}
|
||||
}
|
||||
for (const snippet of [
|
||||
'wraps Expo Network status in the HostBridge response shape',
|
||||
'normalizes disconnected network state before wrapping response',
|
||||
'lets protocol layer convert native network failures to host errors',
|
||||
'connectionType: \'cellular\'',
|
||||
'connectionType: \'none\'',
|
||||
'network query failed',
|
||||
]) {
|
||||
if (!hostBridgeNetworkTestSource.includes(snippet)) {
|
||||
throw new Error(`mobile shell network tests missing ${snippet}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (!shellAppSource.includes('openMobileShellExternalNavigation(Linking, request.url)')) {
|
||||
throw new Error(
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
import * as Network from 'expo-network';
|
||||
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
||||
|
||||
import {
|
||||
HOST_BRIDGE_PROTOCOL,
|
||||
HOST_BRIDGE_VERSION,
|
||||
type HostBridgeRequest,
|
||||
} from '../../../../packages/shared/src/contracts/hostBridge';
|
||||
import { getMobileHostBridgeNetworkStatus } from './network';
|
||||
|
||||
vi.mock('expo-network', () => ({
|
||||
getNetworkStateAsync: vi.fn(),
|
||||
NetworkStateType: {
|
||||
CELLULAR: 'CELLULAR',
|
||||
NONE: 'NONE',
|
||||
WIFI: 'WIFI',
|
||||
},
|
||||
}));
|
||||
|
||||
function request(): HostBridgeRequest {
|
||||
return {
|
||||
bridge: HOST_BRIDGE_PROTOCOL,
|
||||
version: HOST_BRIDGE_VERSION,
|
||||
id: 'network-request',
|
||||
method: 'network.status',
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.mocked(Network.getNetworkStateAsync).mockReset();
|
||||
});
|
||||
|
||||
describe('mobile HostBridge network helper', () => {
|
||||
test('wraps Expo Network status in the HostBridge response shape', async () => {
|
||||
vi.mocked(Network.getNetworkStateAsync).mockResolvedValue({
|
||||
type: Network.NetworkStateType.CELLULAR,
|
||||
isConnected: true,
|
||||
isInternetReachable: false,
|
||||
});
|
||||
|
||||
await expect(getMobileHostBridgeNetworkStatus(request())).resolves.toEqual({
|
||||
bridge: HOST_BRIDGE_PROTOCOL,
|
||||
version: HOST_BRIDGE_VERSION,
|
||||
id: 'network-request',
|
||||
ok: true,
|
||||
result: {
|
||||
isConnected: true,
|
||||
isInternetReachable: false,
|
||||
connectionType: 'cellular',
|
||||
nativeType: 'CELLULAR',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('normalizes disconnected network state before wrapping response', async () => {
|
||||
vi.mocked(Network.getNetworkStateAsync).mockResolvedValue({
|
||||
type: Network.NetworkStateType.NONE,
|
||||
});
|
||||
|
||||
await expect(getMobileHostBridgeNetworkStatus(request())).resolves.toEqual({
|
||||
bridge: HOST_BRIDGE_PROTOCOL,
|
||||
version: HOST_BRIDGE_VERSION,
|
||||
id: 'network-request',
|
||||
ok: true,
|
||||
result: {
|
||||
isConnected: false,
|
||||
isInternetReachable: null,
|
||||
connectionType: 'none',
|
||||
nativeType: 'NONE',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('lets protocol layer convert native network failures to host errors', async () => {
|
||||
vi.mocked(Network.getNetworkStateAsync).mockRejectedValue(
|
||||
new Error('network query failed'),
|
||||
);
|
||||
|
||||
await expect(getMobileHostBridgeNetworkStatus(request())).rejects.toThrow(
|
||||
'network query failed',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -2927,3 +2927,10 @@
|
||||
- 决策:新增 `apps/mobile-shell/src/host-bridge/share.test.ts`,直接覆盖显式分享 payload、缓存作品目标、同源路径归一、非法 URL / 协议相对 URL 拒绝、非法显式 payload 不回退缓存、空分享拒绝和无效 `share.setTarget` 不清空已有目标;移动壳单端配置检查和根级原生壳门禁登记该测试文件并反查关键断言片段。
|
||||
- 影响范围:`apps/mobile-shell/src/host-bridge/share.test.ts`、`apps/mobile-shell/scripts/check-config.mjs`、`scripts/check-native-shells.mjs`、宿主壳方案文档、宿主壳能力统一协议文档。
|
||||
- 验证方式:`npm run mobile-shell:test -- src/host-bridge/share.test.ts`、`npm run mobile-shell:typecheck`、`npm run check:native-shells`、`npm run check:encoding`、`git diff --check`。
|
||||
|
||||
## 2026-06-20 移动网络 HostBridge 单测边界
|
||||
|
||||
- 背景:Expo 移动壳 `network.status` 已经由 `src/host-bridge/network.ts` 包装真实 Expo Network 查询,但可执行测试主要在 shell network 归一化和巨型 bridge 测试中,缺少对 HostBridge response 形状、离线状态和底层网络失败传播的直接 helper 覆盖。
|
||||
- 决策:新增 `apps/mobile-shell/src/host-bridge/network.test.ts`,直接覆盖 `network.status` 成功响应、断网响应和原生查询失败传播;移动壳单端配置检查和根级原生壳门禁登记该测试文件并反查关键断言片段。该变更不新增 capability,不改变 shell network 归一化逻辑,也不在分发层包装网络状态。
|
||||
- 影响范围:`apps/mobile-shell/src/host-bridge/network.test.ts`、`apps/mobile-shell/scripts/check-config.mjs`、`scripts/check-native-shells.mjs`、宿主壳方案文档、宿主壳能力统一协议文档。
|
||||
- 验证方式:`npm run mobile-shell:test -- src/host-bridge/network.test.ts`、`npm run mobile-shell:typecheck`、`npm run check:native-shells`、`npm run check:encoding`、`git diff --check`。
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -263,6 +263,7 @@ const expectedMobileHostBridgeFiles = [
|
||||
'haptics.test.ts',
|
||||
'haptics.ts',
|
||||
'navigation.ts',
|
||||
'network.test.ts',
|
||||
'network.ts',
|
||||
'notifications.test.ts',
|
||||
'notifications.ts',
|
||||
|
||||
Reference in New Issue
Block a user