在 dom-testing-library 或 react-testing-library 中测试输入值的最佳方法

IT技术 reactjs typescript react-testing-library
2021-05-05 14:43:39

测试/ 中<input>元素值的最佳方法是什么dom-testing-libraryreact-testing-library

我采用的方法是通过closest()方法获取原始输入元素本身,然后我可以直接访问value属性:

const input = getByLabelText("Some Label")
expect(input.closest("input").value).toEqual("Some Value")

我希望有一种方法可以做到这一点,而不必直接访问 HTML 属性。这似乎不符合测试库的精神。也许类似于jest-dom toHaveTextContent 匹配匹配器:

const input = getByLabelText("Some Label")
expect(input).toHaveTextContent("Some Value")

更新

根据评论中的要求,这里是一个代码示例,显示了我觉得需要测试输入框中的值的情况。

这是我在我的应用程序中构建的模态组件的简化版本。喜欢,极其简化。这里的整个想法是,基于字符串props,模态打开时输入预先填充了一些文本。用户可以自由编辑此输入并通过按按钮提交。但是,如果用户关闭模态然后重新打开它,我希望将文本重置为该原始字符串props。我为它写了一个测试,因为模式的先前版本没有重置输入值。

我是用 TypeScript 写的,所以每个props的类型都非常清楚。

interface Props {
  onClose: () => void
  isOpen: boolean
  initialValue: string
}

export default function MyModal({ onClose, isOpen, initialValue }) {
  const [inputValue, setInputValue] = useState(initialValue)

  // useEffect does the reset!
  useEffect(() => {
    if (!isOpen) {
      setNameInput(initialValue)
    }
  }, [isOpen, initialValue])

  return (
    <SomeExternalLibraryModal isOpen={isOpen} onClose={onClose}>
      <form>
        <input
          value={inputValue}
          onChange={(e: ChangeEvent<HTMLInputElement>) =>
            setInputValue(e.target.value)
          }
        />
        <button onClick={onClose}>Cancel</button>
      </form>
    </SomeExternalLibraryModal>
  )
}
4个回答

关于这个测试库希望你如何测试,你对你的测试方法持怀疑态度是正确的。这个问题最简单的答案是使用getByDisplayValue查询。它将搜索textarea具有您要查找的值的输入、或选择。例如,以您的组件为例,如果我试图验证它inputValue = 'test',我会像这样搜索

expect(screen.getByDisplayValue('test')).toBeInTheDocument();

这就是您需要做的所有事情。我假设您的测试仅呈现MyModal组件。即使您有多个输入,在测试理念方面也无关紧要。只要getByDisplayValue找到具有该值的任何输入,它就是一个成功的测试。如果您有多个输入并想要测试确切的输入是否具有值,那么您可以深入研究元素以确定它是正确的输入:

注意:你需要jest-dom这个才能工作。

expect(screen.getByDisplayValue('test')).toHaveAttribute('id', 'the-id');

或(没有jest-dom):

expect(screen.getByDisplayValue('test').id).toBe('the-id');

您当然可以搜索您喜欢的任何属性。

测试值的最后一种替代方法是按角色查找输入。这在您的示例中不起作用,除非您添加标签并通过htmlFor属性将其关联到您的输入然后你可以像这样测试它:

expect(screen.getByRole('input', { name: 'the-inputs-id' })).toHaveValue('test');

或(没有jest-dom):

expect(screen.getByRole('input', { name: 'the-inputs-id' }).value).toBe('test');

我认为这是测试值的最佳方法,同时确保正确的输入具有值。我会建议该getByRole方法,但同样,您需要为示例添加一个标签。

您可以使用screen.getByDisplayValue()获取具有显示值的输入元素并将其与您的元素进行比较。

type TestElement = Document | Element | Window | Node

function hasInputValue(e: TestElement, inputValue: string) {
  return screen.getByDisplayValue(inputValue) === e
}

在您的测试中:

const input = screen.getByLabelText("Some Label")

fireEvent.change(input, { target: { value: '123' } })
expect(hasInputValue(input, "123")).toBe(true)

expect(screen.getByLabelText("Name")).toHaveValue("hello"); - 这会让你获得输入的value:)

<label class="label" for="name">
      Name
</label>
<div class="control ">
       <input
          class="input"
          for="name"
          id="name"
          name="name"
          value="hello"
       />
</div>

测试:

userEvent.type(screen.getByLabelText("Name"), "hello")
await waitFor(() => {
   expect(screen.getByLabelText("Name")).toHaveValue("hello");
});

使用测试库有一种非常干净的方法来测试它。

//In describe
  const renderComponent = (searchInputValue, handleSearchInputValue) => {
    const wrapper = render(<yourComponentWithInput
      value={searchInputValue}
      onChange={handleSearchInputValue}
    />);
    return wrapper;
  };


//In test
    const mockHandleSearchInputValue = jest.fn();
    const { getByLabelText } = renderComponent('g', mockHandleSearchInputValue);
    const inputNode = getByLabelText('Search label'); // your  input label
    expect(inputNode.value).toBe('s'); // to test input value
    fireEvent.change(inputNode, { target: { value: 'su' } }); // triggers onChange event
    expect(mockHandleSearchInputValue).toBeCalledWith('su'); // tests if onChange handler is called with proper value