You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用React Test Utils测试Select onChange时history.push未触发

Fixing React Router History Push Test Failure for Select Component

Let's break down why your test isn't passing and fix it step by step:

The Core Problem

You created a standalone createMemoryHistory() instance in your test, but the <ComponentList> component uses useHistory() to get the history object provided by the <MemoryRouter> component. These are two completely separate instances—so your mock history.push never gets called because the component is using a different history object entirely.

Solution 1: Pass Your Mocked History to the Router

Instead of using <MemoryRouter>, use the base <Router> component and pass your mocked history instance to it. This ensures the component uses the exact same history object you're mocking:

import { Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import { render, act, Simulate } from 'react-dom/test-utils';
import ComponentList from './ComponentList';

it('should call history.push on change component list selected value', () => {
  // Create and mock the history instance
  const history = createMemoryHistory();
  history.push = jest.fn();

  // Render the component with our custom Router + mocked history
  act(() => {
    render(
      <Router history={history}>
        <ComponentList />
      </Router>, 
      container
    );
  });

  const selectElement = document.getElementById('components-select');
  
  // Trigger the change event (not select!) for the dropdown
  act(() => {
    Simulate.change(selectElement, { target: { value: 'ui-textarea' } });
  });

  // Verify the state and mock call
  expect(selectElement.value).toBe('ui-textarea');
  expect(selectElement.options[1].selected).toBeTruthy();
  // Bonus: Verify the exact path that was pushed
  expect(history.push).toHaveBeenCalledWith('/component-list/ui-textarea');
});

Solution 2: Mock the useHistory Hook Directly

If you prefer not to swap out the router component, you can mock the useHistory hook itself to return your mocked push function:

import { useHistory } from 'react-router-dom';
import { render, act, Simulate } from 'react-dom/test-utils';
import ComponentList from './ComponentList';

// Mock react-router-dom's useHistory hook
jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom'), // Keep other exports intact
  useHistory: jest.fn(),
}));

it('should call history.push on change component list selected value', () => {
  const mockPush = jest.fn();
  // Make useHistory return our mocked push function
  useHistory.mockReturnValue({ push: mockPush });

  act(() => {
    render(
      <MemoryRouter>
        <ComponentList />
      </MemoryRouter>, 
      container
    );
  });

  const selectElement = document.getElementById('components-select');
  
  act(() => {
    Simulate.change(selectElement, { target: { value: 'ui-textarea' } });
  });

  expect(selectElement.value).toBe('ui-textarea');
  expect(selectElement.options[1].selected).toBeTruthy();
  expect(mockPush).toHaveBeenCalledWith('/component-list/ui-textarea');
});

Key Notes to Remember

  • Use Simulate.change for dropdowns: React maps the <select> element's onChange handler to the change synthetic event, not the select event. Using Simulate.select won't trigger your handler.
  • Verify exact arguments: Checking that history.push was called with the correct path (/component-list/ui-textarea) makes your test more robust than just checking if it was called.

内容的提问来源于stack exchange,提问作者Jean

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:55:16