Reactjs 如何通过更改useState来测试React钩子组件

Reactjs 如何通过更改useState来测试React钩子组件,reactjs,unit-testing,jestjs,react-hooks,enzyme,Reactjs,Unit Testing,Jestjs,React Hooks,Enzyme,我有一个功能组件,我想用Jest/酶测试。我想根据useState值测试它的第三级渲染行为。我似乎在网上找不到任何例子。没有“单击”来模拟-没有API调用来模拟,因为在最后,我仍然需要基于useState值进行测试。 在过去,通过类组件,我可以设置状态。有了新的钩子,我不能。 那么,基本上-如何在模拟的submitForm函数中模拟async Wait,以使渲染行为正常 以下是我的组件: import React, { useState } from 'react'; import { Redi

我有一个功能组件,我想用Jest/酶测试。我想根据useState值测试它的第三级渲染行为。我似乎在网上找不到任何例子。没有“单击”来模拟-没有API调用来模拟,因为在最后,我仍然需要基于useState值进行测试。 在过去,通过类组件,我可以设置状态。有了新的钩子,我不能。 那么,基本上-如何在模拟的submitForm函数中模拟async Wait,以使渲染行为正常

以下是我的组件:

import React, { useState } from 'react';
import { Redirect } from 'react-router-dom';

import Form from 'core/Form';

export const Parent = ({submitForm}) => {
  const [formValues, setFormValues] = useState({});
  const [redirect, setRedirect] = useState(false);

  const handleChange = name => evt => {
    setFormValues({ ...formValues, [name]: evt.target.value });
  };

  const onSubmit = async () => {
      try {
        const res = await submitForm(formValues);
        if (res) setRedirect(true);
        else setRedirect(false);
      } catch (err) {
        console.log('Submit error: ', err);
      }
  };

  return redirect ? (
    <Redirect push to={path} />
  ) : (
    <Form onSubmit={onSubmit} values={formValues} onChange={handleChange} />
  );
};

export default Parent;
import React,{useState}来自“React”;
从'react router dom'导入{Redirect};
从“核心/表格”导入表格;
导出常量父项=({submitForm})=>{
const[formValues,setFormValues]=useState({});
const[redirect,setRedirect]=useState(false);
const handleChange=name=>evt=>{
setFormValues({…formValues,[名称]:evt.target.value});
};
const onSubmit=async()=>{
试一试{
const res=等待提交表单(formValues);
if(res)setRedirect(true);
else setRedirect(false);
}捕捉(错误){
log('submiterror:',err);
}
};
返回重定向(
) : (
);
};
导出默认父对象;
以下是我目前的测试:

import React from 'react';
import { shallow } from 'enzyme';
import { Redirect } from 'react-router-dom';

import Parent from './Parent';
import Form from 'core/Form';

let wrapper, props;
.
.
.

describe('<Parent /> rendering', () => {
  beforeEach(() => {
    props = createTestProps();
    wrapper = shallow(<Parent {...props} />);
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  const setState = jest.fn();
  const useStateSpy = jest.spyOn(React, 'useState');
  useStateSpy.mockImplementation(init => [init, setState]);

  it('Should render 1 Form', () => {
    expect(wrapper.find(Form)).toHaveLength(1);
  });

  it('renders Redirect after API call', () => {
    setRedirect = jest.fn(() => false);

    expect(wrapper.find(Redirect)).toHaveLength(1);
  });

  it('renders Form before API call', () => {
    setRedirect = jest.fn(() => true);

    expect(wrapper.find(Form)).toHaveLength(1);
  });
});
从“React”导入React;
从“酶”导入{shall};
从'react router dom'导入{Redirect};
从“./Parent”导入父项;
从“核心/表格”导入表格;
让包装,道具;
.
.
.
描述(‘呈现’,()=>{
在每个之前(()=>{
props=createTestProps();
包装器=浅();
});
之后(()=>{
开玩笑。clearAllMocks();
});
const setState=jest.fn();
const useStateSpy=jest.spyOn(React,'useState');
useStateSpy.mockImplementation(init=>[init,setState]);
它('应该呈现1个表单',()=>{
expect(wrapper.find(Form)).toHaveLength(1);
});
它('在API调用后呈现重定向',()=>{
setRedirect=jest.fn(()=>false);
expect(wrapper.find(Redirect)).toHaveLength(1);
});
它('在API调用之前呈现表单',()=>{
setRedirect=jest.fn(()=>true);
expect(wrapper.find(Form)).toHaveLength(1);
});
});

您不需要监视
useState
hook。这意味着您不应该直接测试组件的这些挂钩和方法。相反,您应该测试组件的行为(状态、道具以及呈现的内容)

例如

index.tsx

import React,{useState}来自“React”;
从'react router dom'导入{Redirect};
导出常量形式=({onSubmit,onChange,values})=>;
常量路径='/user';
导出常量父项=({submitForm})=>{
const[formValues,setFormValues]=useState({});
const[redirect,setRedirect]=useState(false);
常量handleChange=(名称)=>(evt)=>{
setFormValues({…formValues,[名称]:evt.target.value});
};
const onSubmit=async()=>{
试一试{
const res=等待提交表单(formValues);
if(res)setRedirect(true);
else setRedirect(false);
}捕捉(错误){
log('submiterror:',err);
}
};
返回重定向(
) : (
);
};
导出默认父对象;
index.test.tsx

从“/”导入父项,{Form};
从“React”导入React;
从“酶”导入{shall};
从'react router dom'导入{Redirect};
从'react dom/test utils'导入{act};
常量whenStable=async()=>
等待动作(异步()=>{
等待新承诺((resolve)=>setTimeout(resolve,0));
});
描述('60137762',()=>{
它('应该呈现形式',()=>{
constprops={submitForm:jest.fn()};
常量包装器=浅();
expect(wrapper.find(Form)).toBeTruthy();
});
它('应该处理提交和呈现重定向',异步()=>{
const props={submitForm:jest.fn().mockResolvedValueOnce(true)};
常量包装器=浅();
wrapper.find(Form.simulate('submit');
等待何时稳定();
expect(props.submitForm).toBeCalledWith({});
expect(wrapper.find(Redirect)).toBeTruthy();
});
它('应该处理提交和呈现表单',异步()=>{
const props={submitForm:jest.fn().mockResolvedValueOnce(false)};
常量包装器=浅();
wrapper.find(Form.simulate('submit');
等待何时稳定();
expect(props.submitForm).toBeCalledWith({});
expect(wrapper.find(Form)).toBeTruthy();
});
它('提交失败时应处理错误',异步()=>{
constlogspy=jest.spyOn(控制台,'log');
const mError=新错误(“网络”);
const props={submitForm:jest.fn().mockRejectedValueOnce(mError)};
常量包装器=浅();
wrapper.find(Form.simulate('submit');
等待何时稳定();
expect(props.submitForm).toBeCalledWith({});
expect(logSpy).toHaveBeenCalledWith('submiterror:',mError);
});
});
单元测试结果和覆盖率报告:

PASS stackoverflow/60137762/index.test.tsx
60137762
✓ 应呈现形式(18ms)
✓ 应处理提交和呈现重定向(15毫秒)
✓ 应处理提交和提交表格(8ms)
✓ 提交失败时应处理错误(18毫秒)
console.log node_modules/jest environment/node_modules/jest mock/build/index.js:866
提交错误:错误:网络
at/Users/ldu020/workspace/github.com/mrdulin/react apollo graphql starter kit/stackoverflow/60137762/index.test.tsx:39:20
在步骤(/Users/ldu020/workspace/github.com/mrdulin/react apollo graphql starter kit/stackoverflow/60137762/index.test.tsx:44:23)
在Object.next(/Users/ldu020/workspace/github.com/mrdulin/react apollo graphql starter kit/stackoverflow/60137762/index.test.tsx:25:53)
at/Users/ldu020/workspace/github.com/mrdulin/react apollo graphql starter kit/stackoverflow/60137762/index.test.tsx:19:71

在new Promise(

您不应该直接设置t