如何在Chai的单元测试中使用localStorage

时间:2016-05-18 16:07:57

标签: javascript unit-testing reactjs redux

我有一个带有react和redux的应用程序。我的测试引擎是 - Chai

在我的reducer( src / my_reducer.js )中,我尝试从localStorage获取令牌,如下所示:

const initialState = {
  profile: {},
  token: window.localStorage.getItem('id_token') ? window.localStorage.getItem('id_token') : null,
}

在我的测试文件( test / reducer_spec.js )中,我在测试用例之前导入了'my_reducer':

import myReducer from '../src/my_reducer'

我有一个错误,如果我尝试运行test - localStorage(或window.localStorage) - undefined。

我需要嘲笑localStorage吗?如果我需要,它的位置在哪里?

4 个答案:

答案 0 :(得分:4)

我用mock-local-storage解决问题 我的运行测试命令是:

mocha -r mock-local-storage --compilers js:babel-core/register --recursive

答案 1 :(得分:4)

我认为你正在使用摩卡运行测试? mocha测试在node.js中运行,而node.js没有全局窗口变量。但您可以在测试中轻松创建一个:

global.window = {};

您甚至可以立即将localStorage添加到其中:

global.window = { localStorage: /* your mock localStorage */ }

模拟取决于您在本地存储中存储的内容,但对于上面的示例代码,这可能是一个合理的模拟对象:

var mockLocalStorage = {
    getItem: function (key) {
        if( key === 'id_token' ){ return /* a token object */; }
        return null;
    }
}

当然,对于不同的测试,你可以有不同的模拟,例如另一个模拟可能总是返回null来测试无法找到密钥的情况。

答案 2 :(得分:2)

出于测试目的,我建议进行任何可能产生副作用的调用或在声明中调用外部模块。 因为需要/导入你的reducer隐式调用window.localStorage.getItem(...)干净的测试变得很难。

我建议使用init方法包装初始化代码,这样如果在调用init之前需要/导入模块,则不会发生任何事情。然后,您可以使用beforeEach afterEach来干净地设置模拟/沙箱。

import myReducer from '../src/my_reducer'
describe('with faked localStorage', function() {
  var sandbox

  beforeEach(function() {
    sandbox = sinon.sandbox.create()
    // fake window.localStorage
  })

  afterEach(function() {
    sandbox.restore()
  })

  describe('the reducer', function() {
    before(function() {
      myReducer.init()
    })
  })
})

第二个最佳解决方案是推迟导入并在require测试挂钩中使用before

describe('with fake localStorage', function() {
  var sandbox

  beforeEach(function() {
    sandbox = sinon.sandbox.create()
    // fake window.localStorage
  })

  afterEach(function() {
    sandbox.restore()
  })

  describe('the reducer', function() {
    var myReducer

    before(function() {
      myReducer = require('../src/my_reducer')
    })

  })
})

答案 3 :(得分:1)

这是因为您没有在浏览器环境中运行Chai。

尝试:

  // Make sure there is a window object available, and that it has localstorage (old browsers don't)
  const initialState = {
    profile: {},
    // window.localStorage.getItem('id_token') will return null if key not found
    token: window && window.localStorage ? window.localStorage.getItem('id_token') : null,
  }