Мокирование window объекта

Мокирование глобального объекта window в тестах с использованием библиотеки Enzyme часто требуется для имитации работы браузерных API или для проверки поведения компонентов, зависимых от этих API. window является важной частью окружения браузера, и, зачастую, в тестах нужно эмулировать его методы или свойства, чтобы протестировать их взаимодействие с компонентами, не запуская полноценное браузерное окружение.

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

Глобальный объект window предоставляет доступ ко многим важным методам и свойствам, таким как localStorage, sessionStorage, document, location, а также событиям, таким как resize, scroll и другим. В тестах, написанных с использованием Enzyme, может возникнуть необходимость в том, чтобы заменить поведение этих методов или свойств для обеспечения контролируемых условий тестирования. Это полезно, например, когда необходимо протестировать компоненты, которые взаимодействуют с браузерными API, или проверить, как компоненты обрабатывают события, происходящие в окне браузера.

Мокирование с использованием Jest

Jest — это тестовая среда, которая тесно интегрируется с Enzyme и предоставляет возможность мокировать глобальные объекты, такие как window, через свою встроенную функциональность. Мокирование объектов может быть выполнено как на уровне глобальных переменных, так и для конкретных методов объекта window.

Мокирование методов объекта window

Для того чтобы замокировать метод window, нужно использовать встроенные функции Jest, такие как jest.spyOn() или напрямую изменять глобальные методы. Например, если необходимо замокировать метод window.alert, то это можно сделать так:

describe('Тестирование компонента с alert', () => {
  let alertMock;

  beforeEach(() => {
    alertMock = jest.spyOn(window, 'alert').mockImplementation(() => {});
  });

  afterEach(() => {
    alertMock.mockRestore();
  });

  it('должен вызывать alert при определенном условии', () => {
    const wrapper = mount(<MyComponent />);
    wrapper.find('button').simulate('click');
    
    expect(alertMock).toHaveBeenCalledWith('Клик по кнопке');
  });
});

Здесь происходит замена реализации метода alert на пустую функцию, которая ничего не делает. Это предотвращает фактический вызов alert в процессе тестирования. После выполнения теста метод восстанавливается с помощью mockRestore.

Мокирование свойств объекта window

Иногда необходимо замокировать не методы, а свойства объекта window, такие как window.location или window.innerWidth. Например, если тестируется компонент, который зависит от размеров окна браузера, можно замокировать свойство innerWidth:

describe('Тестирование компонента, зависящего от window.innerWidth', () => {
  let originalInnerWidth;

  beforeEach(() => {
    originalInnerWidth = window.innerWidth;
    Object.defineProperty(window, 'innerWidth', {
      writable: true,
      value: 1024
    });
  });

  afterEach(() => {
    Object.defineProperty(window, 'innerWidth', {
      writable: true,
      value: originalInnerWidth
    });
  });

  it('должен рендерить компонент по-разному в зависимости от ширины экрана', () => {
    const wrapper = mount(<MyComponent />);
    expect(wrapper.find('.responsive-class')).toHaveLength(1);
  });
});

В этом примере изменяется значение window.innerWidth перед выполнением теста, что позволяет протестировать компонент в условиях, когда ширина экрана равна 1024 пикселей. После выполнения теста свойство возвращается в исходное состояние.

Мокирование событий окна

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

Мокирование события resize

Для замокирования события resize необходимо использовать функцию jest.fn() и вручную симулировать его с помощью window.dispatchEvent().

describe('Тестирование компонента с обработчиком события resize', () => {
  let resizeSpy;

  beforeEach(() => {
    resizeSpy = jest.fn();
    window.addEventListener('resize', resizeSpy);
  });

  afterEach(() => {
    window.removeEventListener('resize', resizeSpy);
  });

  it('должен вызывать обработчик resize при изменении размера окна', () => {
    const wrapper = mount(<MyComponent />);
    window.dispatchEvent(new Event('resize'));

    expect(resizeSpy).toHaveBeenCalled();
  });
});

В этом примере создается шпион для события resize, который проверяет, был ли вызван обработчик этого события, когда оно происходит в окне браузера.

Мокирование события scroll

Аналогично, можно мокировать событие прокрутки scroll:

describe('Тестирование компонента с обработчиком события scroll', () => {
  let scrollSpy;

  beforeEach(() => {
    scrollSpy = jest.fn();
    window.addEventListener('scroll', scrollSpy);
  });

  afterEach(() => {
    window.removeEventListener('scroll', scrollSpy);
  });

  it('должен вызывать обработчик scroll при прокрутке окна', () => {
    const wrapper = mount(<MyComponent />);
    window.dispatchEvent(new Event('scroll'));

    expect(scrollSpy).toHaveBeenCalled();
  });
});

Здесь также используется шпион, чтобы отслеживать вызов обработчика события scroll.

Мокирование других браузерных API

Иногда компоненты могут зависеть от других браузерных API, таких как localStorage, sessionStorage или navigator. Мокирование этих объектов можно выполнить аналогичным образом, используя функции Jest для замены их стандартной реализации.

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

describe('Тестирование компонента с использованием localStorage', () => {
  let localStorageMock;

  beforeEach(() => {
    localStorageMock = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn()
    };
    global.localStorage = localStorageMock;
  });

  afterEach(() => {
    jest.restoreAllMocks();
  });

  it('должен сохранять данные в localStorage', () => {
    const wrapper = mount(<MyComponent />);
    wrapper.find('button').simulate('click');

    expect(localStorageMock.setItem).toHaveBeenCalledWith('key', 'value');
  });
});

В данном примере создается мок для объекта localStorage, который позволяет контролировать поведение методов getItem, setItem и removeItem.

Особенности мокирования window в Enzyme

Мокирование объекта window в Enzyme требует внимательности, особенно при работе с глобальными состояниями, такими как размеры окна или события. Важно помнить, что мокирование должно быть минимальным и только для тех частей, которые действительно нужны для тестирования компонента. Это позволит избежать излишней сложности и не повлияет на другие тесты, которые могут работать с реальными значениями этих объектов.

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