Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Principle:Webdriverio Webdriverio Custom Service Development

From Leeroopedia
Revision as of 18:02, 16 February 2026 by Admin (talk | contribs) (Auto-imported from principles/Webdriverio_Webdriverio_Custom_Service_Development.md)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Template:Metadata

Overview

A plugin architecture for extending the WDIO test lifecycle through custom service classes that hook into predefined execution points.

Description

Custom Service Development enables extending WebdriverIO's behavior at specific lifecycle points without modifying core code. Services can intercept test preparation (onPrepare), session creation (beforeSession), test execution (beforeTest/afterTest), and completion (onComplete). This supports use cases like custom logging, test data setup, third-party integrations, and environment management.

The service architecture divides the test execution into two distinct process contexts:

  • Launcher process -- The main process that orchestrates test execution. Launcher hooks (onPrepare, onWorkerStart, onWorkerEnd, onComplete) run here. This is where you set up shared resources like databases, servers, or tunnels.
  • Worker process -- Each test worker runs in its own process. Worker hooks (beforeSession, before, beforeTest, afterTest, after, afterSession) run here. This is where you interact with the browser instance.

This separation is critical because launcher services and worker services are instantiated independently. A service can export both a launcher class (via a static launcher property or a named launcher export) and a default worker class. If a service only exports a launcher class, it is added to the ignoredWorkerServices list so it is not loaded in worker processes.

Services receive three constructor arguments:

  1. options -- Service-specific configuration passed as the second element of the [service, options] tuple
  2. capabilities -- The resolved capabilities for the current session
  3. config -- The full WDIO configuration object

This provides services with complete context about the test environment, enabling them to adapt their behavior based on the target browser, test framework, or custom settings.

Usage

Use Custom Service Development when you need to extend WDIO's behavior beyond what built-in services provide. Common use cases include:

  • Test data management -- Setting up and tearing down test databases before/after test suites
  • Authentication -- Acquiring and injecting authentication tokens before sessions
  • Custom dashboards -- Sending test results to internal reporting systems
  • Environment management -- Starting/stopping local servers, tunnels, or containers
  • Pre/post-test cleanup -- Clearing browser state, resetting application data between tests

Creating a basic custom service:

// my.custom.service.js
export default class CustomService {
    constructor(serviceOptions, capabilities, config) {
        this.options = serviceOptions
    }

    // Runs in the launcher process before any workers start
    onPrepare(config, capabilities) {
        console.log('Setting up shared resources...')
    }

    // Runs in each worker before tests begin
    before(capabilities, specs) {
        console.log('Worker initialized for specs:', specs)
    }

    // Runs before each test
    beforeTest(test, context) {
        console.log('About to run:', test.title)
    }

    // Runs after each test
    afterTest(test, context, { error, result, duration, passed }) {
        if (!passed) {
            console.log('Test failed:', test.title, error?.message)
        }
    }

    // Runs in the launcher after all workers finish
    onComplete(exitCode, config, capabilities, results) {
        console.log('All tests complete. Exit code:', exitCode)
    }
}

Registering the service:

// wdio.conf.ts
import CustomService from './my.custom.service.js'

export const config: WebdriverIO.Config = {
    services: [
        [CustomService, { someOption: true }]
    ]
}

Inline service (object form):

// wdio.conf.ts -- services can also be plain objects
export const config: WebdriverIO.Config = {
    services: [
        [{ beforeTest: (test) => console.log('Running:', test.title) }]
    ]
}

When to use:

  • When existing WDIO services do not cover your integration requirements
  • When you need custom setup/teardown logic around the test lifecycle
  • When building reusable test infrastructure for your organization

When not to use:

  • When a built-in or community service already exists for your use case
  • For one-off setup logic that can be handled in before/after hooks in the config file

Theoretical Basis

Services implement the Plugin/Hook pattern. WDIO defines 20+ lifecycle hooks executed at specific points (preparation, session creation, test execution, cleanup). Services register for these hooks by implementing methods with the hook names. The executeHooksWithArgs utility calls all registered hook implementations, collecting results and errors.

This is an extension of the Strategy pattern where multiple strategies (services) can be active simultaneously. Unlike a traditional strategy where one implementation is selected, all active services receive every lifecycle event, and their hook implementations are called in registration order.

The hook execution model has several important properties:

  • Parallel service hooks -- All service hooks for a given lifecycle event are collected and executed. Errors in one service's hook do not prevent other services' hooks from running.
  • Promise-aware -- Hook return values are awaited if they are Promises, enabling async operations like API calls or file I/O.
  • Error aggregation -- Errors from hook execution are collected and reported, but individual hook failures do not halt the test runner.

The three registration forms each follow a different code path in initialization:

Form Example Resolution Path
String name services: ['browserstack'] Resolved via initializePlugin (npm package lookup)
Class reference services: [MyService] Instantiated directly with new MyService(options, caps, config)
Object literal services: [{ beforeTest: fn }] Used directly as a hook container

The framework also supports Cucumber-specific hooks (beforeFeature, beforeScenario, beforeStep, afterStep, afterScenario, afterFeature) for services that need to integrate with BDD test flows.

Related Pages

Implementation:Webdriverio_Webdriverio_Service_Lifecycle_Hooks_Pattern

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment