В современных проектах на Vue часто применяются CSS модули для изоляции стилей компонентов. CSS модули позволяют локализовать классы и предотвращают конфликты имен, но при этом создают особенности при тестировании компонентов. Vue Test Utils предоставляет гибкие возможности для проверки интеграции CSS модулей с компонентами.
CSS модули обычно подключаются через Webpack или Vite с конфигурацией
module: true. В компоненте Vue импорт CSS модуля выглядит
так:
<script setup>
import styles from './Button.module.css';
</script>
<template>
<button :class="styles.primary">Click me</button>
</template>
В тестах необходимо учитывать, что классы CSS модулей обычно
преобразуются в уникальные строки. Например, класс primary
может превратиться в Button_primary__3XyZ.
Чтобы тесты были стабильными, существует два подхода:
При тестировании Jest часто применяется мок для CSS модулей. Это позволяет вернуть оригинальные имена классов без их преобразования в уникальные строки. В конфигурации Jest можно добавить:
moduleNameMapper: {
'\\.module\\.css$': 'identity-obj-proxy'
}
identity-obj-proxy возвращает объект, где каждый ключ
CSS модуля совпадает с его значением, что упрощает проверку классов:
import { mount } from '@vue/test-utils';
import Button from '@/components/Button.vue';
import styles from '@/components/Button.module.css';
test('кнопка содержит класс primary', () => {
const wrapper = mount(Button);
expect(wrapper.classes()).toContain(styles.primary);
});
Такой подход позволяет проверять наличие классов без зависимости от внутреннего хэширования Webpack.
Компоненты Vue часто используют динамическое присвоение классов:
<template>
<button :class="[styles.button, { [styles.active]: isActive }]">Click</button>
</template>
В тестах важно правильно проверять условия:
test('кнопка активна при isActive=true', async () => {
const wrapper = mount(Button, {
props: { isActive: true }
});
expect(wrapper.classes()).toContain(styles.active);
await wrapper.setProps({ isActive: false });
expect(wrapper.classes()).not.toContain(styles.active);
});
Использование wrapper.classes() возвращает массив
классов, что упрощает проверку как статических, так и динамических CSS
модулей.
Иногда требуется убедиться, что конкретный стиль применён к элементу.
CSS модули из-за локальных классов усложняют прямое сравнение
element.style. Для таких случаев применяются методы:
classes().getComputedStyle.Пример:
test('кнопка имеет правильный цвет фона', () => {
const wrapper = mount(Button);
document.body.appendChild(wrapper.element); // нужен для getComputedStyle
const bgColor = getComputedStyle(wrapper.element).backgroundColor;
expect(bgColor).toBe('rgb(0, 123, 255)');
});
Такой способ полезен для интеграционных тестов, когда важно не только наличие класса, но и фактическое применение стилей.
Scoped CSS автоматически добавляет атрибуты вроде
data-v-xxxx к элементам. При комбинации с CSS модулями
необходимо учитывать:
wrapper.attributes().Пример проверки:
<template>
<div :class="styles.container"></div>
</template>
<style scoped>
div[data-v-1234] {
padding: 10px;
}
</style>
В тесте можно проверить как наличие класса, так и атрибут:
const wrapper = mount(Container);
expect(wrapper.classes()).toContain(styles.container);
expect(wrapper.attributes()).toHaveProperty('data-v-1234');
Это гарантирует корректное взаимодействие CSS модулей и scoped стилей.
identity-obj-proxy для стабильных классов
в Jest.wrapper.classes()
вместо прямой строки класса.getComputedStyle
только при необходимости.При использовании библиотек вроде Tailwind с CSS модулями проверка классов становится ключевой. В этом случае:
classes().getComputedStyle, так как они могут изменяться в
зависимости от темы.Пример:
const wrapper = mount(Button);
expect(wrapper.classes()).toEqual(expect.arrayContaining(['btn', 'btn-primary']));
Использование arrayContaining позволяет проверять
наличие необходимых классов без полной зависимости от всех классов
элемента.
Тщательная настройка и тестирование CSS модулей в Vue Test Utils обеспечивает стабильные и предсказуемые тесты компонентов, минимизируя риск ошибок при изменении сборки или стилей.