RTL языки и их особенности

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

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

Ключевые отличия:

  • Поток документа перемещается справа налево.
  • Поля ввода учитывают направление курсора и зеркальное поведение выделения.
  • Меняется расположение иконок (пример: кнопка поиска слева от поля).
  • Изменяются значения CSS-свойств float, text-align, margin-inline, padding-inline.

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

Создание контекста браузера с корректной локалью упрощает выявление дефектов. Для RTL-языков важны:

  • locale
  • timezoneId
  • viewport
  • deviceScaleFactor

Типовая конфигурация для арабского языка:

const context = await browser.newContext({
  locale: 'ar-EG',
  timezoneId: 'Africa/Cairo'
});

При использовании locale браузер меняет параметры Intl и форматирование дат, чисел и валют, а интерфейсы с адаптивной версткой переключаются на RTL-режим. В некоторых приложениях этот режим включается через серверную или клиентскую настройку (например, параметр dir="rtl" на уровне <html>).

Работа с селекторами и зеркальной версткой

В RTL-режиме важно проверять, что селекторы не завязаны на визуальные признаки (например, положение кнопки относительно поля). Предпочтительны:

  • role-селекторы
  • aria-label
  • test-id
  • текстовые узлы с учетом направления

Нерекомендуемые подходы: выбор по .button:first-child, .icon-left, .pull-right, так как направления могут инвертироваться.

Интернационализация данных и сравнения

Проверки текстовых значений должны учитывать Unicode-особенности: варианты нормализации, формы написания и варианты диакритики. Для числовых и временных значений используются Intl.DateTimeFormat и Intl.NumberFormat.

Пример сравнения форматированной даты:

const date = new Date('2026-01-09T10:00:00Z');
const formatted = new Intl.DateTimeFormat('ar-EG').format(date);
await expect(page.getByTestId('date')).toHaveText(formatted);

Тестирование полей ввода и поведения курсора

Поля ввода RTL отличаются направлением выделения текста, обработкой клавиш Home/End и логикой вставки. В Playwright можно эмулировать ввод с учетом локали:

await page.fill('[name="fullName"]', 'أحمد');
await page.press('[name="fullName"]', 'Home');
await page.press('[name="fullName"]', 'Shift+ArrowLeft');

Важно проверять:

  • корректность выделения справа налево
  • зеркальный перенос строки
  • курсив и наклон в сочетании с латиницей

Визуальное тестирование в RTL

Скриншотный подход критичен для зеркальных интерфейсов. Задача — фиксировать:

  • смещение иконок
  • направление списков
  • выравнивание таблиц
  • текстовые переполнения

Playwright поддерживает сравнение изображений через toHaveScreenshot(), что полезно для регрессии RTL-стилей:

await expect(page).toHaveScreenshot('rtl-home.png', { maxDiffPixelRatio: 0.02 });

При адаптивной верстке проверяются разные брейкпоинты, так как мобильные интерфейсы чаще всего содержат отдельную RTL-сетку.

Проверка навигации с клавиатуры

В RTL-языках стрелочные клавиши изменяют направление навигации. Это напрямую влияет на:

  • карусели и галереи
  • выпадающие списки
  • табы
  • меню выбора даты и времени

Пример тестирования карусели:

await page.press('[role="tablist"]', 'ArrowRight');
await page.press('[role="tablist"]', 'ArrowLeft');

В RTL-режиме может быть инверсия: ArrowRight перемещает назад, ArrowLeft — вперед. Это часто становится источником дефектов, особенно в компонентах библиотеки UI.

Особенности проверок таблиц и списков

Табличные колонки зеркально меняют порядок. Для тестов необходимо использовать явные селекторы колонок по заголовкам, а не по индексам.

const cell = page.getByRole('cell', { name: 'السعر' });
await expect(cell).toHaveText(/^[0-9]/);

Списки и древовидные структуры также подстраиваются под RTL: стрелочная навигация меняет логику разворачивания узлов.

Комбинирование RTL и LTR-контента

Часто интерфейсы содержат смешанные блоки: арабский текст, латинские имена, email-адреса и URL. Эти фрагменты имеют разные направления в пределах одного контейнера, что влияет на:

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

При тестировании такого контента полезно проверять управление unicode-bidi, direction и text-align.

Числа, валюты и форматирование

Формат отображения валют в RTL отличается положением символов, разделителей и интервалов. Например, для ar-EG пробел между значением и символом может отсутствовать или быть неразрывным. Для тестов используется Intl.NumberFormat.

const formattedPrice = new Intl.NumberFormat('ar-EG', {
  style: 'currency',
  currency: 'EGP'
}).format(1234.5);
await expect(page.getByTestId('price')).toHaveText(formattedPrice);

Рекомендации по стабильности тестов

Полезные приемы:

  • фиксация локали и часового пояса
  • отказ от позиций и индексов
  • скриншотная регрессия с раздельными эталонами LTR/RTL
  • разделение тестов по локалям (артефакты выводов, форматирования, вёрстки)
  • использование mock-данных с реальными RTL-строками

Работа с RTL-языками в Playwright требует учета культурных и технических аспектов. В сочетании с инструментами интернационализации и визуального контроля достигается высокая точность воспроизведения поведения пользователей в восточных регионах.