Параллельные пайплайны

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


Запуск нескольких экземпляров браузера

Puppeteer поддерживает создание нескольких экземпляров браузера, каждый из которых работает независимо:

const puppeteer = require(&

async function runBrowsers() {
    const browsers = await Promise.all([
        puppeteer.launch(),
        puppeteer.launch(),
        puppeteer.launch()
    ]);

    const pages = await Promise.all(browsers.map(browser => browser.newPage()));

    await Promise.all(pages.map((page, index) => 
        page.goto(`https://example.com/page${index}`)
    ));

    await Promise.all(browsers.map(browser => browser.close()));
}

runBrowsers();

Ключевые моменты:

  • Каждый браузер изолирован и имеет собственное состояние, кэш и куки.
  • Использование Promise.all позволяет запускать действия одновременно.
  • Подход подходит для независимых тестов, но потребляет больше ресурсов.

Параллельные страницы в одном экземпляре браузера

Для экономии ресурсов можно использовать один экземпляр браузера с несколькими страницами:

const browser = await puppeteer.launch();
const pages = await Promise.all([
    browser.newPage(),
    browser.newPage(),
    browser.newPage()
]);

await Promise.all(pages.map(page => page.goto('https://example.com')));
await browser.close();

Особенности:

  • Экономит ресурсы системы.
  • Страницы могут делить общие настройки браузера (например, куки или локальное хранилище).
  • Подходит для тестов, где не требуется полная изоляция браузеров.

Управление асинхронными задачами

При работе с параллельными пайплайнами важно грамотно управлять асинхронными задачами. Puppeteer полностью поддерживает async/await и промисы:

async function processPage(url) {
    const page = await browser.newPage();
    await page.goto(url);
    const content = await page.content();
    await page.close();
    return content;
}

const urls = ['https://example.com/1', 'https://example.com/2', 'https://example.com/3'];
const results = await Promise.all(urls.map(url => processPage(url)));

Преимущества такого подхода:

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

Ограничение параллелизма

Одновременный запуск слишком большого числа страниц может перегрузить систему. Используется контроль количества параллельных потоков с помощью очередей:

const pLimit = require('p-limit');
const limit = pLimit(3);

const tasks = urls.map(url => limit(() => processPage(url)));
const results = await Promise.all(tasks);

Пояснение:

  • p-limit позволяет ограничить количество одновременно выполняющихся промисов.
  • Обеспечивает баланс между производительностью и стабильностью системы.
  • Полезно при работе с тяжелыми страницами или ограниченными ресурсами.

Параллельное тестирование с Jest и Puppeteer

При интеграции с фреймворками тестирования Puppeteer позволяет параллельное выполнение тестов через нативные возможности Jest:

describe('Parallel Tests', () => {
    const urls = ['https://example.com/1', 'https://example.com/2'];

    test.each(urls)('Check page %s', async (url) => {
        const browser = await puppeteer.launch();
        const page = await browser.newPage();
        await page.goto(url);
        const title = await page.title();
        expect(title).toBeDefined();
        await browser.close();
    });
});

Особенности:

  • test.each позволяет запускать один и тот же тест для разных данных.
  • Настройка maxWorkers в Jest контролирует количество параллельных процессов.
  • Совместное использование с Puppeteer обеспечивает изоляцию каждой страницы.

Оптимизация производительности

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

  • Использование headless режима: позволяет экономить ресурсы и ускоряет запуск браузера.
  • Повторное использование браузера: открытие новых страниц вместо новых браузеров уменьшает нагрузку на систему.
  • Минимизация загрузки ресурсов: блокировка изображений, шрифтов и других медиа ускоряет загрузку страниц.
await page.setRequestInterception(true);
page.on('request', request => {
    if (['image', 'font', 'stylesheet'].includes(request.resourceType())) {
        request.abort();
    } else {
        request.continue();
    }
});
  • Обработка ошибок: обязательно использовать try/catch для каждой параллельной задачи, чтобы сбой одной страницы не прерывал весь пайплайн.

Масштабирование на кластеры

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

const { Cluster } = require('puppeteer-cluster');

const cluster = await Cluster.launch({
    concurrency: Cluster.CONCURRENCY_PAGE,
    maxConcurrency: 5
});

await cluster.task(async ({ page, data: url }) => {
    await page.goto(url);
    console.log(await page.title());
});

cluster.queue('https://example.com');
cluster.queue('https://example.org');

await cluster.idle();
await cluster.close();

Преимущества кластера:

  • Автоматическое управление количеством одновременно открытых страниц.
  • Повторная обработка задач при сбоях.
  • Высокая стабильность при масштабировании на десятки или сотни страниц.

Выводы по организации параллельных пайплайнов

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

Понимание этих принципов позволяет строить эффективные и надежные параллельные тестовые сценарии на Puppeteer, минимизируя время выполнения и повышая производительность автоматизации.