英文:
Can't update the searched todos in the react testing library?
问题
程序运行正常,但当我尝试测试它时,它不能正常工作。我想在搜索后重新渲染待办事项,但是测试中的这部分似乎不能正常工作:我获取数据并将其设置为待办事项,搜索状态也在工作,因为当我记录它时,我可以看到该值,但是重新渲染没有触发,搜索的项目未显示,我仍然可以看到所有待办事项。我不知道该怎么做。我应该怎么做?
以下是代码:
useEffect(() => {
fetch("some url todos")
.then((response) => {
return response.json();
})
.then((response) => {
setTodos((todos) => ({ ...todos, all: response }));
})
.catch((e) => console.error(e));
}, []);
useEffect(() => {
setTodos((todos) => ({
...todos,
searched: search
? todos.all.filter((item) => {
return item.title.toLowerCase().includes(search.toLowerCase());
})
: null,
}));
}, [search]);
const handleOnChangeInput = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearch(e.target.value);
};
<div className="search-container">
<input
className="search"
value={search}
onChange={handleOnChangeInput}
placeholder="Search todo..."
data-testid="search"
type="text"
/>
</div>
<div className="todos" data-testid="todos">
{(todos.searched && todos.searched.length > 0
? todos.searched
: todos.all
).map(({ title }) => (
<p data-testid="todo">
{title}
</p>
))}
</div>
以下是测试的代码:
const mockResponse = [
{
userId: 1,
id: 1,
title: "Todo S",
completed: false,
},
{
userId: 1,
id: 2,
title: "Todo A",
completed: true,
},
];
beforeEach(() => {
jest.spyOn(global, "fetch" as any).mockResolvedValue({
json: () => mockResponse,
});
});
afterEach(() => {
jest.restoreAllMocks();
});
it("should filter todos based on search input", async () => {
render(
<MemoryRouter>
<Home />
</MemoryRouter>
);
const searchInput = screen.getByTestId("search");
fireEvent.change(searchInput, {
target: { value: "A" },
});
const todos = await screen.findAllByTestId("todo");
expect(todos).toHaveLength(1);
});
希望这些翻译对您有帮助。
英文:
The program is working fine but when I try to test it does not work properly. I want to rerender the todos after they are searched but this part in the test seems to not work properly: I fetch the data and set it to the todos, also the search state is working because when I log it I can see the value, however, the rerender is not triggered and the searched items are not displayed, I can see still all the todos.
I don't know how to do it. What should I do?
here is the code:
useEffect(() => {
fetch("some url todos")
.then((response) => {
return response.json();
})
.then((response) => {
setTodos((todos) => ({ ...todos, all: response }));
})
.catch((e) => console.error(e));
}, []);
useEffect(() => {
setTodos((todos) => ({
...todos,
searched: search
? todos.all.filter((item) => { return item.title.toLowerCase().includes(search.toLowerCase());
})
: null,
}));
}, [search]);
const handleOnChangeInput = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearch(e.target.value);
};
<div className="search-container">
<input
className="search"
value={search}
onChange={handleOnChangeInput}
placeholder="Search todo..."
data-testid="search"
type="text"
/>
</div>
<div className="todos" data-testid="todos">
{(todos.searched && todos.searched.length > 0
? todos.searched
: todos.all
).map(({title}) => (
<p
data-testid="todo"
>
{title}
</p>
))}
</div>
Here are codes for the test:
const mockResponse = [
{
userId: 1,
id: 1,
title: "Todo S",
completed: false,
},
{
userId: 1,
id: 2,
title: "Todo A",
completed: true,
},
];
beforeEach(() => {
jest.spyOn(global, "fetch" as any).mockResolvedValue({
json: () => mockResponse,
});
});
afterEach(() => {
jest.restoreAllMocks();
});
it("should filter todos based on search input", async () => {
render(
<MemoryRouter>
<Home />
</MemoryRouter>
);
const searchInput = screen.getByTestId("search");
fireEvent.change(searchInput, {
target: { value: "A" },
});
const todos = await screen.findAllByTestId("todo");
expect(todos).toHaveLength(1);
});
答案1
得分: 1
因为您正在渲染组件并在渲染期间设置状态,所以需要使用waitFor
异步实用函数等待UI完全渲染。
对我有效的一个好方法是在渲染后添加waitFor
函数。
render(
<MemoryRouter>
<Home />
</MemoryRouter>
);
await waitFor(async () => Promise<void>);
然后其余部分应该正常工作。
英文:
because you are rendering component and setting the state during rendering, you need to wait for the ui to be fully rendered using the waitFor
async utitliy function.
a good technique that works for me.
adding waitFor
fun after the render.
render(
<MemoryRouter>
<Home />
</MemoryRouter>
);
await waitFor(async () => Promise<void>);
and the rest should works fine.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论