WebdriverIO предоставляет гибкую архитектуру, позволяющую расширять функциональность с помощью кастомных сервисов. Сервис — это модуль, который интегрируется в жизненный цикл тестов, управляет состоянием тестовой среды и предоставляет вспомогательные методы, не вмешиваясь напрямую в тестовые сценарии. Создание собственного сервиса позволяет автоматизировать повторяющиеся задачи, интегрировать сторонние системы или расширять возможности отчётности.
Сервис в WebdriverIO реализуется как объект с набором методов-хуков, которые вызываются в разные моменты жизненного цикла сессии и тестов. Основные хуки включают:
onPrepare(config, capabilities) — вызывается перед
запуском тестов. Используется для подготовки среды, логирования
информации или запуска внешних сервисов.onWorkerStart(cid, caps, specs, args, execArgv) —
вызывается при старте каждого рабочего процесса в параллельном
запуске.beforeSession(config, capabilities, specs) —
выполняется перед инициализацией сессии WebDriver.before(capabilities, specs) — запускается перед
выполнением тестов в рамках сессии.beforeTest(test, context) — выполняется перед каждым
тестом.afterTest(test, context, { error, result, duration, passed, retries })
— выполняется после каждого теста.after(capabilities, specs) — вызывается после
завершения всех тестов в сессии.onComplete(exitCode, config, capabilities, results) —
вызывается после завершения всех процессов WebdriverIO. Используется для
финальной отчётности или очистки ресурсов.Сервис реализуется как класс или объект, экспортируемый модулем Node.js:
class CustomService {
constructor(options) {
this.options = options;
}
onPrepare(config, capabilities) {
console.log('Подготовка перед тестами');
}
beforeTest(test) {
console.log(`Начало теста: ${test.title}`);
}
afterTest(test, context, { error, result, duration, passed }) {
if (!passed) {
console.log(`Тест провалился: ${test.title}`);
}
}
onComplete(exitCode) {
console.log(`Тесты завершены с кодом выхода: ${exitCode}`);
}
}
module.exports = CustomService;
После реализации сервиса его необходимо зарегистрировать в
конфигурационном файле wdio.conf.js в разделе
services:
exports.config = {
// ...
services: [
[CustomService, { option1: 'value1', option2: 'value2' }]
],
// ...
};
Каждый сервис получает объект с опциями при инициализации, что позволяет создавать конфигурируемые решения, адаптированные под разные проекты.
Сервисы могут использовать глобальный объект browser
WebdriverIO для управления сессией или выполнения вспомогательных
действий. Например, можно реализовать автоматическое создание скриншотов
при падении теста:
afterTest(test, context, { error, result, duration, passed }) {
if (!passed) {
const fileName = `./errorShots/${test.title.replace(/\s+/g, '_')}.png`;
browser.saveScreenshot(fileName);
console.log(`Скриншот ошибки сохранён: ${fileName}`);
}
}
Также сервис может интегрироваться с внешними API, базами данных, CI/CD системами или системами мониторинга. Главное — не нарушать изоляцию тестов, выполняя долгие или блокирующие операции в хуках, которые вызываются перед или после каждого теста.
Сервисы WebdriverIO поддерживают передачу параметров через конфигурацию. Это позволяет создавать универсальные сервисы, которые легко адаптируются под разные сценарии. Пример с параметрами таймаута и логирования:
class CustomService {
constructor(options) {
this.timeout = options.timeout || 5000;
this.verbose = options.verbose || false;
}
beforeTest(test) {
if (this.verbose) {
console.log(`Тест начинается: ${test.title}`);
}
browser.setTimeout({ 'implicit': this.timeout });
}
}
Кастомные сервисы могут наследоваться от существующих, чтобы добавлять функциональность поверх базовой логики. Это удобно, когда требуется частичная модификация поведения, например, расширение Allure или Sauce Labs сервиса.
const SauceService = require('@wdio/sauce-service').default;
class ExtendedSauceService extends SauceService {
afterTest(test, context, { passed }) {
super.afterTest(test, context, { passed });
if (!passed) {
console.log('Дополнительная обработка падения теста на Sauce Labs');
}
}
}
module.exports = ExtendedSauceService;
Promise или быть async.Создание кастомного сервиса позволяет повысить масштабируемость тестовой инфраструктуры и стандартизировать повторяющиеся процессы без изменения тестовых сценариев. Такой подход делает проект WebdriverIO гибким и поддерживаемым на долгосрочной основе.