Skip to content

WebdriverIO ​

This guide covers WebdriverIO 9.0 or newer. You need Node.js 22.12 or newer to run test-inventory and an existing JavaScript or TypeScript test suite. The scanner reads your source without executing your tests or starting a browser. These are minimum supported versions; CI comparisons list tested versions.

Choose another framework · Use an AI client

Install ​

sh
npm install --save-dev test-inventory

Scan your suite ​

Run from the folder containing your project's package.json:

sh
npx test-inventory --framework webdriverio --pretty --output inventory.json

To select files explicitly, use quoted globs. This example matches the broker-portal fixture used below; adjust the globs to your suite's layout:

sh
npx test-inventory "test/specs/*.e2e.js" "test/specs/{orders,accounts}/*.e2e.js" --framework webdriverio --output inventory.json

The command replaces inventory.json once the new output is complete. It does not change your test files.

Check the result ​

Print the counts and diagnostics from the saved file:

sh
node -e "const i = require('./inventory.json'); console.log(i.summary); console.log(i.diagnostics)"

For matching tests, summary.fileCount and summary.testCount should be greater than zero. Review diagnostics even when the command exits with 0: errors can mean tests are missing. If the result is empty or unexpected, use troubleshooting.

The inventory describes source declarations, not execution results. Conditional skips are not proof that a run skipped the test. Loops and tables are one record by default; supported cases can be expanded with --expand-cases. Expected-to-fail tests execute and check for failure; they are not disabled tests.

Tests created by unreadable helpers can be missing without a diagnostic. A dependency hash does not prove complete coverage of runtime dependencies. Read the shared limits before using scans to make CI decisions.

Find skipped tests ​

sh
npx test-inventory --framework webdriverio --state skip --fields fullName,state,condition,reason --pretty

This uses the same file selection as the first scan. If you supplied globs, --root or --framework-version, repeat those options here.

This selects source declarations marked skip; it is not a report of a test run. See query recipes for other inventory queries.

Example ​

broker-portal checks a broker's client portal with WebdriverIO on Mocha. A number after a test's function is WebdriverIO's retry count, and this.timeout() sets the describe's timeout over the config's mochaOpts.timeout.

