Implementation:Webdriverio Webdriverio Cloud Service Hooks
Overview
Concrete tool for managing cloud testing session metadata through WDIO service lifecycle hooks.
Description
The BrowserstackService, SauceService, and TestingBotService classes implement WDIO's Services.ServiceInstance interface to synchronize test execution with cloud platforms. They intercept lifecycle events and update cloud APIs with test names, results, and metadata.
Each service class follows the same fundamental pattern:
- Accept configuration options, capabilities, and config in the constructor
- Store a reference to the browser instance in the
beforehook - Update the cloud session name in
beforeTest - Record pass/fail results in
afterTest - Set the final session status in
after - Handle session refresh in
onReload
BrowserstackService (857 lines) is the most feature-rich, incorporating observability, accessibility testing, Percy visual testing, performance measurement, and crash reporting. It manages a complex state machine tracking test outcomes, scenario names, and failure reasons.
SauceService (505 lines) integrates with the Sauce Labs REST API and supports both the Virtual Cloud and Real Device Cloud (RDC). It includes CI metadata detection, test run batching, and asset management for screenshots and logs.
TestingBotService (279 lines) is the most lightweight, focusing on core session status updates and name synchronization.
Source Files
| Service | File | Lines |
|---|---|---|
| BrowserstackService | packages/wdio-browserstack-service/src/service.ts |
L44-857 |
| SauceService | packages/wdio-sauce-service/src/service.ts |
L24-505 |
| TestingBotService | packages/wdio-testingbot-service/src/service.ts |
L9-279 |
Code Reference
Class Signatures
// packages/wdio-browserstack-service/src/service.ts:L44
export default class BrowserstackService implements Services.ServiceInstance {
private _sessionBaseUrl = 'https://api.browserstack.com/automate/sessions'
private _failReasons: string[] = []
private _scenariosThatRan: string[] = []
private _failures: number = 0
private _browser?: WebdriverIO.Browser
private _suiteTitle?: string
private _options: BrowserstackConfig & BrowserstackOptions
constructor(
options: BrowserstackConfig & Options.Testrunner,
private _caps: Capabilities.ResolvedTestrunnerCapabilities,
private _config: Options.Testrunner
)
}
// packages/wdio-sauce-service/src/service.ts:L24
export default class SauceService implements Services.ServiceInstance {
private _testCnt = 0
private _failures = 0
private _isServiceEnabled = true
private _options: SauceServiceConfig
private _api: SauceLabs.default
private _browser?: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser
constructor(
options: SauceServiceConfig,
private _capabilities: Capabilities.ResolvedTestrunnerCapabilities,
private _config: Options.Testrunner
)
}
// packages/wdio-testingbot-service/src/service.ts:L9
export default class TestingBotService implements Services.ServiceInstance {
private _browser?: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser
private _isServiceEnabled?: boolean
private _suiteTitle?: string
private _failures = 0
private _testCnt = 0
constructor(
private _options: TestingbotOptions,
private _capabilities: Capabilities.ResolvedTestrunnerCapabilities,
private _config: Options.Testrunner
)
}
Key Hooks Implemented
All three services implement a common set of lifecycle hooks:
| Hook | Signature | Purpose |
|---|---|---|
beforeSession |
beforeSession(config, capabilities) |
Configure session metadata before WebDriver session creation |
before |
before(caps, specs, browser) |
Store browser reference, initialize session tracking |
beforeSuite |
beforeSuite(suite) |
Track current suite title for session naming |
beforeTest |
beforeTest(test) |
Update cloud session name with current test title |
afterTest |
afterTest(test, context, results) |
Record test pass/fail, capture error messages |
after |
after(result) |
Set final session status (passed/failed) via REST API |
onReload |
onReload(oldSessionId, newSessionId) |
Transfer metadata and update status on session refresh |
I/O Contract
Inputs:
- Test lifecycle events emitted by the WDIO test runner
- Session IDs from the WebDriver session
- Test results including pass/fail status, error messages, and duration
- Configuration options (user credentials, build name, project name)
Outputs:
- Cloud session status updated via REST API (
PUT /sessions/{id}) - Session name and annotations set on the cloud dashboard
- Build and project grouping metadata applied
- Videos and screenshots captured and correlated with test results
Error Handling:
- Services check for valid credentials before making API calls (
_isServiceEnabled) - API call failures are logged but do not fail the test
- Missing session IDs (e.g., multiremote without proper setup) are handled gracefully
Configuration
// BrowserStack
services: ['browserstack']
// Sauce Labs
services: ['sauce']
// TestingBot with options
services: [['testingbot', {
tbTunnel: false,
tbSecret: 'your-secret',
tbUser: 'your-user'
}]]
Services are configured via the services array in wdio.conf.ts and auto-loaded by the WDIO test runner through the plugin resolution mechanism.
Usage Examples
Automatic session naming in BrowserStack:
// No code changes needed -- the service automatically names sessions
// In wdio.conf.ts:
export const config = {
services: ['browserstack'],
capabilities: [{
'bstack:options': {
buildName: 'nightly-2024-01-15',
projectName: 'e-commerce-app'
}
}]
}
// Tests will appear in BrowserStack with names like:
// "Login Suite - should authenticate valid user"
Sauce Labs with custom job data:
// wdio.conf.ts
export const config = {
services: [['sauce', {
setJobName: true,
maxErrorStackLength: 10
}]],
capabilities: [{
'sauce:options': {
build: `build-${Date.now()}`,
tags: ['smoke', 'regression'],
name: 'default-job-name'
}
}]
}