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


当前回答

上面的答案对我都没用。经过一番挖掘,这就是我要做的。这要归功于一些来源和其他答案。

https://www.codeblocq.com/2021/01/Jest-Mock-Local-Storage/ https://github.com/facebook/jest/issues/6798#issuecomment-440988627 https://gist.github.com/mayank23/7b994385eb030f1efb7075c4f1f6ac4c https://github.com/facebook/jest/issues/6798#issuecomment-514266034

我的全部要点:https://gist.github.com/ar-to/01fa07f2c03e7c1b2cfe6b8c612d4c6b

/**
 * Build Local Storage object
 * @see https://www.codeblocq.com/2021/01/Jest-Mock-Local-Storage/ for source
 * @see https://stackoverflow.com/a/32911774/9270352 for source
 * @returns
 */
export const fakeLocalStorage = () => {
  let store: { [key: string]: string } = {}

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

/**
 * Mock window properties for testing
 * @see https://gist.github.com/mayank23/7b994385eb030f1efb7075c4f1f6ac4c for source
 * @see https://github.com/facebook/jest/issues/6798#issuecomment-514266034 for sample implementation
 * @see https://developer.mozilla.org/en-US/docs/Web/API/Window#properties for window properties
 * @param { string } property window property string but set to any due to some warnings
 * @param { Object } value for property
 *
 * @example
 *
 *  const testLS = {
 *    id: 5,
 *    name: 'My Test',
 *  }
 * mockWindowProperty('localStorage', fakeLocalStorage())
 * window.localStorage.setItem('currentPage', JSON.stringify(testLS))
 *
 */
const mockWindowProperty = (property: string | any, value: any) => {
  const { [property]: originalProperty } = window
  delete window[property]
  beforeAll(() => {
    Object.defineProperty(window, property, {
      configurable: true,
      writable: true,
      value,
    })
  })
  afterAll(() => {
    window[property] = originalProperty
  })
}

export default mockWindowProperty

其他回答

describe('getToken', () => {
    const Auth = new AuthService();
    const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Ik1yIEpvc2VwaCIsImlkIjoiNWQwYjk1Mzg2NTVhOTQ0ZjA0NjE5ZTA5IiwiZW1haWwiOiJ0cmV2X2pvc0Bob3RtYWlsLmNvbSIsInByb2ZpbGVVc2VybmFtZSI6Ii9tcmpvc2VwaCIsInByb2ZpbGVJbWFnZSI6Ii9Eb3Nlbi10LUdpci1sb29rLWN1dGUtbnVrZWNhdDMxNnMtMzExNzAwNDYtMTI4MC04MDAuanBnIiwiaWF0IjoxNTYyMzE4NDA0LCJleHAiOjE1OTM4NzYwMDR9.YwU15SqHMh1nO51eSa0YsOK-YLlaCx6ijceOKhZfQZc';
    beforeEach(() => {
        global.localStorage = jest.fn().mockImplementation(() => {
            return {
                getItem: jest.fn().mockReturnValue(token)
            }
        });
    });
    it('should get the token from localStorage', () => {

        const result  = Auth.getToken();
        expect(result).toEqual(token);

    });
});

创建一个模拟并将其添加到全局对象

如果使用create-react-app,文档中解释了一个更简单和直接的解决方案。

创建src/setupTests.js,并把这个放在里面:

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

Tom Mertz的评论如下:

然后,您可以通过执行以下操作来测试localStorageMock的函数是否被使用

expect(localStorage.getItem).toBeCalledWith('token')
// or
expect(localStorage.getItem.mock.calls.length).toBe(1)

在你的测试中,如果你想确保它被调用。查看https://facebook.github.io/jest/docs/en/mock-functions.html

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

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

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

2022年12月:Nx 14使用Angular 14 Jest。 我们有一个测试设置。Ts文件在每个app和libs文件夹。我们设置本地存储模拟全局。

import 'jest-preset-angular/setup-jest';

Storage.prototype.getItem = jest.fn();
Storage.prototype.setItem = jest.fn();
Storage.prototype.removeItem = jest.fn();

然后localStorage.service.spec.ts文件如下所示:

import { LocalStorageService } from './localstorage.service';

describe('LocalStorageService', () => {
    let localStorageService: LocalStorageService;

    beforeEach(() => {
        localStorageService = new LocalStorageService();
    });

    it('should set "identityKey" in localStorage', async () => {
        localStorageService.saveData('identityKey', '99');
        expect(window.localStorage.setItem).toHaveBeenCalled();
 expect(window.localStorage.setItem).toHaveBeenCalledWith('identityKey', '99');
        expect(window.localStorage.setItem).toHaveBeenCalledTimes(1);
});

it('should get "identityKey" from localStorage', async () => {
    localStorageService.getData('identityKey');
    expect(window.localStorage.getItem).toHaveBeenCalled();
    expect(window.localStorage.getItem).toHaveBeenCalledWith('identityKey');
    expect(window.localStorage.getItem).toHaveBeenCalledTimes(1);
});

it('should remove "identityKey" from localStorage', async () => {
    localStorageService.removeData('identityKey');
    expect(window.localStorage.removeItem).toHaveBeenCalled();
expect(window.localStorage.removeItem).toHaveBeenCalledWith('identityKey');
            expect(window.localStorage.removeItem).toHaveBeenCalledTimes(1);
        });
    });

注:不好意思,这个SatckOverflow窗口很糟糕。

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();