Таймауты и как их избежать

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

Виды таймаутов

  1. Глобальный таймаут Устанавливается на уровне всего теста или сценария. Определяет максимальное время ожидания для любого действия, если не задано локально.

    const { test, expect } = require('@playwright/test');
    
    test.use({ timeout: 30000 }); // 30 секунд для всех тестов
  2. Таймауты команд Каждая команда Playwright может иметь собственный таймаут. Например, page.click() или page.waitForSelector(). Это позволяет гибко управлять ожиданием конкретных операций.

    await page.click('button#submit', { timeout: 5000 }); // 5 секунд
    await page.waitForSelector('#result', { timeout: 10000 }); // 10 секунд
  3. Таймаут ожидания навигации Действия, связанные с переходами между страницами (page.goto(), page.waitForNavigation()), имеют собственные таймауты, которые часто вызывают ошибки при медленной сети или тяжелых страницах.

    await page.goto('https://example.com', { timeout: 20000 });

Причины возникновения таймаутов

  • Медленная загрузка ресурсов — изображения, скрипты или сторонние виджеты могут замедлять рендер страницы.
  • Асинхронные операции — данные подгружаются после события DOMContentLoaded, и попытка взаимодействовать с элементом слишком рано приводит к таймауту.
  • Динамические селекторы — элементы появляются в DOM с задержкой, особенно при SPA (Single Page Application).
  • Неправильные селекторы — использование селекторов, которые не гарантируют уникальность или стабильность, повышает риск ошибок времени ожидания.

Стратегии предотвращения таймаутов

  1. Использование ожиданий вместо пауз Playwright рекомендует избегать статических задержек (page.waitForTimeout(5000)), так как они не гарантируют завершения асинхронной операции. Лучше использовать ожидания конкретных условий:

    await page.waitForSelector('#login-button', { state: 'visible', timeout: 10000 });
    await page.click('#login-button');

    Параметр state может быть:

    • 'attached' — элемент добавлен в DOM
    • 'visible' — элемент видим
    • 'hidden' — элемент скрыт
    • 'detached' — элемент удалён из DOM
  2. Оптимизация селекторов

    • Предпочтение data-* атрибутам (data-test-id) вместо классов или текстов.
    • Использование nth-of-type для уникализации элементов, если структура страницы сложная.
    await page.click('[data-test-id="submit-button"]');
  3. Явные ожидания навигации При переходе между страницами следует использовать комбинацию действий и ожиданий:

    await Promise.all([
      page.waitForNavigation({ timeout: 15000 }),
      page.click('a#next-page')
    ]);
  4. Увеличение таймаутов там, где это оправдано Для страниц с большим количеством данных или медленными API иногда разумно расширять таймаут команд.

    await page.waitForSelector('#data-loaded', { timeout: 30000 });
  5. Использование expect с ожиданиями Playwright Test предоставляет встроенные ассерты с возможностью ожидания:

    await expect(page.locator('#success-message')).toHaveText('Готово', { timeout: 10000 });

    Это позволяет сочетать проверку и ожидание без ручного контроля состояния элемента.

  6. Обработка нестабильных элементов Для элементов, которые появляются не всегда, можно использовать условные проверки:

    const element = page.locator('#optional-element');
    if (await element.count() > 0) {
        await element.click();
    }

Логирование и диагностика таймаутов

Для анализа причин таймаутов полезно включить детальный лог Playwright:

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch({ headless: false, slowMo: 50 });
  const context = await browser.newContext({ recordVideo: { dir: './videos/' } });
  const page = await context.newPage();
  await page.goto('https://example.com');
})();
  • slowMo позволяет замедлить выполнение команд для визуального контроля.
  • recordVideo или скриншоты помогают отследить момент, когда элемент не появился или страница зависла.

Итоговые рекомендации по таймаутам

  • Предпочтение отдавать условным ожиданиям, а не статическим паузам.
  • Использовать локальные таймауты для отдельных действий, а глобальные только как запасной механизм.
  • Анализировать и оптимизировать селекторы, избегать нестабильных элементов.
  • Комбинировать действия с ожиданиями навигации и асинхронных изменений.
  • Ведение логов и видео помогает быстро диагностировать причину таймаута.

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