测试去抖函数 React - React-testing-library

Testing debounced function React - React-testing-library

我有以下组件

import React, { useState, useEffect } from 'react';
import { FiSearch } from 'react-icons/fi';
import { useProducts } from '../../hooks';

export default function SearchBar() {
  const [query, setQuery] = useState('');
  const [debounced, setDebounced] = useState('');

  useEffect(() => {
    const timeout = setTimeout(() => {
      setDebounced(query);
    }, 300);
    return () => {
      clearTimeout(timeout);
    };
  }, [query]);

  const handleChange = (e) => {
    e.preventDefault();
    setQuery(e.target.value);
  };

  useProducts(debounced);

  return (
    <div className="search-form">
      <FiSearch className="search-form__icon" />
      <input
        type="text"
        className="search-form__input"
        placeholder="Search for brands or shoes..."
        onChange={handleChange}
        value={query}
      />
    </div>
  );
}

我想测试输入后 300 毫秒后是否真的调用了 useProducts(debounced);。遗憾的是,我不知道从哪里开始,希望有人能提供帮助。

我建议使用 @testing-library/user-event<input> 元素上输入,因为它更接近于模拟用户的触发事件。

至于测试,您应该模拟 useProducts 实现以断言它被正确调用。

import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import SearchBar from '<path-to-search-bar-component>'; // Update this accordingly
import * as hooks from '<path-to-hooks-file>'; // Update this accordingly

describe('Test <SearchBar />', () => {
    it('should call useProducts after 300ms after typing', async () => {
        const mockHook = jest.fn();
        jest.spyOn(hooks, 'useProducts').mockImplementation(mockHook);
        render(<SearchBar />);
        const input = screen.getByPlaceholderText('Search for brands or shoes...');
        userEvent.type(input, 'A');
        expect(mockHook).not.toHaveBeenCalledWith('A'); // It won't be called immediately
        await waitFor(() => expect(mockHook).toHaveBeenCalledWith('A'), { timeout: 350 }); // But will get called within 350ms
        jest.clearAllMocks();
    });
});