Skip to content

Commit 6aa6e5f

Browse files
committed
Fix Jasmine withContext + use project global instead of wdio one
1 parent 515567d commit 6aa6e5f

15 files changed

Lines changed: 135 additions & 52 deletions

jasmine-wdio-expect-async.d.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,37 @@
11
/// <reference types="./types/expect-webdriverio.d.ts"/>
22

3+
declare namespace jasmine {
4+
5+
/**
6+
* Async matchers for Jasmine to allow the typing of `expectAsync` with WebDriverIO matchers.
7+
* T is the type of the actual value
8+
* U is the type of the expected value
9+
* Both T,U must stay named as they are to override the default `AsyncMatchers` type from Jasmine.
10+
*
11+
* We force Matchers to return a `Promise<void>` since Jasmine's `expectAsync` expects a promise in all cases (different from Jest)
12+
*/
13+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
14+
interface AsyncMatchers<T, U> extends Omit<ExpectWebdriverIO.Matchers<Promise<void>, T>, 'toMatchSnapshot' | 'toMatchInlineSnapshot'> {
15+
/**
16+
* snapshot matcher
17+
* @param label optional snapshot label
18+
*/
19+
toMatchSnapshot(label?: string): Promise<void>;
20+
/**
21+
* inline snapshot matcher
22+
* @param snapshot snapshot string (autogenerated if not specified)
23+
* @param label optional snapshot label
24+
*/
25+
toMatchInlineSnapshot(snapshot?: string, label?: string): Promise<void>;
26+
}
27+
}
28+
329
/**
430
* Overrides the default WDIO expect specifically for Jasmine, since `expectAsync` is forced into `expect`, making all matchers fully asynchronous. This is not the case under Jest or Mocha.
31+
* Using `jasmine.AsyncMatchers` pull on WdioMatchers above but also allow to using Jasmine's built-in matchers and also `withContext` matcher.
532
*/
633
declare namespace ExpectWebdriverIO {
7-
interface Expect extends ExpectWebdriverIO.AsymmetricMatchers, ExpectLibInverse<ExpectWebdriverIO.InverseAsymmetricMatchers>, WdioExpect {
34+
interface Expect {
835
/**
936
* The `expect` function is used every time you want to test a value.
1037
* You will rarely call `expect` by itself.
@@ -17,6 +44,6 @@ declare namespace ExpectWebdriverIO {
1744
*
1845
* @param actual The value to apply matchers against.
1946
*/
20-
<T = unknown>(actual: T): ExpectWebdriverIO.MatchersAndInverse<Promise<void>, T>
47+
<T = unknown>(actual: T): jasmine.AsyncMatchers<T, void>
2148
}
2249
}

playgrounds/jasmine/test/specs/basic-matchers.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,14 @@ describe('Basic Expect Matchers', () => {
8686
it('should handle promises', async () => {
8787
const titlePromise = browser.getTitle()
8888

89-
// @ts-expect-error -- resolves does not exist under Jasmine typings
89+
// @ts-expect-error -- resolves should not exists on expect
9090
await expect(titlePromise).resolves.toContain('WebdriverIO')
9191
})
9292

9393
it('should not reject', async () => {
9494
const urlPromise = browser.getUrl()
9595

96-
// @ts-expect-error -- resolves does not exist under Jasmine typings
96+
// @ts-expect-error -- rejects should not exists on expect
9797
await expect(urlPromise).resolves.toBeDefined()
9898
})
9999
})

playgrounds/jasmine/test/specs/jasmine-specific.test.ts

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ describe('Jasmine-Specific Features', () => {
5757
await expect(tagName).toBe('button')
5858
})
5959

60+
it('should use withContext on WDIO matcher', async () => {
61+
const searchButton = await $('.DocSearch-Button')
62+
63+
await expect(searchButton).withContext('Search button should be visible on the homepage').toBeDisplayed()
64+
await expect(searchButton).withContext('Search button should exist on the homepage').toExist()
65+
})
66+
6067
// TODO failing on jasmine.stringContaining not working properly with wdio matchers
6168
xit('should use asymmetric matchers in toHaveAttribute', async () => {
6269
const docsLink = await $('a[href="/docs/gettingstarted"]')
@@ -166,13 +173,51 @@ describe('Jasmine-Specific Features', () => {
166173
})
167174
})
168175

169-
describe('Expect.withContext usage', () => {
170-
xit('should provide additional context on failure', async () => {
176+
describe('Jasmine core matcher use cases with expect', () => {
177+
it('should use all core Jasmine matchers with expect', async () => {
171178
const title = await browser.getTitle()
179+
const navLinks = await $$('nav a')
180+
const count = navLinks.length
181+
const firstLink = navLinks[0]
182+
const tagName = await firstLink.getTagName()
183+
const arr = [1, 2, 3]
184+
const obj = { foo: 'bar', num: 42 }
172185

173-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
174-
// @ts-ignore -- withContext fails tsc, see https://github.com/webdriverio/expect-webdriverio/issues/1407
175-
await expect(title).withContext('Checking page title for webdriver.io').toBe('Non-Matching Title')
186+
// Equality
187+
await expect(title).toEqual('WebdriverIO · Next-gen browser and mobile automation test framework for Node.js | WebdriverIO')
188+
await expect(count).toBeGreaterThan(0)
189+
await expect(count).toBeLessThan(100)
190+
await expect(count).toBeGreaterThanOrEqual(1)
191+
await expect(count).toBeLessThanOrEqual(100)
192+
await expect(count).toBeCloseTo(49, 3)
193+
await expect(count).not.toBeNaN()
194+
await expect(tagName).toBeDefined()
195+
await expect(tagName).not.toBeUndefined()
196+
await expect(tagName).toBeTruthy()
197+
await expect('').toBeFalsy()
198+
await expect(arr).toContain(2)
199+
await expect(arr).not.toContain(99)
200+
await expect(obj).toEqual(jasmine.objectContaining({ foo: 'bar' }))
201+
await expect(arr).toEqual(jasmine.arrayContaining([1, 2]))
202+
await expect(title).toMatch(/WebdriverIO/)
203+
await expect(title).toEqual(jasmine.stringContaining('WebdriverIO'))
204+
await expect(obj).toBeInstanceOf(Object)
205+
await expect(Promise.resolve(1)).toBeResolved()
206+
await expect(Promise.reject('fail')).toBeRejected()
207+
208+
// @ts-expect-error -- toThrowError is not recognized properly to fix one day
209+
await expect(Promise.resolve(42)).toBeResolvedTo(42)
210+
// @ts-expect-error -- toBeRejectedWith is not recognized properly to fix one day
211+
await expect(Promise.reject('fail')).toBeRejectedWith('fail')
212+
// @ts-expect-error -- toThrowError is not recognized properly to fix one day
213+
await expect(() => { throw new Error('fail') }).toThrowError('fail')
214+
215+
// withContext with various matchers
216+
await expect(title).withContext('Title should contain WebdriverIO').toMatch(/WebdriverIO/)
217+
await expect(arr).withContext('Array should contain 2').toContain(2)
218+
await expect(obj).withContext('Object should have foo').toEqual(jasmine.objectContaining({ foo: 'bar' }))
176219
})
220+
221+
177222
})
178223
})

playgrounds/jasmine/test/specs/snapshot.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,18 @@ describe('Snapshot Testing', () => {
44
})
55

66
describe('Object snapshots', () => {
7-
it('should match arbitrary object snapshot', () => {
7+
it('should match arbitrary object snapshot', async () => {
88
const data = {
99
framework: 'WebdriverIO',
1010
type: 'automation',
1111
features: ['browser', 'mobile', 'desktop']
1212
}
13-
expect(data).toMatchSnapshot()
13+
await expect(data).toMatchSnapshot()
1414
})
1515

16-
it('should match inline snapshot', () => {
16+
it('should match inline snapshot', async () => {
1717
const config = { timeout: 5000, retries: 3 }
18-
expect(config).toMatchInlineSnapshot(`
18+
await expect(config).toMatchInlineSnapshot(`
1919
{
2020
"retries": 3,
2121
"timeout": 5000,
@@ -33,18 +33,18 @@ describe('Snapshot Testing', () => {
3333
it('should match command result snapshot', async () => {
3434
const heading = await $$('h1')[1]
3535
const cssProperty = await heading.getCSSProperty('font-weight')
36-
expect(cssProperty).toMatchSnapshot()
36+
await expect(cssProperty).toMatchSnapshot()
3737
})
3838
})
3939

4040
describe('Multiple element snapshots', () => {
41-
it('should snapshot navigation links', async () => {
41+
xit('should snapshot navigation links', async () => {
4242
const navLinks = await $$('nav a')
4343
const hrefs = []
4444
for (let i = 0; i < Math.min(5, await navLinks.length); i++) {
4545
hrefs.push(await navLinks[i].getAttribute('href'))
4646
}
47-
expect(hrefs).toMatchSnapshot()
47+
await expect(hrefs).toMatchSnapshot()
4848
})
4949
})
5050
})

playgrounds/jasmine/test/specs/visual-snapshot.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ xdescribe('Visual Snapshot Testing', () => {
6464
})
6565

6666
it('should match full page snapshot with zero mismatch', async () => {
67-
await expect(browser).toMatchFullPageSnapshot('fullPageExact', 0.1)
67+
await expect(browser).toMatchFullPageSnapshot('fullPageExact', 0.15)
6868
})
6969

7070
it('should match full page snapshot with options', async () => {
@@ -83,7 +83,7 @@ xdescribe('Visual Snapshot Testing', () => {
8383

8484
describe('Tabbable Page Visual Snapshots', () => {
8585
it('should match tabbable page visual snapshot', async () => {
86-
await expect(browser).toMatchTabbablePageSnapshot('tabbable', 0.1)
86+
await expect(browser).toMatchTabbablePageSnapshot('tabbable', 0.15)
8787
})
8888

8989
it('should match tabbable page with zero mismatch', async () => {

playgrounds/jasmine/test/specs/wdio-matchers.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ describe('WebdriverIO Custom Matchers', () => {
148148
await searchButton.click()
149149

150150
// The search modal input should be focused after clicking
151-
151+
152152
await browser.pause(500) // Wait for modal to open
153153
const searchInput = await $('.DocSearch-Input')
154154
if (await searchInput.isExisting()) {

playgrounds/jasmine/tsconfig.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
"moduleResolution": "bundler",
66
"types": [
77
"node",
8-
"@wdio/globals/types",
8+
"expect-webdriverio/expect-global",
9+
"expect-webdriverio/jasmine-wdio-expect-async",
910
"@types/jasmine",
10-
"expect-webdriverio/jasmine",
11+
"@wdio/globals/types", // Need to be last to so the above from the projects have priority
1112
"@wdio/visual-service",
12-
"expect-webdriverio/jasmine-wdio-expect-async"
1313
],
1414
"resolveJsonModule": true,
1515
"esModuleInterop": true,

playgrounds/jasmine/wdio.conf.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
import { join } from 'node:path'
33
import type { VisualServiceOptions } from '@wdio/visual-service'
4-
import { SoftAssertionService, setOptions } from 'expect-webdriverio'
4+
import { setOptions } from 'expect-webdriverio'
55

66
export const config: WebdriverIO.Config = {
77
//
@@ -18,7 +18,8 @@ export const config: WebdriverIO.Config = {
1818
//
1919
specs: [
2020
'./test/specs/**/*.test.ts'
21-
// './test/specs/**/jasmine-specific.test.ts'
21+
// './test/specs/**/jasmine-specific.test.ts',
22+
// './test/specs/**/snapshot.test.ts'
2223
],
2324

2425
//
@@ -49,20 +50,21 @@ export const config: WebdriverIO.Config = {
4950
connectionRetryTimeout: 120000,
5051
connectionRetryCount: 3,
5152
services: [
52-
// Not working with Jasmine yet
53-
[SoftAssertionService, {}],
54-
// Not working with Jasmine yet
5553
[
54+
// SoftAssertionService is not supported since anyway Jasmine is designed that way out of the box
5655
'visual',
5756
{
57+
// TODO Add back snapshot tests and generate visual baselines
5858
baselineFolder: join(process.cwd(), '.tmp/visual/baseline'),
5959
formatImageName: '{tag}-{logName}-{width}x{height}',
6060
screenshotPath: join(process.cwd(), '.tmp/visual'),
6161
savePerInstance: true,
6262
autoSaveBaseline: true,
63-
// Block out the changing elements
64-
blockOutStatusBar: true,
65-
blockOutToolBar: true
63+
compareOptions: {
64+
// Block out the changing elements
65+
blockOutStatusBar: true,
66+
blockOutToolBar: true
67+
}
6668
} satisfies VisualServiceOptions
6769
]
6870
],

playgrounds/jest/test/specs/visual-snapshot.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ describe('Visual Snapshot Testing', () => {
6363
})
6464

6565
it('should match full page snapshot with zero mismatch', async () => {
66-
await expect(browser).toMatchFullPageSnapshot('fullPageExact', 0.1)
66+
await expect(browser).toMatchFullPageSnapshot('fullPageExact', 0.15)
6767
})
6868

6969
// Skipping flaky test
@@ -83,7 +83,7 @@ describe('Visual Snapshot Testing', () => {
8383

8484
describe('Tabbable Page Visual Snapshots', () => {
8585
it('should match tabbable page visual snapshot', async () => {
86-
await expect(browser).toMatchTabbablePageSnapshot('tabbable', 0.1)
86+
await expect(browser).toMatchTabbablePageSnapshot('tabbable', 0.15)
8787
})
8888

8989
it('should match tabbable page with zero mismatch', async () => {

playgrounds/jest/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
"moduleResolution": "bundler",
66
"types": [
77
"node",
8-
"@wdio/globals/types",
8+
"expect-webdriverio/expect-global",
99
"@types/jest",
1010
"expect-webdriverio/jest",
11+
"@wdio/globals/types", // Need to be last to so the above from the projects have priority
1112
"@wdio/visual-service"
1213
],
1314
"resolveJsonModule": true,

0 commit comments

Comments
 (0)