Reactjs&Jest,测试操作也改变了localStorage

时间:2018-09-09 20:36:05

标签: reactjs jestjs

在我的react + redux应用程序中,我有一个动作,除了返回类型和有效负载外,还更改了localStorage,如:

export const cancel = () => {
  localStorage.removeItem("MyAppData");
  return { type: types.USER_CANCEL};
};

我的测试如下:

test("user cancels", () => {
  const action = actions.cancel();
  expect(action).toEqual({
    type: types.USER_CANCEL
  });
});

我没有为本地存储编写任何测试

  ● user cancels

    ReferenceError: localStorage is not defined

      33 |
      34 | export const cancel = () => {
    > 35 |   localStorage.removeItem("MyAppData");
         |   ^
      36 |   return { type: types.USER_CANCEL};
      37 | };
      38 |

      at Object.localStorage [as cancel] (src/actions/AllActions.js:35:3)
      at Object.cancel (__test__/actions/AllActions.test.js:56:26)

因此我对本地存储做了一个模拟

const mockStorage = {};
const localStorage = {
  setItem: (key, val) => Object.assign(mockStorage, { [key]: val }),
  getItem: key => mockStorage[key],
  removeItem: key => {delete mockStorage[key];console.log("Deleted: ", key);},
  clear: () => mockStorage
};
export default localStorage;

导入此模拟或使用localStorage API,我仍然会遇到相同的错误

对于在调用cancel()时也调用localStorge.removeItem还是删除键和值的情况我感到困惑吗?

3 个答案:

答案 0 :(得分:1)

由于某种原因,Jest的测试环境中没有window.localStorage对象。我建议您将模拟对象分配给window对象。您可以在测试文件的beforeAll方法内进行该操作,也可以按照here的说明针对所有测试进行全局操作。

之后,您的代码和测试会将其用作本机localStorage:

test("user cancels", () => {
  localStorage.setItem("MyAppData", "some_data");

  const action = actions.cancel();
  expect(action).toEqual({
    type: types.USER_CANCEL
  });

  expect(localStorage.getItem("MyAppData")).toBeNull();
});

答案 1 :(得分:1)

如果要模拟localStorage,请模拟其所有方法(例如removeItem)以查看是否被调用,可以在其模拟方法中使用console.log。

jest.config.js内部

添加

  setupFiles: [
    './jest.globals.js'
  ],

jest.globals.js

const mockStorage = {};
const localStorage = {
  setItem: (key, val) => Object.assign(mockStorage, {[key]: val}),
  getItem: key => mockStorage[key],
  removeItem: key => { delete mockStorage[key]; console.log('Deleted: ' + key); },
  clear: () => mockStorage,
};
global.localStorage = localStorage;

现在在整个测试过程中,localStorage将在全球范围内可用。

要测试:

test("user cancels", () => {
     const action = actions.cancel();
      expect(action).toEqual({
        type: types.USER_CANCEL
      });

      expect(localStorage.getItem("MyAppData")).toBeNull();
});

编辑:

作为最终解决方案,将您的jest.config.js更新为使用testEnvironment: "jsdom",这将使用jsdom的localStorage,您将不再需要对其进行模拟。

答案 2 :(得分:0)

感谢@Ayushya和@Oleksandr Kovpashko。我只是发现,如果该应用程序是由CRA创建的,则整个方法要简单得多。因此,请卸载所有软件包并恢复为CRA默认值。据我所知,only one answer提到了这一点。另外,我还在jest文档中搜索CRA docs

中的答案

因此创建src/setupTests.js

const localStorageMock = {
  getItem: jest.fn(),
  setItem: jest.fn(),
  removeItem: jest.fn(),
  clear: jest.fn()
};
global.localStorage = localStorageMock;

默认情况下,CRA的测试脚本为

 "test": "react-scripts test --env=jsdom",

可以更改为node