首页 > 解决方案 > React 测试库:无法选择 Material UI DatePicker 按钮

问题描述

我有一个 React 组件,它是 Material UI 的 KeyboardDatePicker 的薄包装器。我正在尝试使用 React 测试库为其编写测试。我遇到的问题是我无法选择用于打开日历的按钮。我尝试了几个不同的查询。我还使用 debug() 来确认按钮确实正在呈现。

这是组件:

import React from 'react'
import MomentUtils from '@date-io/moment'
import {
  KeyboardDatePicker,
  MuiPickersUtilsProvider,
} from '@material-ui/pickers'
import { StyledDatePickerWrap } from './style'

const DatePicker = (props) => {
  const {
    handleDateChange,
    label,
    selectedDate,
    disableFuture,
    disablePast,
    variant,
  } = props

  return (
    <StyledDatePickerWrap>
      <MuiPickersUtilsProvider utils={MomentUtils}>
        <KeyboardDatePicker
          disableFuture={disableFuture}
          disablePast={disablePast}
          label={label}
          value={selectedDate}
          variant={variant}
          onChange={handleDateChange}
          InputProps={{
            disableUnderline: true,
          }}
          KeyboardButtonProps={{
            'aria-label': 'change date',
            'data-testid': 'changeDate',
          }}
        />
      </MuiPickersUtilsProvider>
    </StyledDatePickerWrap>
  )
}

DatePicker.defaultProps = {
  variant: 'dialog',
  disableFuture: true,
  disablePast: false,
}

export default DatePicker

这是测试规范:

import React from 'react'
import { render, fireEvent } from 'Utils/test-utils'
import moment from 'moment'
import DatePicker from './DatePicker'

describe('DatePicker', () => {
  const handleDateChange = jest.fn()
  const selectedDate = moment('2020-05-21T19:25:00.000Z')

  const props = {
    handleDateChange,
    selectedDate,
  }

  const { debug, queryByDisplayValue, getByTestId, queryByText } = render(
    <DatePicker {...props} />
  )

  debug()

  it('should render the correct Date', () => {
    expect(queryByDisplayValue(/May 21st/)).not.toBeNull()
  })

  it('should render the "change date" button', () => {
    // why can't I select this button?
    // I've also tried by  getByLabelText('change date') and even container.querySelector('button')
    const button = getByTestId('changeDate')
    fireEvent.click(button)
    expect(queryByText('Thu, May 21')).not.toBeNull()
  })
})

这是测试错误:

 ● DatePicker › should render the "change date" button

    TestingLibraryElementError: Unable to find an element by: [data-testid="changeDate"]

    <body />

      26 |     // why can't I select this button?
      27 |     // I've also tried by  getByLabelText('change date') and even container.querySelector('button')
    > 28 |     const button = getByTestId('changeDate')
         |                    ^
      29 |     fireEvent.click(button)
      30 |     expect(queryByText('Thu, May 21')).not.toBeNull()
      31 |   })

      at Object.getElementError (node_modules/@testing-library/dom/dist/config.js:32:19)
      at node_modules/@testing-library/dom/dist/query-helpers.js:76:38
      at getByTestId (node_modules/@testing-library/dom/dist/query-helpers.js:59:17)
      at Object.<anonymous> (src/Components/CaseManagement/DatePicker/DatePicker.spec.js:28:20)

这是调试调用的控制台输出:

 ● Console

    console.log node_modules/@testing-library/react/dist/pure.js:94
      <body>
        <div>
          <div
            class="sc-bdVaJa eYAdNP"
          >
            <div
              class="MuiFormControl-root MuiTextField-root"
            >
              <div
                class="MuiInputBase-root MuiInput-root MuiInputBase-formControl MuiInput-formControl MuiInputBase-adornedEnd"
              >
                <input
                  aria-invalid="false"
                  class="MuiInputBase-input MuiInput-input MuiInputBase-inputAdornedEnd"
                  type="text"
                  value="May 21st"
                />
                <div
                  class="MuiInputAdornment-root MuiInputAdornment-positionEnd"
                >
                  <button
                    aria-label="change date"
                    class="MuiButtonBase-root MuiIconButton-root"
                    data-testid="changeDate"
                    tabindex="0"
                    type="button"
                  >
                    <span
                      class="MuiIconButton-label"
                    >
                      <svg
                        aria-hidden="true"
                        class="MuiSvgIcon-root"
                        focusable="false"
                        viewBox="0 0 24 24"
                      >
                        <path
                          d="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2h-1V1h-2zm3 18H5V8h14v11z"
                        />
                        <path
                          d="M0 0h24v24H0z"
                          fill="none"
                        />
                      </svg>
                    </span>
                    <span
                      class="MuiTouchRipple-root"
                    />
                  </button>
                </div>
              </div>

            </div>
          </div>
        </div>
      </body>

请注意以下关于debug()输出的内容:

  1. 该按钮确实出现并且它同时具有 adata-testid和 a aria-label,它们都没有用作选择器

  2. 请注意HTML 标记上>和中的换行符的奇怪格式。/>这正常吗?也许这是更大问题的征兆?

与往常一样,提前感谢您!

标签: reactjsmaterial-uireact-testing-library

解决方案


你可以试试@aquinq 发布的内容。我正在使用与您类似的代码,并且它正在工作:

这是在TypeScript中:我们设置data-testid里面KeyboardButtonProps如下图:

<KeyboardDatePicker
          {...props}
          className={cls(styles.root, props.className)}
          label="Fecha"
          // https://github.com/mui-org/material-ui-pickers/issues/1651#issuecomment-614315006
          autoOk={true}
          variant="inline"
          format="dd/MM/yyyy"
          margin="normal"
          id="date-picker-inline"
          value={selectedDate}
          name={name}
          onChange={handleDateChange}
          disablePast={disablePast}
          disableFuture={disableFuture}
          shouldDisableDate={shouldDisableDate}
          KeyboardButtonProps={{
            "aria-label": "change date",
            ...({ ["data-testid"]: "js-datepicker" } as any),
          }}
          InputLabelProps={{ shrink: true }}
        />

这就是我测试它的方式:

describe("Tests the Anonymous version of the triage", () => {
  it("Happy Path of the Triage will be completed successfully", async () => {
    // The Triage Component has the <KeyboardDatePicker rendered inside it.
    const renderer = await render(<Triage variant="ANONYMOUS" />);
    const calendar = await waitFor(async () => renderer.getByTestId(FECHA));

    await fireEvent.click(calendar);
    // We get the 22nd day of the month:
    const day = await waitFor(async () => renderer.getByText("22"));

    // I'm wrapping 
    await act(async () => {
      await fireEvent.click(day);
      await fireEvent.click(continueBtn);
    });
  });
});

推荐阅读