Тестирование интернационализации в Playwright: лучшие практики выбора элементов
Изучите стратегии выбора стабильных элементов для E2E-тестов Playwright в интернационализированных React-приложениях. Избегайте выбора элементов на основе текста с помощью подходов на основе ролей и testid.
Каковы лучшие практики для идентификации HTML-элементов в современных веб-приложениях, особенно при написании тестов E2E Playwright для приложения React, поддерживающего несколько языков? Выбор элементов по тексту не работает при смене языка. Какой рекомендуемый подход следует использовать для выбора элементов в этой ситуации, чтобы обеспечить стабильность и поддерживаемость тестов?
Тестирование интернационализированных React-приложений с помощью Playwright
При написании E2E-тестов для React-приложений с интернационализацией лучшей практикой является избегать выбора элементов по текстовому содержимому и вместо этого использовать стабильные атрибуты, такие как data-testid или селекторы на основе семантических ролей. Этот подход гарантирует, что тесты останутся стабильными при переключении между разными языками, сохраняя при этом читаемость и поддерживаемость. Рекомендуемая стратегия сочетает правильную настройку локали в тестах с надежными методами выбора элементов, которые не зависят от переведенного контента.
Содержание
- Почему выбор по тексту не работает в i18n-приложениях
- Рекомендуемые стратегии выбора элементов
- Реализация практик тестирования с учетом i18n
- Продвинутые техники для стабильного тестирования
- Распространенные ошибки, которых следует избегать
Почему выбор по тексту не работает в i18n-приложениях
При тестировании интернационализированных React-приложений выбор элементов по их текстовому содержимому становится проблематичным, поскольку видимый текст изменяется в зависимости от языковых настроек пользователя. Эта фундаментальная проблема приводит к нестабильным тестам, которые часто ломаются при переключении между разными языковыми версиями вашего приложения.
Проблема селекторов, зависящих от текста
// ❌ Это не будет работать в неанглийских локалях
await page.getByText('Welcome').click();
await expect(page.getByText('Submit')).toBeVisible();
Как рекомендует команда Playwright, текстовые селекторы хрупки, потому что они зависят от контента, который различается в разных языковых реализациях. Когда ваше приложение поддерживает несколько языков, эти селекторы становятся ненадежными и нарушают стабильность вашего набора тестов.
Влияние на поддержку тестов
Тесты, использующие текстовые селекторы, требуют постоянных обновлений по мере изменения переводов, что делает их сложными в поддержке. Кроме того, они не могут эффективно тестировать саму функциональность интернационализации, что противоречит цели создания комплексных E2E-тестов для многоязычной поддержки.
Рекомендуемые стратегии выбора элементов
Для стабильных и поддерживаемых тестов в интернационализированных React-приложениях отдавайте предпочтение следующим стратегиям выбора элементов в порядке убывания приоритета:
1. Селекторы на основе ролей (getByRole)
Селекторы ролей являются наиболее рекомендуемым подходом, поскольку они отражают то, как пользователи и вспомогательные технологии взаимодействуют с вашим приложением. Эти селекторы семантичны, стабильны и не зависят от языка.
// ✅ Стабильно и независимо от языка
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 предоставляют надежный способ идентификации элементов, которые не имеют значимых семантических ролей или когда требуется более точное целеполагание.
// ✅ Стабильно на всех языках
await page.getByTestId('submit-button').click();
await expect(page.getByTestId('welcome-message')).toBeVisible();
TestingMint подчеркивает, что атрибуты data-testid необходимы для предотвращения нестабильных тестов, зависящих от изменений в макете или тексте. Эти атрибуты следует добавлять в ваши React-компоненты специально для целей тестирования.
3. Селекторы меток и форм
Для элементов форм используйте метки и атрибуты доступности, чтобы убедиться, что ваши тесты работают независимо от языка.
// ✅ Работает с любым языком
await page.getByLabel('Email address').fill('test@example.com');
await page.getByPlaceholder('Enter your email').fill('test@example.com');
4. Пользовательские движки селекторов
Для сложных приложений рассмотрите возможность создания пользовательских движков селекторов, которые нацелены на определенные атрибуты данных или шаблоны, используемые в ваших интернационализированных компонентах.
// Пользовательский селектор для элементов с поддержкой i18n
const $i18nElement = page.locator('[data-i18n-key="welcome"]');
Реализация практик тестирования с учетом i18n
Настройка конфигурации локали
Playwright предоставляет встроенную поддержку для тестирования разных локалей. Настройте свои тесты для использования конкретных локалей, соответствующих поддерживаемым языкам вашего приложения.
// 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, установка локали для каждого блока тестов гарантирует, что ваш сайт правильно определяет язык, установленный в браузере, что имеет решающее значение для тестирования функций интернационализации.
Использование фикстур для доступа к переводам
Для более сложных сценариев тестирования создайте фикстуры, предоставляющие доступ к вашей системе переводов.
// 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 позволяет программно получать доступ к переводам, продолжая использовать стабильные селекторы для взаимодействия с элементами.
Тестирование переключения языков
Реализуйте тесты, которые проверяют правильность работы функции переключения языков вашего приложения.
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.
// 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-компоненты в изоляции, когда это возможно, фокусируясь на их поведении, а не на содержимом.
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 рекомендует делать тесты поведенческими, а не техническими, фокусируясь на пользовательских взаимодействиях, а не на деталях реализации.
Комбинирование нескольких селекторов
Для сложных сценариев комбинируйте несколько стратегий селекторов для создания надежных тестов, которые работают на разных языках.
// Комбинируем роль, testid и текст (когда уместно)
const submitButton = page
.getByRole('button', { name: /submit|enviar|send/i })
.or(page.getByTestId('submit-button'));
await submitButton.click();
Распространенные ошибки, которых следует избегать
1. Избегайте статических таймаутов
Никогда не используйте статические таймауты, такие как waitForTimeout(3000), поскольку они делают тесты ненадежными и медленными.
// ❌ Избегайте этого
await page.waitForTimeout(3000);
// ✅ Используйте явные ожидания
await expect(page.getByRole('loading-indicator')).toBeHidden();
2. Не смешивайте текстовые и стабильные селекторы несистематично
Будьте последовательны в своей стратегии селекторов. Если вы используете test ID для большинства элементов, не переключайтесь внезапно на текстовые селекторы для некоторых.
3. Избегайте жестко закодированного языка-специфичного текста
Никогда не жестко кодируйте язык-специфичный текст в ваших тестах, поскольку это противоречит цели тестирования интернационализации.
// ❌ Это работает только для английского
await expect(page.getByText('Welcome')).toBeVisible();
// ✅ Используйте языко-независимые селекторы
await expect(page.getByTestId('welcome-message')).toBeVisible();
4. Не пренебрегайте тестированием доступности
Селекторы на основе ролей естественно поддерживают тестирование доступности, гарантируя, что ваше приложение хорошо работает с экранными читалками и другими вспомогательными технологиями.
5. Избегайте чрезмерной зависимости от одного типа селекторов
Хотя data-testid надежен, его чрезмерное использование может сделать тесты менее поддерживаемыми. Сбалансируйте его с семантическими селекторами, когда это уместно.
Заключение
При тестировании интернационализированных React-приложений с помощью Playwright ключом к стабильным и поддерживаемым тестам является избегание текстозависимых селекторов в пользу семантических и атрибутно-основанных подходов. Приоритизируйте селекторы на основе ролей (getByRole) и атрибуты test ID (getByTestId), чтобы убедиться, что ваши тесты работают последовательно на всех поддерживаемых языках. Настройте правильные настройки локали в вашей конфигурации тестов, чтобы точно имитировать разные языковые среды, и рассмотрите возможность использования фикстур для продвинутого доступа к переводам при необходимости.
Практические рекомендации:
- Начните внедрять атрибуты data-testid в ваших React-компонентах специально для тестирования
- Замените существующие текстовые селекторы на альтернативы на основе ролей
- Настройте конфигурации тестов, специфичные для локали, для каждого поддерживаемого языка
- Создайте стратегию тестирования, которая балансирует стабильность и поддерживаемость
- Регулярно пересматривайте и обновляйте ваши селекторы по мере развития вашего приложения
Следуя этим практикам, вы создадите надежный набор тестов, который проверяет как функциональность вашего приложения, так и его возможности интернационализации, обеспечивая последовательный пользовательский опыт на всех поддерживаемых языках.
Источники
- Better Stack Community - 9 лучших практик и ловушек Playwright, которых следует избегать
- Jeremie Fleurant - Использование переводов с Playwright и i18n для E2E-тестов
- TestingMint - Глава 17 – Продвинутые советы и оптимизация Playwright
- Stack Overflow - playwright - какая лучшая практика для тестирования локализации
- DEV Community - Упростите и стабилизируйте ваши локаторы Playwright
- BigBinary Academy - Лучшие практики - Автоматизация с использованием Playwright
- BugBug Blog - Локаторы Playwright - Всеобъемлющее руководство
- Reddit - r/QualityAssurance - Не следует ли использовать data-testid для идентификации элементов?
- LambdaTest - Используйте Playwright Internal в Playwright Internal с примерами
- DEV Community - Тестирование с Playwright: Используйте i18next-переводы в тестах, но не
t('key')