使用 @testing-library/react 测试材质 ui 滑块

int*_*der 11 testing reactjs jestjs material-ui react-testing-library

您好我想测试与材料的UI创建一个Slider组件,但我不能让我的测试通过。我想使用fireEventwith测试值的变化@testing-library/react。我一直在关注这篇文章以正确查询 DOM,但我无法获得正确的 DOM 节点。

提前致谢。

<Slider /> 成分

// @format
// @flow

import * as React from "react";
import styled from "styled-components";
import { Slider as MaterialUISlider } from "@material-ui/core";
import { withStyles, makeStyles } from "@material-ui/core/styles";
import { priceRange } from "../../../domain/Search/PriceRange/priceRange";

const Wrapper = styled.div`
  width: 93%;
  display: inline-block;
  margin-left: 0.5em;
  margin-right: 0.5em;
  margin-bottom: 0.5em;
`;

// ommited code pertaining props and styles for simplicity

function Slider(props: SliderProps) {
  const initialState = [1, 100];
  const [value, setValue] = React.useState(initialState);

  function onHandleChangeCommitted(e, latestValue) {
    e.preventDefault();
    const { onUpdate } = props;
    const newPriceRange = priceRange(latestValue);
    onUpdate(newPriceRange);
  }

  function onHandleChange(e, newValue) {
    e.preventDefault();
    setValue(newValue);
  }

  return (
    <Wrapper
      aria-label="range-slider"
    >
      <SliderWithStyles
        aria-labelledby="range-slider"
        defaultValue={initialState}
        // getAriaLabel={index =>
        //   index === 0 ? "Minimum Price" : "Maximum Price"
        // }
        getAriaValueText={valueText}
        onChange={onHandleChange}
        onChangeCommitted={onHandleChangeCommitted}
        valueLabelDisplay="auto"
        value={value}
      />
    </Wrapper>
  );
}

export default Slider;
Run Code Online (Sandbox Code Playgroud)

Slider.test.js

// @flow

import React from "react";
import { cleanup,
  render,
  getAllByAltText,
  fireEvent,
  waitForElement } from "@testing-library/react";
import "@testing-library/jest-dom/extend-expect";

import Slider from "../Slider";


afterEach(cleanup);

describe("<Slider /> specs", () => {

  // [NOTE]: Works, but maybe a better way to do it ?
  xdescribe("<Slider /> component aria-label", () => {

    it("renders without crashing", () => {
      const { container } = render(<Slider />);
      expect(container.firstChild).toBeInTheDocument(); 
    });
  });

  // [ASK]: How to test the event handlers with fireEvent.
  describe("<Slider /> props", () => {

    it("display a initial min value of '1'", () => {
      const renderResult = render(<Slider />);
      // TODO
    });

    it("display a initial max value of '100'", () => {
      const renderResult = render(<Slider />);
      // TODO
    });

    xit("display to values via the onHandleChangeCommitted event when dragging stop", () => {
      const renderResult = render(<Slider />);
      console.log(renderResult)
      // fireEvent.change(renderResult.getByText("1"))
      // expect(onChange).toHaveBeenCalled(0);
    });

    // [NOTE]: Does not work, returns undefined
    xit("display to values via the onHandleChange event when dragging stop", () => {
      const renderResult = render(<Slider />);

      console.log(renderResult.container);
      
      const spanNodeWithAriaAttribute = renderResult.container.firstChild.getElementsByTagName("span")[0].getAttribute('aria-label')
      expect(spanNodeWithAriaAttribute).toBe(/range-slider/)
    });
  });

  // [ASK]: Works, but a snapshot is an overkill a better way of doing this ?
  xdescribe("<Slider /> snapshot", () => {

    it("renders without crashing", () => {
      const { container } = render(<Slider />);
      expect(container.firstChild).toMatchSnapshot();
    });
  });
});
Run Code Online (Sandbox Code Playgroud)

reh*_*001 10

我建议不要为自定义组件编写测试,并相信该组件适用于我们所有的情况。

阅读本文以了解更多详细信息。他们提到了如何为包装react-select.

我遵循类似的方法并为我的第三方滑块组件编写了一个模拟。

setupTests.js

jest.mock('@material-ui/core/Slider', () => (props) => {
  const { id, name, min, max, onChange, testid } = props;
  return (
    <input
      data-testid={testid}
      type="range"
      id={id}
      name={name}
      min={min}
      max={max}
      onChange={(event) => onChange(event.target.value)}
    />
  );
});
Run Code Online (Sandbox Code Playgroud)

通过这个模拟,您可以简单地在测试中触发更改事件,如下所示:

fireEvent.change(getByTestId(`slider`), { target: { value: 25 } });
Run Code Online (Sandbox Code Playgroud)

确保将正确的属性testid作为 prop 传递给您的SliderWithStyles组件

  • `fireEvent.change(getByTestId('slider'), { target: { value: 25 } });` 只是这个更改。感谢 bdw 的这个想法。比上述解决方案干净得多 (2认同)

wat*_*ata 5

经过几个小时的战斗后,我能够解决与测试 MUI 滑块相关的案例

这实际上取决于您需要如何测试您的,在我的情况下,我必须检查使用marks滑块道具单击标记后标签文本内容是否已更改。

问题

1)slider组件根据元素计算返回值getBoundingClientRectMouseEvent

2) 如何查询slider和触发事件。

3)JSDOM对读取元素实际高度和宽度的限制导致问题1

解决方案

1)模拟getBoundingClientRect也应该解决问题3

2)将测试ID添加到滑块并使用使用 fireEvent.mouseDown(contaner, {....})

const sliderLabel = screen.getByText("Default text that the user should see")

// add data-testid to slider
const sliderInput = screen.getByTestId("slider")

// mock the getBoundingClientRect
    sliderInput.getBoundingClientRect = jest.fn(() => {
      return {
        bottom: 286.22918701171875,
        height: 28,
        left: 19.572917938232422,
        right: 583.0937919616699,
        top: 258.22918701171875,
        width: 563.5208740234375,
        x: 19.572917938232422,
        y: 258.22918701171875,
      }
    })

    expect(sliderInput).toBeInTheDocument()

    expect(sliderLabel).toHaveTextContent("Default text that the user should see")
    await fireEvent.mouseDown(sliderInput, { clientX: 162, clientY: 302 })
    expect(sliderLabel).toHaveTextContent(
      "New text that the user should see"
    )

Run Code Online (Sandbox Code Playgroud)