Jest报错:function must be a mock or spy,测试App动作时断言未触发
Hey there! Let's break down what's going on with your test case issue and fix it step by step.
First: Why the last expect isn't running
The most common culprit here is unhandled asynchronous code in your action. If your action uses promises, async/await, or callbacks, your test might finish executing before the action completes—so the final expect never gets triggered.
Fix for async actions:
Make sure your test waits for the action to finish. Here are a few ways to do this:
- Use
async/awaitif your action returns a promise:test('should trigger final assertion', async () => { const dispatch = jest.fn(); // Wait for the async action to resolve await yourAsyncAction()(dispatch); // Now this expect will run after the action completes expect(dispatch).toHaveBeenCalledWith({ type: 'FINAL_ACTION' }); }); - Use a
donecallback for callback-based async logic:test('should trigger final assertion', (done) => { const dispatch = jest.fn(); yourCallbackAction((result) => { expect(dispatch).toHaveBeenCalledWith({ type: 'FINAL_ACTION', result }); done(); // Signal Jest the test is complete }); });
Second: The "jest function must be a mock or spy" error
This happens when you try to use Jest's mock-specific matchers (like toHaveBeenCalled(), toHaveBeenCalledWith()) on a regular function instead of a Jest mock/spy.
Fix for mock/spy requirements:
You need to replace the function you're asserting on with a Jest mock. Here's how:
- Create a mock function with
jest.fn():// Instead of a regular function: // const myFunction = () => {}; // Use a mock: const myFunction = jest.fn(); - If the function comes from an external module, mock the entire module with
jest.mock():// Mock the api module that your action uses jest.mock('../api'); import { fetchData } from '../api'; test('should call fetchData', async () => { const dispatch = jest.fn(); // Set up mock return value fetchData.mockResolvedValue({ data: 'test' }); await yourAction()(dispatch); // Now this assertion is valid because fetchData is a mock expect(fetchData).toHaveBeenCalled(); });
Quick sanity checks
- Double-check that your mock function is actually being used by your action (not a different instance of the function).
- Look for uncaught errors in your action—if an error is thrown before reaching the final logic, the test will terminate early without running the last
expect. You can wrap the action call in atry/catchto debug this:test('debug action errors', async () => { try { await yourAction()(dispatch); expect(...); } catch (err) { console.error('Action threw an error:', err); throw err; // Re-throw to let Jest report the error } });
内容的提问来源于stack exchange,提问作者FranWalker

