Strategy паттерн для мультибраузерности

Мультибраузерное тестирование является одной из ключевых задач автоматизации современного веб-приложения. Playwright предоставляет встроенную поддержку нескольких браузеров — Chromium, Firefox и WebKit. Для эффективного управления различными браузерными контекстами и обеспечения гибкости тестовой инфраструктуры используется паттерн Strategy. Он позволяет инкапсулировать логику работы с браузерами и легко переключать их без изменения кода тестов.


Принципы Strategy паттерна

Паттерн Strategy предполагает выделение общего интерфейса для выполнения определённой операции и создание нескольких реализаций этого интерфейса. В контексте Playwright:

  • Интерфейс описывает методы для запуска браузера, создания страниц и управления контекстами.
  • Конкретные стратегии реализуют интерфейс для Chromium, Firefox и WebKit.
  • Контекст тестирования выбирает нужную стратегию во время выполнения.

Преимущества использования Strategy:

  • Гибкость: легко добавлять поддержку новых браузеров.
  • Поддерживаемость: тесты не зависят от конкретного браузера.
  • Повторное использование: общий код для тестов работает с любым браузером.

Определение интерфейса

Для реализации Strategy создаётся базовый интерфейс BrowserStrategy. Он описывает минимальный набор операций:

class BrowserStrategy {
  async launch() {
    throw new Error('Метод launch() должен быть реализован');
  }

  async newContext() {
    throw new Error('Метод newContext() должен быть реализован');
  }

  async close() {
    throw new Error('Метод close() должен быть реализован');
  }
}

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

  • launch() — инициализация браузера.
  • newContext() — создание нового контекста для теста.
  • close() — завершение работы браузера.

Реализация конкретных стратегий

Для каждого браузера создаются отдельные классы, наследующиеся от BrowserStrategy.

ChromiumStrategy:

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

class ChromiumStrategy extends BrowserStrategy {
  async launch() {
    this.browser = await chromium.launch({ headless: false });
  }

  async newContext() {
    this.context = await this.browser.newContext();
    return this.context.newPage();
  }

  async close() {
    await this.browser.close();
  }
}

FirefoxStrategy:

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

class FirefoxStrategy extends BrowserStrategy {
  async launch() {
    this.browser = await firefox.launch({ headless: false });
  }

  async newContext() {
    this.context = await this.browser.newContext();
    return this.context.newPage();
  }

  async close() {
    await this.browser.close();
  }
}

WebKitStrategy:

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

class WebKitStrategy extends BrowserStrategy {
  async launch() {
    this.browser = await webkit.launch({ headless: false });
  }

  async newContext() {
    this.context = await this.browser.newContext();
    return this.context.newPage();
  }

  async close() {
    await this.browser.close();
  }
}

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


Использование контекста с Strategy

Контроллер или BrowserContextManager выбирает нужную стратегию и предоставляет тестам готовую страницу:

class BrowserContextManager {
  constructor(strategy) {
    this.strategy = strategy;
  }

  async init() {
    await this.strategy.launch();
    this.page = await this.strategy.newContext();
  }

  async close() {
    await this.strategy.close();
  }

  getPage() {
    return this.page;
  }
}

Пример использования с разными браузерами:

(async () => {
  const chromiumManager = new BrowserContextManager(new ChromiumStrategy());
  await chromiumManager.init();

  const page = chromiumManager.getPage();
  await page.goto('https://example.com');
  console.log(await page.title());

  await chromiumManager.close();
})();

Подобная структура позволяет легко подменять браузер, не изменяя тестовую логику.


Интеграция с тестовыми фреймворками

Для Playwright-тестов с Jest, Mocha или Playwright Test можно использовать фабрику стратегий:

function getBrowserStrategy(browserName) {
  switch (browserName) {
    case 'chromium': return new ChromiumStrategy();
    case 'firefox': return new FirefoxStrategy();
    case 'webkit': return new WebKitStrategy();
    default: throw new Error(`Неизвестный браузер: ${browserName}`);
  }
}

// Пример конфигурации Playwright Test
const browserManager = new BrowserContextManager(getBrowserStrategy(process.env.BROWSER));

beforeAll(async () => {
  await browserManager.init();
});

afterAll(async () => {
  await browserManager.close();
});

test('Заголовок страницы', async () => {
  const page = browserManager.getPage();
  await page.goto('https://example.com');
  expect(await page.title()).toBe('Example Domain');
});

Расширение возможностей

Strategy паттерн легко расширяется для:

  • Настроек браузера (viewport, geolocation, permissions).
  • Параллельного запуска нескольких браузеров.
  • Разделения конфигураций для локального и CI окружений.

Пример добавления пользовательских настроек:

class ChromiumStrategy extends BrowserStrategy {
  constructor(options = {}) {
    super();
    this.options = options;
  }

  async launch() {
    this.browser = await chromium.launch(this.options);
  }
}

Теперь можно создавать инстанс с разными параметрами:

const headlessChromium = new ChromiumStrategy({ headless: true });
const fullChromium = new ChromiumStrategy({ headless: false });

Выводы по архитектуре

Использование Strategy паттерна при мультибраузерном тестировании в Playwright:

  • Разделяет логику браузеров и тестов.
  • Позволяет централизованно управлять конфигурацией.
  • Упрощает расширение и поддержку тестового фреймворка.
  • Обеспечивает читаемость и чистоту кода.

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