Подтвердить что ты не робот

Как я могу работать с localStorage в тестах шутки?

Я продолжаю получать "localStorage не определено" в тестах Jest, что имеет смысл, но каковы мои варианты? Нанесение кирпичных стен.

4b9b3361

Ответ 1

Отличное решение от @chiedo

Тем не менее, мы используем синтаксис ES2015, и мне показалось, что писать его таким образом немного чище.

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

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

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

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

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

global.localStorage = new LocalStorageMock;

Ответ 2

Разобрался с помощью этого: https://groups.google.com/forum/#!topic/jestjs/9EPhuNWVYTg

Настройте файл со следующим содержимым:

var localStorageMock = (function() {
  var store = {};
  return {
    getItem: function(key) {
      return store[key];
    },
    setItem: function(key, value) {
      store[key] = value.toString();
    },
    clear: function() {
      store = {};
    },
    removeItem: function(key) {
      delete store[key];
    }
  };
})();
Object.defineProperty(window, 'localStorage', { value: localStorageMock });

Затем вы добавляете следующую строку в свой package.json под вашими конфигами Jest

"setupTestFrameworkScriptFile":"PATH_TO_YOUR_FILE",

Ответ 3

При использовании create-реагировать-приложение есть более простое и понятное решение, объясненное в документации.

Создайте src/setupTests.js и поместите в него это:

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

Вклад Тома Мерца в комментарии ниже:

Затем вы можете проверить, что ваши функции 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

Ответ 4

В настоящее время (январь 19 года) localStorage нельзя шутить или шпионить за шутками, как вы это обычно делаете, и как описано в документации create-реагировать на приложение. Это связано с изменениями, внесенными в JSDOM. Вы можете прочитать об этом здесь https://github.com/facebook/jest/issues/6798 и здесь https://github.com/jsdom/jsdom/issues/2318.

В качестве обходного пути вы можете шпионить за прототипом:

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

// works:
jest.spyOn(window.localStorage.__proto__, 'setItem');
window.localStorage.__proto__.setItem = jest.fn();

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

Ответ 5

или вы просто возьмите макет пакета, как это:

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

он обрабатывает не только функциональность хранилища, но и позволяет вам проверить, действительно ли хранилище было вызвано.

Ответ 6

Лучшая альтернатива, которая обрабатывает значения undefined (она не имеет 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

Ответ 7

Поскольку @ck4 предлагает документацию, есть четкое объяснение использования localStorage в jest. Однако фиктивные функции не выполнялись ни одним из методов localStorage.

Ниже приведен подробный пример моего компонента реагирования, который использует абстрактные методы для записи и чтения данных,

//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

Fix:
Добавьте ниже макет функции для шутки (путь: .jest/mocks/setUpStore.js)

let mockStorage = {};

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

Фрагмент ссылки здесь

Ответ 8

Сбросил некоторые другие ответы здесь, чтобы решить его для проекта с 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, который я использую для доступа к локальному хранилищу в приложении вместо прямого доступа к глобальной локальной переменной хранилища. Легко было установить макет в обертку для тестов.

Ответ 9

Если вы ищете макет, а не заглушку, вот решение, которое я использую:

export const localStorageMock = {
   getItem: jest.fn().mockImplementation(key => localStorageItems[key]),
   setItem: jest.fn().mockImplementation((key, value) => {
       localStorageItems[key] = value;
   }),
   clear: jest.fn().mockImplementation(() => {
       localStorageItems = {};
   }),
   removeItem: jest.fn().mockImplementation((key) => {
       localStorageItems[key] = undefined;
   }),
};

export let localStorageItems = {}; // eslint-disable-line import/no-mutable-exports

Я экспортирую элементы хранения для легкой инициализации. IE я могу легко установить его для объекта

В более новых версиях Jest + JSDom это невозможно установить, но локальное хранилище уже доступно, и вы можете следить за ним следующим образом:

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

Ответ 10

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

    });
});

Создайте макет и добавьте его в global объект.

Ответ 11

Я нашел это решение от github

var localStorageMock = (function() {
  var store = {};

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

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

Вы можете вставить этот код в свои установочные тесты, и он должен работать нормально.

Я проверил это в проекте с typesctipt.

Ответ 12

Следующее решение совместимо для тестирования с более строгими конфигурациями 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/fooobar.com/questions/1012562/... для того, как обновить global.localStorage

Ответ 13

Вы должны следить за прототипом объекта Storage.

const spy = jest.spyOn(Storage.prototype, 'getItem');

И после этого утверждать это как:

expect(spy).toHaveBeenCalledWith(somevalue);