简体   繁体   English

开玩笑地模拟 window.sessionStorage 的最佳方法是什么

[英]what is the best way to mock window.sessionStorage in jest

Below is a very simple jest unit test and when running it, you will get error like下面是一个非常简单的 jest 单元测试,运行它时,你会得到如下错误

Cannot spyOn on a primitive value;不能监视原始值; undefined given未定义给定

TypeError: Cannot read property 'getItem' of undefined类型错误:无法读取未定义的属性“getItem”

but according to the last two comments of this post , localStorage and sessionStorage were already added to latest JSDOM and jest.但根据这篇文章的最后两条评论,localStorage 和 sessionStorage 已经添加到最新的 JSDOM 和 jest 中。 If using jest-localstorage-mock and add it to my jest setupFiles then you will see weird error like如果使用jest-localstorage-mock并将其添加到我的 jest setupFiles 那么你会看到奇怪的错误,如

TypeError: object[methodName].mockImplementation is not a function TypeError: object[methodName].mockImplementation 不是 function

So my question is what's the best way to mock localStorage/sessionStorage in jest.所以我的问题是开玩笑地模拟 localStorage/sessionStorage 的最佳方法是什么。 Thanks谢谢

describe('window.sessionStorage', () => {
    let mockSessionStorage;
    beforeEach(() => {
        mockSessionStorage = {};
        jest.spyOn(window.sessionStorage, "getItem").mockImplementation(key => {
            return mockSessionStorage[key];
        });
    });

    describe('getItem-', () => {
        beforeEach(() => {
            mockSessionStorage = {
                foo: 'bar',
            }
        });

        it('gets string item', () => {
            const ret = window.sessionStorage.getItem('foo');
            expect(ret).toBe('bar');
        });
    });
});

Below is my jest config下面是我的笑话配置

module.exports = {
    verbose: true,
    //setupFiles: ["jest-localstorage-mock"],
    testURL: "http://localhost/"
};

Here is the solution only use jestjs and typescript , nothing more.这里是解决方案仅使用jestjstypescript ,仅此而已。

index.ts : index.ts

export function getUserInfo() {
  const userInfo = window.sessionStorage.getItem('userInfo');
  if (userInfo) {
    return JSON.parse(userInfo);
  }
  return {};
}

index.spec.ts : index.spec.ts

import { getUserInfo } from './';

const localStorageMock = (() => {
  let store = {};

  return {
    getItem(key) {
      return store[key] || null;
    },
    setItem(key, value) {
      store[key] = value.toString();
    },
    removeItem(key) {
      delete store[key];
    },
    clear() {
      store = {};
    }
  };
})();

Object.defineProperty(window, 'sessionStorage', {
  value: localStorageMock
});

describe('getUserInfo', () => {
  beforeEach(() => {
    window.sessionStorage.clear();
    jest.restoreAllMocks();
  });
  it('should get user info from session storage', () => {
    const getItemSpy = jest.spyOn(window.sessionStorage, 'getItem');
    window.sessionStorage.setItem('userInfo', JSON.stringify({ userId: 1, userEmail: 'example@gmail.com' }));
    const actualValue = getUserInfo();
    expect(actualValue).toEqual({ userId: 1, userEmail: 'example@gmail.com' });
    expect(getItemSpy).toBeCalledWith('userInfo');
  });

  it('should get empty object if no user info in session storage', () => {
    const getItemSpy = jest.spyOn(window.sessionStorage, 'getItem');
    const actualValue = getUserInfo();
    expect(actualValue).toEqual({});
    expect(window.sessionStorage.getItem).toBeCalledWith('userInfo');
    expect(getItemSpy).toBeCalledWith('userInfo');
  });
});

Unit test result with 100% coverage report:带有 100% 覆盖率报告的单元测试结果:

 PASS  src/stackoverflow/51566816/index.spec.ts
  getUserInfo
    ✓ should get user info from session storage (6ms)
    ✓ should get empty object if no user info in session storage (1ms)

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |      100 |      100 |      100 |      100 |                   |
 index.ts |      100 |      100 |      100 |      100 |                   |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        4.548s, estimated 6s

Here is the completed demo: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/51566816这是完整的演示: https : //github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/51566816

You probably do not even need a mock.您可能甚至不需要模拟。 Just use window.sessionStorage as usual and write your condition based on window.sessionStorage.getItem(...) result instead of spying window.sessionStorage.setItem .只需像往常一样使用window.sessionStorage并根据window.sessionStorage.getItem(...)结果而不是监视window.sessionStorage.setItem编写您的条件。 Simply don't forget to call window.sessionStorage.clear() in beforeEach as demonstrated.只需不要忘记在beforeEach调用window.sessionStorage.clear()beforeEach所示。

From Eric Burel's comment来自Eric Burel 的评论

This works for me along with adding object:这与添加 object 一起对我有用:

defineProperty(window, 'sessionStorage', {
   writable: true,
   configurable: true,
   value: localStorageMock
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM