Другое

Тестирование интернационализации в Playwright: лучшие практики выбора элементов

Изучите стратегии выбора стабильных элементов для E2E-тестов Playwright в интернационализированных React-приложениях. Избегайте выбора элементов на основе текста с помощью подходов на основе ролей и testid.

Каковы лучшие практики для идентификации HTML-элементов в современных веб-приложениях, особенно при написании тестов E2E Playwright для приложения React, поддерживающего несколько языков? Выбор элементов по тексту не работает при смене языка. Какой рекомендуемый подход следует использовать для выбора элементов в этой ситуации, чтобы обеспечить стабильность и поддерживаемость тестов?

Тестирование интернационализированных React-приложений с помощью Playwright

При написании E2E-тестов для React-приложений с интернационализацией лучшей практикой является избегать выбора элементов по текстовому содержимому и вместо этого использовать стабильные атрибуты, такие как data-testid или селекторы на основе семантических ролей. Этот подход гарантирует, что тесты останутся стабильными при переключении между разными языками, сохраняя при этом читаемость и поддерживаемость. Рекомендуемая стратегия сочетает правильную настройку локали в тестах с надежными методами выбора элементов, которые не зависят от переведенного контента.

Содержание

Почему выбор по тексту не работает в i18n-приложениях

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

Проблема селекторов, зависящих от текста

typescript
// ❌ Это не будет работать в неанглийских локалях
await page.getByText('Welcome').click();
await expect(page.getByText('Submit')).toBeVisible();

Как рекомендует команда Playwright, текстовые селекторы хрупки, потому что они зависят от контента, который различается в разных языковых реализациях. Когда ваше приложение поддерживает несколько языков, эти селекторы становятся ненадежными и нарушают стабильность вашего набора тестов.

Влияние на поддержку тестов
Тесты, использующие текстовые селекторы, требуют постоянных обновлений по мере изменения переводов, что делает их сложными в поддержке. Кроме того, они не могут эффективно тестировать саму функциональность интернационализации, что противоречит цели создания комплексных E2E-тестов для многоязычной поддержки.


Рекомендуемые стратегии выбора элементов

Для стабильных и поддерживаемых тестов в интернационализированных React-приложениях отдавайте предпочтение следующим стратегиям выбора элементов в порядке убывания приоритета:

1. Селекторы на основе ролей (getByRole)

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

typescript
// ✅ Стабильно и независимо от языка
await page.getByRole('button', { name: /submit/i }).click();
await page.getByRole('heading', { name: /welcome/i }).isVisible();

Согласно Better Stack Community, приоритет селекторов на основе ролей является лучшей практикой, поскольку они closely отражают пользовательское поведение и менее подвержены изменениям при обновлении интерфейса.

2. Атрибуты Test ID (getByTestId)

Атрибуты data-testid предоставляют надежный способ идентификации элементов, которые не имеют значимых семантических ролей или когда требуется более точное целеполагание.

typescript
// ✅ Стабильно на всех языках
await page.getByTestId('submit-button').click();
await expect(page.getByTestId('welcome-message')).toBeVisible();

TestingMint подчеркивает, что атрибуты data-testid необходимы для предотвращения нестабильных тестов, зависящих от изменений в макете или тексте. Эти атрибуты следует добавлять в ваши React-компоненты специально для целей тестирования.

3. Селекторы меток и форм

Для элементов форм используйте метки и атрибуты доступности, чтобы убедиться, что ваши тесты работают независимо от языка.

typescript
// ✅ Работает с любым языком
await page.getByLabel('Email address').fill('test@example.com');
await page.getByPlaceholder('Enter your email').fill('test@example.com');

4. Пользовательские движки селекторов

Для сложных приложений рассмотрите возможность создания пользовательских движков селекторов, которые нацелены на определенные атрибуты данных или шаблоны, используемые в ваших интернационализированных компонентах.

typescript
// Пользовательский селектор для элементов с поддержкой i18n
const $i18nElement = page.locator('[data-i18n-key="welcome"]');

Реализация практик тестирования с учетом i18n

Настройка конфигурации локали

Playwright предоставляет встроенную поддержку для тестирования разных локалей. Настройте свои тесты для использования конкретных локалей, соответствующих поддерживаемым языкам вашего приложения.

typescript
// test.spec.ts
test.use({ 
  locale: 'es-ES',
  timezoneId: 'Europe/Madrid'
});

test('Испанский языковой поток', async ({ page }) => {
  await page.goto('/es');
  // Тестирование элементов с использованием стабильных селекторов
  await page.getByRole('button', { name: /enviar/i }).click();
});

Как объясняет Jeremie Fleurant, установка локали для каждого блока тестов гарантирует, что ваш сайт правильно определяет язык, установленный в браузере, что имеет решающее значение для тестирования функций интернационализации.

Использование фикстур для доступа к переводам

Для более сложных сценариев тестирования создайте фикстуры, предоставляющие доступ к вашей системе переводов.

typescript
// i18n-fixture.ts
import { test as base } from '@playwright/test';

export const test = base.extend({
  t: async ({ page }, use) => {
    // Получите доступ к вашей i18n-системе здесь
    const translations = await page.evaluate(() => window.i18n.translations);
    await use((key) => translations[key]);
  }
});

// Использование в тестах
test('использует фикстуру переводов', async ({ t }) => {
  const translatedText = t('common.submit');
  await expect(page.getByRole('button')).toContainText(translatedText);
});

Подход playwright-i18n-fixture позволяет программно получать доступ к переводам, продолжая использовать стабильные селекторы для взаимодействия с элементами.

Тестирование переключения языков

Реализуйте тесты, которые проверяют правильность работы функции переключения языков вашего приложения.

