act()
trong React Testing Library: Hướng dẫn toàn diện cho người mới bắt đầuBạn đã bao giờ gặp phải lỗi act()
khó chịu trong React Testing Library (RTL) khi viết test chưa? Lỗi này có thể gây bối rối, đặc biệt đối với người mới bắt đầu. Bài viết này sẽ giúp bạn hiểu rõ nguyên nhân gây ra lỗi act()
và cung cấp các giải pháp thiết thực để khắc phục, giúp bạn viết test một cách hiệu quả và tự tin hơn. Chúng ta sẽ đi sâu vào các khái niệm, ví dụ cụ thể và các tình huống thường gặp để bạn có thể dễ dàng áp dụng vào dự án của mình.
act()
là gì và tại sao nó lại quan trọng?Lỗi act()
xuất hiện khi bạn thực hiện các cập nhật trạng thái (state) bên ngoài phạm vi của một hành động (action) được RTL theo dõi. act()
đóng vai trò như một ranh giới, đảm bảo rằng tất cả các cập nhật liên quan đến một tương tác người dùng hoặc một hành động nào đó đều được xử lý hoàn tất trước khi bạn thực hiện các kiểm tra (assertion). Điều này giúp test của bạn phản ánh chính xác trải nghiệm của người dùng thực tế và tránh các lỗi không mong muốn.
React yêu cầu bạn khai báo khi nào một cập nhật trạng thái được mong đợi trong quá trình test. Điều này có vẻ phiền toái, nhưng nó thực sự hữu ích. Nó nhắc nhở bạn rằng có thể bạn đã bỏ quên một chuỗi các sự kiện và cập nhật được kích hoạt bởi test của bạn - và do đó sẽ được tính là đã được kiểm tra - nhưng lại không được mong đợi và do đó có thể không được xác minh đầy đủ.
act()
act()
hoạt động như thế nào?Hãy tưởng tượng bạn có một component hiển thị dữ liệu từ một API. Khi component được mount, nó sẽ gọi API để lấy dữ liệu. Nếu bạn không bọc thao tác này trong act()
, RTL sẽ không biết rằng component đang thực hiện một cập nhật trạng thái. Khi bạn thực hiện các kiểm tra, chúng có thể không phản ánh trạng thái cuối cùng của component, dẫn đến các kết quả sai lệch. act()
đảm bảo rằng tất cả các cập nhật trạng thái liên quan đến việc gọi API đều được xử lý trước khi bạn kiểm tra component.
act()
?Bạn cần sử dụng act()
khi bạn thực hiện bất kỳ thao tác nào có thể dẫn đến cập nhật trạng thái bên ngoài callstack của React, chẳng hạn như:
setTimeout
hoặc setInterval
act()
RTL cung cấp các tiện ích bất đồng bộ như waitFor
và findBy*
, được tự động bọc trong act()
. Sử dụng chúng để chờ đợi các cập nhật trạng thái hoàn tất trước khi thực hiện các kiểm tra.
Ví dụ:
await waitFor(() => {
expect(screen.getByText('Dữ liệu đã tải')).toBeInTheDocument();
});
act()
Nếu bạn thực hiện các thao tác bất đồng bộ trực tiếp, hãy bọc chúng trong act()
.
Ví dụ:
await act(async () => {
await fetchData();
});
expect(screen.getByText('Dữ liệu đã tải')).toBeInTheDocument();
Đôi khi, lỗi act()
chỉ ra rằng có một cập nhật trạng thái xảy ra mà bạn chưa lường trước. Trong trường hợp này, bạn nên thêm một kiểm tra để chờ đợi cập nhật trạng thái đó hoàn tất.
Ví dụ:
await waitForElementToBeRemoved(() => screen.getByText('Đang tải...'));
expect(screen.getByText('Dữ liệu đã tải')).toBeInTheDocument();
Giả sử bạn có một component hiển thị danh sách sản phẩm từ một API. Khi component được mount, nó sẽ gọi API để lấy dữ liệu và cập nhật trạng thái. Bạn có thể viết test như sau:
test('Hiển thị danh sách sản phẩm', async () => {
mockApi.get.mockResolvedValueOnce({ data: [{ id: 1, name: 'Sản phẩm 1' }] });
render( );
await waitFor(() => {
expect(screen.getByText('Sản phẩm 1')).toBeInTheDocument();
});
});
Ở đây, chúng ta sử dụng waitFor
để chờ đợi component hoàn tất việc tải dữ liệu và hiển thị sản phẩm.
setTimeout
để hiển thị thông báoGiả sử bạn có một component sử dụng setTimeout
để hiển thị thông báo sau một khoảng thời gian nhất định. Bạn có thể viết test như sau:
test('Hiển thị thông báo sau 2 giây', async () => {
jest.useFakeTimers();
render( );
act(() => {
jest.advanceTimersByTime(2000);
});
await waitFor(() => {
expect(screen.getByText('Thông báo')).toBeInTheDocument();
});
jest.useRealTimers();
});
Ở đây, chúng ta sử dụng act
để bọc việc gọi jest.advanceTimersByTime
, đảm bảo rằng RTL biết rằng component đang thực hiện một cập nhật trạng thái do setTimeout
.
Lỗi act()
trong React Testing Library có thể gây khó chịu, nhưng khi bạn hiểu rõ nguyên nhân và cách khắc phục, bạn có thể viết test một cách hiệu quả và tự tin hơn. Hãy nhớ rằng act()
là một công cụ hữu ích để đảm bảo rằng test của bạn phản ánh chính xác trải nghiệm của người dùng thực tế và giúp bạn phát hiện các lỗi tiềm ẩn trong ứng dụng của mình. Hãy luôn ưu tiên sử dụng các tiện ích bất đồng bộ của RTL và bọc các hành động bên ngoài callstack của React bằng act()
khi cần thiết.
Bài viết liên quan