簡體   English   中英

使用Jest和create-react-app測試React Async

[英]Testing React Async with Jest and create-react-app

我似乎無法想出這個。 我正在使用create-react-app,它是在測試運行器Jest中構建的。 對於所有同步代碼,它似乎工作得很好,但是當嘲笑承諾時,我似乎無法讓它工作。

反應組件具有我能夠模擬提交的形式。

反應組件代碼段。

//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
})

API lib返回一個promise。 而不是使用它,我旁邊有一個__mocks__/API_V2.js 看起來像這樣

function auth (lastname, accountNumber) {
  console.log('yay!?')
  return new Promise((resolve) => {
    resolve({
      accountNumber,
      lastName: lastname
    })
  })
}     

我的模擬測試代碼似乎永遠不會運行。 如果我記錄模擬函數,我得到function auth() {return mockConstructor.apply(this,arguments);}

我試圖按照說明https://facebook.github.io/jest/docs/tutorial-async.html但似乎我的模擬方法沒有被調用。 實際方法也不是。 相反,我對auth()調用返回undefined。

有人有主意嗎?

- 補充資料 -

src
  Components
    AuthComponent
      AuthComponent.js
      AuthComponent.test.js
      index.js
  Lib
    API_V2
      API_V2.js
      index.js
      __mocks__
        API_V2.js

我認為你遇到了與此問題相關的錯誤: https//github.com/facebook/jest/issues/2070

由於您實際上是在嘗試導入名為API_V2/index.js的文件,因此需要模擬index.js 但是,這樣做會非常糟糕,因為它對於您嘗試模擬的每個 index.js文件都是有效的模擬。

目前執行此操作的最佳方法是重寫一些代碼以使用依賴注入並將模擬傳遞給需要使用的任何內容{ auth }

在您的模擬的新Promise中,即使您立即解決,此解決方案也不會同步發生。 Promise回調總是作為一個排隊的微任務來運行,所以當你在測試中模擬一個點擊時,你的模擬中的Promise回調還沒有運行(所以myMock還沒有被調用)。 這就是你的期望失敗的原因。

你可以解決這個問題的一種(有點hacky)方法是使用setTimeout。 setTimeout將排隊任務 ,任務總是在微任務之后運行。 開玩笑通過返回的承諾,從支持異步測試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);
}))

有關任務和微任務如何在這里工作的一個很好的解釋: https ://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM