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

How to use localStorage in unit tests with Chai

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

在我的减速器(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'

我有一个错误,如果我尝试 运行 测试 - localStorage(或 window.localStorage) - 未定义。

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

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

我建议用 init 方法包装您的初始化代码,这样如果您在调用 init 之前 require/import 您的模块,则不会发生任何事情。然后你可以使用 beforeEach afterEach 来干净地设置 mocks/sandboxes.

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

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

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

  })
})

那是因为你不是浏览器环境下的运行 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,
  }

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

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

我猜你是 运行用 mocha 进行测试? mocha 在 node.js 中测试 运行,而 node.js 没有全局 window 变量。但是您可以轻松地在测试中创建一个:

global.window = {};

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

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

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

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

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