import { beforeEach, describe, expect, it, vi } from 'vitest' const { invokeMock } = vi.hoisted(() => ({ invokeMock: vi.fn() })) vi.mock('@tauri-apps/api/core', () => ({ invoke: invokeMock })) vi.mock('../../src/platform/runtime', () => ({ isTauriRuntime: () => true })) import { invokeEnvelope, invokeNative, NativeCommandError } from '../../src/platform/invoke' describe('native error boundary', () => { beforeEach(() => vi.clearAllMocks()) it('preserves business failures as envelopes', async () => { const response = { success: false, error: 'bad data', errorCode: 'native.invalidBase64' } invokeMock.mockResolvedValueOnce(response) expect(await invokeNative('write_file')).toBe(response) }) it('normalizes structured rejections without losing their code or cause', async () => { const cause = { error: 'invalid encoding', errorCode: 'native.invalidBase64' } invokeMock.mockRejectedValueOnce(cause) const error = await invokeNative('write_file').catch((value: unknown) => value) expect(error).toBeInstanceOf(NativeCommandError) expect(error).toMatchObject({ command: 'write_file', detail: 'invalid encoding', errorCode: cause.errorCode, originalError: cause, }) expect((error as Error).message).not.toContain('[object Object]') }) it('retains codes when adapting rejected calls to envelopes', async () => { invokeMock.mockRejectedValueOnce({ error: 'join failed', errorCode: 'native.taskJoin' }) expect(await invokeEnvelope('read_file')).toMatchObject({ success: false, errorCode: 'native.taskJoin' }) }) it('preserves plain rejection messages', async () => { invokeMock.mockRejectedValueOnce('custom native failure') await expect(invokeNative('test')).rejects.toThrow('custom native failure') }) })