typescript
test('функция переключения языков', async ({ page }) => {
  // Начинаем с языка по умолчанию
  await page.goto('/');
  await page.getByRole('button', { name: 'English' }).click();
  
  // Проверяем, что элементы все еще можно выбрать
  await page.getByTestId('language-selector').click();
  await page.getByRole('menuitem', { name: 'Español' }).click();
  
  // Тестируем, что контент изменился, но селекторы все еще работают
  await expect(page.getByTestId('submit-button')).toBeVisible();
});

Продвинутые техники для стабильного тестирования

Конфигурация селекторов для каждой локали

Для приложений со значительно разными макетами для каждой локали настройте специфичные для локали селекторы в вашей конфигурации Playwright.

typescript
// playwright.config.ts
export default defineConfig({
  use: {
    locale: 'en-US',
    selectors: {
      getStarted: 'getByRole("button", { name: "Get Started" })',
      headingText: 'getByTestId("main-heading")'
    }
  },
  projects: [
    {
      name: 'spanish',
      use: { 
        locale: 'es-ES',
        selectors: {
          getStarted: 'getByRole("button", { name: /comenzar/i })',
          headingText: 'getByTestId("encabezado-principal")'
        }
      }
    }
  ]
});

Как отмечено в обсуждении на Stack Overflow, этот подход позволяет поддерживать разные селекторы для разных локалей, сохраняя структуру ваших тестов.

Семантическое тестирование компонентов

Тестируйте React-компоненты в изоляции, когда это возможно, фокусируясь на их поведении, а не на содержимом.

typescript
test('счетчик увеличивается правильно', async ({ page }) => {
  await page.goto('/counter');
  const button = page.getByTestId('increment-button');
  await button.click();
  await expect(page.getByTestId('counter-value')).toHaveText('1');
});

BigBinary Academy рекомендует делать тесты поведенческими, а не техническими, фокусируясь на пользовательских взаимодействиях, а не на деталях реализации.

Комбинирование нескольких селекторов

Для сложных сценариев комбинируйте несколько стратегий селекторов для создания надежных тестов, которые работают на разных языках.

typescript
// Комбинируем роль, testid и текст (когда уместно)
const submitButton = page
  .getByRole('button', { name: /submit|enviar|send/i })
  .or(page.getByTestId('submit-button'));

await submitButton.click();

Распространенные ошибки, которых следует избегать

1. Избегайте статических таймаутов

Никогда не используйте статические таймауты, такие как waitForTimeout(3000), поскольку они делают тесты ненадежными и медленными.

typescript
// ❌ Избегайте этого
await page.waitForTimeout(3000);

// ✅ Используйте явные ожидания
await expect(page.getByRole('loading-indicator')).toBeHidden();

2. Не смешивайте текстовые и стабильные селекторы несистематично

Будьте последовательны в своей стратегии селекторов. Если вы используете test ID для большинства элементов, не переключайтесь внезапно на текстовые селекторы для некоторых.

3. Избегайте жестко закодированного языка-специфичного текста

Никогда не жестко кодируйте язык-специфичный текст в ваших тестах, поскольку это противоречит цели тестирования интернационализации.

typescript
// ❌ Это работает только для английского
await expect(page.getByText('Welcome')).toBeVisible();

// ✅ Используйте языко-независимые селекторы
await expect(page.getByTestId('welcome-message')).toBeVisible();

4. Не пренебрегайте тестированием доступности

Селекторы на основе ролей естественно поддерживают тестирование доступности, гарантируя, что ваше приложение хорошо работает с экранными читалками и другими вспомогательными технологиями.

5. Избегайте чрезмерной зависимости от одного типа селекторов

Хотя data-testid надежен, его чрезмерное использование может сделать тесты менее поддерживаемыми. Сбалансируйте его с семантическими селекторами, когда это уместно.

Заключение

При тестировании интернационализированных React-приложений с помощью Playwright ключом к стабильным и поддерживаемым тестам является избегание текстозависимых селекторов в пользу семантических и атрибутно-основанных подходов. Приоритизируйте селекторы на основе ролей (getByRole) и атрибуты test ID (getByTestId), чтобы убедиться, что ваши тесты работают последовательно на всех поддерживаемых языках. Настройте правильные настройки локали в вашей конфигурации тестов, чтобы точно имитировать разные языковые среды, и рассмотрите возможность использования фикстур для продвинутого доступа к переводам при необходимости.

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

  1. Начните внедрять атрибуты data-testid в ваших React-компонентах специально для тестирования
  2. Замените существующие текстовые селекторы на альтернативы на основе ролей
  3. Настройте конфигурации тестов, специфичные для локали, для каждого поддерживаемого языка
  4. Создайте стратегию тестирования, которая балансирует стабильность и поддерживаемость
  5. Регулярно пересматривайте и обновляйте ваши селекторы по мере развития вашего приложения

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

Источники

  1. Better Stack Community - 9 лучших практик и ловушек Playwright, которых следует избегать
  2. Jeremie Fleurant - Использование переводов с Playwright и i18n для E2E-тестов
  3. TestingMint - Глава 17 – Продвинутые советы и оптимизация Playwright
  4. Stack Overflow - playwright - какая лучшая практика для тестирования локализации
  5. DEV Community - Упростите и стабилизируйте ваши локаторы Playwright
  6. BigBinary Academy - Лучшие практики - Автоматизация с использованием Playwright
  7. BugBug Blog - Локаторы Playwright - Всеобъемлющее руководство
  8. Reddit - r/QualityAssurance - Не следует ли использовать data-testid для идентификации элементов?
  9. LambdaTest - Используйте Playwright Internal в Playwright Internal с примерами
  10. DEV Community - Тестирование с Playwright: Используйте i18next-переводы в тестах, но не t('key')
Авторы
Проверено модерацией
Модерация