Files
openmaic/OpenMAIC/tests/web-search/bocha.test.ts
2026-08-16 14:58:47 +08:00

128 lines
3.7 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
const proxyFetchMock = vi.hoisted(() => vi.fn());
vi.mock('@/lib/server/proxy-fetch', () => ({
proxyFetch: proxyFetchMock,
}));
import { searchWithBocha } from '@/lib/web-search/bocha';
describe('searchWithBocha', () => {
beforeEach(() => {
proxyFetchMock.mockReset();
});
it('calls Bocha Web Search API and maps web page results', async () => {
proxyFetchMock.mockResolvedValueOnce(
new Response(
JSON.stringify({
code: 200,
log_id: 'log-ok',
msg: null,
data: {
queryContext: { originalQuery: '阿里巴巴 ESG' },
webPages: {
value: [
{
name: 'Alibaba ESG report',
url: 'https://example.com/esg',
snippet: 'Short snippet',
summary: 'Long summary',
},
{
name: 'Snippet only',
url: 'https://example.com/snippet',
snippet: 'Fallback snippet',
},
],
},
},
}),
{ status: 200, headers: { 'content-type': 'application/json' } },
),
);
const result = await searchWithBocha({
query: '阿里巴巴 ESG',
apiKey: 'bocha-key',
maxResults: 100,
});
expect(proxyFetchMock).toHaveBeenCalledWith(
'https://api.bocha.cn/v1/web-search',
expect.objectContaining({
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer bocha-key',
},
body: JSON.stringify({
query: '阿里巴巴 ESG',
freshness: 'noLimit',
summary: true,
count: 50,
}),
}),
);
expect(result.query).toBe('阿里巴巴 ESG');
expect(result.answer).toBe('');
expect(result.sources).toEqual([
{
title: 'Alibaba ESG report',
url: 'https://example.com/esg',
content: 'Long summary',
score: 0,
},
{
title: 'Snippet only',
url: 'https://example.com/snippet',
content: 'Fallback snippet',
score: 0,
},
]);
});
it('supports custom base URLs ending at either host, /v1, or full endpoint', async () => {
proxyFetchMock.mockImplementation(() =>
Promise.resolve(
new Response(JSON.stringify({ code: 200, data: { webPages: { value: [] } } }), {
status: 200,
headers: { 'content-type': 'application/json' },
}),
),
);
await searchWithBocha({ query: 'q1', apiKey: 'key', baseUrl: 'https://proxy.example.com' });
await searchWithBocha({ query: 'q2', apiKey: 'key', baseUrl: 'https://proxy.example.com/v1' });
await searchWithBocha({
query: 'q3',
apiKey: 'key',
baseUrl: 'https://proxy.example.com/v1/web-search',
});
expect(proxyFetchMock.mock.calls.map((call) => call[0])).toEqual([
'https://proxy.example.com/v1/web-search',
'https://proxy.example.com/v1/web-search',
'https://proxy.example.com/v1/web-search',
]);
});
it('includes Bocha error details when requests fail', async () => {
proxyFetchMock.mockResolvedValueOnce(
new Response(
JSON.stringify({
code: '403',
message: 'You do not have enough money',
log_id: 'bocha-log-id',
}),
{ status: 403, statusText: 'Forbidden', headers: { 'content-type': 'application/json' } },
),
);
await expect(searchWithBocha({ query: 'q', apiKey: 'key' })).rejects.toThrow(
'Bocha API error (403): You do not have enough money, log_id: bocha-log-id',
);
});
});