简体   繁体   English

使用酶和玩笑测试reactjs时如何在组件中模拟异步功能?

[英]How do I mock a async function in a component when testing reactjs with enzyme and jest?

I have a TextField (named EmailTextField) of which is used to enter e-mail address. 我有一个TextField(名为EmailTextField),用于输入电子邮件地址。 When user enters email address and 'onBlur' event is occur, I have a async function named 'verifyUserNameAvailable' to make api call to server and check if email address is already taken or not. 当用户输入电子邮件地址并且发生“ onBlur”事件时,我有一个名为“ verifyUserNameAvailable”的异步函数可以对服务器进行api调用,并检查电子邮件地址是否已被占用。

Now, I want to create a unit test for this TextField. 现在,我想为此TextField创建一个单元测试。 I do not want to test the 'verifyUserNameAvailable' as I already have a test for that in different test suite. 我不想测试“ verifyUserNameAvailable”,因为我已经在其他测试套件中对此进行了测试。 Is there a way to mock 有没有办法嘲笑

const response = await verifyUserNameAvailable(emailAddress);

call in handleOnBlur function? 调用handleOnBlur函数?

ex. 恩。 I want to unit test EmailTextField when response is 'true' and response is 'false'. 我想在响应为“ true”且响应为“ false”时对EmailTextField进行单元测试。

EmailTextField component EmailTextField组件

import React, {useRef, useState} from 'react';
import TextField from "@material-ui/core/TextField";
import Grid from "@material-ui/core/Grid";
import {verifyUserNameAvailable} from "../../../../api/auth/authApiConsumer";

export const EmailTextField = props => {

  const {onStateChange} = props;
  const [state, setState] = useState({
    errors: [],
    onChange: false,
    pristine: false,
    touched: false,
    inProgress: false,
    value: {
      email: '',
    },
  });
  const [currentReq, setCurrentReq] = useState(0);
  const latestReq = useRef(currentReq);

  const helperText = 'Email address will be used as your account id';
  const helperTextPristine = "'" + state.value.email + "' is available.";

  const handleOnBlur = async (event) => {

  const emailAddress = String(event.target.value).toLowerCase();



  // If true, verify username is available
  const updatedState = {
    ...state,
    touched: true,
    pristine: false,
    value: {
      email: emailAddress,
    },
    inProgress: true
  };
  setState(updatedState);
  onStateChange(updatedState);


  const response = await verifyUserNameAvailable(emailAddress);


  if (response === true) {

    const updatedState = {
      ...state,
      touched: true,
      pristine: true,
      value: {
        email: emailAddress,
      },
      inProgress: false,
      errors: [],
    };
    setState(updatedState);
    onStateChange(updatedState);

  } else {

    const updatedState = {
      ...state,
      touched: true,
      pristine: false,
      value: {
        email: emailAddress,
      },
      inProgress: false,
      errors: ["'" + emailAddress + "' is already used."],
    };
    setState(updatedState);
    onStateChange(updatedState);

  }

  };

  return (
      <Grid container spacing={1}>
        <Grid item xs={12}>
          <TextField
              variant="outlined"
              required
              fullWidth
              id="email"
              label="email address"
              error={state.errors.length > 0}
              helperText={state.errors.length > 0 ? state.errors[0]
                  : state.pristine === true ? helperTextPristine : helperText}
              name="email"
              autoComplete="email"
              margin='dense'
              onBlur={handleOnBlur}
          />
        </Grid>
      </Grid>
  )

};

export default EmailTextField;

Below is a unit test that I want to create. 下面是我要创建的单元测试。


import React from 'react';
import {configure} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import EmailTextField from './EmailTextField';
import TextField from '@material-ui/core/TextField';
import {createShallow} from '@material-ui/core/test-utils';
import {act} from 'react-dom/test-utils';

configure({adapter: new Adapter()});

describe('<EmailTextField />', () => {
  let shallow;

  beforeAll(() => {
    shallow = createShallow();
  });
  let wrapper;
  beforeEach(() => {
    wrapper = shallow(<EmailTextField onStateChange={handleStateChange}/>);
  });

  const handleStateChange = jest.fn()


  it('should show error when already registered account is entered', () => {

    // MOCK - Not a working code here.. but I want to do something like...
    when(verifyUserNameAvailable).isCalledReturn(false);
    ////////////////////////

    act(() => {
      wrapper.find(TextField).at(0).simulate('blur', {target: {value: 'test@abc.net'}});
    });
    wrapper.update();
    expect(wrapper.find(TextField).at(0).props().error).toBe(
        true);
    expect(wrapper.find(TextField).at(0).props().helperText).toBe(
        "test@abc.net is already used.");
    expect(handleStateChange).toHaveBeenCalledWith({
      "errors": ["test@abc.net is already used."],
      "inProgress": false,
      "onChange": false,
      "pristine": false,
      "touched": true,
      "value": {"email": "test@abc.net"}
    });
  });

  it('should not show error when account is not previously registered', () => {

    // MOCK - Not a working code here.. but I want to do something like...
    when(verifyUserNameAvailable).isCalledReturn(true);
    ////////////////////////

    act(() => {
      wrapper.find(TextField).at(0).simulate('blur', {target: {value: 'test@abc.net'}});
    });
    wrapper.update();
    expect(wrapper.find(TextField).at(0).props().error).toBe(
        true);
    expect(wrapper.find(TextField).at(0).props().helperText).toBe(
        "test@abc.net is available.");
    expect(handleStateChange).toHaveBeenCalledWith({
      "errors": ["test@abc.net is available."],
      "inProgress": false,
      "onChange": false,
      "pristine": true,
      "touched": true,
      "value": {"email": "test@abc.net"}
    });
  });

});

Is there a way to do something like this in above? 上面有没有办法做这样的事情?

// MOCK - Not a working code here.. but I want to do something like...
when(verifyUserNameAvailable).isCalledReturn(true);
////////////////////////

update 更新

I tried to create a mock under ../../../../api/auth/__mocks__/authApiConsumer 我试图在../../../../api/auth/__mocks__/authApiConsumer下创建一个模拟

export const verifyUserNameAvailable = (email) => new Promise(
    function (resolve, reject) {
     resolve(true);
    });

and updated the unit test to look like 并更新了单元测试,使其看起来像


import React from 'react';
import {configure} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import EmailTextField from './EmailTextField';
import TextField from '@material-ui/core/TextField';
import {createShallow} from '@material-ui/core/test-utils';
import {act} from 'react-dom/test-utils';

jest.mock("../../../../api/auth/authApiConsumer");

configure({adapter: new Adapter()});

describe('<EmailTextField />', () => {
  let shallow;

  beforeAll(() => {
    shallow = createShallow();
  });
  let wrapper;
  beforeEach(() => {
    wrapper = shallow(<EmailTextField onStateChange={handleStateChange}/>);
  });

  const handleStateChange = jest.fn()


  it('should not show error when account is not previously registered', () => {

    act(() => {
      wrapper.find(TextField).at(0).simulate('blur', {target: {value: 'test@abc.net'}});
    });
    wrapper.update();
    expect(wrapper.find(TextField).at(0).props().error).toBe(
        true);
    expect(wrapper.find(TextField).at(0).props().helperText).toBe(
        "test@abc.net is available.");
    expect(handleStateChange).toHaveBeenCalledWith({
      "errors": ["test@abc.net is available."],
      "inProgress": false,
      "onChange": false,
      "pristine": true,
      "touched": true,
      "value": {"email": "test@abc.net"}
    });
  });

});

But this does not work... 但这行不通...

Looks like the mock function I created is being ignored or something.. 看起来我创建的模拟函数被忽略了。

You need to run the test in the next tick. 您需要在下一个刻度中运行测试。 Try this code. 试试这个代码。 It works fine. 工作正常。

import React from 'react';
import { configure } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import EmailTextField from "./EmailTextField";
import TextField from "@material-ui/core/TextField";
import { createShallow } from "@material-ui/core/test-utils";
import { act } from "react-dom/test-utils";


jest.mock('./api/authApiConsumer');
const MOCK_MAIL = "test@abc.net";

configure({ adapter: new Adapter() });

describe("<EmailTextField />", () => {
    const handleStateChange = jest.fn();
    let shallow;

    beforeAll(() => {
        shallow = createShallow();
    });
    let wrapper;
    it("should work", () => {
        wrapper = shallow(
            <EmailTextField onStateChange={handleStateChange} />
        );
    });

    it("should not show error when account is not previously registered", (done) => {
        act(() => {
            wrapper.find(TextField).at(0).simulate('blur', { target: { value: 'test@abc.net' } });
        });
        process.nextTick(() => {
            wrapper.update();
            expect(
                wrapper
                    .find(TextField)
                    .at(0)
                    .props().error
            ).toBe(false);
            expect(
                wrapper
                    .find(TextField)
                    .at(0)
                    .props().helperText
            ).toBe(`'${MOCK_MAIL}' is available.`);
            expect(handleStateChange).toHaveBeenCalledWith({
                errors: [],
                inProgress: false,
                onChange: false,
                pristine: true,
                touched: true,
                value: { email: MOCK_MAIL }
            });
            done();

        })
    });
});

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

相关问题 React组件使用的Jest / Enzyme / Reactjs测试功能 - Jest/Enzyme/Reactjs testing function used by react component 如何模拟 Graphql 查询并将加载程序设置为 false 以在使用 Jest &amp; Enzyme 加载 = false 时测试反应组件? - How do I mock Graphql queries and set the loader false to test the react component when loading = false with Jest & Enzyme? 如何在笑话和酶中模拟 function - How to mock a function in jest and enzyme 如何在Jest测试中模拟React组件正在使用的功能? - How do I mock a function being used by my React Component in Jest testing? 功能组件中的玩笑/酶模拟功能 - jest/enzyme mock function in functional component 使用 Jest 和 Enzyme 单元测试 reactjs 组件功能 - Unit test reactjs component function with Jest and Enzyme Reactjs、jest、enzyme、react-universal-component - 如何使用动态导入测试组件结构? - Reactjs, jest, enzyme, react-universal-component - How do I test a components structure with dynamic imports? 如何通过玩笑酶测试来测试使用React.useState()的功能组件的功能? - How can I test a function of a function component that uses React.useState() using jest enzyme testing? 如何在无状态组件内部执行功能以进行Jest和Enzyme测试 - How to Execute a Function Inside a Stateless Component for Testing in Jest and Enzyme 如何使用Jest和Enzyme模拟组件方法 - How to mock component method using Jest and Enzyme
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM