Работа с памятью и утечками

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


Управление жизненным циклом браузера, контекста и страницы

Основные объекты Playwright, которые потребляют память:

  • Browser — экземпляр браузера.
  • BrowserContext — отдельная среда внутри браузера, изолирующая куки и сессии.
  • Page — отдельная вкладка, в которой выполняется взаимодействие с сайтом.

Неправильное управление этими объектами приводит к накапливанию памяти. Рекомендуется использовать строгий порядок создания и закрытия:

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

(async () => {
    const browser = await chromium.launch();
    const context = await browser.newContext();
    const page = await context.newPage();

    await page.goto('https://example.com');

    await page.close();
    await context.close();
    await browser.close();
})();

Ключевой момент: каждый созданный объект необходимо явно закрывать. Использование browser.close() автоматически закрывает все контексты и страницы, но при работе с множеством параллельных страниц лучше закрывать их вручную, чтобы высвободить память быстрее.


Работа с большим количеством страниц

При тестировании масштабируемых сценариев часто создаются десятки страниц. Удерживание всех страниц одновременно может привести к резкому росту потребления памяти. Для оптимизации:

  • Использовать пулы страниц и повторно открывать уже существующие объекты.
  • Избегать длительного хранения ссылок на страницы в глобальных переменных.
  • Удалять обработчики событий после завершения работы:
page.on('console', msg => console.log(msg.text()));
// ...
page.removeAllListeners();

Это предотвращает накопление объектов, связанных с коллбэками.


Мониторинг памяти

Playwright предоставляет возможность собирать данные о потреблении памяти браузером через CDP (Chrome DevTools Protocol) для Chromium:

const client = await context.newCDPSession(page);
const memory = await client.send('Memory.getAllTimeSamplingProfile');
console.log(memory);

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


Управление временными файлами и ресурсами

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

  • Использовать контексты без сохранения данных (browser.newContext() без storageState), если нет необходимости сохранять состояние между тестами.
  • Регулярно очищать временные файлы с помощью context.clearCookies() или context.close().
  • При работе с большими медиафайлами следить, чтобы ссылки на них не сохранялись в переменных после закрытия страниц.

Параллельные прогоны и утечки памяти

При запуске нескольких тестов одновременно (например, через test.parallel() в Playwright Test) важно учитывать:

  • Каждый тест получает отдельный контекст. Неправильное закрытие контекста приводит к накоплению объектов.
  • Не использовать глобальные страницы для параллельных тестов, чтобы избежать конфликта ресурсов и утечек.
  • Следить за асинхронными операциями. Незавершенные промисы, таймеры или сетевые события могут удерживать страницы в памяти.
test('example', async ({ browser }) => {
    const context = await browser.newContext();
    const page = await context.newPage();

    await page.goto('https://example.com');

    await page.close();
    await context.close();
});

Отслеживание утечек через инструментальные средства

Для выявления утечек используются несколько подходов:

  1. Профилирование Node.js — позволяет отслеживать удерживаемые объекты на уровне тестового процесса.
  2. Chrome DevTools Protocol — снимает снимки памяти браузера и показывает количество DOM-элементов, страниц и контекстов.
  3. Логи Playwright — включение DEBUG=pw:api помогает выявить объекты, которые не были закрыты.

Регулярное профилирование помогает находить сценарии с утечками еще на этапе написания тестов, предотвращая замедление выполнения и падение системы при длительных прогонках.


Практики предотвращения утечек

  • Закрывать все страницы и контексты после теста.
  • Не хранить ссылки на страницы в глобальных объектах.
  • Использовать beforeEach и afterEach для автоматического создания и закрытия контекстов.
  • Проверять асинхронные операции: setTimeout, setInterval, обработчики событий.
  • Минимизировать хранение больших объектов в памяти между тестами.

Выводы по управлению памятью

Эффективное управление памятью в Playwright требует дисциплины и внимательности к жизненному циклу объектов. Каждая страница, каждый контекст и каждый браузер создают свои ресурсы, которые нужно контролировать. Использование профилирования, закрытия объектов и очистки временных данных позволяет поддерживать стабильное выполнение тестов и предотвращает накопление утечек даже при сложных параллельных сценариях.