93 lines
3.1 KiB
TypeScript
93 lines
3.1 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
const handleMock = vi.fn();
|
|
|
|
vi.mock('electron', () => ({
|
|
ipcMain: { handle: handleMock },
|
|
}));
|
|
|
|
vi.mock('../../electron/utils/config', () => ({
|
|
getPort: () => 13210,
|
|
}));
|
|
|
|
vi.mock('../../electron/api/server', () => ({
|
|
getHostApiToken: () => 'host-token',
|
|
}));
|
|
|
|
vi.mock('../../electron/api/renderer-capability', () => ({
|
|
getRendererCapability: () => 'renderer-token',
|
|
RENDERER_CAPABILITY_HEADER: 'x-niancode-renderer-capability',
|
|
}));
|
|
|
|
describe('Host API IPC proxy', () => {
|
|
beforeEach(() => {
|
|
vi.resetModules();
|
|
vi.clearAllMocks();
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
it('connects to the loopback Host API with direct fetch', async () => {
|
|
const fetchMock = vi.fn().mockResolvedValue(new Response(
|
|
JSON.stringify({ success: true }),
|
|
{ status: 200, headers: { 'content-type': 'application/json' } },
|
|
));
|
|
vi.stubGlobal('fetch', fetchMock);
|
|
|
|
const { registerHostApiProxyHandlers } = await import('../../electron/main/ipc/host-api-proxy');
|
|
registerHostApiProxyHandlers();
|
|
|
|
const fetchHandler = handleMock.mock.calls.find(([channel]) => channel === 'hostapi:fetch')?.[1];
|
|
expect(fetchHandler).toBeTypeOf('function');
|
|
|
|
const result = await fetchHandler(undefined, {
|
|
path: '/api/opencode/projects/create',
|
|
method: 'POST',
|
|
body: JSON.stringify({ projectName: '测试项目' }),
|
|
});
|
|
|
|
expect(fetchMock).toHaveBeenCalledWith(
|
|
'http://127.0.0.1:13210/api/opencode/projects/create',
|
|
expect.objectContaining({
|
|
method: 'POST',
|
|
headers: expect.objectContaining({
|
|
Authorization: 'Bearer host-token',
|
|
'Content-Type': 'application/json',
|
|
'x-niancode-renderer-capability': 'renderer-token',
|
|
}),
|
|
}),
|
|
);
|
|
expect(result).toEqual({
|
|
ok: true,
|
|
data: { status: 200, ok: true, json: { success: true } },
|
|
});
|
|
});
|
|
|
|
it('preserves ordinary renderer headers but replaces forged security headers', async () => {
|
|
const fetchMock = vi.fn().mockResolvedValue(new Response(null, { status: 204 }));
|
|
vi.stubGlobal('fetch', fetchMock);
|
|
|
|
const { registerHostApiProxyHandlers } = await import('../../electron/main/ipc/host-api-proxy');
|
|
registerHostApiProxyHandlers();
|
|
|
|
const fetchHandler = handleMock.mock.calls.find(([channel]) => channel === 'hostapi:fetch')?.[1];
|
|
expect(fetchHandler).toBeTypeOf('function');
|
|
|
|
await fetchHandler(undefined, {
|
|
path: '/api/ai-hardware',
|
|
headers: {
|
|
Accept: 'application/json',
|
|
'X-Renderer-Request': 'hardware-overview',
|
|
authorization: 'Bearer renderer-forged-token',
|
|
'X-NIANCODE-RENDERER-CAPABILITY': 'renderer-forged-capability',
|
|
},
|
|
});
|
|
|
|
const [, init] = fetchMock.mock.calls[0] as [string, RequestInit];
|
|
const headers = new Headers(init.headers);
|
|
expect(headers.get('accept')).toBe('application/json');
|
|
expect(headers.get('x-renderer-request')).toBe('hardware-overview');
|
|
expect(headers.get('authorization')).toBe('Bearer host-token');
|
|
expect(headers.get('x-niancode-renderer-capability')).toBe('renderer-token');
|
|
});
|
|
});
|