Implementation:Webdriverio Webdriverio Monad
| Knowledge Sources | |
|---|---|
| Domains | Core_Architecture, Command_Pattern |
| Last Updated | 2026-02-12 00:00 GMT |
Overview
Implements the monad pattern for creating WebdriverIO client objects that support command chaining, dynamic command registration, and event emission.
Description
The Monad module exports a default WebDriver factory function that returns a unit function serving as the core monad creator. When invoked with a session ID and optional command wrapper, unit constructs a client object with all registered commands as properties, an event emitter interface (on, off, emit, once, removeListener, removeAllListeners) backed by mitt, and methods for addCommand and overwriteCommand. The unit.lift static method attaches new command functions to the prototype, logging command invocations and emitting command and result events. Command wrapping enables the wdio-cli to intercept commands for element chaining. The module supports both browser and element scopes, creating named prototypes for better debugging visibility.
Usage
Use this module when building or extending the WebdriverIO client object. It is the foundation that creates browser and element instances with all protocol commands attached, and it is the mechanism through which addCommand and overwriteCommand work at runtime.
Code Reference
Source Location
- Repository: Webdriverio_Webdriverio
- File: packages/wdio-utils/src/monad.ts
- Lines: 22-313
Signature
export default function WebDriver(
options: object,
modifier?: Function,
propertiesObject?: PropertiesObject
): unit
function unit(
sessionId: string,
commandWrapper?: Function,
elementCmdImplicitWaitExclusionList?: string[]
): Client
unit.lift(
name: string,
func: Function,
proto: Record<string, any>,
origCommand?: Function
): void
// On the returned client:
client.addCommand(
name: string,
func: Function | Promise<unknown>,
attachToElementOrOptions?: boolean | CustomCommandOptions,
proto?: Record<string, unknown>,
instances?: Record<string, CustomCommands.Instances>
): void
client.overwriteCommand(
name: string,
func: Function,
attachToElement?: boolean,
proto?: Record<string, unknown>,
instances?: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser
): void
Import
import WebDriver from '@wdio/utils/monad'
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| options | object | Yes | Configuration object containing capabilities, requestedCapabilities, and connection settings. |
| modifier | Function | No | Optional function to modify the client after creation (receives client and options, returns modified client). |
| propertiesObject | PropertiesObject | No | Property descriptors defining commands and properties to attach to the client prototype. |
| sessionId | string | Yes (unit) | The WebDriver session identifier. |
| commandWrapper | Function | No (unit) | Optional wrapper function applied to each command for interception (e.g., before/after hooks). |
| elementCmdImplicitWaitExclusionList | string[] | No (unit) | List of element command names excluded from implicit wait behavior. |
Outputs
| Name | Type | Description |
|---|---|---|
| unit | Function | The monad unit function that creates client instances when called with a sessionId. |
| client | Object | A WebdriverIO browser or element client with all commands, event emitter methods, addCommand, and overwriteCommand. |
Usage Examples
import WebDriver from '@wdio/utils/monad'
// Create a monad with protocol commands as properties
const propertiesObject = {
getTitle: {
value: async function () {
return this._execute('getTitle')
}
},
scope: { value: 'browser' }
}
const unit = WebDriver(
{ capabilities: { browserName: 'chrome' } },
(client, options) => {
client.capabilities = options.capabilities
return client
},
propertiesObject
)
// Create a client instance
const browser = unit('session-id-123', wrapCommand)
// Add a custom command at runtime
browser.addCommand('getPageSource', async function () {
return this.execute(() => document.documentElement.outerHTML)
})
// Overwrite an existing command
browser.overwriteCommand('getTitle', async function (origFn) {
const title = await origFn()
return title.toUpperCase()
})
// Listen for events
browser.on('command', ({ command, body }) => {
console.log(`Executing: ${command}`)
})