我可以(而且我应该)断言组件使用 Enzyme 的 shallow() 呈现哪些 HTML 元素吗?

Can I, (and should I), make assertions about what HTML elements a component renders using Enzyme's shallow()?

问题:

我正在为名为 <BaseEdit /> 的 React 组件编写单元测试。为了测试该组件是否有效,我想断言它将呈现一个 HTML 元素 <input/>,并且我想使用 shallow() 而不是 mount() 来实现。

以下测试用例有效:

const baseEditWrapper = mount(<BaseEdit />)
const inputElement = baseEditWrapper.find('input')
assert(inputElement.exists())
assert.strictEqual(inputElement.prop('type'), 'text')

但是,如果我将 mount() 更改为 shallow(),则测试失败。它失败了,因为 baseEditWrapper.find('input') returns 一个 empty/stub/nonexistant ShallowWrapper 对象。


底层HTML:

<BaseEdit /> 组件在使用 Enzyme 和 JSDom 安装时会创建以下 DOM 个元素。

<div class="MuiFormControl-root MuiTextField-root WithStyles(ForwardRef(TextField))-root-27 WithStyles(ForwardRef(TextField))-root-96" style="width:120px">
  <div class="MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-formControl MuiInput-formControl">
    <input type="text" aria-invalid="false" class="MuiInputBase-input MuiInput-input"/>
  </div>
</div>

额外详情:

shallow() 的文档是 here

问题 表明使用 shallow() 时支持通过选择器查找。

下面的测试用例证明 shallow 确实渲染了多层 HTML 元素,并作为我的问题的解决方案。

const shallowWrapper = shallow(<BaseEdit />)
assert(shallowWrapper.html().includes('<input')
assert(shallowWrapper.html().includes('type=\"text\"'))

但是,这样的解决方案似乎很老套,我宁愿让我的解决方案与 Enzyme 的 ShallowWrapper 界面的使用保持一致。

您应该可以使用 .dive() 找到输入:

const input = wrapper.find(TextField).dive().find('input')

如果 input 嵌套在多个 React 组件中,您甚至可能需要多次潜水:

// This is a little contrived, but something like this:
const InnerTextField = () => <input />;
const TextField = () => <InnerTextField />;
const BaseEdit = () => <TextField />;

// You would need to do this to find the input:
const input = wrapper.find(TextField).dive().dive().find('input');

你还问过你是否应该使用shallow:

如果你想对基础 HTML 进行断言(例如,你想确保 BaseEdit 总是呈现 input),你最好使用mount,除非有理由不这样做。

shallow 当您想测试组件树的单层时很有用。看起来您正在使用 Material UI,因此可能的测试可能是检查 BaseEdit 是否将道具正确传递给 TextField

it('passes the required prop to the underlying component', () => {
  const wrapper = shallow(<BaseEdit required />);
  expect(wrapper.find(TextEdit).props().required).toBe(true);
  wrapper.setProps({ required: false });
  expect(wrapper.find(TextEdit).props().required).toBe(false);
})