首页 > 解决方案 > 在基于 Material-UI 的组件中模拟道具 - Jest 和 React-Testing-Library

问题描述

我无法以任何方式模拟 Material-UI 中的 Switch 组件。我应该如何正确模拟组件的道具?

我测试了函数的逻辑并且它有效。手动它也可以。但是我无法通过快照触发 DOM 树中的任何更改;甚至无法将标签从“深色模式”更改为“浅色模式”。

单元测试所有工作;使用 fireEvent.change 进行快照测试,但更改不会出现在快照上。在代码中指出失败的地方。我应该如何正确模拟它?

测试

import React from 'react';
import { render, cleanup, fireEvent, screen } from '@testing-library/react';
import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom';
import userEvent from '@testing-library/user-event';
import Component from '../index';
import store from '../../../@state/createStore';
import '@testing-library/jest-dom/extend-expect';
import { GtagService, GtagServiceInterface } from '../../../../shared/services/gtag-service/index';

import SENSORS_TABLE_CONSTANTS from '../../../../pages/dashboard-page/components/sensors-table/constants';
import GTAG_EVENTS, { GtagEvent } from '../../../../shared/gtag/constants';

// BASIC UNIT TESTS FOR THE TOGGLE METHODS, all work here

afterEach(cleanup);

describe('Top Bar Switch: methods and behaviour:', () => {
  let service: GtagServiceInterface;
  let sendEventMockImplementation;

  describe('when behaviour tracking is enabled', () => {
    beforeEach(() => {
      service = new GtagService((...args) => {}, true, SENSORS_TABLE_CONSTANTS.SENSORS_TABLE_COLUMNS);
      sendEventMockImplementation = jest.spyOn(service, 'sendEvent').mockImplementation(() => true);
    });

    describe('method: darkModeToggle', () => {
      it('passes GTAG_EVENTS.HEADER.LIGHT_MODE event to sendEvent method when DARK_MODE enabled', () => {
        service.darkModeToggle(true);
        expect(sendEventMockImplementation).toHaveBeenCalled();
        expect(sendEventMockImplementation).toHaveBeenCalledWith(GTAG_EVENTS.HEADER.LIGHT_MODE);
      });
    });

    it('Should pass the correct objects props once the dark mode IS toggled', () => {
      service.darkModeToggle(true);
      expect(sendEventMockImplementation).toHaveBeenCalledWith({ ACTION: 'Click', CATEGORY: 'Header', LABEL: 'Light Mode', VALUE: 0 });
      expect(sendEventMockImplementation).toHaveBeenCalledWith(GTAG_EVENTS.HEADER.LIGHT_MODE);
    });

    it('Should pass the correct objects props once the dark mode IS NOT toggled', () => {
      service.darkModeToggle(false);
      expect(sendEventMockImplementation).toHaveBeenCalledWith({ ACTION: 'Click', CATEGORY: 'Header', LABEL: 'Dark Mode', VALUE: 0 });
      expect(sendEventMockImplementation).not.toHaveBeenCalledWith(GTAG_EVENTS.HEADER.LIGHT_MODE);
    });
  });

  // SNAPSHOT TESTS - snapshots stay the same, nothing changes even if i try to interract with the app
  describe('Switch tests:', () => {
    let isDarkModeOn;

    const WrappedComponent = (isDarkModeOn: boolean) =>
      render(
        <Provider store={store}>
          <Router>
            <Component isDarkModeOn={isDarkModeOn} />
          </Router>
        </Provider>,
      );

    it('Should create a snapshot', () => {
      const { asFragment } = WrappedComponent((isDarkModeOn = false));
      expect(asFragment()).toMatchSnapshot();
    });

    it('Should create a switch snapshot', () => {
      const { getByRole, asFragment, getByTestId } = WrappedComponent((isDarkModeOn = false));
      const testswitch = getByTestId('switch');

      expect(testswitch).toMatchSnapshot();
    });

    it('Should change the switch', () => {
      const { getByRole, asFragment, getByTestId } = WrappedComponent((isDarkModeOn = false));
      const label = getByTestId('label');

      fireEvent.change(getByRole('checkbox'), { target: { checked: 'true' } });

      // event fired, target checked property correct, but not visible on the snapshot

      expect(getByRole('checkbox')).toHaveProperty('checked', true);
      // test below fails
      expect(label.textContent).toContain('TO LIGHT MODE');

      expect(asFragment()).toMatchSnapshot();
    });

    it('Should NOT change the switch', () => {
      const { getByRole, asFragment, getByTestId } = WrappedComponent((isDarkModeOn = false));
      const testswitch = getByTestId('switch');

      fireEvent.change(getByRole('checkbox'), { target: { checked: '' } });

      // Event fired, target checked property correct, but not visible on the snapshot

      expect(getByRole('checkbox')).toHaveProperty('checked', false);
      expect(asFragment()).toMatchSnapshot();
    });

    it('Should call gtag Send Event (but idk why it doesnt change the label)', () => {
      const { getByRole, asFragment, getByTestId } = WrappedComponent((isDarkModeOn = false));
      const label = getByTestId('label');

      service.darkModeToggle(true);

      // Methods work correctly, correct gtag events are called, but doesnt change the label in the Typography component

      expect(sendEventMockImplementation).toHaveBeenCalledWith({ ACTION: 'Click', CATEGORY: 'Header', LABEL: 'Light Mode', VALUE: 0 });
      expect(sendEventMockImplementation).toHaveBeenCalledWith(GTAG_EVENTS.HEADER.LIGHT_MODE);
      // expect(label.textContent).toContain('TO LIGHT MODE');

      expect(asFragment()).toMatchSnapshot();
    });
  });
});

零件:

import FormControlLabel from '@material-ui/core/FormControlLabel';
import FormGroup from '@material-ui/core/FormGroup';
import Switch from '@material-ui/core/Switch';
import Typography from '@material-ui/core/Typography';
import { ClassNameMap } from '@material-ui/styles';
import React, { FC } from 'react';
import { ActionCreator } from 'redux';
import { GtagServiceInterface } from '../../../shared/services/gtag-service';
import { TOGGLE } from '../../@state/@dark-mode/dark-mode-action-annotations';

const Component: FC<Props> = ({ classes, gtagService, isDarkModeOn, darkModeToggle }) => (
  <FormGroup>
    <FormControlLabel
      control={
        <Switch
          data-testid="switch"
          checked={isDarkModeOn}
          onChange={() => {
            gtagService.darkModeToggle(isDarkModeOn);
            darkModeToggle();
          }}
        />
      }
      label={
        <Typography variant="button" className={classes.label} data-testid="label">
          {isDarkModeOn ? 'TO LIGHT MODE' : 'TO DARK MODE'}
        </Typography>
      }
      labelPlacement="start"
    />
  </FormGroup>
);

interface Props {
  classes: Partial<ClassNameMap>;
  gtagService: GtagServiceInterface;
  isDarkModeOn: boolean;
  darkModeToggle: ActionCreator<TOGGLE>;
}

export default Component;

标签: reactjsunit-testingjestjsmaterial-uireact-testing-library

解决方案


推荐阅读