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


当前回答

2021年,打印稿

class LocalStorageMock {
  store: { [k: string]: string };
  length: number;

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

  /**
   * @see https://developer.mozilla.org/en-US/docs/Web/API/Storage/key
   * @returns
   */
  key = (idx: number): string => {
    const values = Object.values(this.store);
    return values[idx];
  };

  clear() {
    this.store = {};
  }

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

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

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

export default LocalStorageMock;

然后你可以用它

global.localStorage = new LocalStorageMock();

其他回答

正如Niket Pathak在评论中提到的, 从jest@24 / jsdom@11.12.0及以上开始,localStorage将自动被模拟。

答:

目前(7月22日)localStorage不能像你通常会被嘲笑或监视,并在创建-反应-应用程序文档中概述。这是由于jsdom中所做的更改。你可以在jest和jsdom问题跟踪器中读到它。

作为一种变通方法,你可以监视原型:

// does not work:
jest.spyOn(localStorage, "setItem");
localStorage.setItem = jest.fn();

// either of these lines will work, different syntax that does the same thing:
jest.spyOn(Storage.prototype, 'setItem');
Storage.prototype.setItem = jest.fn();

// assertions as usual:
expect(localStorage.setItem).toHaveBeenCalled();

关于监视原型机的注意事项:

监视实例使您能够观察和模拟特定对象的行为。

另一方面,监视原型,将同时观察/操作该类的每个实例。除非您有一个特殊的用例,否则这可能不是您想要的。

但是,在本例中没有区别,因为localStorage只存在一个实例。

至少到目前为止,localStorage可以很容易地在你的笑话测试中被监视,例如:

const spyRemoveItem = jest.spyOn(window.localStorage, 'removeItem')

就是这样。你可以像以前一样使用你的间谍。

在这里引用了一些其他的答案来解决一个用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类,我使用它来访问应用程序中的所有本地存储,而不是直接访问全局本地存储变量。便于在包装器中为测试设置模拟。

这对我来说是可行的,只需要一行代码

const setItem = jest.spyOn(Object.getPrototypeOf(localStorage), 'setItem');