繁体   English   中英

如何通过开玩笑和酶测试框架访问内部的反应组件和模拟api调用?

[英]How to access internal pieces of react component and mock api call with jest & enzyme testing framework?

我正在为一个带有jest和酶的react-redux组件制作一个javascript单元测试套件; 有问题的组件是一个文件上载表单,其中包含一些字段,这些字段根据用户输入和/或服务器响应进行了一些基本样式更改。 Jest和酶都已设置好并且正常工作,我能够成功地编写基本测试。

我想使用jest和酶来模拟用户与这些UI元素(文件输入和文本字段)的交互,但我很难这样做; 我对使用这些测试框架并且对react-redux有一个基本的了解是相当新的,我有点不知所措,以确保正确的部分到位,以便编写有意义的单元测试。

一般情况下:这个单元测试是在事实之后进行的,几个月前我加入了这个使用测试驱动开发技术的项目,我之前没有开发过,所以我将它作为未来开发的示例/模板。

截至目前,单元测试成功地创建了组件(使用酶的mountshallow的mockStore和初始状态)。 我试过做两件事:

  1. 根据jest docs创建一个__mocks__ api,用于不同模块使用的单元测试(一个使用辅助方法进行api调用的redux动作减少器)
  2. 查找/访问表单字段(文件输入和文本区域)以模拟用户交互

我在这两种情况下都没有完全成功,并且有单元测试,涵盖了这些方面,但没有完全集成的方式。

这是我试图进行单元测试的组件的render方法:

render() {
    const { dataset } = this.props;

    let serverResp;
    dataset ? serverResp = dataset.fileUploadResp : null;

    let catFeats = this.state.catFeatures;
    let errorMsg = this.state.errorResp;
    let ordFeatureSelection = "";
    let catFeatureSelection = "";
    let dataPrevTable = this.getDataTablePreview();
    // default to hidden until a file is selected, then display input areas
    let formInputClass = "file-upload-form-hide-inputs";

    // server message to display in popup (or other UI element)
    serverResp ? serverResp = ( <p style={{display: 'block'}}> {JSON.stringify(serverResp)} </p> ) :
                 null;
    // check if file with filename has been selected, if so then use css to show form
    this.state.selectedFile && this.state.selectedFile.name ?
      formInputClass = "file-upload-form-show-inputs" : null;

    return (
      <div>
        <Form inverted>
          <Segment className="file-upload-segment">
            <Input
              className="file-upload-form-text-input"
              type="file"
              label="Select new dataset"
              id="upload_dataset_file_browser_button"
              onChange={this.handleSelectedFile}
            />
            <br/>
            <div
              id="file-upload-form-input-area"
              className={formInputClass}
            >
              <Form.Input
                label="Dependent Column"
                placeholder="class"
                value={this.state.dependentCol ? this.state.dependentCol : ""}
                type="text"
                onChange={this.handleDepColField}
              />
              <Form.Input
                label="Ordinal Features"
              >
                <textarea
                  label="Ordinal Features"
                  placeholder={"{\"ord_feat_1\": [\"MALE\", \"FEMALE\"], \"ord_feat_2\": [\"FIRST\", \"SECOND\", \"THIRD\"]}"}
                  onChange={this.handleOrdinalFeatures}
                />
              </Form.Input>
              <Form.Input
                label="Categorical Features"
              >
                <textarea
                  label="Categorical Features"
                  placeholder={"cat_feat_1, cat_feat_2"}
                  onChange={this.handleCatFeatures}
                />
              </Form.Input>
              <Popup
                header="Error Submitting Dataset"
                content={serverResp}
                open={errorMsg ? true : false}
                trigger={
                  <Button
                    inverted
                    color="blue"
                    compact
                    size="small"
                    icon="upload"
                    content="Upload dataset"
                    onClick={this.handleUpload}
                  />
                }
              />
            </div>
          </Segment>
        </Form>
        {dataPrevTable}
      </div>
    );
  }

它是一个相当基本的反应组件,连接到app redux商店,带有一些语义ui的东西,可以很好地造型。 有一个带有文件输入,文本区域输入和按钮/弹出窗口的表单; 如果未选择任何文件,则仅显示文件输入,如果提交文件的尝试不成功,则弹出窗口中将显示错误消息。

对于第1点 - 我试图遵循jest中的指南/ docs并创建组件使用的模拟api片段并使用jest.mock()

jest.mock('../../utils/apiHelper');
import uploadDataset from '../../data/datasets/dataset/api';

但是当我尝试时,在单元测试中

  it('testing promise for successfully case, proper dependent_col', () => {
    expect.assertions(1);
    return uploadDataset(fakeDataset).then(data => expect(data.name).toEqual('iris.csv'));
  })

测试因TypeError: (0 , _api2.default) is not a function失败TypeError: (0 , _api2.default) is not a function我直接导入mock api并直接调用它TypeError: (0 , _api2.default) is not a function ,它工作正常但无法测试应该进行api调用的模块; 我觉得以这种方式测试这个功能几乎是一个没有实际意义,并且更愿意以正确模拟它实际工作方式的方式测试组件,即触发导致api调用的事件而不是直接调用api 。 应该如何使用jest.mock() 我不正确地使用它?

对于第2点 - 我正在直接操作组件反应状态并检查UI更新,而不是通过表单字段模拟用户输入。 我尝试使用酶的find来访问文件输入字段

let testFileUpload;

beforeEach(() => {
  testFileUpload = mount(<FileUpload store={store} testProp="hello" />);
})

... other tests ...

it('click file upload button', () => {
 testFileUpload.find('#upload_dataset_file_browser_button').simulate("change", 
 {
       target: {
         files: [ 'iris.csv' ]
       }
     });
 })
}

并且测试失败并出现错误Method “simulate” is meant to be run on 1 node. 2 found instead. Method “simulate” is meant to be run on 1 node. 2 found instead. 我应该如何通过ID访问文件输入/ html元素和/或酶对模拟的期望是什么? 我花了最近几天查看jest / enzyme文档和示例,需要一些帮助。 当只有一个具有该id的元素时,为什么find方法返回2个节点? 我应该如何在所述节点上模拟文件选择的更改事件? 与上面提到的解决方法类似,我正在直接更改组件的状态并从该点检查事物,但我更愿意尽可能地模拟实际用例。

任何帮助是极大的赞赏。

尽管如此,是否可以绕过单元测试中的某些事情来基本上完成相同的结果? 有了我的问题,我在模拟输入到表单字段时遇到了一些麻烦,该表单字段应该在用户输入/更改时使用react setState,所以我只是直接更改状态而不是通过UI元素获取输入。 熟悉单元测试的人认为,这种单元测试方式是否足够或者这是非常不正确的? 现在我几乎是唯一一个为这个项目的前端UI组件进行单元测试的人,我不太确定如何正确测试这些部分。

不确定为什么带有#id的元素被挂载两次。 但你可以使用索引:

testFileUpload.find('#upload_dataset_file_browser_button').at(0).simulate("change")

我曾经认为酶的工作原理与jquery与css选择器相同。 但似乎不是。 即使是库的创建者也不建议使用带模拟操作的mount。 但我仍然使用,因为这是我在测试中获得良好报道的最佳方式。 使用酶我主要使用元素选择器而不是css选择器。

我使用prop来模拟动作,因为模拟不能真正“模拟”自定义动作。 尝试这个:

testFileUpload.find(Input).prop('onChange')('paramatertosendtofunction')

编辑:您可以使用辅助函数

function flushPromises() {
  return new Promise(resolve => setImmediate(resolve));
}


test('', () => {
  testFileUpload.find(Input).prop('onChange')('paramatertosendtofunction')
  testFileUpload.update()
  return flushPromises().then(() => {
    expect(textFileUpload.state.foo).toBe('bar')
  });
})

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM