【问题标题】:How do I mock only one value returned by a custom hook?如何仅模拟自定义挂钩返回的一个值?
【发布时间】:2021-11-22 17:39:21
【问题描述】:

我有一个简单的TodoList 组件,它使用自定义挂钩useTodos

import { useState } from 'react'

export const useTodos = (initialTodos = []) => {
  const [todos, setTodos] = useState(initialTodos)

  const addTodo = (value) => {
    const updatedTodos = [...todos, value]
    setTodos(updatedTodos)
  }

  const removeTodo = (index) => {
    const updatedTodos = todos.filter((todo, i) => i !== index)
    setTodos(updatedTodos)
  }

  return { todos, addTodo, removeTodo }
}

我想用React Testing Library 测试组件。

为此,我想模拟钩子返回的初始todos

jest.mock('hooks/useTodos', () => ({
  useTodos: () => ({
    todos: ['Wake up', 'Go to work'],
  }),
}))

但是 addTodoremoveTodo 方法是未定义的。另一方面,当我用jest.fn() 模拟它们时,它们不再起作用了。

有什么方法可以模拟只模拟todos 并保持其他方法正常工作

【问题讨论】:

    标签: javascript reactjs react-hooks jestjs react-testing-library


    【解决方案1】:

    您可以基于真实的useTodos 钩子创建一个模拟的useTodos 钩子,并带有模拟待办事项初始状态。

    hooks.js:

    import { useState } from 'react';
    
    export const useTodos = (initialTodos = []) => {
      const [todos, setTodos] = useState(initialTodos);
    
      const addTodo = (value) => {
        const updatedTodos = [...todos, value];
        setTodos(updatedTodos);
      };
    
      const removeTodo = (index) => {
        const updatedTodos = todos.filter((todo, i) => i !== index);
        setTodos(updatedTodos);
      };
    
      return { todos, addTodo, removeTodo };
    };
    

    index.jsx:

    import React from 'react';
    import { useTodos } from './hooks';
    
    export default function MyComponent() {
      const { todos, addTodo, removeTodo } = useTodos();
      return (
        <div>
          {todos.map((todo, i) => (
            <p key={i}>
              {todo}
              <button type="button" onClick={() => removeTodo(i)}>
                Remove
              </button>
            </p>
          ))}
          <button type="button" onClick={() => addTodo('have a drink')}>
            Add
          </button>
        </div>
      );
    }
    

    index.test.jsx:

    import React from 'react';
    import { render, screen, fireEvent } from '@testing-library/react';
    import '@testing-library/jest-dom/extend-expect';
    import MyComponent from '.';
    
    jest.mock('./hooks', () => {
      const { useTodos } = jest.requireActual('./hooks');
      return {
        useTodos: () => useTodos(['Wake up', 'Go to work']),
      };
    });
    
    describe('69399677', () => {
      test('should render todos', () => {
        render(<MyComponent />);
        expect(screen.getByText(/Wake up/)).toBeInTheDocument();
        expect(screen.getByText(/Go to work/)).toBeInTheDocument();
      });
      test('should add todo', () => {
        render(<MyComponent />);
        fireEvent.click(screen.getByText(/Add/));
        expect(screen.getByText(/have a drink/)).toBeInTheDocument();
      });
      test('should remove todo', () => {
        render(<MyComponent />);
        fireEvent.click(screen.getByText(/Go to work/).querySelector('button'));
        expect(screen.queryByText(/Go to work/)).not.toBeInTheDocument();
      });
    });
    

    测试结果:

     PASS  examples/69399677/index.test.jsx (8.788 s)
      69399677
        ✓ should render todos (26 ms)
        ✓ should add todo (10 ms)
        ✓ should remove todo (4 ms)
    
    -----------|---------|----------|---------|---------|-------------------
    File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    -----------|---------|----------|---------|---------|-------------------
    All files  |     100 |        0 |     100 |     100 |                   
     hooks.js  |     100 |        0 |     100 |     100 | 3                 
     index.jsx |     100 |      100 |     100 |     100 |                   
    -----------|---------|----------|---------|---------|-------------------
    Test Suites: 1 passed, 1 total
    Tests:       3 passed, 3 total
    Snapshots:   0 total
    Time:        9.406 s
    

    【讨论】:

      猜你喜欢
      • 2022-01-27
      • 2020-06-01
      • 1970-01-01
      • 2020-04-19
      • 1970-01-01
      • 2021-07-17
      • 1970-01-01
      • 1970-01-01
      • 2020-08-15
      相关资源
      最近更新 更多