feat: solution for 'Повторный экзамен #2: Сравнительный обзор 3 сущностей (Tavily)'
This commit is contained in:
+57
-54
@@ -1,71 +1,74 @@
|
||||
const nock = require('nock');
|
||||
const { compareEntities } = require('../src/compare');
|
||||
require('dotenv').config({ path: '.env.example' });
|
||||
/**
|
||||
* Unit tests for the compare function.
|
||||
*
|
||||
* These tests mock the Tavily API calls to ensure that the compare
|
||||
* function behaves correctly without making real HTTP requests.
|
||||
*/
|
||||
|
||||
describe('compareEntities', () => {
|
||||
const baseUrl = 'https://api.tavily.com';
|
||||
const apiKey = 'test-key';
|
||||
import { compare } from '../src/index.js';
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
beforeAll(() => {
|
||||
process.env.TAVILY_API_KEY = apiKey;
|
||||
jest.mock('node-fetch', () => jest.fn());
|
||||
|
||||
const { Response } = jest.requireActual('node-fetch');
|
||||
|
||||
describe('compare', () => {
|
||||
beforeEach(() => {
|
||||
fetch.mockClear();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
nock.cleanAll();
|
||||
});
|
||||
test('returns results for three entities', async () => {
|
||||
const mockResponses = [
|
||||
{ result: 'entity1 result' },
|
||||
{ result: 'entity2 result' },
|
||||
{ result: 'entity3 result' }
|
||||
];
|
||||
|
||||
test('returns ranked results based on number of results', async () => {
|
||||
nock(baseUrl)
|
||||
.post('/search', { query: 'entity1' })
|
||||
.reply(200, { results: [{}, {}] }); // 2 results
|
||||
nock(baseUrl)
|
||||
.post('/search', { query: 'entity2' })
|
||||
.reply(200, { results: [{}, {}, {}] }); // 3 results
|
||||
nock(baseUrl)
|
||||
.post('/search', { query: 'entity3' })
|
||||
.reply(200, { results: [{}, {}] }); // 2 results
|
||||
fetch
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify(mockResponses[0]), { status: 200 }))
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify(mockResponses[1]), { status: 200 }))
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify(mockResponses[2]), { status: 200 }));
|
||||
|
||||
const result = await compareEntities('entity1', 'entity2', 'entity3');
|
||||
expect(result.ranked[0].entity).toBe('entity2');
|
||||
expect(result.ranked[1].entity).toBe('entity1');
|
||||
expect(result.ranked[2].entity).toBe('entity3');
|
||||
});
|
||||
const result = await compare('entity1', 'entity2', 'entity3');
|
||||
|
||||
test('throws error on empty entity', async () => {
|
||||
await expect(compareEntities('', 'b', 'c')).rejects.toThrow(
|
||||
'All entities must be non-empty strings.'
|
||||
expect(result).toEqual({
|
||||
entity1: mockResponses[0],
|
||||
entity2: mockResponses[1],
|
||||
entity3: mockResponses[2]
|
||||
});
|
||||
|
||||
expect(fetch).toHaveBeenCalledTimes(3);
|
||||
expect(fetch).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.stringContaining('entity1'),
|
||||
expect.any(Object)
|
||||
);
|
||||
expect(fetch).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
expect.stringContaining('entity2'),
|
||||
expect.any(Object)
|
||||
);
|
||||
expect(fetch).toHaveBeenNthCalledWith(
|
||||
3,
|
||||
expect.stringContaining('entity3'),
|
||||
expect.any(Object)
|
||||
);
|
||||
});
|
||||
|
||||
test('handles API error', async () => {
|
||||
nock(baseUrl)
|
||||
.post('/search', { query: 'entity1' })
|
||||
.reply(401, { error: 'Invalid API key' });
|
||||
nock(baseUrl)
|
||||
.post('/search', { query: 'entity2' })
|
||||
.reply(200, { results: [] });
|
||||
nock(baseUrl)
|
||||
.post('/search', { query: 'entity3' })
|
||||
.reply(200, { results: [] });
|
||||
test('throws error if any API call fails', async () => {
|
||||
fetch
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify({ result: 'ok' }), { status: 200 }))
|
||||
.mockResolvedValueOnce(new Response('Not Found', { status: 404 }))
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify({ result: 'ok' }), { status: 200 }));
|
||||
|
||||
await expect(compareEntities('entity1', 'entity2', 'entity3')).rejects.toThrow(
|
||||
'Tavily API error: 401 Invalid API key'
|
||||
await expect(compare('entity1', 'entity2', 'entity3')).rejects.toThrow(
|
||||
/Comparison failed/
|
||||
);
|
||||
});
|
||||
|
||||
test('handles network failure', async () => {
|
||||
nock(baseUrl)
|
||||
.post('/search', { query: 'entity1' })
|
||||
.replyWithError('Network down');
|
||||
nock(baseUrl)
|
||||
.post('/search', { query: 'entity2' })
|
||||
.reply(200, { results: [] });
|
||||
nock(baseUrl)
|
||||
.post('/search', { query: 'entity3' })
|
||||
.reply(200, { results: [] });
|
||||
|
||||
await expect(compareEntities('entity1', 'entity2', 'entity3')).rejects.toThrow(
|
||||
'Network error: Network down'
|
||||
test('throws error if missing entity arguments', async () => {
|
||||
await expect(compare('entity1', 'entity2')).rejects.toThrow(
|
||||
/All three entities must be provided/
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Jest setup file.
|
||||
*
|
||||
* This file can be used to configure global test settings, such as
|
||||
* mocking fetch or setting environment variables.
|
||||
*/
|
||||
|
||||
process.env.TAVILY_API_KEY = 'test-api-key';
|
||||
Reference in New Issue
Block a user