在Jest测试中,我一直得到“localStorage is not defined”,这是有意义的,但我的选项是什么?碰壁。


当前回答

2022年的更新。

Jest@24+具有自动模拟本地存储的能力。但是,默认情况下,它不再附带所需的依赖项。

npm 和 -D 是 environment-jsdom

你还需要改变你的笑话测试模式:

// jest.config.cjs
module.exports = {
  ...
  testEnvironment: "jsdom",
  ...
};

现在localStorage已经被模拟了。

例子:

// myStore.js
const saveLocally = (key, value) => {
  localStorage.setItem(key, value)
};

测试:

// myStore.spec.ts
import { saveLocally } from "./myStore.js"

it("saves key-value pair", () => {
  let key = "myKey";
  let value = "myValue";
  expect(localStorage.getItem(key)).toBe(null);
  saveLocally(key, value);
  expect(localStorage.getItem(key)).toBe(value);
};

其他回答

在这里引用了一些其他的答案来解决一个用Typescript的项目。我像这样创建了一个LocalStorageMock:

export class LocalStorageMock {

    private store = {}

    clear() {
        this.store = {}
    }

    getItem(key: string) {
        return this.store[key] || null
    }

    setItem(key: string, value: string) {
        this.store[key] = value
    }

    removeItem(key: string) {
        delete this.store[key]
    }
}

然后我创建了一个LocalStorageWrapper类,我使用它来访问应用程序中的所有本地存储,而不是直接访问全局本地存储变量。便于在包装器中为测试设置模拟。

首先,我创建了一个名为localStorage.ts(localStorage.js)的文件

class LocalStorageMock {
  store: Store;
  length: number;

  constructor() {
    this.store = {};
    this.length = 0;
  }

  key(n: number): any {
    if (typeof n === 'undefined') {
      throw new Error(
        "Uncaught TypeError: Failed to execute 'key' on 'Storage': 1 argument required, but only 0 present."
      );
    }

    if (n >= Object.keys(this.store).length) {
      return null;
    }

    return Object.keys(this.store)[n];
  }

  getItem(key: string): Store | null {
    if (!Object.keys(this.store).includes(key)) {
      return null;
    }

    return this.store[key];
  }

  setItem(key: string, value: any): undefined {
    if (typeof key === 'undefined' && typeof value === 'undefined') {
      throw new Error(
        "Uncaught TypeError: Failed to execute 'setItem' on 'Storage': 2 arguments required, but only 0 present."
      );
    }

    if (typeof value === 'undefined') {
      throw new Error(
        "Uncaught TypeError: Failed to execute 'setItem' on 'Storage': 2 arguments required, but only 1 present."
      );
    }

    if (!key) return undefined;

    this.store[key] = value.toString() || '';
    this.length = Object.keys(this.store).length;

    return undefined;
  }

  removeItem(key: string): undefined {
    if (typeof key === 'undefined') {
      throw new Error(
        "Uncaught TypeError: Failed to execute 'removeItem' on 'Storage': 1 argument required, but only 0 present."
      );
    }

    delete this.store[key];
    this.length = Object.keys(this.store).length;
    return undefined;
  }

  clear(): undefined {
    this.store = {};
    this.length = 0;

    return undefined;
  }
}

export const getLocalStorageMock = (): any => {
  return new LocalStorageMock();
};

global.localStorage = new LocalStorageMock();

然后创建名为session.test.ts的测试文件(session.test.js)

import { getLocalStorageMock } from '../localstorage';
describe('session storage', () => {
  let localStorage;
  beforeEach(() => {
    localStorage = getLocalStorageMock();
  });

  describe('getItem', () => {
    it('should return null if the item is undefined', () => {
      expect(localStorage.getItem('item')).toBeNull();
    });
    it("should return '' instead of null", () => {
      localStorage.setItem('item', '');
      expect(localStorage.getItem('item')).toBe('');
    });
    it('should return navid', () => {
      localStorage.setItem('item', 'navid');
      expect(localStorage.getItem('item')).toBe('navid');
    });

  });
});

或者你只是像这样使用一个模拟包:

https://www.npmjs.com/package/jest-localstorage-mock

它不仅处理存储功能,还允许您测试是否实际调用了存储。

Object.defineProperty(window, "localStorage", {
  value: {
    getItem: jest.fn(),
    setItem: jest.fn(),
    removeItem: jest.fn(),
  },
});

or

jest.spyOn(Object.getPrototypeOf(localStorage), "getItem");
jest.spyOn(Object.getPrototypeOf(localStorage), "setItem");

正如@ck4所建议的那样,文档已经清楚地解释了如何使用localStorage。然而,模拟函数无法执行任何localStorage方法。

下面是我的react组件的详细示例,它使用抽象方法来写入和读取数据,

//file: storage.js
const key = 'ABC';
export function readFromStore (){
    return JSON.parse(localStorage.getItem(key));
}
export function saveToStore (value) {
    localStorage.setItem(key, JSON.stringify(value));
}

export default { readFromStore, saveToStore };

错误:

TypeError: _setupLocalStorage2.default.setItem is not a function

解决办法: 为jest添加以下mock函数(路径:.jest/mocks/setUpStore.js)

let mockStorage = {};

module.exports = window.localStorage = {
  setItem: (key, val) => Object.assign(mockStorage, {[key]: val}),
  getItem: (key) => mockStorage[key],
  clear: () => mockStorage = {}
};

Snippet从这里引用