-
-
Notifications
You must be signed in to change notification settings - Fork 58
Enhanced expect wdio typing #1863
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
dprevost-LMI
wants to merge
100
commits into
webdriverio:main
Choose a base branch
from
dprevost-LMI:enhanced-expect-wdio-typing
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 84 commits
Commits
Show all changes
100 commits
Select commit
Hold shift + click to select a range
9683aac
Working case with only matchers
dprevost-LMI 7b69c77
Block toHaveUrl on element
dprevost-LMI 7b85731
Working overloaded snapshot in jest
dprevost-LMI 07f43ae
A good working case with standalone + add back snapshot
dprevost-LMI 9a72d90
A good working version of standalone
dprevost-LMI 74fc414
Code review + add a toBe with element + chainable
dprevost-LMI ffac6f7
Bring back `snapshot.test.ts`
dprevost-LMI b254057
Bring back toBeRequestedWith
dprevost-LMI f5d9cbf
Bring back `toBeRequestedWith`
dprevost-LMI 53317aa
Pretty solid typing for both Jest & mocha (standalone)
dprevost-LMI 2d4fb6e
Bring back soft assertion + add tsc + code review
dprevost-LMI 4cac925
Code review
dprevost-LMI fc92f7e
Code review + add linter in types
dprevost-LMI 47faaee
Add decent not finished typing for Jasmine + soft assertion
dprevost-LMI a75fecc
ish working with jasmine expect and matcher + fix unimplemented method
dprevost-LMI ff52916
Use `ExpectWebdriverIO` where we can to be more verbose
dprevost-LMI 85e0fad
Separate Browser, mock and element matcher + better typing
dprevost-LMI b7fa0a1
fix rebase + add more UT typing cases
dprevost-LMI 7ecd093
Review test template to be better
dprevost-LMI a1d32a5
Add a working case of custom matchers with types!
dprevost-LMI 59a287c
Remove this file
dprevost-LMI ece01bd
Fix rebase
dprevost-LMI 144611b
Copy better type testing to mocha + clean package.json
dprevost-LMI e8b9432
Working asymmetric matcher
dprevost-LMI 267b4da
Apply suggestions from code review
dprevost-LMI c597d88
Update types/expect-webdriverio.d.ts
dprevost-LMI ed63525
Remove unneeded changes
dprevost-LMI 912faab
Use built-in PromiseLike
dprevost-LMI 5c68ef4
Have snapshot use await only on promises
dprevost-LMI 5dc6e89
More reusable types
dprevost-LMI 75caff7
Validated that asymmetric matchers previously not included works
dprevost-LMI 2d0d058
ignore not needed anymore!
dprevost-LMI e68e916
Fix some missing options pararmter + dig matchers and still not sure!
dprevost-LMI 3fbf20c
Moving types into expect-webdriverio.d.ts and remove standalone.d.ts
dprevost-LMI 2b138b0
Move new mocha test to jest, review + simplify jest.d.ts
dprevost-LMI e28a899
Simplify further jest.d.ts
dprevost-LMI 20aa50a
Finalize simplification of Jest namespace
dprevost-LMI ea039f9
Test `ExpectWebdriverIO` for custom matcher when using Jest!
dprevost-LMI b65fe35
Remove unused code!
dprevost-LMI 1d0e64b
Have better tsc check on types but filtering out node_module errors
dprevost-LMI 53db48c
Brin back tsc on types + exclude file in coverage and review %
dprevost-LMI 27968b1
fix and add UT for custom asymmetric matchers
dprevost-LMI d01529b
Review overloaded functions from `expect` lib
dprevost-LMI 2f8182b
Make inverse matcher works under the ExpectWebDriverIO namespace!
dprevost-LMI ba08e5a
Make inverse asymmetric matcher works under Jest
dprevost-LMI 82b31de
Upgrade the ts config to more recent values
dprevost-LMI a33f007
Working types under jasmine
dprevost-LMI 832028f
Add Jasmine case + force the global expect also for Jasmine
dprevost-LMI 1ebc16c
Review jasmine usage in the project
dprevost-LMI fb74809
Add support for both `@jest/global` and `@types/jest` + add doc
dprevost-LMI c44baa7
Review defined types in package.json
dprevost-LMI a3aa5bf
Review doc and fix some type issues
dprevost-LMI 93d0bdd
Doc review
dprevost-LMI 9d2324d
Test and document Jasmine typing
dprevost-LMI 9fd54b5
Fix impact of supporting Jasmine typing
dprevost-LMI 3145c40
Use latest Jest with exportable Inverse
dprevost-LMI 3e4504c
Fix Jasmine left over problem
dprevost-LMI 69057ca
Review some TODOs
dprevost-LMI a97198d
Simplify Jasmine augmentation
dprevost-LMI 4482755
Add jest types check to the ts command
dprevost-LMI 19a3263
Review doc by the AI
dprevost-LMI bcaba9b
Review dead link with AI
dprevost-LMI cfc0af3
Add details with Chai
dprevost-LMI df5f93d
Remove out of scope TODOs
dprevost-LMI acaaeb3
Add back promise matchers!
dprevost-LMI 3cebbe1
Review more TODOs
dprevost-LMI 8eacdfa
Add finding on augmentation of `@jest/globals`
dprevost-LMI 60ccb41
Update doc following finding requiring registering matcher with Jest
dprevost-LMI 4f159d2
Align `AssertionResult` and `matchers` type with expect library
dprevost-LMI e5843b2
Add documentation on required configuration
dprevost-LMI 506d528
Document more findings around soft assertions
dprevost-LMI 8fa83e1
Add known limitations for soft assertions
dprevost-LMI 538bbcb
Clarify usage of `expectAsync`
dprevost-LMI 34408ff
Processing more TODOs
dprevost-LMI 10c1d52
Rebase + clean example + Add note on augmentation limitations
dprevost-LMI f42f159
Document better limitation of soft assertion with Jasmine
dprevost-LMI 551de19
Add cucumber to doc + fix some errors
dprevost-LMI d3b00b1
Simplify node constraints
dprevost-LMI d1be84d
Have `expect(Promise).toBeDefined()` be void and not a Promise
dprevost-LMI b1795b1
Even jest does not support `expect.not.anything()`
dprevost-LMI cebf40f
Force expect under Jasmine to always be async
dprevost-LMI 415d3ba
Finalize jasmine support with typing for wdio expect being asyncrhonous
dprevost-LMI 07fe3a3
Revert matchers type breaking changes + better jasmine sync `d.ts` name
dprevost-LMI 58a8244
Have `InverseAsymmetricMatchers` for easier typing
dprevost-LMI 1d11d0a
Update docs/Framework.md
christian-bromann eefed07
Update docs/Framework.md
christian-bromann 446b182
Update docs/Framework.md
christian-bromann 4f32ad2
Update docs/Framework.md
christian-bromann 66cd08a
Update docs/Framework.md
christian-bromann e242f3b
Update docs/Framework.md
christian-bromann 888f8ff
Update docs/Framework.md
christian-bromann 64e9198
Update docs/Framework.md
christian-bromann 79516ea
Update docs/Framework.md
christian-bromann 4092e00
Update docs/Framework.md
christian-bromann e12557c
Update jasmine-wdio-expect-async.d.ts
christian-bromann f716df6
Update docs/Framework.md
christian-bromann dc6486e
Update docs/Framework.md
christian-bromann cc9aafc
Update docs/Framework.md
christian-bromann 743d98f
Update docs/Framework.md
christian-bromann 2576b38
Merge branch 'main' into enhanced-expect-wdio-typing
dprevost-LMI File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,261 @@ | ||
# 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. | ||
- Note: Yes, this is a package of Jest but it is usable without Jest. | ||
|
||
## 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 it with a [WDIO Testrunner](https://webdriver.io/docs/clioptions) which provides additional auto-configuration for a plug-and-play experience. | ||
|
||
When used <u>**outside of [WDIO Testrunner](https://webdriver.io/docs/clioptions)**</u>, 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. | ||
|
||
#### 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 () => { | ||
|
||
christian-bromann marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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: | ||
```json | ||
christian-bromann marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
"compilerOptions": { | ||
"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. | ||
|
||
This [Jest issue](https://github.com/jestjs/jest/issues/12424) seems to target this problem, but it is still in progress. | ||
|
||
|
||
christian-bromann marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#### 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. | ||
|
||
If you are NOT using WDIO Testrunner, some prerequisite configuration is required. | ||
|
||
Option 1: Replace the expect globally with the `expect-webdriverio` one: | ||
```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: | ||
```ts | ||
// Configure the custom matchers: | ||
import { expect } from "@jest/globals"; | ||
import { matchers } from "expect-webdriverio"; | ||
|
||
beforeAll(async () => { | ||
expect.extend(matchers as Record<string, any>); | ||
}); | ||
``` | ||
|
||
[Optional] For the soft assertion, the `createSoftExpect` is currently not correctly exposed but the below works: | ||
```ts | ||
// @ts-ignore | ||
import * as createSoftExpect from "expect-webdriverio/lib/softExpect"; | ||
|
||
beforeAll(async () => { | ||
Object.defineProperty(expect, "soft", { | ||
value: <T = unknown>(actual: T) => createSoftExpect.default(actual), | ||
}); | ||
|
||
// Add soft assertions utility methods | ||
Object.defineProperty(expect, "getSoftFailures", { | ||
value: (testId?: string) => SoftAssertService.getInstance().getFailures(testId), | ||
}); | ||
|
||
Object.defineProperty(expect, "assertSoftFailures", { | ||
value: (testId?: string) => SoftAssertService.getInstance().assertNoFailures(testId), | ||
}); | ||
|
||
Object.defineProperty(expect, "clearSoftFailures", { | ||
value: (testId?: string) => SoftAssertService.getInstance().clearFailures(testId), | ||
}); | ||
}); | ||
``` | ||
|
||
Then as shown below, no imports are required and we can use WDIO matchers directly on Jest's `expect`: | ||
```ts | ||
describe('My tests', async () => { | ||
|
||
christian-bromann marked this conversation as resolved.
Show resolved
Hide resolved
|
||
it('should verify my browser to have the expected url', async () => { | ||
await expect(browser).toHaveUrl('https://example.com') | ||
}) | ||
}) | ||
``` | ||
|
||
Expected in `tsconfig.json`: | ||
```json | ||
{ | ||
"compilerOptions": { | ||
"types": [ | ||
"@types/jest", | ||
"expect-webdriverio/jest" // Must be last for overloaded matchers `toMatchSnapshot` and `toMatchInlineSnapshot` | ||
] | ||
} | ||
} | ||
``` | ||
|
||
### 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. | ||
|
||
```ts | ||
describe('My tests', async () => { | ||
|
||
christian-bromann marked this conversation as resolved.
Show resolved
Hide resolved
|
||
it('should verify my browser to have the expected url', async () => { | ||
await expect(browser).toHaveUrl('https://example.com') | ||
}) | ||
}) | ||
``` | ||
|
||
Expected in `tsconfig.json`: | ||
```json | ||
{ | ||
"compilerOptions": { | ||
"types": [ | ||
"@types/mocha", | ||
"expect-webdriverio/expect-global" | ||
] | ||
} | ||
} | ||
``` | ||
|
||
#### 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). | ||
|
||
### 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. | ||
|
||
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`. | ||
- Note: Without `@wdio/jasmine-framework`, matchers will need to be registered manually. | ||
christian-bromann marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
```ts | ||
describe('My tests', async () => { | ||
|
||
christian-bromann marked this conversation as resolved.
Show resolved
Hide resolved
|
||
it('should verify my browser to have the expected url', async () => { | ||
await expectAsync(browser).toHaveUrl('https://example.com') | ||
|
||
christian-bromann marked this conversation as resolved.
Show resolved
Hide resolved
|
||
await expectAsync(true).toBe(true) | ||
}) | ||
}) | ||
``` | ||
|
||
Expected in `tsconfig.json`: | ||
```json | ||
{ | ||
"compilerOptions": { | ||
"types": [ | ||
"@types/jasmine", | ||
"expect-webdriverio/jasmine" | ||
] | ||
} | ||
} | ||
``` | ||
|
||
#### Global `expectAsync` force as `expect` | ||
When the global ambiant is the `expect` of wdio but forced to be `expectAsync` under the hood, like when using `@wdio/jasmine-framework`, then even the basic matchers need to be awaited | ||
|
||
```ts | ||
describe('My tests', async () => { | ||
|
||
christian-bromann marked this conversation as resolved.
Show resolved
Hide resolved
|
||
it('should verify my browser to have the expected url', async () => { | ||
await expect(browser).toHaveUrl('https://example.com') | ||
|
||
// Even basic matchers requires expect since they are promises underneath | ||
await expect(true).toBe(true) | ||
}) | ||
}) | ||
``` | ||
|
||
Expected in `tsconfig.json`: | ||
```json | ||
{ | ||
"compilerOptions": { | ||
"types": [ | ||
"@wdio/globals/types", | ||
"@wdio/jasmine-framework", | ||
"@types/jasmine", | ||
"expect-webdriverio/jasmine-wdio-expect-async", // Force expect to return Promises | ||
] | ||
christian-bromann marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
``` | ||
|
||
#### `expect` of `expect-webdriverio` | ||
It is preferable to use the `expect` from `expect-webdriverio` to guarantee future compatibility. | ||
|
||
```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 () => { | ||
|
||
christian-bromann marked this conversation as resolved.
Show resolved
Hide resolved
|
||
it('should verify my browser to have the expected url', async () => { | ||
await wdioExpect(browser).toHaveUrl('https://example.com') | ||
|
||
// No required 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 | ||
Asymmetric matchers have limited support. Even though `jasmine.stringContaining` does not produce a typing error, it may not work even with `@wdio/jasmine-framework`. However, the example below should work: | ||
|
||
```ts | ||
describe('My tests', async () => { | ||
|
||
christian-bromann marked this conversation as resolved.
Show resolved
Hide resolved
|
||
it('should verify my browser to have the expected url', async () => { | ||
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). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/// <reference types="./types/expect-webdriverio.d.ts"/> | ||
|
||
/** | ||
* Overrides the default wdio `expect` for Jasmine case specifically since the `expect` is now completely asynchronous which is not the case under Jest or standalone. | ||
*/ | ||
declare namespace ExpectWebdriverIO { | ||
|
||
christian-bromann marked this conversation as resolved.
Show resolved
Hide resolved
|
||
interface Expect extends ExpectWebdriverIO.AsymmetricMatchers, ExpectLibInverse<ExpectWebdriverIO.InverseAsymmetricMatchers>, WdioExpect { | ||
/** | ||
* The `expect` function is used every time you want to test a value. | ||
* You will rarely call `expect` by itself. | ||
* | ||
* expect function declaration contains two generics: | ||
* - T: the type of the actual value, e.g. any type, not just WebdriverIO.Browser or WebdriverIO.Element | ||
* - R: the type of the return value, e.g. Promise<void> or void | ||
* | ||
* Note: The function must stay here in the namespace to overwrite correctly the expect function from the expect library. | ||
* | ||
* @param actual The value to apply matchers against. | ||
*/ | ||
<T = unknown>(actual: T): ExpectWebdriverIO.MatchersAndInverse<Promise<void>, T> | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.