Mục lục

Testing Custom Hooks: renderHook & act

Cách test logic tách biệt trong Custom Hooks. Sử dụng renderHook để test hook cô lập. Khái niệm 'act' để wrap các state updates.

Custom Hooks thường chứa logic nghiệp vụ phức tạp. Test chúng độc lập giúp bạn tự tin tái sử dụng. Thư viện RTL cung cấp renderHook cho việc này.

1. Ví dụ: useCounter

ts:
import { useState, useCallback } from 'react';

export function useCounter(initialValue = 0) {
  const [count, setCount] = useState(initialValue);
  const increment = useCallback(() => setCount((x) => x + 1), []);
  return { count, increment };
}

2. Viết Test

ts:
import { renderHook, act } from '@testing-library/react';
import { useCounter } from './useCounter';

describe('useCounter', () => {
  it('should initialize with default value', () => {
    const { result } = renderHook(() => useCounter());
    // result.current là giá trị trả về mới nhất của hook
    expect(result.current.count).toBe(0);
  });

  it('should increment', () => {
    const { result } = renderHook(() => useCounter(10));
    
    // ⚠️ QUAN TRỌNG: Mọi hành động update state phải bọc trong act()
    act(() => {
      result.current.increment();
    });

    expect(result.current.count).toBe(11);
  });
});

3. Tại sao phải dùng act?

React đảm bảo mọi update state được hoàn tất và DOM được cập nhật trước khi chạy dòng lệnh tiếp theo. Khi test, môi trường giả lập không có cơ chế loop này tự động. act giúp giả lập việc "xả" các update vào DOM/State. Nếu không dùng act, bạn sẽ gặp warning đỏ lòm console: "An update to Component inside a test was not wrapped in act...".

Nên nhớ:

  • userEvent của RTL đã tự bọc act bên trong.
  • renderHook update state thủ công thì BẮT BUỘC dùng act.

4. Test Hook có Async (API)

ts:
it('should load user data', async () => {
  const { result } = renderHook(() => useUser('123'));
  
  // Chờ cho đến khi loading = false
  await waitFor(() => {
    expect(result.current.isLoading).toBe(false);
  });

  expect(result.current.data).toEqual({ name: 'John' });
});
Quảng cáo
mdhorizontal