锁定移动壳剪贴板失败响应
移动壳剪贴板写入失败返回稳定错误 移动壳剪贴板读取失败返回稳定错误 移动壳协议兜底测试改用外链原生异常触发 移动壳配置检查补充剪贴板失败边界反查
This commit is contained in:
@@ -2207,7 +2207,7 @@ if (
|
||||
'const clipboardText = normalizeHostBridgeClipboardText(',
|
||||
) ||
|
||||
!clipboardSource.includes('Clipboard.setStringAsync(clipboardText.text)') ||
|
||||
!clipboardSource.includes('await Clipboard.getStringAsync()')
|
||||
!clipboardSource.includes('rawText = await Clipboard.getStringAsync()')
|
||||
) {
|
||||
throw new Error(
|
||||
'mobile shell clipboard bridge must normalize text with the shared HostBridge clipboard boundary',
|
||||
@@ -2236,6 +2236,8 @@ for (const snippet of [
|
||||
'writeMobileClipboardText(text)',
|
||||
'readMobileHostBridgeClipboardText',
|
||||
'ok(request, await readMobileClipboardText())',
|
||||
"message: 'clipboard write unavailable'",
|
||||
"message: 'clipboard read unavailable'",
|
||||
]) {
|
||||
if (!clipboardSource.includes(snippet)) {
|
||||
throw new Error(`mobile shell clipboard module is missing ${snippet}`);
|
||||
@@ -2245,6 +2247,10 @@ if (!clipboardTestSource.includes("'猫'.repeat(100000)")) {
|
||||
throw new Error('mobile shell clipboard tests must cover Unicode truncation');
|
||||
}
|
||||
for (const snippet of [
|
||||
'maps native clipboard write failures to stable host errors',
|
||||
"message: 'clipboard write unavailable'",
|
||||
'maps native clipboard read failures to stable host errors',
|
||||
"message: 'clipboard read unavailable'",
|
||||
'rejects unavailable clipboard text without reporting a successful empty value',
|
||||
'Clipboard.getStringAsync).mockResolvedValue(undefined as never)',
|
||||
"code: 'host_error'",
|
||||
|
||||
@@ -587,13 +587,17 @@ describe('handleMobileHostBridgeMessage', () => {
|
||||
});
|
||||
|
||||
test('原生异常对象不会透传非协议错误码', async () => {
|
||||
vi.mocked(Clipboard.getStringAsync).mockRejectedValue({
|
||||
code: 'native_clipboard_failure',
|
||||
message: 'native clipboard failed',
|
||||
vi.mocked(Linking.canOpenURL).mockRejectedValue({
|
||||
code: 'native_linking_failure',
|
||||
message: 'native linking failed',
|
||||
nativeStackIOS: ['private native frame'],
|
||||
});
|
||||
|
||||
const response = await send(request('clipboard.readText'));
|
||||
const response = await send(
|
||||
request('app.openExternalUrl', {
|
||||
url: 'https://example.com/path',
|
||||
}),
|
||||
);
|
||||
|
||||
const failedResponse = expectFailed(response);
|
||||
|
||||
|
||||
@@ -63,6 +63,17 @@ describe('mobile clipboard helpers', () => {
|
||||
expect(Clipboard.setStringAsync).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('maps native clipboard write failures to stable host errors', async () => {
|
||||
vi.mocked(Clipboard.setStringAsync).mockRejectedValueOnce(
|
||||
new Error('native clipboard write failed'),
|
||||
);
|
||||
|
||||
await expect(writeMobileClipboardText('作品号 PZ-1')).rejects.toMatchObject({
|
||||
code: 'host_error',
|
||||
message: 'clipboard write unavailable',
|
||||
});
|
||||
});
|
||||
|
||||
test('wraps HostBridge clipboard write responses', async () => {
|
||||
const response = await writeMobileHostBridgeClipboardText(
|
||||
request('clipboard.writeText', {
|
||||
@@ -128,6 +139,17 @@ describe('mobile clipboard helpers', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('maps native clipboard read failures to stable host errors', async () => {
|
||||
vi.mocked(Clipboard.getStringAsync).mockRejectedValueOnce(
|
||||
new Error('native clipboard read failed'),
|
||||
);
|
||||
|
||||
await expect(readMobileClipboardText()).rejects.toMatchObject({
|
||||
code: 'host_error',
|
||||
message: 'clipboard read unavailable',
|
||||
});
|
||||
});
|
||||
|
||||
test('wraps HostBridge clipboard read responses', async () => {
|
||||
vi.mocked(Clipboard.getStringAsync).mockResolvedValue('作品号 PZ-1');
|
||||
|
||||
|
||||
@@ -15,7 +15,14 @@ export async function writeMobileClipboardText(rawText: unknown) {
|
||||
return false;
|
||||
}
|
||||
|
||||
await Clipboard.setStringAsync(clipboardText.text);
|
||||
try {
|
||||
await Clipboard.setStringAsync(clipboardText.text);
|
||||
} catch {
|
||||
throw {
|
||||
code: 'host_error',
|
||||
message: 'clipboard write unavailable',
|
||||
} satisfies HostBridgeError;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -37,9 +44,17 @@ export async function readMobileHostBridgeClipboardText(
|
||||
}
|
||||
|
||||
export async function readMobileClipboardText(): Promise<ClipboardReadTextResult> {
|
||||
const result = normalizeHostBridgeClipboardText(
|
||||
await Clipboard.getStringAsync(),
|
||||
);
|
||||
let rawText: unknown;
|
||||
try {
|
||||
rawText = await Clipboard.getStringAsync();
|
||||
} catch {
|
||||
throw {
|
||||
code: 'host_error',
|
||||
message: 'clipboard read unavailable',
|
||||
} satisfies HostBridgeError;
|
||||
}
|
||||
|
||||
const result = normalizeHostBridgeClipboardText(rawText);
|
||||
if (!result) {
|
||||
throw {
|
||||
code: 'host_error',
|
||||
|
||||
Reference in New Issue
Block a user