Тестирование адаптивности

Тестирование адаптивности интерфейсов в Vue-компонентах играет критическую роль в поддержании качественного пользовательского опыта на разных устройствах и разрешениях экранов. Vue Test Utils предоставляет инструменты для изоляции компонентов и проверки их поведения под различными условиями отображения.

Настройка окружения для тестирования адаптивности

Для работы с Vue Test Utils необходимы следующие зависимости:

npm install @vue/test-utils jest vue-jest jsdom

jsdom имитирует браузерное окружение, что позволяет тестировать реакцию компонентов на изменение размеров окна и медиазапросов.

Конфигурация Jest может включать настройку глобальных свойств для эмуляции размеров окна:

global.innerWidth = 1024;
global.innerHeight = 768;

window.resizeTo = (width, height) => {
  global.innerWidth = width;
  global.innerHeight = height;
  window.dispatchEvent(new Event('resize'));
};

Это позволяет программно изменять размеры окна и проверять адаптивное поведение компонентов.

Основные подходы к тестированию адаптивности

  1. Тестирование условного рендеринга Компоненты часто используют условные конструкции v-if, v-show или динамические классы для адаптации под различные размеры. Проверка заключается в том, чтобы изменить размеры окна и убедиться, что отображение элементов соответствует ожиданиям:
import { mount } from '@vue/test-utils';
import ResponsiveComponent from '@/components/ResponsiveComponent.vue';

test('показывает мобильное меню при малой ширине', async () => {
  window.resizeTo(480, 800);
  const wrapper = mount(ResponsiveComponent);
  
  expect(wrapper.find('.mobile-menu').exists()).toBe(true);
  expect(wrapper.find('.desktop-menu').exists()).toBe(false);
});
  1. Тестирование реактивных свойств Для компонентов, использующих computed свойства или watch для отслеживания размеров экрана, важно проверять правильное обновление значений при изменении window.innerWidth:
test('computed-свойство корректно обновляется при изменении окна', async () => {
  const wrapper = mount(ResponsiveComponent);
  window.resizeTo(320, 600);
  await wrapper.vm.$nextTick();
  
  expect(wrapper.vm.isMobile).toBe(true);
  
  window.resizeTo(1024, 768);
  await wrapper.vm.$nextTick();
  
  expect(wrapper.vm.isMobile).toBe(false);
});
  1. Использование медиазапросов CSS в тестах Проверка адаптивности через классы, которые добавляются с помощью CSS медиазапросов, требует сочетания window.getComputedStyle и имитации событий resize. Пример:
test('класс адаптивного блока корректно применяется', () => {
  window.resizeTo(500, 700);
  const wrapper = mount(ResponsiveComponent);
  
  const block = wrapper.find('.adaptive-block').element;
  const style = window.getComputedStyle(block);
  
  expect(style.display).toBe('block'); // предполагаемое поведение для мобильной версии
});

Стратегии комплексного тестирования

  • Эмуляция разных разрешений: запуск тестов с заранее определенными размерами (mobile, tablet, desktop) помогает гарантировать предсказуемость поведения.
  • Тестирование событий resize: важно проверять не только начальное состояние компонента, но и реакцию на динамическое изменение размеров окна.
  • Сравнение снимков (snapshot testing): эффективен для компонентов с сильно изменяющейся разметкой в зависимости от разрешения.
import { mount } from '@vue/test-utils';
import AdaptiveLayout from '@/components/AdaptiveLayout.vue';

test('snapshot мобильной версии', () => {
  window.resizeTo(375, 667);
  const wrapper = mount(AdaptiveLayout);
  
  expect(wrapper.html()).toMatchSnapshot();
});

Особенности работы с Vue 3 и Composition API

При использовании Composition API можно отслеживать размеры через реактивные переменные:

import { ref, onMounted, onUnmounted } from 'vue';

export default {
  setup() {
    const width = ref(window.innerWidth);

    const handleResize = () => {
      width.value = window.innerWidth;
    };

    onMounted(() => window.addEventListener('resize', handleResize));
    onUnmounted(() => window.removeEventListener('resize', handleResize));

    return { width, isMobile: computed(() => width.value < 768) };
  }
};

В тестах для такого подхода важно триггерить событие resize и ждать обновления реактивных данных через await wrapper.vm.$nextTick().

Проверка комбинаций условий

Сложные компоненты могут сочетать медиазапросы, динамические классы и условный рендеринг. Тестирование должно учитывать все комбинации, чтобы исключить визуальные или функциональные баги на различных устройствах:

const sizes = [
  { width: 375, expectedMobile: true },
  { width: 768, expectedMobile: false },
  { width: 1024, expectedMobile: false }
];

sizes.forEach(({ width, expectedMobile }) => {
  test(`адаптивное состояние для ширины ${width}`, async () => {
    window.resizeTo(width, 800);
    const wrapper = mount(ResponsiveComponent);
    await wrapper.vm.$nextTick();
    expect(wrapper.vm.isMobile).toBe(expectedMobile);
  });
});

Такой подход обеспечивает покрытие всех критических сценариев и позволяет выявить скрытые ошибки адаптивной верстки.

Важные моменты при интеграции с CI/CD

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