2016-05-23 114 views
3

我目前在我的redux操作上运行测试时遇到了很多麻烦。测试通过,但我得到在每次运行时出现以下错误:Redux测试 - ReferenceError:localStorage未定义

ReferenceError: localStorage is not defined 

我也得到了错误之前这是:

ReferenceError: fetch is not defined 

我用固定该同构取。无论如何,我不确定我应该如何配置Mocha来运行这些前端测试。任何帮助将非常感激。


摩卡测试指令:

mocha -w test/test_helper.js test/*.spec.js 

test_helper.js:

require('babel-register')(); 
var jsdom = require('jsdom').jsdom; 

var exposedProperties = ['window', 'navigator', 'document']; 

global.document = jsdom(''); 
global.window = document.defaultView; 

Object.keys(document.defaultView).forEach((property) => { 
    if (typeof global[property] === 'undefined') { 
    exposedProperties.push(property); 
    global[property] = document.defaultView[property]; 
    } 
}); 

global.navigator = { 
    userAgent: 'node.js' 
}; 

documentRef = document; 

auth.actions.spec.js

import configureMockStore from 'redux-mock-store' 
import thunk from 'redux-thunk' 
import * as actions from '../client/app/actions/auth' 
import * as types from '../client/app/constants/ActionTypes' 
import nock from 'nock' 
import chai from 'chai' 
import sinon from 'sinon' 

var expect = chai.expect 

import { SERVER_API } from './config' 

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

describe('auth actions',() => { 

afterEach(() => { 
    nock.cleanAll() 
}) 

it('creates LOGIN_REQUEST and LOGINSUCCESS when correct username and password provided',() => { 

    nock(SERVER_API) 
    .post('/login', { 
     username: 'test', 
     password: 'password' 
    }) 
    .reply(200, { 
     token: 'TOKEN' 
    }); 

    const expectedActions = [ 
    { 
     type: types.LOGIN_REQUEST, 
     isFetching: true, 
     isAuthenticated: false, 
     creds: { 
      username: 'test', 
     password: 'password' 
     } 
    }, 
    { 
     type: types.LOGIN_SUCCESS, 
     isFetching: false, 
     isAuthenticated: true, 
     token: 'TOKEN' 
    } 
    ] 

    const INITAL_STATE = { 
     isFetching: false, 
     isAuthenticated: false 
    } 
    const store = mockStore(INITAL_STATE) 

    return store.dispatch(actions.loginUser({username:'test',password:'password'})) 
     .then(() => { 
     expect(store.getActions()).to.deep.equal(expectedActions) 
     }) 
    }) 
}) 

auth.js

import { push } from 'react-router-redux' 
import 'es6-promise' 
import fetch from 'isomorphic-fetch' 

import { 
    LOGIN_REQUEST, LOGIN_SUCCESS, LOGIN_FAILURE 
} from '../constants/ActionTypes.js' 

import { SERVER_PORT } from '../constants/config' 


function requestLogin(creds) { 
    return { 
    type: LOGIN_REQUEST, 
    isFetching: true, 
    isAuthenticated: false, 
    creds 
    } 
} 

function receiveLogin(user) { 
    return { 
    type: LOGIN_SUCCESS, 
    isFetching: false, 
    isAuthenticated: true, 
    token: user.token 
    } 
} 

function loginError(message) { 
    return { 
    type: LOGIN_FAILURE, 
    isFetching: false, 
    isAuthenticated: false, 
    message 
    } 
} 

export function loginUser(creds) { 

    let config = { 
    method: 'POST', 
    headers: { 'Content-Type':'application/x-www-form-urlencoded' }, 
    body: `username=${creds.username}&password=${creds.password}` 
    } 

    return dispatch => { 
    dispatch(requestLogin(creds)) 
    return fetch('http://localhost:'+SERVER_PORT+'/api/login', config) 
     .then(response => 
     response.json() 
     .then(user => ({ user, response })) 
    ).then(({ user, response }) => { 
     if (!response.ok) { 
      dispatch(loginError(user.message)) 
      return Promise.reject(user) 
     } 
     else { 
      dispatch(receiveLogin(user)) 
      localStorage.setItem('token', user.token) //offending line 
      dispatch(push('foo')) 
     } 
     }).catch(err => console.log("Error: ", err)) 
    } 
} 

感谢。

回答

4

非常直接的错误,您不能在您的摩卡测试中使用localStorage,因为window.localStorage未定义。有两种方法可以解决这个问题。更“正典”的方式是将您的动作中的localStorage调用移除,因为这是一种副作用,它是redux操作中的反模式。相反,您应该拥有捕获此操作并设置localStorage的中间件。

通过这样做,您已经消除了测试此操作的问题。

但是,如果你不知道如何做到这一点,并不认为这是明智的,那么你可以通过在你的摩卡测试文件的顶部创建一个全局变量来伪造localStorage 。我建议不要这样做,但它绝对是一种解决方案,可以适用于您的情况。

+0

感谢您的回复和建议。我认为这是为什么,但不知道我是否可以使用test_helper来伪造本地存储。我一定会尝试使用中间件。谢谢。 – edcarr

+0

@ZekeDroid在这种情况下,还需要在localStorage全局变量中创建'setItem'方法吗? – Emo

+0

其他方法,是的 – ZekeDroid