#reactjs #react-hooks #react-testing-library #swr
Вопрос:
У меня есть компонент, который использует крюк, который извлекает данные с сервера, и я издевался над этим крючком, чтобы вернуть свои данные тестирования. Теперь, если mutate
функция (возвращаемая крючком) вызывается, обычная реализация снова извлекает данные и вызывает повторный рендеринг (я использую swr
, вот mutate
ссылка).
Как запустить повторный рендеринг / setState
на издевательском крючке?
Что я хочу проверить: просто, если пользователь создает элемент, список элементов должен быть повторно извлечен и отображен.
Код для иллюстрации проблемы:
const existing = [...]
const newlyCreated = [...];
useData.mockReturnValue({ data: [existing] });
const { getByRole, findByText } = render(<MyComponent />);
const form = getByRole("form");
const createButton = within(form).getByText("Create");
useData.mockReturnValue({ data: [existing, newlyCreated] });
// createButton.click();
// Somehow trigger re-render???
for (const { name } of [existing, newlyCreated]) await findByText(name);
Комментарии:
1. Рассматривали ли вы возможность издеваться над ответом API, а не над
useData
крючком?2. @juliomalves да, у меня есть. Но наличие специального крючка для извлечения данных и насмешек, которые были рекомендованы в SO и в вопросах
swr
. Сначала я пытался издеватьсяswr
, но на самом деле ничего не вышло. Я мог бы посмеятьсяfetch
, но я не думаю, что это правильный путь, не так ли? Особенно потому, что это детали реализации.3. Я имел в виду издевательство над ответами API с помощью перехватчиков запросов, таких как
nock
илиmsw
.4. @juliomalves, это предпочтительнее, чем издеваться над крючком? Я хотел бы прочитать некоторые ресурсы, прежде чем менять весь свой код и в конечном итоге замечать, что что-то не так, как должно быть 😅. Я быстро просмотрел readme связанных библиотек, и правильно
msw
ли это, что в моем случае это не сработало бы? Поскольку тестирование выполняется не в реальной среде браузера, а в js-dom (msw
используйте работников службы).5. Я только что заметил, что
msw
в нем есть раздел о выполнении в узле, так что это не должно быть проблемой.
Ответ №1:
Вам не нужно запускать повторный рендеринг в своем тесте.
Проблема в том, что кнопка в вашем пользовательском интерфейсе изменяет данные, но, поскольку вы издеваетесь useData
, этой мутации не происходит.
Вы можете просто добавить mutate()
в свой макет и назначить ему функцию макета.
Вам не нужно модульно тестировать внутреннюю работу собственных SWR mutate()
— это уже охвачено их собственным проектом.
const existing = ["Mercury", "Venus", "Earth", "Mars"];
const newItem = "Jupiter";
test("Create button should call mutate() with correct value", async () => {
const mutate = jest.fn();
jest.spyOn(useData, "default").mockImplementation(() => ({
data: existing,
mutate
}));
let resu<
act(() => {
result = render(<Form />);
});
await waitFor(() => {
existing.forEach((item) => {
expect(result.getByText(item)).toBeInTheDocument();
});
});
const input = result.container.querySelector("input");
fireEvent.change(input, { target: { value: newItem } });
const createButton = result.getByText("Create");
createButton.click();
expect(mutate).toBeCalledWith([...existing, newItem], false);
});
Комментарии:
1. Действительно, мне не нужно проверять, что
mutate
это работает, но я хочу проверить, что мой экран отображает правильные новые данные. Я полагаю, что я мог бы проверить, был ли вызван mute, и добавить второй тест, который охватывает случай после мутации.2. Учитывая асинхронный характер моего
mutate
вызова, тест будет выполнен до вызова функции. Это (как я теперь помню) основная причина, по которой я хотел изменить состояние, чтобы я мог ожидать изменений на экране.