错误:已经调用了预期的模拟函数 - onclick Jest酶

问题描述 投票:0回答:1

无法通过以下测试...抱歉提出了很多代码....我能够获得一些其他点击事件但我现在仍然坚持这个

获取以下消息:

“期待(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()
  }
})

}

以下是我试图测试它的方法:使用jest / enzyme。我一直在使用相同的设置用于其他一些点击事件,它一直在工作。无法弄清楚以下内容:

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
});
javascript reactjs unit-testing jestjs enzyme
1个回答
0
投票

addValueAttribute很贵,所以你想要嘲笑它立即解决。 addValueAttribute是一个class field所以你需要使用组件实例来模拟它。

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

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

此时您需要暂停测试以使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
});
© www.soinside.com 2019 - 2024. All rights reserved.