Тестирование в JavaScript невозможно без проверки асинхронных операций, таких как HTTP-запросы. В реальных приложениях часто используется API для обмена данными между клиентом и сервером, и такие запросы должны быть проверены. В Jasmine для этих целей можно использовать технику mocking (мока). Это позволяет эмулировать поведение сетевых запросов без необходимости реально обращаться к серверу.
Использование реальных сетевых запросов в тестах может замедлить выполнение тестов и зависеть от внешних факторов, таких как доступность сервера и стабильность интернет-соединения. Mocking позволяет контролировать поведение запросов, не зависеть от внешней среды и тестировать только логику работы приложения.
Метод fetch является встроенной функцией для выполнения
асинхронных HTTP-запросов. Он возвращает Promise,
который резолвится в объект Response. Ответ можно
обрабатывать с помощью методов json(), text(),
blob() и других.
Пример использования fetch:
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
Этот код отправляет GET-запрос на указанный URL и выводит результат в консоль. Однако, в тестах нам нужно будет эмулировать этот процесс, не делая реальных HTTP-запросов.
В Jasmine для мока сетевых запросов можно использовать глобальный
объект spyOn. С помощью этой функции можно заменить
реальную реализацию метода fetch на поддельную, которая
будет возвращать заранее подготовленные ответы.
Для начала нужно создать фиктивную реализацию функции
fetch. Пример:
beforeEach(() => {
spyOn(window, 'fetch').and.returnValue(Promise.resolve({
json: () => Promise.resolve({ data: 'test data' })
}));
});
В этом примере мы заменяем fetch на фейковую версию,
которая всегда возвращает объект Response с методом
json, который резолвится в объект с тестовыми данными.
Теперь, когда мы замокали fetch, можно писать тесты.
Рассмотрим пример:
it('должен сделать запрос и вернуть данные', async () => {
const data = await fetchDataFromApi(); // наша функция, использующая fetch
expect(data).toEqual({ data: 'test data' });
expect(fetch).toHaveBeenCalledWith('https://api.example.com/data');
});
Здесь мы тестируем функцию fetchDataFromApi, которая
использует fetch для получения данных с сервера. Мы
проверяем, что данные, которые она возвращает, совпадают с тем, что
возвращает мок. Также важно убедиться, что fetch был вызван
с правильным URL.
Важно также тестировать, как ваше приложение будет вести себя при
ошибках. Для этого можно мокировать ошибку в fetch:
beforeEach(() => {
spyOn(window, 'fetch').and.returnValue(Promise.reject('Ошибка'));
});
it('должен обработать ошибку при запросе', async () => {
try {
await fetchDataFromApi();
} catch (error) {
expect(error).toBe('Ошибка');
}
});
Здесь мы мокируем fetch, чтобы он всегда резолвился с
ошибкой. В тесте проверяется, что ошибка правильно обрабатывается и
передается в catch блок.
В Jasmine можно использовать другие библиотеки и инструменты для более сложного мока. Одним из таких инструментов является Sinon.js, который предоставляет дополнительные возможности для создания моков, спаев и фейков.
Пример использования Sinon для мока fetch:
import sinon from 'sinon';
let fetchStub;
beforeEach(() => {
fetchStub = sinon.stub(window, 'fetch').resolves({
json: () => Promise.resolve({ data: 'test data' })
});
});
afterEach(() => {
fetchStub.restore();
});
it('должен вернуть данные через мокированное API', async () => {
const data = await fetchDataFromApi();
expect(data).toEqual({ data: 'test data' });
expect(fetchStub.calledOnce).toBe(true);
});
При мокировании fetch можно возвращать различные типы
ответов. В примерах выше использовался метод json(), но
можно мокировать другие методы, такие как:
text(): для получения текстовых данных.blob(): для работы с бинарными данными.ok: чтобы контролировать успешность ответа.Пример мока с проверкой свойства ok:
beforeEach(() => {
spyOn(window, 'fetch').and.returnValue(Promise.resolve({
ok: true,
json: () => Promise.resolve({ data: 'test data' })
}));
});
it('должен проверять успешность ответа', async () => {
const response = await fetch('https://api.example.com/data');
expect(response.ok).toBe(true);
const data = await response.json();
expect(data).toEqual({ data: 'test data' });
});
В Jasmine можно менять поведение мока в зависимости от конкретных тестов. Например, для одного теста можно мокировать успешный ответ, а для другого — ошибку:
it('должен обработать успешный ответ', async () => {
spyOn(window, 'fetch').and.returnValue(Promise.resolve({
json: () => Promise.resolve({ data: 'test data' })
}));
const data = await fetchDataFromApi();
expect(data).toEqual({ data: 'test data' });
});
it('должен обработать ошибку при запросе', async () => {
spyOn(window, 'fetch').and.returnValue(Promise.reject('Ошибка'));
try {
await fetchDataFromApi();
} catch (error) {
expect(error).toBe('Ошибка');
}
});
fetch с
параметрамиДля более сложных тестов важно учитывать параметры запроса. Например, можно проверять, был ли запрос отправлен с нужными заголовками или методами:
beforeEach(() => {
spyOn(window, 'fetch').and.callFake((url, options) => {
expect(url).toBe('https://api.example.com/data');
expect(options.method).toBe('POST');
expect(options.headers['Content-Type']).toBe('application/json');
return Promise.resolve({
json: () => Promise.resolve({ data: 'test data' })
});
});
});
it('должен отправить POST-запрос с правильными заголовками', async () => {
const data = await fetchDataFromApi();
expect(data).toEqual({ data: 'test data' });
});
В этом примере мы проверяем, что запрос был отправлен методом
POST, с нужным URL и заголовками.
Mocking fetch в Jasmine — это мощный инструмент для
тестирования асинхронных операций без реальных сетевых запросов. Он
позволяет контролировать ответы, исключать зависимость от внешних
факторов и ускорять выполнение тестов. Важно помнить о правильной
настройке моков и их проверке, чтобы тесты были точными и
воспроизводимыми.