Тестирование Scoped CSS

Scoped CSS в компонентах Vue позволяет изолировать стили конкретного компонента, предотвращая их влияние на глобальные элементы или другие компоненты. При тестировании важно убедиться, что стили применяются корректно и ведут себя ожидаемым образом при рендеринге компонента. Vue Test Utils предоставляет инструменты для работы с компонентами, но проверка Scoped CSS требует понимания того, как Vue обрабатывает атрибуты data-v-* и динамическое присваивание классов.


Основы Scoped CSS

Когда в компоненте используется <style scoped>, Vue автоматически добавляет уникальный атрибут ко всем элементам шаблона. Например:

<template>
  <div class="button">Кнопка</div>
</template>

<style scoped>
.button {
  color: red;
}
</style>

После компиляции шаблон станет примерно таким:

<div class="button" data-v-123abc>Кнопка</div>

А CSS будет преобразован в:

.button[data-v-123abc] {
  color: red;
}

Эта уникальность позволяет безопасно применять стили внутри компонента, не влияя на другие элементы с таким же классом вне компонента.


Проверка наличия Scoped CSS в тестах

Vue Test Utils не предоставляет прямой способ проверить, что конкретный стиль применен через CSS. Вместо этого используется проверка присутствия атрибута data-v-*, либо вычисленных классов и стилей через wrapper.element.

Пример:

import { mount } from '@vue/test-utils'
import Button from '@/components/Button.vue'

test('Scoped CSS применяется к элементу', () => {
  const wrapper = mount(Button)
  const div = wrapper.find('div')

  // Проверка наличия data-v-* атрибута
  expect(div.attributes()).toHaveProperty('data-v-123abc')

  // Проверка inline-стиля (если используется computed style)
  const style = window.getComputedStyle(div.element)
  expect(style.color).toBe('red')
})

Ключевой момент: уникальный атрибут генерируется при сборке с Vue CLI или Vite. В среде Jest и jsdom атрибуты будут присутствовать, но реальные CSS-свойства могут не применяться, если тестовый рантайм не поддерживает полный рендер стилей.


Тестирование реактивных классов с Scoped CSS

Scoped CSS часто комбинируется с динамическими классами:

<template>
  <button :class="{ active: isActive }">Нажми меня</button>
</template>

<script>
export default {
  data() {
    return { isActive: false }
  }
}
</script>

<style scoped>
button.active {
  background-color: blue;
}
</style>

В тестах можно проверить присутствие класса и реактивное изменение стилей через изменение состояния:

test('Динамический класс active применяется при изменении состояния', async () => {
  const wrapper = mount(Button)
  expect(wrapper.classes()).not.toContain('active')

  await wrapper.setData({ isActive: true })
  expect(wrapper.classes()).toContain('active')
})

Это позволяет гарантировать, что Scoped CSS корректно взаимодействует с реактивными данными компонента.


Работа с дочерними элементами и селекторами

Scoped CSS влияет на все элементы внутри компонента, но для тестов важно различать рендеринг в DOM и выбор элементов через wrapper.find(). Vue Test Utils позволяет использовать селекторы как обычные CSS-селекторы, а атрибут data-v-* можно проверить через attributes():

const wrapper = mount(Component)
const child = wrapper.find('span.button')
expect(child.attributes()).toHaveProperty('data-v-xyz')

Если стиль применяется к псевдоэлементам (::before, ::after) или через вложенные селекторы, jsdom не всегда отобразит computed styles. В таких случаях проверяется наличие класса или атрибута, а не фактический визуальный результат.


Mock CSS в Jest

Для изоляции тестов от реальных стилей часто используется mock стилей:

jest.mock('*.css', () => ({}))

Это позволяет не загружать реальные CSS-файлы и сосредоточиться на логике применения классов и реактивности без ошибок от jsdom.


Проверка интеграции с библиотеками компонентов

Если компонент использует UI-библиотеку с собственным Scoped CSS, Vue Test Utils позволяет:

  1. Монтировать компонент с shallowMount или mount.
  2. Проверять классы и атрибуты дочерних элементов.
  3. Использовать селекторы библиотечных классов для проверки их корректного применения.

Пример для Vuetify или Element Plus:

const wrapper = mount(MyComponent)
const button = wrapper.find('.el-button')
expect(button.attributes()).toHaveProperty('data-v-abc123')

Практические рекомендации

  • Scoped CSS следует тестировать через классы и data-атрибуты, а не через фактические визуальные свойства.
  • Для динамических стилей важна проверка реактивного изменения классов через setData или setProps.
  • Если тест зависит от computed styles, использовать window.getComputedStyle, но учитывать ограничения jsdom.
  • В больших приложениях полезно проверять отдельно взаимодействие стилей и логики, разделяя юнит-тесты компонентов и end-to-end тесты визуального отображения.

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