Могу ли я вручную вызвать изменение состояния при тестировании с использованием реагирующей-тестирующей библиотеки?
Я все еще перевожу свои тесты Enzyme в библиотеку реагирования-тестирования, и у меня есть довольно распространенный сценарий, когда при монтировании компонента он запускает Ajax-запрос для получения некоторых данных. Непосредственно перед началом выборки он устанавливает некоторое значение состояния, чтобы указать, что он загружается, что, в свою очередь, отображает счетчик. По завершении состояние обновляется как данными, так и "loadingState" устанавливается в "Completed" или "Failed", где это уместно.
import React, { useEffect, useState } from "react";
import { SwapSpinner } from "react-spinners-kit";
import styled from "styled-components";
import * as R from "ramda";
import { getPeople } from "./getPeople";
const FlexCenter = styled.div`
height: 250px;
display: flex;
justify-content: center;
align-items: center;
`;
const loadingStates = {
notStarted: "notStarted",
isLoading: "isLoading",
success: "success",
failure: "failure"
};
function App() {
const [people, setPeople] = useState([]);
const [isLoading, setLoading] = useState(loadingStates.notStarted);
useEffect(() => {
setLoading(loadingStates.isLoading);
getPeople()
.then(({ results }) => {
setPeople(results);
setLoading(loadingStates.success);
})
.catch(error => {
setLoading(loadingStates.failure);
});
}, []);
return (
<div>
{R.cond([
[
R.equals(loadingStates.isLoading),
() => (
<FlexCenter data-testid="spinner">
<SwapSpinner />
</FlexCenter>
)
],
[
R.equals(loadingStates.success),
() => (
<ul data-testid="people-list">
{people.map(({ name }) => (
<li key={name}>{name}</li>
))}
</ul>
)
],
[R.equals(loadingStates.failure), <div>An error occured</div>]
])(isLoading)}
</div>
);
}
export default App;
С помощью Enzyme я мог вручную установить состояние любого из loadingStates
ключи, и утверждают, что условный рендеринг отдает соответствующие изменения.
Есть ли способ, которым я могу сделать это в RTL?
1 ответ
Вы не можете сделать это с помощью RTL. Вы не должны взаимодействовать с внутренними компонентами ваших компонентов.
Примерно так я бы протестировал ваш компонент:
import { getPeople } from "./getPeople";
jest.mock('./getPeople')
test('skeleton of a test', async () => {
const people = [/* Put some mock people in here */]
getPeople.mockResolveValueOnce({ results: people })
render(<App />)
expect(/* Somehow get the loading spinner */).toBeInTheDocument()
await wait(() => expect(/* Here you check that the people is on the page */).toBeInTheDocument())
// We also check that the API gets called
expect(getPeople).toHaveBeenCalledOnce()
expect(getPeople).toHaveBeenCalledWith()
})
Как видите, я не проверяю, каково внутреннее состояние App
, Вместо этого я проверяю, отображается ли индикатор загрузки и что после этого на экране появляются люди и вызывается API.
Этот тест более надежен, потому что вы тестируете то, что увидит пользователь, а не детали реализации.