Excerpt: js
// test/specs/orders/ticket.e2e.js
describe('client order ticket', function () {
  this.timeout(90_000);
  // ...
  it('blocks an order above the buying power', async () => {
  // ...
  }, 2);
  // ...
  context('after the close', () => {
    it('queues the order for the open', async function () {
      if (!process.env.AFTER_HOURS) this.skip();
sh
npx test-inventory "test/specs/*.e2e.js" "test/specs/{orders,accounts}/*.e2e.js" --framework webdriverio --output inventory.json

Without the globs and --framework, the scan finds the files from wdio.conf.js, whose exclude leaves out the drafts, and WebdriverIO from package.json:

json
{
  "fullName": "client order ticket > blocks an order above the buying power",
  "state": "active",
  "timeout": 90000,
  "retries": 2
}

A test that skips itself under a condition keeps the condition:

json
{
  "fullName": "client order ticket > after the close > queues the order for the open",
  "state": "skip",
  "isConditional": true,
  "condition": "!process.env.AFTER_HOURS"
}

WebdriverIO with Jasmine ​

broker-portal-jasmine models a WebdriverIO project using the Jasmine adapter. Its config selects Jasmine and sets the default spec timeout:

js
export const config = {
  runner: 'local',
  specs: ['./test/specs/**/*.e2e.js'],
  baseUrl: 'http://localhost:4173',
  capabilities: [{ browserName: 'chrome' }],
  framework: 'jasmine',
  jasmineOpts: { defaultTimeoutInterval: 45000 },
};

A spec can override that timeout with its third argument. This spec also marks itself pending under a condition:

Excerpt: js
// test/specs/statements.e2e.js
it('offers archived statements', async () => {
  if (!process.env.ARCHIVE_ENABLED) pending('Archived statements require archive access');
  await browser.url('/statements/archive');
  await expect($('[data-test="archive-download"]')).toBeEnabled();
}, 15000);

Keep --framework webdriverio; the framework setting in wdio.conf.js selects Jasmine's syntax:

sh
npx test-inventory "test/specs/**/*.e2e.js" --framework webdriverio --pretty

Omitting the glob finds the same files from specs. These record excerpts show the config timeout and the spec's override:

json
{
  "fullName": "statement downloads > offers the latest monthly statement",
  "timeout": 45000,
  "timeoutSource": "config"
}
json
{
  "fullName": "statement downloads > offers archived statements",
  "state": "skip",
  "isConditional": true,
  "condition": "!process.env.ARCHIVE_ENABLED",
  "reason": "Archived statements require archive access",
  "timeout": 15000,
  "timeoutSource": "test"
}

The conditional pending() keeps its reason; the scanner does not evaluate the environment variable or run the spec. Use WebdriverIO's supported syntax for adapter-specific behavior.

Configuration and limits ​

The scan reads the root wdio.conf.js, .ts, .mjs, .mts, .cjs or .cts, using its config export. The config's framework selects Mocha (the default) or Jasmine. Their syntax is part of WebdriverIO support; use the matching syntax link below. Cucumber feature files are not read and that selection is reported.

Explicit scan globs replace specs, less excludes. suites, which need the runner's --suite, and mochaOpts.grep or jasmineOpts.grep are not read. A spec used by several capabilities or workers is listed once. The inventory counts declarations, not browser executions.

The config's mochaOpts.timeout, retries and ui, or jasmineOpts.defaultTimeoutInterval, apply. The default timeout is WebdriverIO's 10 seconds; defaultTimeoutInterval: 0 means 60 seconds.

Exact file selection

For WebdriverIO: the files under rootDir, the config's folder unless the config sets it, that a specs glob matches, also in the nested lists that group files into one worker, with an extension WebdriverIO takes, such as .js or .ts, without dot files and folders, less those exclude leaves out. A capability's own wdio:specs, or before WebdriverIO 10 its specs, replace the config's for that capability, and its wdio:exclude, or before 10 its exclude, adds to the config's, read inside its alwaysMatch when it has one; a file runs when a capability runs it. As in WebdriverIO, a glob without a / matches a file's name at any depth, though ./ counts as one, a glob that starts with ! matches nothing, and a \ is read as /; when every exclude entry holds a /, \ or *, they are globs too, and otherwise each leaves out every file whose path contains it. suites run only with --suite, so they are not read. Scanned with globs, every file they match counts as run, less the excludes, as files given with --spec replace specs. A file that two capabilities run, or that a group of files and another entry both name, runs in two workers, but is listed once. The config's framework, Mocha by default, or Jasmine, decides how the files are read, and its mochaOpts.timeout, retries and ui, or jasmineOpts.defaultTimeoutInterval, apply to every test. Without them the timeout is WebdriverIO's, 10 seconds, and a defaultTimeoutInterval of 0 is 60 seconds. Cucumber runs feature files, which the scan doesn't read, and is reported. mochaOpts.grep and jasmineOpts.grep are not read.

Supported syntax ​

WebdriverIO 9.0 and newer, with Mocha or Jasmine. The config's framework decides which, Mocha by default; Cucumber's feature files are not read.

Where test comes from ​

FormExample
GlobalsWith Mocha, its BDD globals, or with mochaOpts.ui: 'tdd' suite and test; with Jasmine, describe, it and their x and f forms. WebdriverIO sets them in every spec file.
Kept in a variableconst later = it.skip: only what both branches of a choice share applies, also of one written in place, as (process.env.CI ? it.skip : it)(...)
Local helpers fileimport { it } from './helpers' or require('./helpers'), followed through local imports, and helper functions that declare tests, read at each call

Calls ​

Tests and describes are read as in Mocha or Jasmine, with these differences:

CallRead as
it(title, fn, n) with Mocharetries: WebdriverIO runs the function up to n more times when it fails. It does so inside each of Mocha's attempts, so with this.retries() as well, the record shows WebdriverIO's count; 0 leaves Mocha's. it.only and it.skip drop the count, as they pass Mocha only the title and function.
it(title, fn, ms, n) with Jasminetimeout, as in Jasmine, and retries, WebdriverIO's.
A Mocha or Jasmine version gateRead with the version WebdriverIO depends on: Mocha 12 and Jasmine 6 from WebdriverIO 10, Mocha 10.8 and Jasmine 5 before. So describe(...).timeout(ms) reaches its tests from WebdriverIO 10, and Jasmine 7's notApplicable() is not read.
A call the runner refusesThe same errors as in Mocha or Jasmine, with what WebdriverIO does then. With Mocha, the file stops loading at the call: the tests declared above it run, those below are notLoaded, and the spec files grouped after it in the same worker don't run. With Jasmine, a call refused at the top level fails the whole worker: the file's tests are notLoaded, and the files grouped with it don't run either. Other workers run.

The shared syntax rules also apply.

Next ​

Documentation for test-inventory 0.10.1. Released under the MIT License.