From 080b4f3404b5fa277e776cf7c35bad57d1462c35 Mon Sep 17 00:00:00 2001 From: dprevost-perso Date: Sun, 28 Jun 2026 16:44:13 -0400 Subject: [PATCH 1/7] Review docs before Jasmine big release --- docs/Framework.md | 135 ++++++++++++++++++-------------- playgrounds/mocha/tsconfig.json | 8 +- 2 files changed, 82 insertions(+), 61 deletions(-) diff --git a/docs/Framework.md b/docs/Framework.md index 9182da68..d6a194b2 100644 --- a/docs/Framework.md +++ b/docs/Framework.md @@ -1,49 +1,69 @@ # Expect-WebDriverIO Framework -Expect-WebDriverIO is inspired by [`expect`](https://www.npmjs.com/package/expect) but also extends it. Therefore, we can use everything provided by the expect API with some WebDriverIO enhancements. Yes, this is a package of Jest but it is usable without Jest. +`expect-webdriverio` extends Jest's [`expect`](https://www.npmjs.com/package/expect) API with WebDriverIO-specific enhancements. It can be used standalone or within other testing environments. ## Compatibility -We can pair `expect-webdriverio` with [Jest](https://jestjs.io/), [Mocha](https://mochajs.org/), and [Jasmine](https://jasmine.github.io/) and even [Cucumber](https://www.npmjs.com/package/@cucumber/cucumber) +It is highly recommended to use this package with the [WDIO Testrunner](https://webdriver.io/docs/clioptions) and a compatible framework adapter, which together provide a plug-and-play experience. -It is highly recommended to use it with a [WDIO Testrunner](https://webdriver.io/docs/clioptions) which provides additional auto-configuration for a plug-and-play experience. +Pair it with your preferred framework using the appropriate adapter: +- **[Mocha](https://mochajs.org/):** Use [`@wdio/mocha-framework`](https://www.npmjs.com/package/@wdio/mocha-framework) +- **[Cucumber](https://www.npmjs.com/package/@cucumber/cucumber):** Use [`@wdio/cucumber-framework`](https://www.npmjs.com/package/@wdio/cucumber-framework) +- **[Jasmine](https://jasmine.github.io/):** Use [`@wdio/jasmine-framework`](https://www.npmjs.com/package/@wdio/jasmine-framework) +- **[Jest](https://jestjs.io/):** Works (no framework exists; requires manual configuration—see note below)z -When used **outside of [WDIO Testrunner](https://webdriver.io/docs/clioptions)**, types need to be added to your [`tsconfig.json`](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html), and some additional configuration for WDIO matchers, soft assertions, and snapshot service is required. - -### Jest -We can use `expect-webdriverio` with [Jest](https://jestjs.io/) using [`@jest/globals`](https://www.npmjs.com/package/@jest/globals) alone (preferred) and optionally [`@types/jest`](https://www.npmjs.com/package/@types/jest) (which has global ambient support). - - Note: Jest maintainers do not support [`@types/jest`](https://www.npmjs.com/package/@types/jest). If this library gets out of date or has problems, support might be dropped. - - Note: With Jest, the matchers `toMatchSnapshot` and `toMatchInlineSnapshot` are overloaded. To resolve the types correctly, `expect-webdriverio/jest` must be last. +> **Note:** When using **Jest**, or when running **outside of the WDIO Testrunner without a compatible framework adapter**, additional manual configuration can be required, such as adding types to your [`tsconfig.json`](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) and configuring WDIO matchers, soft assertions, and the snapshot service. + +### Mocha +When pairing with [Mocha](https://mochajs.org/), you can use `expect-webdriverio` directly or combine it with [`chai`](https://www.chaijs.com/) (or any other assertion library). +- It is strongly recommended to leverage `@wdio/mocha-framework` for automatic configuration and a plug-and-play experience. -#### With `@jest/globals` -When paired only with [`@jest/globals`](https://www.npmjs.com/package/@jest/globals), we should `import` the `expect` function from `expect-webdriverio`. +#### Standalone +No import is required; everything is set globally. ```ts -import { expect } from 'expect-webdriverio' -import { describe, it, expect as jestExpect } from '@jest/globals' - describe('My tests', async () => { it('should verify my browser to have the expected url', async () => { await expect(browser).toHaveUrl('https://example.com') }) -}) +}) ``` -No `types` are expected in `tsconfig.json`. -Optionally, to avoid needing `import { expect } from 'expect-webdriverio'`, you can use the following: +Minimum types expected in `tsconfig.json`: +When depending on `@wdio/mocha-framework` +```json +{ + "compilerOptions": { + "types": [ + "@wdio/mocha-framework", + "@wdio/globals/types" + ] + } +} +``` +When not depending on `@wdio/mocha-framework` ```json { "compilerOptions": { - "types": ["expect-webdriverio/expect-global"] + "types": [ + "@types/mocha", + "expect-webdriverio/expect-global" + ] } } -``` -##### Augmenting `@jest/globals` JestMatchers -Multiple attempts were made to augment `@jest/globals` to support `expect-webdriverio` matchers directly on JestMatchers. However, no namespace is available to augment it; therefore, only module augmentation can be used. This method does not allow adding matchers with the `extends` keyword; instead, they need to be added directly in the interface of the module declaration augmentation, which would create a lot of code duplication. +``` -This [Jest issue](https://github.com/jestjs/jest/issues/12424) seems to target this problem, but it is still in progress. +#### Chai +`expect-webdriverio` can coexist with the [Chai](https://www.chaijs.com/) assertion library by importing both libraries explicitly. +See also this [documentation](https://webdriver.io/docs/assertion/#migrating-from-chai). + +### Jest +We can use `expect-webdriverio` with [Jest](https://jestjs.io/) using [`@types/jest`](https://www.npmjs.com/package/@types/jest) (which has global ambient support) or [`@jest/globals`](https://www.npmjs.com/package/@jest/globals) (no playground yet) + - Note: Jest maintainers do not support [`@types/jest`](https://www.npmjs.com/package/@types/jest). If this library gets out of date or has problems, support might be dropped. + - Note: With Jest, the matchers `toMatchSnapshot` and `toMatchInlineSnapshot` are overloaded. To resolve the types correctly, `expect-webdriverio/jest` must be last. + - Wdio provider no runner #### With `@types/jest` When also paired with [`@types/jest`](https://www.npmjs.com/package/@types/jest), no imports are required. Global ambient types are already defined correctly and you can simply use Jest's `expect` directly. @@ -107,44 +127,45 @@ Expected in `tsconfig.json`: "compilerOptions": { "types": [ "@types/jest", - "expect-webdriverio/jest" // Must be last for overloaded matchers `toMatchSnapshot` and `toMatchInlineSnapshot` + "expect-webdriverio/jest" // Must be last for overloaded matchers `toMatchSnapshot` and ] } } ``` - -### Mocha -When paired with [Mocha](https://mochajs.org/), it can be used without (standalone) or with [`chai`](https://www.chaijs.com/) (or any other assertion library). -#### Standalone -No import is required; everything is set globally. +#### With `@jest/globals` +When paired only with [`@jest/globals`](https://www.npmjs.com/package/@jest/globals), we should `import` the `expect` function from `expect-webdriverio`. ```ts +import { expect } from 'expect-webdriverio' +import { describe, it, expect as jestExpect } from '@jest/globals' + describe('My tests', async () => { it('should verify my browser to have the expected url', async () => { await expect(browser).toHaveUrl('https://example.com') }) -}) +}) ``` -Expected in `tsconfig.json`: +No `types` are expected in `tsconfig.json`. +Optionally, to avoid needing `import { expect } from 'expect-webdriverio'`, you can use the following: + + ```json { "compilerOptions": { - "types": [ - "@types/mocha", - "expect-webdriverio/expect-global" - ] + "types": ["expect-webdriverio/expect-global"] } } -``` +``` +##### Augmenting `@jest/globals` JestMatchers +Multiple attempts were made to augment `@jest/globals` to support `expect-webdriverio` matchers directly on JestMatchers. However, no namespace is available to augment it; therefore, only module augmentation can be used. This method does not allow adding matchers with the `extends` keyword; instead, they need to be added directly in the interface of the module declaration augmentation, which would create a lot of code duplication. -#### Chai -`expect-webdriverio` can coexist with the [Chai](https://www.chaijs.com/) assertion library by importing both libraries explicitly. -See also this [documentation](https://webdriver.io/docs/assertion/#migrating-from-chai). +This [Jest issue](https://github.com/jestjs/jest/issues/12424) seems to target this problem, but it is still in progress. ### Jasmine -When paired with [Jasmine](https://jasmine.github.io/), [`@wdio/jasmine-framework`](https://www.npmjs.com/package/@wdio/jasmine-framework) is also required to configure it correctly, as it needs to force `expect` to be `expectAsync` and also register the WDIO matchers with `addAsyncMatcher` since `expect-webdriverio` only supports the Jest-style `expect.extend` version. +When paired with [Jasmine](https://jasmine.github.io/), [`@wdio/jasmine-framework`](https://www.npmjs.com/package/@wdio/jasmine-framework) is also required to configure it correctly, as it forces `expect` to be `expectAsync` and also register the WDIO matchers with `addAsyncMatcher` + - `expect-webdriverio` only register using the Jest's style `expect.extend` version which does not work for Jasmine. Jasmine differs from other assertion libraries in two key ways: 1. Jasmine performs soft assertions by default, collecting failures and only failing the test at the end. Because of this, the SoftAssertion service is not needed or supported. @@ -153,14 +174,16 @@ Jasmine differs from other assertion libraries in two key ways: The types `expect-webdriverio/jasmine` are still offered but are subject to removal or being moved into `@wdio/jasmine-framework`. The usage of `expectAsync` is also subject to future removal. -#### Jasmine `expectAsync` -When not using `@wdio/globals/types` or having `@types/jasmine` before it, the Jasmine expect is shown as the global ambient type. Therefore, when also defining `expect-webdriverio/jasmine`, we can use WDIO custom matchers on the `expectAsync`. Without `@wdio/jasmine-framework`, matchers will need to be registered manually. +#### Global `expectAsync` force as `expect` +When the global ambient `expect` is actually `expectAsync` under the hood (as with `@wdio/jasmine-framework`), it is recommended to `await` even basic matchers, even though Jasmine will handle any un-awaited assertions at the end of the test. ```ts describe('My tests', async () => { it('should verify my browser to have the expected url', async () => { - await expectAsync(browser).toHaveUrl('https://example.com') - await expectAsync(true).toBe(true) + await expect(browser).toHaveUrl('https://example.com') + + // Even basic matchers should have `await` since they are promises underneath + await expect(true).toBe(true) }) }) ``` @@ -170,23 +193,23 @@ Expected in `tsconfig.json`: { "compilerOptions": { "types": [ - "@types/jasmine", - "expect-webdriverio/jasmine" - ] + "@wdio/globals/types", + // Force expect to return Promises (In beta testing, expect breaking changes, will move into @wdio/jasmine-framework one day) + "expect-webdriverio/jasmine-wdio-expect-async", + "@types/jasmine", + ] } } ``` -#### Global `expectAsync` force as `expect` -When the global ambient `expect` is actually `expectAsync` under the hood (as with `@wdio/jasmine-framework`), it is recommended to `await` even basic matchers, even though Jasmine will handle any un-awaited assertions at the end of the test. +#### Jasmine `expectAsync` +When not using `@wdio/globals/types` or having `@types/jasmine` before it, the Jasmine expect is shown as the global ambient type. Therefore, when also defining `expect-webdriverio/jasmine`, we can use WDIO custom matchers on the `expectAsync`. Without `@wdio/jasmine-framework`, matchers will need to be registered manually. ```ts describe('My tests', async () => { it('should verify my browser to have the expected url', async () => { - await expect(browser).toHaveUrl('https://example.com') - - // Even basic matchers should have `await` since they are promises underneath - await expect(true).toBe(true) + await expectAsync(browser).toHaveUrl('https://example.com') + await expectAsync(true).toBe(true) }) }) ``` @@ -196,11 +219,9 @@ Expected in `tsconfig.json`: { "compilerOptions": { "types": [ - "@wdio/globals/types", - // Force expect to return Promises (In beta testing, expect breaking changes, will move into @wdio/jasmine-framework one day) - "expect-webdriverio/jasmine-wdio-expect-async", - "@types/jasmine", - ] + "@types/jasmine", + "expect-webdriverio/jasmine" + ] } } ``` diff --git a/playgrounds/mocha/tsconfig.json b/playgrounds/mocha/tsconfig.json index d293b2f5..9e95e281 100644 --- a/playgrounds/mocha/tsconfig.json +++ b/playgrounds/mocha/tsconfig.json @@ -5,10 +5,10 @@ "moduleResolution": "bundler", "types": [ "node", - "expect-webdriverio/expect-global", - "@wdio/mocha-framework", - "expect-webdriverio", - "@wdio/globals/types", // Need to be last to so the above from the projects have priority + "expect-webdriverio/expect-global", // Pull the development version from this project + "expect-webdriverio", // Pull the development version from this project + "@wdio/mocha-framework", // Need below the so development version from this project have priority + "@wdio/globals/types", // Need below the so development version from this project have priority "@wdio/visual-service" ], "esModuleInterop": true, From 04ad20fbbfecdee8095a3967db731244ca7d5011 Mon Sep 17 00:00:00 2001 From: David Prevost <77302423+dprevost-LMI@users.noreply.github.com> Date: Sun, 28 Jun 2026 18:26:47 -0400 Subject: [PATCH 2/7] Update docs/Framework.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- docs/Framework.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Framework.md b/docs/Framework.md index d6a194b2..774d1956 100644 --- a/docs/Framework.md +++ b/docs/Framework.md @@ -10,7 +10,7 @@ Pair it with your preferred framework using the appropriate adapter: - **[Mocha](https://mochajs.org/):** Use [`@wdio/mocha-framework`](https://www.npmjs.com/package/@wdio/mocha-framework) - **[Cucumber](https://www.npmjs.com/package/@cucumber/cucumber):** Use [`@wdio/cucumber-framework`](https://www.npmjs.com/package/@wdio/cucumber-framework) - **[Jasmine](https://jasmine.github.io/):** Use [`@wdio/jasmine-framework`](https://www.npmjs.com/package/@wdio/jasmine-framework) -- **[Jest](https://jestjs.io/):** Works (no framework exists; requires manual configuration—see note below)z +- **[Jest](https://jestjs.io/):** Works (no framework exists; requires manual configuration—see note below) > **Note:** When using **Jest**, or when running **outside of the WDIO Testrunner without a compatible framework adapter**, additional manual configuration can be required, such as adding types to your [`tsconfig.json`](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) and configuring WDIO matchers, soft assertions, and the snapshot service. From 884564b66a247099df2f647a9ef021fbfb05c47d Mon Sep 17 00:00:00 2001 From: David Prevost <77302423+dprevost-LMI@users.noreply.github.com> Date: Sun, 28 Jun 2026 18:27:06 -0400 Subject: [PATCH 3/7] Update docs/Framework.md Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- docs/Framework.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Framework.md b/docs/Framework.md index 774d1956..a1867ab6 100644 --- a/docs/Framework.md +++ b/docs/Framework.md @@ -127,7 +127,7 @@ Expected in `tsconfig.json`: "compilerOptions": { "types": [ "@types/jest", - "expect-webdriverio/jest" // Must be last for overloaded matchers `toMatchSnapshot` and + "expect-webdriverio/jest" // Must be last for overloaded matchers `toMatchSnapshot` and `toMatchInlineSnapshot` ] } } From b213b229c2d3b2ed359f2b17cefc0ecdb12c1263 Mon Sep 17 00:00:00 2001 From: David Prevost <77302423+dprevost-LMI@users.noreply.github.com> Date: Sun, 28 Jun 2026 18:27:16 -0400 Subject: [PATCH 4/7] Update playgrounds/mocha/tsconfig.json Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- playgrounds/mocha/tsconfig.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/playgrounds/mocha/tsconfig.json b/playgrounds/mocha/tsconfig.json index 9e95e281..9130daba 100644 --- a/playgrounds/mocha/tsconfig.json +++ b/playgrounds/mocha/tsconfig.json @@ -7,8 +7,8 @@ "node", "expect-webdriverio/expect-global", // Pull the development version from this project "expect-webdriverio", // Pull the development version from this project - "@wdio/mocha-framework", // Need below the so development version from this project have priority - "@wdio/globals/types", // Need below the so development version from this project have priority + "@wdio/mocha-framework", // Must be listed after development versions so they take priority + "@wdio/globals/types", // Must be listed after development versions so they take priority "@wdio/visual-service" ], "esModuleInterop": true, From d60c156503f18321b77b4d9569d1533a9b30439f Mon Sep 17 00:00:00 2001 From: dprevost-perso Date: Sun, 28 Jun 2026 20:36:10 -0400 Subject: [PATCH 5/7] Complete reviewed docs --- docs/Framework.md | 148 +++++++++++++++++++++++++--------------------- 1 file changed, 82 insertions(+), 66 deletions(-) diff --git a/docs/Framework.md b/docs/Framework.md index a1867ab6..8b1ed93a 100644 --- a/docs/Framework.md +++ b/docs/Framework.md @@ -12,11 +12,16 @@ Pair it with your preferred framework using the appropriate adapter: - **[Jasmine](https://jasmine.github.io/):** Use [`@wdio/jasmine-framework`](https://www.npmjs.com/package/@wdio/jasmine-framework) - **[Jest](https://jestjs.io/):** Works (no framework exists; requires manual configuration—see note below) -> **Note:** When using **Jest**, or when running **outside of the WDIO Testrunner without a compatible framework adapter**, additional manual configuration can be required, such as adding types to your [`tsconfig.json`](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) and configuring WDIO matchers, soft assertions, and the snapshot service. - +> **Note:** When using **Jest**, or when running **outside of the WDIO Testrunner without a compatible framework adapter**, additional manual configuration may be required, such as adding types to your [`tsconfig.json`](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) and configuring WDIO matchers, soft assertions, and the snapshot service. + +### Playgrounds +Example playgrounds are available, though their `tsconfig.json` files may use modified configurations for development purposes. +- See Mocha, Jasmine, and Jest [examples here](https://github.com/webdriverio/expect-webdriverio/tree/main/playgrounds). + ### Mocha When pairing with [Mocha](https://mochajs.org/), you can use `expect-webdriverio` directly or combine it with [`chai`](https://www.chaijs.com/) (or any other assertion library). - It is strongly recommended to leverage `@wdio/mocha-framework` for automatic configuration and a plug-and-play experience. +- See [Mocha playground example here](https://github.com/webdriverio/expect-webdriverio/tree/main/playgrounds/mocha) #### Standalone No import is required; everything is set globally. @@ -60,35 +65,44 @@ When not depending on `@wdio/mocha-framework` See also this [documentation](https://webdriver.io/docs/assertion/#migrating-from-chai). ### Jest -We can use `expect-webdriverio` with [Jest](https://jestjs.io/) using [`@types/jest`](https://www.npmjs.com/package/@types/jest) (which has global ambient support) or [`@jest/globals`](https://www.npmjs.com/package/@jest/globals) (no playground yet) - - Note: Jest maintainers do not support [`@types/jest`](https://www.npmjs.com/package/@types/jest). If this library gets out of date or has problems, support might be dropped. - - Note: With Jest, the matchers `toMatchSnapshot` and `toMatchInlineSnapshot` are overloaded. To resolve the types correctly, `expect-webdriverio/jest` must be last. - - Wdio provider no runner +You can use `expect-webdriverio` with [Jest](https://jestjs.io/) by leveraging either [`@types/jest`](https://www.npmjs.com/package/@types/jest) (which provides global ambient support) or [`@jest/globals`](https://www.npmjs.com/package/@jest/globals). + - Note: Jest maintainers do not officially support [`@types/jest`](https://www.npmjs.com/package/@types/jest). Should this package become outdated or experience issues, support may be dropped. + - Note: With Jest, the matchers `toMatchSnapshot` and `toMatchInlineSnapshot` are overloaded. To resolve the types correctly, `expect-webdriverio/jest` must be listed last. + - Note: WebdriverIO does not provide a compatible framework adapter for Jest; manual configuration is required. #### With `@types/jest` -When also paired with [`@types/jest`](https://www.npmjs.com/package/@types/jest), no imports are required. Global ambient types are already defined correctly and you can simply use Jest's `expect` directly. +When paired with [`@types/jest`](https://www.npmjs.com/package/@types/jest), no imports are required in your test files. Global ambient types are already defined correctly, allowing you to use Jest's `expect` directly after some manual configuration. + - Note: `jest` and `ts-jest` are also required. + - See the [Jest with `@types/jest` playground example](https://github.com/webdriverio/expect-webdriverio/tree/main/playgrounds/jest). -If you are NOT using WDIO Testrunner, some prerequisite configuration is required. +Since no WDIO Testrunner and framework adapter are used, additional prerequisite configuration is required. -Option 1: Replace the expect globally with the `expect-webdriverio` one: +##### Option 1: Replace the global expect with the `expect-webdriverio` instance: ```ts import { expect } from "expect-webdriverio"; (globalThis as any).expect = expect; ``` -Option 2: Reconfigure Jest's expect with the custom matchers and the soft assertion: +##### Option 2: Extend Jest's global `expect` with custom matchers and soft assertions: +If not already set, define a file path for `setupFilesAfterEnv` in your Jest configuration: +```ts +setupFilesAfterEnv: ['./jest.setup.after-env.ts'], +``` +Then, add the following configuration to your `jest.setup.after-env.ts` file: + ```ts -// Configure the custom matchers: import { expect } from "@jest/globals"; import { wdioCustomMatchers } from "expect-webdriverio"; beforeAll(async () => { + // Extend the imported Jest expect instance with WDIO matchers expect.extend(wdioCustomMatchers); }); ``` -[Optional] For the soft assertion, the `createSoftExpect` is currently not correctly exposed but the below works: +##### Optional: For soft assertions, `createSoftExpect` is currently not correctly exposed, but the configuration below works: ```ts +import { SoftAssertService } from "expect-webdriverio"; // @ts-ignore import * as createSoftExpect from "expect-webdriverio/lib/softExpect"; @@ -112,7 +126,8 @@ beforeAll(async () => { }); ``` -Then as shown below, no imports are required and we can use WDIO matchers directly on Jest's `expect`: + +Then, as shown below, no imports are required and we can use WDIO matchers directly on Jest's `expect`: ```ts describe('My tests', async () => { it('should verify my browser to have the expected url', async () => { @@ -133,9 +148,11 @@ Expected in `tsconfig.json`: } ``` -#### With `@jest/globals` -When paired only with [`@jest/globals`](https://www.npmjs.com/package/@jest/globals), we should `import` the `expect` function from `expect-webdriverio`. +#### With Only `@jest/globals` +When using [`@jest/globals`](https://www.npmjs.com/package/@jest/globals) directly instead of global ambient types, you explicitly import Jest's utilities. To use `expect-webdriverio` you have two approaches: + - Note: No example playground available +##### Option 1: Explicit Imports ```ts import { expect } from 'expect-webdriverio' import { describe, it, expect as jestExpect } from '@jest/globals' @@ -148,9 +165,9 @@ describe('My tests', async () => { ``` No `types` are expected in `tsconfig.json`. -Optionally, to avoid needing `import { expect } from 'expect-webdriverio'`, you can use the following: - +##### Option 2: Global Type Definition +To avoid explicitly importing `expect` from `expect-webdriverio` in every test file, add the global entry point to your `tsconfig.json`: ```json { "compilerOptions": { @@ -159,30 +176,40 @@ Optionally, to avoid needing `import { expect } from 'expect-webdriverio'`, you } ``` ##### Augmenting `@jest/globals` JestMatchers -Multiple attempts were made to augment `@jest/globals` to support `expect-webdriverio` matchers directly on JestMatchers. However, no namespace is available to augment it; therefore, only module augmentation can be used. This method does not allow adding matchers with the `extends` keyword; instead, they need to be added directly in the interface of the module declaration augmentation, which would create a lot of code duplication. +Unlike `@types/jest`, `@jest/globals` does not export a global namespace that can be easily extended. While module augmentation is possible, it does not support inheriting matchers via the extends keyword. Supporting it would require manually duplicating all expect-webdriverio matcher interfaces inside the module declaration. + +This limitation is a known [upstream issue](https://github.com/jestjs/jest/issues/12424) tracked in Jest. -This [Jest issue](https://github.com/jestjs/jest/issues/12424) seems to target this problem, but it is still in progress. ### Jasmine -When paired with [Jasmine](https://jasmine.github.io/), [`@wdio/jasmine-framework`](https://www.npmjs.com/package/@wdio/jasmine-framework) is also required to configure it correctly, as it forces `expect` to be `expectAsync` and also register the WDIO matchers with `addAsyncMatcher` - - `expect-webdriverio` only register using the Jest's style `expect.extend` version which does not work for Jasmine. +When paired with [Jasmine](https://jasmine.github.io/), [`@wdio/jasmine-framework`](https://www.npmjs.com/package/@wdio/jasmine-framework) is required to ensure proper runtime configuration. The adapter forces the global `expect` to map to Jasmine's native `expectAsync` and registers the necessary WDIO matchers via `addAsyncMatcher`. -Jasmine differs from other assertion libraries in two key ways: -1. Jasmine performs soft assertions by default, collecting failures and only failing the test at the end. Because of this, the SoftAssertion service is not needed or supported. -2. Forcing `expectAsync` as `expect` (by `@wdio/jasmine-framework`) makes even basic matchers asynchronous. However, since Jasmine handles all promises at the end of the test, assertions appear to work properly—unlike in other frameworks, where using `await` is mandatory for correct behavior. - - Note: This goes against [this recommendation](https://jasmine.github.io/api/edge/async-matchers) and could cause unexpected issues. +Jasmine differs from other standard assertion libraries in two key ways: +1. **Built-in Soft Assertions:** Jasmine executes soft assertions out-of-the-box by tracking and collecting validation failures until a spec block finishes execution. Because this mechanism is native to Jasmine, the `expect-webdriverio` SoftAssertion service is neither required nor supported. +2. **Implicit Promise Handling:** Forcing `expectAsync` to act as the global `expect` binding makes even basic matchers asynchronous. Because Jasmine automatically hooks into outstanding spec promises and flushes them at the end of the test, assertions may *appear* to execute correctly even if you omit the `await` keyword—unlike in other frameworks where `await` is strictly mandatory. -The types `expect-webdriverio/jasmine` are still offered but are subject to removal or being moved into `@wdio/jasmine-framework`. The usage of `expectAsync` is also subject to future removal. +> ⚠️ **Warning:** Omitting `await` directly conflicts with [Jasmine's official async matcher recommendations](https://jasmine.github.io/api/edge/async-matchers) and can introduce silent timing issues or unhandled rejections into your test suite. Always explicitly `await` your assertions. -#### Global `expectAsync` force as `expect` -When the global ambient `expect` is actually `expectAsync` under the hood (as with `@wdio/jasmine-framework`), it is recommended to `await` even basic matchers, even though Jasmine will handle any un-awaited assertions at the end of the test. +#### Available Type Definitions +1. **`expect-webdriverio/jasmine`** + Augments Jasmine's native `expectAsync` interface directly with WebDriverIO custom matchers. + +2. **`expect-webdriverio/jasmine-wdio-expect-async`** + Specifically dedicated to aligning with the `@wdio/jasmine-framework` architecture. This entry point is subject to breaking changes and may be moved directly into the framework adapter in a future release. It performs the following modifications: + - Augments `expect` with WebDriverIO custom matchers. + - Transforms synchronous, native Jasmine matchers on the `expect` interface to return promises (making them asynchronous). + - Establishes a global `expect` type definition with the above modifications. + +#### Global `expectAsync` forced as `expect` +When using `@wdio/jasmine-framework`, the global ambient `expect` is forced to behave as Jasmine's native `expectAsync` under the hood. It is strongly recommended to explicitly `await` all assertions—including basic, non-WDIO matchers. While Jasmine automatically processes un-awaited spec promises at the end of test execution, omitting the keyword can introduce unpredictable timing issues or silent validation bypasses. + - See [example playgrounds](https://github.com/webdriverio/expect-webdriverio/tree/main/playgrounds/jasmine/test/specs/globalImport) ```ts describe('My tests', async () => { it('should verify my browser to have the expected url', async () => { await expect(browser).toHaveUrl('https://example.com') - // Even basic matchers should have `await` since they are promises underneath + // Always await basic assertions as well since they resolve to promises under the hood await expect(true).toBe(true) }) }) @@ -193,25 +220,32 @@ Expected in `tsconfig.json`: { "compilerOptions": { "types": [ + // Enforces Promise-based assertion return types (Beta: Subject to future integration into @wdio/jasmine-framework) + "expect-webdriverio/jasmine-wdio-expect-async", + "@wdio/globals/types", - // Force expect to return Promises (In beta testing, expect breaking changes, will move into @wdio/jasmine-framework one day) - "expect-webdriverio/jasmine-wdio-expect-async", - "@types/jasmine", + "@types/jasmine" ] } } ``` +> **Warning**: Because `@wdio/jasmine-framework` overrides synchronous matchers and introduces complicated type augmentations, a proposal was made for WebdriverIO v10 to preserve Jasmine's clean `expectAsync` API, attach custom WDIO matchers directly to it, and keep basic matchers synchronous. + +> Note: When using Jasmine, Jest's expect matchers are not leveraged, meaning standard Jest-specific assertion matchers are unavailable. + #### Jasmine `expectAsync` -When not using `@wdio/globals/types` or having `@types/jasmine` before it, the Jasmine expect is shown as the global ambient type. Therefore, when also defining `expect-webdriverio/jasmine`, we can use WDIO custom matchers on the `expectAsync`. Without `@wdio/jasmine-framework`, matchers will need to be registered manually. +When you do not use `@wdio/globals/types` (or when `@types/jasmine` takes type-resolution priority), the global ambient `expect` resolves to Jasmine's native behavior. By defining `expect-webdriverio/jasmine` in your types, you can use WDIO custom matchers directly on `expectAsync`. Note that if you are running outside of `@wdio/jasmine-framework`, these matchers must be registered manually. ```ts describe('My tests', async () => { it('should verify my browser to have the expected url', async () => { await expectAsync(browser).toHaveUrl('https://example.com') - await expectAsync(true).toBe(true) + + // Standard Jasmine async matchers work as expected + await expectAsync(Promise.resolve(true)).toBeResolvedTo(true) }) -}) +}) ``` Expected in `tsconfig.json`: @@ -226,63 +260,45 @@ Expected in `tsconfig.json`: } ``` -#### `expect` of `expect-webdriverio` -It is preferable to use the `expect` from `expect-webdriverio` to guarantee future compatibility. +#### Use `expect` from `expect-webdriverio` +The `expect` export from `expect-webdriverio` remains available under Jasmine if you prefer an explicit import strategy. See the [playground example](https://github.com/webdriverio/expect-webdriverio/tree/main/playgrounds/jasmine/test/specs/expect-wdioImport). ```ts -// Required if we do not force the 'expect-webdriverio' expect globally with `"expect-webdriverio/expect-global"` import { expect as wdioExpect } from 'expect-webdriverio' describe('My tests', async () => { it('should verify my browser to have the expected url', async () => { await wdioExpect(browser).toHaveUrl('https://example.com') - // No required await + // Does not require await wdioExpect(true).toBe(true) }) }) - - -Expected in `tsconfig.json`: -```json -{ - "compilerOptions": { - "types": [ - "@types/jasmine", - // "expect-webdriverio/expect-global", // Optional to have the global ambient expect the one of wdio - ] - } -} ``` - #### Asymmetric matchers -Jasmine's asymmetric matchers got better but limitation can still exits. -- `jasmine.stringContaining`; `jasmine.stringMatching`; `jasmine.any(Type)` & `jasmine.anything()` works across the board -- Network matchers does support `jasmine.objectContaining` while supports in other area like element matchers might be limited. -- Wdio asymmmetrics matchers does work properly too +Jasmine's asymmetric matchers have improved, but certain limitations may still exist. +- `jasmine.stringContaining`, `jasmine.stringMatching`, `jasmine.any(Type)`, and `jasmine.anything()` work seamlessly across the board. +- Network matchers support `jasmine.objectContaining`, whereas support in other areas (such as element matchers) might be limited. +- WDIO asymmetric matchers also work properly. ```ts +import { expect as wdioExpect } from 'expect-webdriverio' + describe('My tests', async () => { it('should verify my browser to have the expected url', async () => { - // Working Jasmine asymmetric matcher + // Working Jasmine asymmetric matchers await expectAsync(browser).toHaveUrl(jasmine.stringContaining('WebdriverIO')) await expectAsync(browser).toHaveUrl(jasmine.stringMatching('/WebdriverIO/')) await expectAsync(browser).toHaveUrl(jasmine.any(String)) await expectAsync(browser).toHaveUrl(jasmine.anything()) - // Working wdio asymmetric matcher + // Working WDIO asymmetric matcher await expectAsync(browser).toHaveUrl(wdioExpect.stringContaining('WebdriverIO')) }) -}) +}) ``` - -### Jest & Jasmine Augmentation Notes - -If you are already using Jest or Jasmine globally, using `import { expect } from 'expect-webdriverio'` is the most compatible approach, even though augmentation exists. -It is recommended to build your project using this approach instead of relying on augmentation, to ensure future compatibility and avoid augmentation limitations. See [this issue](https://github.com/webdriverio/expect-webdriverio/issues/1893) for more information. - ### Cucumber -More details to come. In short, when paired with `@wdio/cucumber-framework`, you can use WDIO's expect with Cucumber and even [Gherkin](https://www.npmjs.com/package/@cucumber/gherkin). +More details to come. In short, when paired with [`@wdio/cucumber-framework`](https://www.npmjs.com/package/@wdio/cucumber-framework), you can use WebDriverIO's `expect` library seamlessly within your Cucumber step definitions and [Gherkin-based](https://www.npmjs.com/package/@cucumber/gherkin) tests. From 1f1a948b291c3d3d43ff5b0d3ef16d2e1c5692f6 Mon Sep 17 00:00:00 2001 From: dprevost-perso Date: Sun, 28 Jun 2026 20:46:40 -0400 Subject: [PATCH 6/7] Small precision --- docs/Framework.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Framework.md b/docs/Framework.md index 8b1ed93a..f5ff639a 100644 --- a/docs/Framework.md +++ b/docs/Framework.md @@ -65,7 +65,7 @@ When not depending on `@wdio/mocha-framework` See also this [documentation](https://webdriver.io/docs/assertion/#migrating-from-chai). ### Jest -You can use `expect-webdriverio` with [Jest](https://jestjs.io/) by leveraging either [`@types/jest`](https://www.npmjs.com/package/@types/jest) (which provides global ambient support) or [`@jest/globals`](https://www.npmjs.com/package/@jest/globals). +You can use `expect-webdriverio` with [Jest](https://jestjs.io/) by leveraging either [`@types/jest`](https://www.npmjs.com/package/@types/jest) (which provides global ambient support) or [`@jest/globals`](https://www.npmjs.com/package/@jest/globals) alone. - Note: Jest maintainers do not officially support [`@types/jest`](https://www.npmjs.com/package/@types/jest). Should this package become outdated or experience issues, support may be dropped. - Note: With Jest, the matchers `toMatchSnapshot` and `toMatchInlineSnapshot` are overloaded. To resolve the types correctly, `expect-webdriverio/jest` must be listed last. - Note: WebdriverIO does not provide a compatible framework adapter for Jest; manual configuration is required. From 279ca63154306964564a6cf0f9c15b04db631e1d Mon Sep 17 00:00:00 2001 From: dprevost-perso Date: Sun, 28 Jun 2026 20:50:56 -0400 Subject: [PATCH 7/7] Ensure `expect as jestExpect` is exploited --- docs/Framework.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/Framework.md b/docs/Framework.md index f5ff639a..6d11063d 100644 --- a/docs/Framework.md +++ b/docs/Framework.md @@ -160,6 +160,9 @@ import { describe, it, expect as jestExpect } from '@jest/globals' describe('My tests', async () => { it('should verify my browser to have the expected url', async () => { await expect(browser).toHaveUrl('https://example.com') + + // Jest's native expect is still usable + jestExpect(myFunction).toHaveBeenCalled() }) }) ```