Testing asynchronous actions with thunk reduction

I am trying to test my action that has an asynchronous call. I use Thunk as my middleware. In the action below, I only send and update the repository if the server returns a response OK.

export const SET_SUBSCRIBED = 'SET_SUBSCRIBED'

export const setSubscribed = (subscribed) => {
  return function(dispatch) {
    var url = 'https://api.github.com/users/1/repos';

    return fetch(url, {method: 'GET'})
      .then(function(result) {
        if (result.status === 200) {
          dispatch({
            type: SET_SUBSCRIBED,
            subscribed: subscribed
          })
          return 'result'
        }
        return 'failed' //todo
      }, function(error) {
        return 'error'
      })
  }
}

I have problems writing tests for those tests that are either sent or not (depending on the server’s response), or I can just let the call go and check if the value in the repository is updated correctly.

I use fetch-mock to make fun of the implementation of web fetch (). However, it seems that the block of my code in is thennot executing. I also tried using the example here with no luck - http://redux.js.org/docs/recipes/WritingTests.html

const middlewares = [ thunk ]
const mockStore = configureStore(middlewares)

//passing test
it('returns SET_SUBSCRIBED type and subscribed true', () => {
  fetchMock.get('https://api.github.com/users/1/repos', { status: 200 })

  const subscribed = { type: 'SET_SUBSCRIBED', subscribed: true }
  const store = mockStore({})

  store.dispatch(subscribed)

  const actions = store.getActions()

  expect(actions).toEqual([subscribed])
  fetchMock.restore()
})

//failing test
it('does nothing', () => {
  fetchMock.get('https://api.github.com/users/1/repos', { status: 400 })

  const subscribed = { type: 'SET_SUBSCRIBED', subscribed: true }
  const store = mockStore({})

  store.dispatch(subscribed)

  const actions = store.getActions()

  expect(actions).toEqual([])
  fetchMock.restore()
})

, , - fetch-mock , . console.log then, .

?

+4
2

Async Thunk Redux

setsubscribed redux-thunk. .

.

  const subscribed = { type: 'SET_SUBSCRIBED', subscribed: true }

API.

API, .

- , actionSubscribed thunk action.

, decx-thunk, , thunk.

Action Creators

, , - , .

"" . , .

, .

function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}

, . , redux, .

toDos . todo, .

const walkDogAction = addTodo('walk the dog')

console.log(walkDogAction)
* 
* { type: 'ADD_TO_DO, text: 'walk the dog' }
*

, .

, , , .

store.dispatch(walkDogAction)

.

, todo, , .

? , , , .

Redux

() ()?

- , . - , .

, , - ? :

  • - ?
  • ? ( , )

, , , , addtodo , .

, , . ? .

. . , , .

Thunk Action?

, - , . , getState.

Here is the code inside Redux thunk that does this:

    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

setSubscribed thunk, , .

, thunk . , .

. action decux thunk , aour async-, HTTP-. , , , ()

actions.js

export function fetchSomethingRequest () {
  return {
    type: 'FETCH_SOMETHING_REQUEST'
  }
}

export function fetchSomethingSuccess (body) {
  return {
    type: 'FETCH_SOMETHING_SUCCESS',
    body: body
  }
}

export function fetchSomethingFailure (err) {
  return {
    type: 'FETCH_SOMETHING_FAILURE',
    err
  }
}

export function fetchSomething () {
  return function (dispatch) {
    dispatch(fetchSomethingRequest())
    return fetchSomething('http://example.com/').then(function (response) {
      if (response.status !== 200) {
        throw new Error('Bad response from server')
      } else {
        dispatch(fetchSomethingSuccess(response))
      }
    }).catch(function (reason) {
      dispatch(fetchSomethingFailure(reason))
    })
  }
}

, , , - action decux. , , .

Mock Redux

store store redux-mock-store .

import configureStore from 'redux-mock-store';

, .

thunk action, redux-thunk , thunk. , , .

const middlewares = [ReduxThunk];
const mockStore = configureStore(middlewares);

mock store store.getActions, .

, -, .

, thunk action Mocha

, thunk -. , . Then, , thunk.

, , , action decux thunk, , .

import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'
import fetchMock from 'fetch-mock'  // You can use any http mocking library
import expect from 'expect' // You can use any testing library

import { fetchSomething } from './actions.js'

const middlewares = [ thunk ]
const mockStore = configureMockStore(middlewares)

describe('Test thunk action creator', () => {
  it('expected actions should be dispatched on successful request', () => {
    const store = mockStore({})
    const expectedActions = [ 
        'FETCH_SOMETHING_REQUEST', 
        'FETCH_SOMETHING_SUCCESS'
    ]

 // Mock the fetch() global to always return the same value for GET
 // requests to all URLs.
 fetchMock.get('*', { response: 200 })

    return store.dispatch(fetchSomething())
      .then(() => {
        const actualActions = store.getActions().map(action => action.type)
        expect(actualActions).toEqual(expectedActions)
     })

    fetchMock.restore()
  })

  it('expected actions should be dispatched on failed request', () => {
    const store = mockStore({})
    const expectedActions = [ 
        'FETCH_SOMETHING_REQUEST', 
        'FETCH_SOMETHING_FAILURE'
    ]
 // Mock the fetch() global to always return the same value for GET
 // requests to all URLs.
 fetchMock.get('*', { response: 404 })

    return store.dispatch(fetchSomething())
      .then(() => {
        const actualActions = store.getActions().map(action => action.type)
        expect(actualActions).toEqual(expectedActions)
     })

    fetchMock.restore()
  })
})

, Redux thunk .

thunk action , , .

- , HTTP- 200, .

Common Gotcha Thunks - Promises Action Creators

, Promises , .

    export function thunkActionCreator () {
          return function thatIsCalledByreduxThunkMiddleware() {

            // Ensure the function below is returned so that 
            // the promise returned is thenable in our tests
            return function returnsPromise()
               .then(function (fulfilledResult) {
                // do something here
            })
          }
     }

, , :

TypeError: Cannot read property 'then' of undefined - store.dispatch - returns undefined

, , .then. , , . , , . Then on undefined. , undefined, , return.

, return promises.

+13

, DevTools - , / . , , 200.

:

return fetch(url, {
    method: 'GET'
  })
  .then(function(result) {
    if (result.status === 200) {
      dispatch({
        type: SET_SUBSCRIBED,
        subscribed: subscribed
      })
      return 'result'
    }
    return 'failed' //todo
  }, function(error) {
    return 'error'
  })

- , : .

+1

Source: https://habr.com/ru/post/1658383/


All Articles