UNPKG

serper-search-scrape-mcp-server

Version:

Serper MCP Server supporting search and webpage scraping

172 lines (171 loc) 7.04 kB
import { SerperClient } from '../serper-client.js'; import fetch from 'node-fetch'; // Mock node-fetch jest.mock('node-fetch'); const mockedFetch = fetch; describe('SerperClient', () => { const mockApiKey = 'test-api-key'; const mockBaseUrl = 'https://test.serper.dev'; let client; beforeEach(() => { client = new SerperClient(mockApiKey, mockBaseUrl); jest.clearAllMocks(); }); describe('Unit Tests', () => { describe('search', () => { const mockSearchParams = { q: 'test query', gl: 'us', hl: 'en' }; const mockSearchResponse = { searchParameters: { q: 'test query', gl: 'us', hl: 'en' }, organic: [ { title: 'Test Result', link: 'https://test.com', snippet: 'Test snippet' } ] }; it('should make correct API call and return results', async () => { mockedFetch.mockResolvedValueOnce({ ok: true, json: async () => mockSearchResponse }); const result = await client.search(mockSearchParams); expect(mockedFetch).toHaveBeenCalledWith(`${mockBaseUrl}/search`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-KEY': mockApiKey }, body: JSON.stringify(mockSearchParams) }); expect(result).toEqual(mockSearchResponse); }); it('should handle API errors correctly', async () => { const errorMessage = 'API Error'; mockedFetch.mockResolvedValueOnce({ ok: false, status: 400, statusText: 'Bad Request', text: async () => errorMessage }); await expect(client.search(mockSearchParams)) .rejects .toThrow(`Serper API error: 400 Bad Request - ${errorMessage}`); }); it('should handle network errors', async () => { const networkError = new Error('Network Error'); mockedFetch.mockRejectedValueOnce(networkError); await expect(client.search(mockSearchParams)) .rejects .toThrow(networkError); }); }); describe('batchSearch', () => { const mockBatchParams = [{ q: 'query1', gl: 'us', hl: 'en' }, { q: 'query2', gl: 'uk', hl: 'en' }]; const mockBatchResponse = { results: [ { searchParameters: { q: 'query1', gl: 'us', hl: 'en' }, organic: [{ title: 'Result 1', link: 'https://test1.com' }] }, { searchParameters: { q: 'query2', gl: 'uk', hl: 'en' }, organic: [{ title: 'Result 2', link: 'https://test2.com' }] } ] }; it('should make correct batch API call and return results', async () => { mockedFetch.mockResolvedValueOnce({ ok: true, json: async () => mockBatchResponse }); const result = await client.batchSearch(mockBatchParams); expect(mockedFetch).toHaveBeenCalledWith(`${mockBaseUrl}/search`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-KEY': mockApiKey }, body: JSON.stringify(mockBatchParams) }); expect(result).toEqual(mockBatchResponse); }); it('should handle batch API errors correctly', async () => { const errorMessage = 'Batch API Error'; mockedFetch.mockResolvedValueOnce({ ok: false, status: 400, statusText: 'Bad Request', text: async () => errorMessage }); await expect(client.batchSearch(mockBatchParams)) .rejects .toThrow(`Serper API error: 400 Bad Request - ${errorMessage}`); }); }); }); describe('Integration Tests', () => { // Note: These tests require a valid API key and will make real API calls // They are disabled by default and should be run manually when needed const realClient = new SerperClient(process.env.SERPER_API_KEY || ''); describe('search', () => { it.skip('should perform a real search with all optional parameters', async () => { const params = { q: 'Latest AI developments', gl: 'us', hl: 'en', num: 5, tbs: 'qdr:d', location: 'Silicon Valley', autocorrect: true }; const result = await realClient.search(params); expect(result).toBeDefined(); expect(result.searchParameters).toBeDefined(); expect(result.searchParameters.q).toBe(params.q); expect(Array.isArray(result.organic)).toBe(true); expect(result.organic.length).toBeLessThanOrEqual(params.num || 10); }, 10000); it.skip('should perform a real batch search with varied parameters', async () => { const batchParams = [ { q: 'Web Development 2024', gl: 'us', hl: 'en', num: 3, tbs: 'qdr:m' }, { q: 'Cloud Computing Trends', gl: 'uk', hl: 'en', num: 3, location: 'London' } ]; const result = await realClient.batchSearch(batchParams); expect(result).toBeDefined(); expect(Array.isArray(result)).toBe(true); expect(result.length).toBe(2); expect(result[0].searchParameters.q).toBe(batchParams[0].q); expect(result[1].searchParameters.q).toBe(batchParams[1].q); }, 15000); }); }); });