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

IT技术 javascript reactjs unit-testing redux chai
2021-04-29 23:31:55

我有一个带有 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 吗?如果我需要,它的位置在哪里?

4个回答

我想你正在用 mocha 运行你的测试?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来测试找不到密钥的情况。

我用模拟本地存储解决了问题 我的运行测试命令是:

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

出于测试目的,我建议不要进行任何可能有副作用的调用或在声明中调用外部module。因为要求/导入您的减速器隐式调用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()
    })
  })
})

第二个最好的解决方案是推迟导入并requirebefore测试钩子中使用。

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,
  }