Мокирование локального хранилища

При тестировании компонентов в JavaScript важным аспектом является работа с локальными хранилищами, такими как localStorage и sessionStorage. Эти механизмы используются для хранения данных в браузере и часто встречаются в реальных приложениях. Однако при написании тестов для компонентов, использующих локальное хранилище, важно правильно замокать эти объекты, чтобы избежать побочных эффектов, связанных с реальным взаимодействием с браузером. Enzyme, в сочетании с Jest, предоставляет эффективные инструменты для мокирования локального хранилища, что позволяет создать изолированные тесты и повысить стабильность тестов.

Зачем мокировать localStorage?

Работа с реальным localStorage может привести к нежелательным побочным эффектам, например, изменению данных, которые используются другими частями приложения. В процессе тестирования необходимо изолировать компоненты и убедиться, что данные хранятся и извлекаются корректно, без влияния на другие тесты или взаимодействия с браузером.

Мокирование localStorage позволяет:

  • Избежать реальных изменений данных в хранилище, что исключает непредсказуемые последствия.
  • Повысить скорость тестов, так как операции с реальным хранилищем могут быть медленнее.
  • Проверить поведение компонента в различных состояниях хранилища (например, пустое хранилище, хранилище с данными и т.д.).
  • Изолировать тесты от внешних факторов, таких как состояние других тестов или работы браузера.

Мокирование localStorage в Jest

В Jest можно мокировать объекты браузера, такие как localStorage, с помощью глобальных функций. Для этого нужно перезаписать методы localStorage, чтобы они использовались в тестах вместо реальных.

Пример мокирования localStorage с использованием Jest:

beforeEach(() => {
  const localStorageMock = (function() {
    let store = {};
    return {
      getItem: (key) => store[key] || null,
      setItem: (key, value) => { store[key] = value.toString(); },
      clear: () => { store = {}; },
      removeItem: (key) => { delete store[key]; },
    };
  })();

  global.localStorage = localStorageMock;
});

Здесь создается мок-объект localStorageMock, который имитирует поведение настоящего localStorage, но хранит данные в памяти, а не в браузере. Используя beforeEach, мы убеждаемся, что каждый тест будет начинаться с чистого состояния хранилища.

Пример теста с мокированием localStorage

Допустим, у нас есть компонент, который сохраняет и загружает данные из локального хранилища. Для его тестирования можно использовать следующий подход:

import React from 'react';
import { mount } from 'enzyme';
import MyComponent from './MyComponent';

describe('MyComponent', () => {
  beforeEach(() => {
    const localStorageMock = (function() {
      let store = {};
      return {
        getItem: (key) => store[key] || null,
        setItem: (key, value) => { store[key] = value.toString(); },
        clear: () => { store = {}; },
        removeItem: (key) => { delete store[key]; },
      };
    })();

    global.localStorage = localStorageMock;
  });

  it('should save and load data from localStorage', () => {
    const wrapper = mount(<MyComponent />);

    // Проверяем, что при первом рендере компонента данные не загружены
    expect(wrapper.find('.data').text()).toBe('');

    // Симулируем сохранение данных в localStorage
    global.localStorage.setItem('data', 'test data');
    wrapper.update();

    // Проверяем, что компонент правильно отобразил данные из localStorage
    expect(wrapper.find('.data').text()).toBe('test data');
  });
});

В этом примере компонент MyComponent использует localStorage для сохранения и получения данных. Мы мокируем localStorage, чтобы имитировать работу с ним в тестах, и проверяем, правильно ли компонент загружает и отображает данные.

Мокирование с использованием библиотеки jest-localstorage-mock

Для удобства можно использовать готовую библиотеку jest-localstorage-mock, которая автоматически мокирует localStorage и sessionStorage. Это избавляет от необходимости вручную создавать мок-объекты и обеспечивает удобную настройку для тестов.

Пример использования:

  1. Установите библиотеку:
npm install --save-dev jest-localstorage-mock
  1. Включите мокирование в конфигурации Jest (например, в файле setupTests.js):
import 'jest-localstorage-mock';

Теперь в каждом тесте можно использовать localStorage как обычно, и библиотека будет автоматически мокировать его поведение.

Мокирование sessionStorage

Аналогично localStorage, можно мокировать и sessionStorage. Основные отличия заключаются только в продолжительности хранения данных: данные в sessionStorage исчезают при закрытии вкладки браузера. Мокирование sessionStorage можно реализовать по аналогии с мокированием localStorage.

Пример мокирования sessionStorage:

beforeEach(() => {
  const sessionStorageMock = (function() {
    let store = {};
    return {
      getItem: (key) => store[key] || null,
      setItem: (key, value) => { store[key] = value.toString(); },
      clear: () => { store = {}; },
      removeItem: (key) => { delete store[key]; },
    };
  })();

  global.sessionStorage = sessionStorageMock;
});

Тестирование компонентов с асинхронной работой с хранилищем

Если компонент использует асинхронные операции с локальным хранилищем, такие как setItem и getItem, важно учитывать асинхронность этих операций при написании тестов. Например, если данные загружаются из localStorage после рендера компонента, необходимо удостовериться, что тесты ожидают выполнения всех асинхронных операций перед проверкой результатов.

Пример с асинхронной загрузкой данных:

import React, { useEffect, useState } from 'react';

const MyComponent = () => {
  const [data, setData] = useState('');

  useEffect(() => {
    const fetchData = async () => {
      const storedData = await localStorage.getItem('data');
      setData(storedData);
    };

    fetchData();
  }, []);

  return <div className="data">{data}</div>;
};

export default MyComponent;

Тест для такого компонента:

it('should load data asynchronously from localStorage', async () => {
  global.localStorage.setItem('data', 'async data');
  const wrapper = mount(<MyComponent />);

  // Ждем, пока компонент обновится после загрузки данных
  await new Promise((resolve) => setImmediate(resolve));
  wrapper.update();

  // Проверяем, что данные из localStorage были корректно загружены
  expect(wrapper.find('.data').text()).toBe('async data');
});

Вывод

Мокирование локального хранилища с использованием Jest и Enzyme позволяет создавать изолированные тесты для компонентов, взаимодействующих с localStorage или sessionStorage. Это подход помогает избежать побочных эффектов, ускоряет тестирование и позволяет легко проверить работу с хранилищем в разных состояниях.