Implementation:Webdriverio Webdriverio TestFnWrapper
| Knowledge Sources | |
|---|---|
| Domains | Test_Framework_Integration, Hook_Management |
| Last Updated | 2026-02-12 00:00 GMT |
Overview
Wraps test framework spec and hook functions with WebdriverIO before/after lifecycle hooks, providing error handling, retry support, and stack trace filtering.
Description
The TestFnWrapper module provides two wrapper functions that form the core of WebdriverIO's test lifecycle integration. testFnWrapper is a convenience entry point that calls testFrameworkFnWrapper with the standard executeHooksWithArgs and executeAsync implementations. testFrameworkFnWrapper orchestrates the full lifecycle: it first runs the beforeFn hooks (beforeTest or beforeHook) with arguments generated by beforeFnArgs, then executes the spec/hook function via executeAsync (which provides timeout and retry support), catches and processes errors (handling Mocha sync skip and Jasmine pending signals specially), measures execution duration, augments the after-hook arguments with { retries, error, result, duration, passed, skipped }, runs the afterFn hooks (afterTest or afterHook), and either throws the error or returns the result. The filterStackTrace function removes internal WebdriverIO/webdriver/node frame lines from stack traces and strips Vite cache invalidation query parameters for cleaner error output. Special handling exists for Jasmine's dynamic result error list (_wdioDynamicJasmineResultErrorList) to properly surface assertion errors.
Usage
Use testFnWrapper from the test interface wrapper when instrumenting Mocha and Jasmine test and hook functions. Use testFrameworkFnWrapper directly when building custom framework adapters that need to inject their own implementations of executeHooksWithArgs and executeAsync. The Cucumber adapter calls testFnWrapper directly rather than going through the test interface wrapper.
Code Reference
Source Location
- Repository: Webdriverio_Webdriverio
- File: packages/wdio-utils/src/test-framework/testFnWrapper.ts
- Lines: 1-160
Signature
export const testFnWrapper: (
this: unknown,
type: string,
spec: SpecFunction,
before: BeforeHookParam<unknown>,
after: AfterHookParam<unknown>,
cid: string,
repeatTest?: number,
hookName?: string,
timeout?: number
) => Promise<any>
export const testFrameworkFnWrapper: (
this: unknown,
wrapFunctions: { executeHooksWithArgs: WrapperMethods['executeHooksWithArgs']; executeAsync: WrapperMethods['executeAsync'] },
type: string,
spec: { specFn: Function; specFnArgs: unknown[] },
before: { beforeFn: Function | Function[]; beforeFnArgs: (ctx: unknown) => unknown[] },
after: { afterFn: Function | Function[]; afterFnArgs: (ctx: unknown) => unknown[] },
cid: string,
repeatTest?: number,
hookName?: string,
timeout?: number
) => Promise<any>
export const filterStackTrace: (stack: string) => string
Import
import { testFnWrapper, testFrameworkFnWrapper } from '@wdio/utils'
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| type | string | Yes | Either "Test", "Step", or "Hook" - determines which before/after hook names are used (e.g., "beforeTest"/"afterTest"). |
| spec | SpecFunction | Yes | Object containing specFn (the actual test/hook function) and specFnArgs (arguments to pass to it). |
| before | BeforeHookParam<unknown> | Yes | Object containing beforeFn (hook function(s) to run before) and beforeFnArgs (function returning arguments for the before hook). |
| after | AfterHookParam<unknown> | Yes | Object containing afterFn (hook function(s) to run after) and afterFnArgs (function returning arguments for the after hook; result metadata is appended). |
| cid | string | Yes | Capability ID for the current worker, used in error logging. |
| repeatTest | number | No | Number of retries for the spec function. Defaults to 0. |
| hookName | string | No | Name of the hook (e.g., "beforeEach") appended to before/after hook arguments when type is "Hook". |
| timeout | number | No | Maximum execution time in milliseconds, passed through to executeAsync. |
| wrapFunctions | WrapperMethods | Yes (testFrameworkFnWrapper) | Object with executeHooksWithArgs and executeAsync implementations to use. |
Outputs
| Name | Type | Description |
|---|---|---|
| result | Promise<any> | The return value of the spec function after successful execution, or throws the error if the spec function failed after all retries. |
| after hook args (appended) | object | The after hook receives an additional argument: { retries: { attempts, limit }, error, result, duration, passed, skipped }. |
| filterStackTrace result | string | Cleaned stack trace with internal WebdriverIO frames removed. |
Usage Examples
import { testFnWrapper, testFrameworkFnWrapper, filterStackTrace } from '@wdio/utils'
// Using testFnWrapper in a framework adapter (called by testInterfaceWrapper)
const result = await testFnWrapper.call(
testContext,
'Test',
{
specFn: async () => {
await browser.url('https://example.com')
expect(await browser.getTitle()).toBe('Example')
},
specFnArgs: []
},
{
beforeFn: config.beforeTest,
beforeFnArgs: (ctx) => [ctx.test, ctx]
},
{
afterFn: config.afterTest,
afterFnArgs: (ctx) => [ctx.test, ctx]
},
'0-0', // cid
2, // retries
undefined, // hookName (not a hook)
30000 // timeout
)
// Using filterStackTrace to clean error output
try {
await someFailingTest()
} catch (err) {
err.stack = filterStackTrace(err.stack)
console.error(err.stack)
// Internal node_modules/@wdio/ lines are removed
}