如何仅模拟自定义挂钩返回的一个值?
How do I mock only one value returned by a custom hook?
我有一个使用自定义挂钩的简单 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'],
}),
}))
但是 addTodo
和 removeTodo
方法是未定义的。另一方面,当我用 jest.fn()
嘲笑它们时,它们不再工作了。
有什么方法可以仅模拟 todos
并保持其他方法正常工作?
您可以创建一个模拟 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
我有一个使用自定义挂钩的简单 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'],
}),
}))
但是 addTodo
和 removeTodo
方法是未定义的。另一方面,当我用 jest.fn()
嘲笑它们时,它们不再工作了。
有什么方法可以仅模拟 todos
并保持其他方法正常工作?
您可以创建一个模拟 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