错误:预期的模拟函数已被调用-onclick笑话酶

时间:2019-02-27 14:08:07

标签: javascript reactjs unit-testing jestjs enzyme

无法通过以下测试... 很抱歉放置很多代码。 我还可以使用其他一些点击事件,但此刻我对此仍然感到困惑

获取以下消息:

  

“ expect(jest.fn())。toHaveBeenCalled()

     

预计将调用模拟函数。”

这是Render方法下的click事件

      className={!this.state.name || !this.state.label || this.state.valueStore === null ? `add-custom-field-button disabled` : `add-custom-field-button`}
          id="test-addclick"
          onClick={() => {this.onAddClick()}}
        >
          Create Field
        </button>

这是onAddClick方法:

onAddClick = () => {
let obj = this.props.selectedFormJSON;

this.addValueAttribute().then(()=>{
  obj.FORM_COLUMN.push(
    {
      Control: this.state.control,
      CreateBy: this.props.user.userId,
      Datatype: this.state.datatype,
      Form_UID: this.props.selectedFormJSON.Form_UID,
      Help: this.state.help,
      ValueStore: this.state.valueStore
    }
  )
  this.props.updateSelectedFormJSON(obj);
  if(!this.props.isNewForm && this.state.valueStore) {
    this.props.patchForm().then((res)=>{
    if(res.Forms[0] && (res.Forms[0].Code === '200' || res.Forms[0].Code===200)) {
      toast(<div>Attribute Added Successfully!</div>, {type: toast.TYPE.SUCCESS,position: toast.POSITION.TOP_LEFT})
    } else {
      toast(<div>Failed to Add Attribute!</div>, {type: toast.TYPE.ERROR,position: toast.POSITION.TOP_LEFT})
    }
  });
  } else if(this.state.valueStore) {
    this.props.postForm().then((res)=>{
      if(res.Forms[0] && (res.Forms[0].Code === '201' || res.Forms[0].Code===201)) {
        toast(<div>Attribute Added Successfully!</div>, {type: toast.TYPE.SUCCESS,position: toast.POSITION.TOP_LEFT})
      } else {
        toast(<div>Failed to Add Attribute!</div>, {type: toast.TYPE.ERROR,position: toast.POSITION.TOP_LEFT})
      }
    })
  }
  this.props.closeModal();
})
}

     addValueAttribute = () => {
return new Promise((resolve, reject) => {
  if(this.state.valueStore) {
    let {valueTables, valueDatatypes, service} = this.state;
    let body = {
      Name: this.state.name,
      TableName: this.props.selectedFormJSON.Entity,
      Datatype: this.state.datatype,
      ChangeType: 'I'
    }
    fetch(service.URL+'/VALUE_ATTRIBUTE', { headers: {
      'Content-Type': 'application/json',
      'Ocp-Apim-Subscription-Key': service.subscription_key,
    },
      method: 'POST',
      credentials: 'include',
      body: JSON.stringify(body),
    })
    .then((res) => {
      res.status === 201 && resolve();
    })
    .catch(() => {
      reject();
    })
  } else {
    //Not a value attr
    resolve()
  }
})

}

这是我尝试测试的方式:使用笑话/酶。我在其他一些点击事件中使用了相同的设置,但它一直在起作用。无法找出以下原因:

it("should call onAddClick", async () => {  // use an async test method
baseProps. closeModal.mockClear();
baseProps. updateSelectedFormJSON.mockClear();

const instance = wrapper.instance();
const spy = jest.spyOn(instance, 'addValueAttribute');  // spy on addValueAttribute...
spy.mockImplementation(() => Promise.resolve())  // give any callbacks queued in PromiseJobs a chance to run
wrapper.find('#test-addclick').at(0).simulate('click');  // simulate click

expect(baseProps.updateSelectedFormJSON).toHaveBeenCalled();  // SUCCESS
expect(baseProps.closeModal).toHaveBeenCalled();  // SUCCESS
});

1 个答案:

答案 0 :(得分:0)

addValueAttribute昂贵,因此您需要模拟它以立即解决。  addValueAttributeclass field,因此您需要使用组件实例对其进行模拟。

调用onAddClick时,它将调用this.addValueAttribute,它将被模拟以立即返回。这将导致Promise中的then回调被添加到the PromiseJobs queue中。在当前消息完成之后和下一条消息开始之前,该队列中的作业运行

这意味着,当点击处理程序返回并继续测试时,在PromiseJobs队列中排队调用this.props.updateSelectedFormJSONthis.props.closeModal的回调。

这时,您需要暂停测试以使PromiseJobs中排队的回调有机会运行。最简单的方法是使测试函数async并调用await Promise.resolve();,这实际上将把其余测试放在PromiseJobs队列的末尾,并允许队列中已有的任何作业运行首先。

将所有内容放在一起,这是经过测试的代码简化版本:

import * as React from 'react';
import { shallow } from 'enzyme';

class Comp extends React.Component {
  onAddClick = () => {
    this.addValueAttribute().then(() => {
      this.props.updateSelectedFormJSON();
      this.props.closeModal();
    })
  }
  addValueAttribute = () => {
    return new Promise((resolve) => {
      setTimeout(resolve, 100000);  // does something computationally expensive
    });  
  }
  render() {
    return (<button onClick={this.onAddClick}>Create Field</button>);
  }
}

it("should call onAddClick", async () => {  // use an async test method
  const props = {
    updateSelectedFormJSON: jest.fn(),
    closeModal: jest.fn()
  }
  const wrapper = shallow(<Comp {...props} />);
  const instance = wrapper.instance();
  const spy = jest.spyOn(instance, 'addValueAttribute');  // spy on addValueAttribute...
  spy.mockResolvedValue();  // ...and mock it to immediately resolve
  wrapper
    .find('button')
    .at(0)
    .simulate('click');  // simulate click
  await Promise.resolve();  // give any callbacks queued in PromiseJobs a chance to run
  expect(props.updateSelectedFormJSON).toHaveBeenCalled();  // SUCCESS
  expect(props.closeModal).toHaveBeenCalled();  // SUCCESS
});