Testing Library для Vue: тесты с позиции пользователя

↑ 4.1 Vue 3: основы, компоненты, Composition API · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Подход «тестируйте как пользователь»: доступные селекторы и устойчивость к рефакторингу.

Объяснение

@testing-library/vue — обёртка над VTU с принципом: тесты должны напоминать то, как пользователь работает с интерфейсом. Ищем элементы по роли, тексту, label — а не по классам и внутренней структуре.

import { render, screen, within, waitFor } from "@testing-library/vue";
import userEvent from "@testing-library/user-event";
 
it("добавляет заказ через форму", async () => {
  const user = userEvent.setup();
  const onSubmit = vi.fn();
  render(OrderForm, { props: { onSubmit }, global: { plugins: [pinia] } });
 
  await user.type(screen.getByLabelText("Клиент"), "Иванов");
  await user.selectOptions(screen.getByRole("combobox", { name: "Статус" }), "paid");
  await user.click(screen.getByRole("button", { name: /сохранить/i }));
 
  expect(onSubmit).toHaveBeenCalledWith(expect.objectContaining({ customer: "Иванов" }));
  expect(await screen.findByText("Сохранено")).toBeInTheDocument();          // findBy = ожидание появления
  expect(screen.queryByRole("alert")).not.toBeInTheDocument();               // queryBy = отсутствие
});

Приоритет запросов (от предпочтительных):

ЗапросКогда
getByRole(role, { name })всё, что имеет роль (кнопки, поля, заголовки): проверяет и доступность
getByLabelTextполя форм
getByPlaceholderText, getByTextтекстовое содержимое
getByDisplayValue, getByAltText, getByTitleспецифические случаи
getByTestIdпоследнее средство

Варианты запросов: getBy (сразу, бросает при отсутствии), queryBy (для проверки отсутствия), findBy (асинхронно с ожиданием), *AllBy. waitFor — повторные проверки; within(el) — поиск внутри области. Матчеры @testing-library/jest-dom: toBeInTheDocument, toBeVisible, toBeDisabled, toHaveValue, toHaveAccessibleName.

Плюсы: тесты устойчивы к рефакторингу, побочно проверяют доступность (роли и label); минус — нужны доступные разметка и названия.

Нюансы и подводные камни

  • userEvent (реалистичные последовательности событий) предпочтительнее fireEvent.
  • Не запрашивайте по классам и структуре DOM.
  • Не используйте waitFor для синхронных проверок.
  • Для дат/таймеров — фейковые таймеры и advanceTimers в userEvent.setup.
  • Много getByTestId — признак недоступной разметки.

Практика

  1. Перепишите тест формы с VTU на Testing Library.
  2. Проверьте доступность через getByRole и name.
  3. Протестируйте асинхронное появление уведомления через findBy.

Вопросы с ответами

Связанные темы