补齐移动壳剪贴板单测
移动壳剪贴板 helper 增加独立单测覆盖 原生壳结构门禁登记移动剪贴板测试 宿主壳文档和共享决策同步剪贴板测试边界
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
import * as Clipboard from 'expo-clipboard';
|
||||
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
||||
|
||||
import {
|
||||
HOST_BRIDGE_PROTOCOL,
|
||||
HOST_BRIDGE_VERSION,
|
||||
type HostBridgeRequest,
|
||||
} from '../../../../packages/shared/src/contracts/hostBridge';
|
||||
import {
|
||||
readMobileClipboardText,
|
||||
readMobileHostBridgeClipboardText,
|
||||
writeMobileClipboardText,
|
||||
writeMobileHostBridgeClipboardText,
|
||||
} from './clipboard';
|
||||
|
||||
vi.mock('expo-clipboard', () => ({
|
||||
getStringAsync: vi.fn(),
|
||||
setStringAsync: vi.fn(),
|
||||
}));
|
||||
|
||||
function request(
|
||||
method: 'clipboard.writeText' | 'clipboard.readText',
|
||||
payload?: unknown,
|
||||
): HostBridgeRequest {
|
||||
return {
|
||||
bridge: HOST_BRIDGE_PROTOCOL,
|
||||
version: HOST_BRIDGE_VERSION,
|
||||
id: `${method}-request`,
|
||||
method,
|
||||
payload,
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.mocked(Clipboard.getStringAsync).mockReset();
|
||||
vi.mocked(Clipboard.setStringAsync).mockReset();
|
||||
});
|
||||
|
||||
describe('mobile clipboard helpers', () => {
|
||||
test('writes normalized text to the Expo clipboard', async () => {
|
||||
await expect(writeMobileClipboardText('作品号 PZ-1')).resolves.toBe(true);
|
||||
|
||||
expect(Clipboard.setStringAsync).toHaveBeenCalledWith('作品号 PZ-1');
|
||||
});
|
||||
|
||||
test('truncates long text before writing to the Expo clipboard', async () => {
|
||||
await expect(writeMobileClipboardText('猫'.repeat(100010))).resolves.toBe(
|
||||
true,
|
||||
);
|
||||
|
||||
expect(Clipboard.setStringAsync).toHaveBeenCalledWith('猫'.repeat(100000));
|
||||
});
|
||||
|
||||
test('writes empty text as a valid pure-text clipboard payload', async () => {
|
||||
await expect(writeMobileClipboardText('')).resolves.toBe(true);
|
||||
|
||||
expect(Clipboard.setStringAsync).toHaveBeenCalledWith('');
|
||||
});
|
||||
|
||||
test('rejects non-string write text without touching the Expo clipboard', async () => {
|
||||
await expect(writeMobileClipboardText(undefined)).resolves.toBe(false);
|
||||
|
||||
expect(Clipboard.setStringAsync).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('wraps HostBridge clipboard write responses', async () => {
|
||||
const response = await writeMobileHostBridgeClipboardText(
|
||||
request('clipboard.writeText', {
|
||||
text: '作品号 PZ-1',
|
||||
}),
|
||||
);
|
||||
|
||||
expect(response).toEqual({
|
||||
bridge: HOST_BRIDGE_PROTOCOL,
|
||||
version: HOST_BRIDGE_VERSION,
|
||||
id: 'clipboard.writeText-request',
|
||||
ok: true,
|
||||
result: true,
|
||||
});
|
||||
expect(Clipboard.setStringAsync).toHaveBeenCalledWith('作品号 PZ-1');
|
||||
});
|
||||
|
||||
test('wraps invalid HostBridge clipboard write payloads', async () => {
|
||||
await expect(
|
||||
writeMobileHostBridgeClipboardText(
|
||||
request('clipboard.writeText', {
|
||||
text: undefined,
|
||||
}),
|
||||
),
|
||||
).rejects.toMatchObject({
|
||||
code: 'invalid_request',
|
||||
message: 'text is required',
|
||||
});
|
||||
|
||||
expect(Clipboard.setStringAsync).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('reads and normalizes pure text from the Expo clipboard', async () => {
|
||||
vi.mocked(Clipboard.getStringAsync).mockResolvedValue('作品号 PZ-1');
|
||||
|
||||
await expect(readMobileClipboardText()).resolves.toEqual({
|
||||
text: '作品号 PZ-1',
|
||||
});
|
||||
});
|
||||
|
||||
test('truncates long clipboard reads at the shared text boundary', async () => {
|
||||
vi.mocked(Clipboard.getStringAsync).mockResolvedValue('猫'.repeat(100010));
|
||||
|
||||
await expect(readMobileClipboardText()).resolves.toEqual({
|
||||
text: '猫'.repeat(100000),
|
||||
});
|
||||
});
|
||||
|
||||
test('reads empty clipboard text as valid pure text', async () => {
|
||||
vi.mocked(Clipboard.getStringAsync).mockResolvedValue('');
|
||||
|
||||
await expect(readMobileClipboardText()).resolves.toEqual({
|
||||
text: '',
|
||||
});
|
||||
});
|
||||
|
||||
test('wraps HostBridge clipboard read responses', async () => {
|
||||
vi.mocked(Clipboard.getStringAsync).mockResolvedValue('作品号 PZ-1');
|
||||
|
||||
const response = await readMobileHostBridgeClipboardText(
|
||||
request('clipboard.readText'),
|
||||
);
|
||||
|
||||
expect(response).toEqual({
|
||||
bridge: HOST_BRIDGE_PROTOCOL,
|
||||
version: HOST_BRIDGE_VERSION,
|
||||
id: 'clipboard.readText-request',
|
||||
ok: true,
|
||||
result: {
|
||||
text: '作品号 PZ-1',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user