2017-04-10 5 views
0

QUESTION ORIGINALImpossible d'écrire des tests Redux pour les créateurs d'action

que je suis l'exemple des tests d'écriture pour les créateurs d'action async énoncées dans le Redux documentation. Je suis l'exemple le plus près possible, mais je n'arrive pas à faire fonctionner le test. Je reçois le message d'erreur suivant:

TypeError: Cannot read property 'then' of undefined 
    (node:789) UnhandledPromiseRejectionWarning: Unhandled promise rejection 
    (rejection id: 28): TypeError: Cannot read property 'data' of undefined 

Voici le code pour mon créateur d'action et d'essai:

actions/index.js

import axios from 'axios'; 
import { browserHistory } from 'react-router'; 
import { AUTH_USER, AUTH_ERROR, RESET_AUTH_ERROR } from './types'; 

const API_HOST = process.env.NODE_ENV == 'production' 
       ? http://production-server 
       : 'http://localhost:3090'; 

export function activateUser(token) { 
    return function(dispatch) { 
    axios.put(`${API_HOST}/activations/${token}`) 
     .then(response => { 
     dispatch({ type: AUTH_USER }); 

     localStorage.setItem('token', response.data.token); 
     }) 
     .catch(error => { 
     dispatch(authError(error.response.data.error)); 
     }); 
    } 
} 

export function authError(error) { 
    return { 
    type: AUTH_ERROR, 
    payload: error 
    } 
} 

confirmation_test.js

import configureMockStore from 'redux-mock-store'; 
import thunk from 'redux-thunk'; 
import * as actions from '../../src/actions'; 
import { AUTH_USER, AUTH_ERROR, RESET_AUTH_ERROR } from 
'../../src/actions/types'; 
import nock from 'nock'; 
import { expect } from 'chai'; 

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

describe('Confirmation_Token action creator',() => { 
    afterEach(() => { 
    nock.cleanAll() 
    }); 

    it('dispatches AUTH_USER', (done) => { 
    nock('http://localhost:3090') 
    .put('/activations/123456') 
    .reply(200, { 
     token: 7891011 
    }); 

    const expectedActions = { type: AUTH_USER }; 

    const store = mockStore({}); 

    return store.dispatch(actions.activateUser(123456)) 
    .then(() => { // return of async actions 
     expect(store.getActions()).toEqual(expectedActions); 
     done(); 
    }); 
    }); 
}); 

MISE À JOUR QUESTION

J'ai partiellement (mais pas entièrement) compris cela. Je l'ai eu à travailler en ajoutant une déclaration return devant axios et en commentant l'appel localstorage.setItem.

J'ai également retourné l'objet que j'ai affecté à expectedActions à un tableau, et a changé mon assertion de toEqual à to.deep.equal. Voici le code modifié:

actions/index.js

export function activateUser(token) { 
    return function(dispatch) { // added return statement 
    return axios.put(`${API_HOST}/activations/${token}`) 
     .then(response => { 
     dispatch({ type: AUTH_USER }); 
     // localStorage.setItem('token', response.data.token); Had to comment out local storage 
     }) 
     .catch(error => { 
     dispatch(authError(error.response.data.error)); 
     }); 
    } 
} 

confirmation_test.js

describe('ConfirmationToken action creator',() => { 
    afterEach(() => { 
    nock.cleanAll() 
    }); 

    it('dispatches AUTH_USER', (done) => { 
    nock('http://localhost:3090') 
    .put('/activations/123456') 
    .reply(200, { 
     token: 7891011 
    }); 

    const expectedActions = [{ type: AUTH_USER }]; 

    const store = mockStore({}); 

    return store.dispatch(actions.activateUser(123456)) 
    .then(() => { // return of async actions 
     expect(store.getActions()).to.deep.equal(expectedActions); 
     done(); 
    }); 
    }); 
}); 

Mais maintenant, je ne peux pas tester localStorage.setItem sans produire ce message d'erreur:

Error: timeout of 2000ms exceeded. Ensure the done() callback is being called 
in this test. 

Est-ce parce que je dois mocker dehors ? Ou y a-t-il une solution plus facile qui me manque?

Répondre

0

J'ai trouvé la solution. Cela implique les modifications que j'ai apportées à ma question mise à jour, ainsi que l'ajout d'une copie de localStorage à mon fichier test_helper.js. Comme il semble y avoir beaucoup de questions à ce sujet en ligne, je me suis dit que ma solution pourrait peut-être aider quelqu'un d'autre.

test_helper.js

import jsdom from 'jsdom'; 

global.localStorage = storageMock(); 

global.document = jsdom.jsdom('<!doctype html><html><body></body></html>'); 
global.window = global.document.defaultView; 
global.navigator = global.window.navigator; 

global.window.localStorage = global.localStorage; 

// localStorage mock 

function storageMock() { 
    var storage = {}; 

    return { 
     setItem: function(key, value) { 
     storage[key] = value || ''; 
     }, 
     getItem: function(key) { 
     return key in storage ? storage[key] : null; 
     }, 
     removeItem: function(key) { 
     delete storage[key]; 
     } 
    }; 
    } 

actions.index.js

export function activateUser(token) { 
    return function(dispatch) { 
    return axios.put(`${API_HOST}/activations/${token}`) 
     .then(response => { 
     dispatch({ type: AUTH_USER }); 
     localStorage.setItem('token', response.data.token); 
     }) 
     .catch(error => { 
     dispatch(authError(error.response.data.error)); 
     }); 
    } 
} 

confirmation_test.js

describe('Confirmation action creator',() => { 
    afterEach(() => { 
    nock.cleanAll() 
    }); 

    it('dispatches AUTH_USER and stores token in localStorage', (done) => { 
    nock('http://localhost:3090') 
    .put('/activations/123456') 
    .reply(200, { 
     token: '7891011' 
    }); 

    const expectedActions = [{ type: AUTH_USER }]; 

    const store = mockStore({}); 

    return store.dispatch(actions.activateUser(123456)) 
    .then(() => { // return of async actions 
     expect(store.getActions()).to.deep.equal(expectedActions); 
     expect(localStorage.getItem('token')).to.equal('7891011'); 
     done(); 
    }); 
    }); 
});