Javascript 使用Jest测试React Async并创建React应用程序

Javascript 使用Jest测试React Async并创建React应用程序,javascript,reactjs,jestjs,create-react-app,Javascript,Reactjs,Jestjs,Create React App,我似乎无法理解这一点。我正在使用CreateReact应用程序,它是内置于TestRunner Jest中的。对于所有的同步代码来说,它似乎工作得非常好,但当我嘲笑承诺时,我似乎无法让它工作 react组件有一个我能够模拟提交的表单 React组件代码片段 //Top of the page import {auth} from '../../lib/API_V2' // ... // // Handle submit runs when the form is submitted handl

我似乎无法理解这一点。我正在使用CreateReact应用程序,它是内置于TestRunner Jest中的。对于所有的同步代码来说,它似乎工作得非常好,但当我嘲笑承诺时,我似乎无法让它工作

react组件有一个我能够模拟提交的表单

React组件代码片段

//Top of the page
import {auth} from '../../lib/API_V2'
// ... //

// Handle submit runs when the form is submitted
handleSubmit = (event) => {
  console.log('submit')
  event.preventDefault()
  this.setState(prevState => ({
    ...prevState,
    loading: true
  }))
  console.log('stateSet')
  auth(this.state.userName, this.state.password)
    .then(results => {
      // NEVER RUNS
      console.log('then')
      // stuff omitted
      this.setState(prevState => ({
        ...prevState,
        loading: false
      }))
      this.props.afterAuth()
    })
  .catch(() => {
    // also never runs
    // omitted
    this.setState(prevState => ({
      ...prevState,
      loading: false
    }))
    this.props.afterAuth()
  })
}
测试代码

jest.mock('../../lib/API_V2')
it.only(`should mock a login`, () => {
  const myMock = jest.fn()
  const authComp = mount(<AuthComponent afterAuth={myMock}/>)

  authComp.find('.userName').simulate('change', {target: {value: 'userName'}})
  authComp.find('.password').simulate('change', {target: {value: 'password'}})
  expect(authComp.state().userName).toEqual('userName')
  expect(authComp.state().password).toEqual('password')
  authComp.find('[type="submit"]').get(0).click()
  expect(myMock.mock.calls.length).toBe(1) // FAILS
})
我的模拟测试代码似乎从未运行过。如果我记录模拟函数,我会得到
函数auth(){return mockConstructor.apply(this,arguments);}

我试图按照说明进行操作,但似乎没有调用我的模拟方法。而实际的方法也不是。相反,我对
auth()
的调用返回undefined

有人有什么想法吗

--补充资料--


我认为您遇到了与此问题相关的错误:

由于您实际上正在尝试导入一个名为
API\u V2/index.js
的文件,因此需要模拟
index.js
。但是,这样做会非常糟糕,因为它对于您尝试模拟的每个index.js文件都是有效的模拟


目前最好的方法是重写一些代码以使用依赖项注入,并将mock传递给mock的新承诺中需要使用的任何东西,即使您立即解析,该解析也不会同步发生。Promise回调始终作为排队的微任务运行,因此当您在测试中模拟单击时,模拟中的Promise回调尚未运行(因此,
myMock
也尚未调用)。这就是你的期望落空的原因

解决此问题的一种方法(有点老套)是使用setTimeout。setTimeout将使任务进入队列,并且任务始终在微任务之后运行。 Jest通过从
it
回调返回承诺来支持异步测试,因此您可以编写:

jest.mock('../../lib/API_V2')
it.only(`should mock a login`, () => new Promise(resolve => {
  const myMock = jest.fn()
  const authComp = mount(<AuthComponent afterAuth={myMock}/>)

  authComp.find('.userName').simulate('change', {target: {value: 'userName'}})
  authComp.find('.password').simulate('change', {target: {value: 'password'}})
  expect(authComp.state().userName).toEqual('userName')
  expect(authComp.state().password).toEqual('password')
  authComp.find('[type="submit"]').get(0).click()
  setTimeout(() => {
    expect(myMock.mock.calls.length).toBe(1)
    resolve() // Tell jest this test is done running
  }, 0);
}))
jest.mock('../../lib/API_V2')
it.only(`should mock a login`,()=>new Promise(resolve=>{
const myMock=jest.fn()

const authComp=mount(

在我的经验中,它只是警告让我恼火,但同名mock并没有被“交换”但是,这样做会非常糟糕,因为它对您尝试模拟的每个index.js文件都是有效的模拟。我不认为这是正确的。如果他把它放在
Lib/API\u V2/\uu mocks\uuuu/index.js
中,它应该可以工作,并且只对
Lib/API\u V2/index.js
进行模拟。抱歉,只是看看引用的bug。这很烦人我最终手动模拟了它,而不是使用mocks目录.jest.mock('../../lib/API_V2,()=>{auth:function…})
src
  Components
    AuthComponent
      AuthComponent.js
      AuthComponent.test.js
      index.js
  Lib
    API_V2
      API_V2.js
      index.js
      __mocks__
        API_V2.js
jest.mock('../../lib/API_V2')
it.only(`should mock a login`, () => new Promise(resolve => {
  const myMock = jest.fn()
  const authComp = mount(<AuthComponent afterAuth={myMock}/>)

  authComp.find('.userName').simulate('change', {target: {value: 'userName'}})
  authComp.find('.password').simulate('change', {target: {value: 'password'}})
  expect(authComp.state().userName).toEqual('userName')
  expect(authComp.state().password).toEqual('password')
  authComp.find('[type="submit"]').get(0).click()
  setTimeout(() => {
    expect(myMock.mock.calls.length).toBe(1)
    resolve() // Tell jest this test is done running
  }, 0);
}))