Настройка Babel для JSX и Template Syntax

В контексте Vue Test Utils Babel используется для трансформации исходного кода компонентов и тестов в формат, который понимает среда выполнения тестов (Node.js, jsdom). Это особенно важно при использовании JSX и Template Syntax, поскольку оба варианта требуют предварительной компиляции.

Babel в тестовой среде решает несколько задач:

  • транспиляция современного JavaScript (ES2015+);
  • поддержка JSX в Vue 3;
  • единое поведение кода между браузером и тестовым раннером;
  • корректная обработка render-функций и шаблонов.

Базовая конфигурация Babel для тестов

Минимальная конфигурация Babel для Vue-проектов строится вокруг @babel/preset-env. Для тестирования важно, чтобы код компилировался под текущую версию Node.js.

babel.config.js

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        targets: {
          node: 'current'
        }
      }
    ]
  ]
}

Использование babel.config.js, а не .babelrc, позволяет Babel корректно работать с монорепозиториями и тестовыми раннерами (Jest, Vitest), которые запускаются из корня проекта.


Поддержка JSX в Vue 3

JSX в Vue 3 не является частью стандартной сборки и подключается явно через Babel-плагин.

Установка зависимостей

npm install --save-dev @vue/babel-plugin-jsx

Подключение JSX-плагина

babel.config.js

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      { targets: { node: 'current' } }
    ]
  ],
  plugins: [
    '@vue/babel-plugin-jsx'
  ]
}

Этот плагин компилирует JSX в вызовы h() и корректно обрабатывает Vue-специфичные конструкции: v-model, v-show, slots, emit.


JSX в тестах с Vue Test Utils

JSX часто используется в тестах для лаконичного описания компонентов-заглушек или динамических wrapper-компонентов.

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

const WrapperComponent = {
  render() {
    return (
      <div>
        <span class="label">Текст</span>
      </div>
    )
  }
}

test('рендер JSX-компонента', () => {
  const wrapper = mount(WrapperComponent)
  expect(wrapper.find('.label').exists()).toBe(true)
})

Без Babel-плагина JSX такой код не будет исполняться в тестовой среде.


Template Syntax и Babel

Шаблоны Vue (<template>) не компилируются напрямую Babel’ом. За их обработку отвечает компилятор Vue (@vue/compiler-sfc). Однако Babel участвует косвенно — он обрабатывает результат компиляции шаблона, который превращается в render-функцию.

В тестах это выглядит прозрачно:

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

test('рендер шаблона', () => {
  const wrapper = mount(MyComponent)
  expect(wrapper.text()).toContain('Hello')
})

Важно, чтобы тестовый раннер был настроен на работу с .vue-файлами. Babel здесь отвечает за:

  • <script> и <script setup>;
  • современный синтаксис JavaScript внутри компонентов;
  • JSX, если он используется вместо шаблонов.

Совмещение JSX и Template Syntax

В одном проекте допустимо использовать оба подхода:

  • template — для обычных компонентов;
  • render() + JSX — для тестовых заглушек и динамических компонентов.

Пример смешанного подхода в тесте:

const Stub = {
  props: ['msg'],
  render() {
    return <div class="stub">{this.msg}</div>
  }
}
mount(MyComponent, {
  global: {
    stubs: {
      ChildComponent: Stub
    }
  }
})

Babel обязан поддерживать оба синтаксиса, иначе тесты начнут падать на этапе трансформации.


Интеграция Babel с Jest

Jest требует явного указания трансформера.

jest.config.js

module.exports = {
  transform: {
    '^.+\\.js$': 'babel-jest',
    '^.+\\.vue$': '@vue/vue3-jest'
  }
}

Здесь:

  • babel-jest использует babel.config.js;
  • @vue/vue3-jest компилирует шаблоны и передаёт результат в Babel.

Без корректной Babel-конфигурации JSX внутри .js и <script> секций .vue работать не будет.


Интеграция Babel с Vitest

Vitest использует Vite и esbuild, но Babel всё равно может понадобиться — особенно для нестандартных плагинов и JSX.

vite.config.js

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'

export default defineConfig({
  plugins: [
    vue(),
    vueJsx()
  ],
  test: {
    environment: 'jsdom'
  }
})

В этом случае Babel-плагин @vue/babel-plugin-jsx может не понадобиться, так как JSX обрабатывается через Vite. Однако при использовании Babel напрямую (например, в монорепозиториях) конфигурация остаётся актуальной.


Частые проблемы и причины

Синтаксическая ошибка JSX в тестах Причина: отсутствует @vue/babel-plugin-jsx или он не подключён в конфигурации, которую использует тестовый раннер.

Unexpected token < Причина: .vue-файл или JSX не прошёл через соответствующий трансформер.

Разное поведение кода в браузере и тестах Причина: Babel настроен под браузеры, а не под node: 'current'.


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

  • использовать единый babel.config.js для приложения и тестов;
  • явно указывать targets.node для тестовой среды;
  • не смешивать Babel JSX и Vite JSX без понимания цепочки трансформаций;
  • держать конфигурацию Babel минимальной и расширять её только при необходимости.

Корректная настройка Babel — фундамент для стабильной работы Vue Test Utils, особенно в проектах, где активно используются JSX, render-функции и сложные тестовые обёртки.