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


当前回答

一个更好的替代方法,它处理未定义的值(它不需要toString()),如果值不存在则返回null。用react v15、redux和redux-auth-wrapper进行了测试

class LocalStorageMock {
  constructor() {
    this.store = {}
  }

  clear() {
    this.store = {}
  }

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

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

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

global.localStorage = new LocalStorageMock

其他回答

以下解决方案兼容更严格的TypeScript、ESLint、TSLint和Prettier配置测试:{"proseWrap": "always", "semi": false, "singleQuote": true, "trailingComma": "es5"}:

class LocalStorageMock {
  public store: {
    [key: string]: string
  }
  constructor() {
    this.store = {}
  }

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

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

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

  public removeItem(key: string) {
    delete this.store[key]
  }
}
/* tslint:disable-next-line:no-any */
;(global as any).localStorage = new LocalStorageMock()

HT/ https://stackoverflow.com/a/51583401/101290了解如何更新global.localStorage

要在Typescript中做同样的事情,请执行以下步骤:

设置一个包含以下内容的文件:

let localStorageMock = (function() {
  let store = new Map()
  return {

    getItem(key: string):string {
      return store.get(key);
    },

    setItem: function(key: string, value: string) {
      store.set(key, value);
    },

    clear: function() {
      store = new Map();
    },

    removeItem: function(key: string) {
        store.delete(key)
    }
  };
})();
Object.defineProperty(window, 'localStorage', { value: localStorageMock });

然后将以下行添加到包中。json在你的Jest配置

:“setupTestFrameworkScriptFile PATH_TO_YOUR_FILE”,

或者在您想要模拟本地存储的测试用例中导入该文件。

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

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

一个使用TypeScript和Jest的更优雅的解决方案。

    interface Spies {
      [key: string]: jest.SpyInstance
    }
    
    describe('→ Local storage', () => {
    
      const spies: Spies = {}
    
      beforeEach(() => {
        ['setItem', 'getItem', 'clear'].forEach((fn: string) => {
          const mock = jest.fn(localStorage[fn])
          spies[fn] = jest.spyOn(Storage.prototype, fn).mockImplementation(mock)
        })
      })
    
      afterEach(() => {
        Object.keys(spies).forEach((key: string) => spies[key].mockRestore())
      })
    
      test('→ setItem ...', async () => {
          localStorage.setItem( 'foo', 'bar' )
          expect(localStorage.getItem('foo')).toEqual('bar')
          expect(spies.setItem).toHaveBeenCalledTimes(1)
      })
    })
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);

    });
});

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