Что я должен протестировать в этом настраиваемом хуке, который обертывает useSWR?
Я создал специальный хук под названием useCity. Он завершает вызов API, сделанный с использованием useSWR.
Вот код для хука:
import useSWR from 'swr';
import { City } from '../interfaces';
import { BASE_URL } from '../../config';
interface CitiesResponse {
data?: {
records: {
fields: {
city: string;
accentcity: string;
}
}[]
},
error?: {
message: string;
}
};
interface Props {
start?: number;
rows: number;
query?: string;
sort?: 'population';
exclude?: string[];
}
const useCity = ({ start = 0, rows, query, sort, exclude }: Props) => {
const params = [`start=${start}`, `rows=${rows}`];
if (query) params.push(`q=${query}`);
if (sort) params.push(`sort=${sort}`);
if (exclude && exclude.length > 0) params.push(...exclude.map(city => `exclude.city=${city}`))
const { data, error }: CitiesResponse = useSWR(
`${BASE_URL.CITIES_SERVICE}?dataset=worldcitiespop&facet=city&${params.join('&')}`,
{ revalidateOnFocus: false, }
);
const cities: City[] = data?.records.map(record => ({
name: record.fields.city,
title: record.fields.accentcity,
})) || [];
return {
cities,
loading: !error && !data,
error,
};
};
export default useCity;
Теперь мне нужно проверить крючок. Итак, я попытался использовать
msw
и
@testing-library/react-hooks
.
Вот моя попытка:
const server = setupServer(
rest.get(BASE_URL.CITIES_SERVICE, (req, res, ctx) => {
const start = req.url.searchParams.get('start');
const rows = req.url.searchParams.get('rows');
const query = req.url.searchParams.get('query');
const sort = req.url.searchParams.get('sort');
const exclude = req.url.searchParams.getAll('exclude.city');
const getReturnVal: () => DatabaseCity[] = () => {
// i will write some code that assumes what server will return
};
return res(
ctx.status(200),
ctx.json({
records: getReturnVal(),
}),
);
}),
...fallbackHandlers,
);
beforeAll(() => server.listen());
afterEach(() => {
server.resetHandlers();
cache.clear();
});
afterAll(() => server.close());
it('should return number of cities equal to passed in rows', async () => {
const wrapper = ({ children } : { children: ReactNode }) => (
<SWRConfig value={{ dedupingInterval: 0 }}>
{children}
</SWRConfig>
);
const { result, waitForNextUpdate, } = renderHook(() => useCity({ rows: 2 }), { wrapper });
const { cities:_cities, loading:_loading, error:_error } = result.current;
expect(_cities).toHaveLength(0);
await waitForNextUpdate();
const { cities, loading, error } = result.current;
expect(cities).toHaveLength(2);
});
Я полагаю, что тестовый пример пройдет, как только я реализую фиктивную функцию.
Но я не знаю, правильный ли это подход к тестированию такого крючка. Я фронтенд-разработчик, обязан ли я тестировать этот вызов API?
Я новичок в написании тестовых примеров, включающих вызовы API. Я иду в правильном направлении? Я не знаю, как называются такого рода тесты. Если кто-то может сказать мне, какой тест я выполняю, это поможет мне найти решения в Google, а не тратить время других разработчиков на ответы на мои вопросы.
2 ответа
Похоже, вы на правильном пути.
Твой
useCity
hook выполняет в основном 2 вещи, которые вы можете проверить в тестах:
- строит URL
- конвертирует города в другой формат
Вы можете проверить
useSWR
вызывается с правильным URL-адресом с помощью шпиона:
import * as SWR from 'swr';
jest.spyOn(SWR, 'default'); // write this line before rendering the hook.
expect(SWR.default).toHaveBeenCalledWith(expectedUrl, {}); // pass any options that were passed in actual object
Вы можете проверить
useCities
возвращает правильные города по
const { cities } = result.current;
expect(cities).toEqual(expectedCities);
Я фронтенд-разработчик, обязан ли я тестировать этот вызов API?
Я думаю, что вам решать. Я лично считаю своей обязанностью тестировать любой код, который я пишу - это, конечно, не догма и зависит от контекста.
Я не знаю, как называются такого рода тесты. Если кто-то может сказать мне, какой тест я выполняю, это поможет мне найти решения в Google.
На это не может быть однозначного ответа. Некоторые люди назвали бы это модульным тестированием (поскольку
useCities
это "единица"). Другие могут назвать это интеграционным тестированием (поскольку вы тестируете
useCities
и
useSWR
в "интеграции").
Лучше всего будет погуглить такие вещи, как "как тестировать перехватчики реакции" или "как тестировать компоненты реакции". Документация RTL - хорошее место для начала.
Дополнительные примечания
Лично я почти никогда не тестирую хуки изолированно. Я считаю, что проще и интуитивнее писать интеграционные тесты для компонентов, использующих хуки.
Однако, если ваш хук будет использоваться в других проектах, я думаю, имеет смысл тестировать их изолированно, как вы это делаете здесь.
Если вы хотите высмеять весь SWR, вы можете это сделать, задача состоит в том, чтобы уклониться от SWRResponse.
import { render, screen, waitFor } from '@testing-library/react';
import * as SWR from 'swr';
...
it('should render profile', async () => {
jest
.spyOn(SWR, 'default')
.mockImplementation(() => ({ data: identifyProfile, isValidating: false, mutate: () => Promise.resolve() }));
render(<MyProfileSection />);
await waitFor(() => {
expect(screen.getByText('John Duo')).toBeInTheDocument();
});
});