Skip to content

Commit 186fd2f

Browse files
committed
Better support of property existence on toHaveElementProperty
1 parent 3d646b5 commit 186fd2f

5 files changed

Lines changed: 169 additions & 193 deletions

File tree

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,20 @@ describe('WebdriverIO Custom Matchers', () => {
106106
})
107107

108108
describe('Element property matchers', () => {
109-
it('should verify element property', async () => {
109+
it('should verify element property value', async () => {
110110
const searchButton = await $('.DocSearch-Button')
111111
await expect(searchButton).toHaveElementProperty('type', 'button')
112112
})
113+
114+
it('should verify that element property exists', async () => {
115+
const searchButton = await $('.DocSearch-Button')
116+
await expect(searchButton).toHaveElementProperty('type')
117+
})
118+
119+
it('should verify that element property does not exist', async () => {
120+
const searchButton = await $('.DocSearch-Button')
121+
await expect(searchButton).not.toHaveElementProperty('doesNNotExist')
122+
})
113123
})
114124

115125
describe('Element value matchers', () => {

src/matchers/element/toHaveElementProperty.ts

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import type { AsyncAssertionResult } from 'expect-webdriverio'
12
import { DEFAULT_OPTIONS } from '../../constants.js'
23
import type { WdioElementMaybePromise } from '../../types.js'
4+
import { isStringOptions } from '../../util/commandOptionsUtils.js'
35
import {
46
compareText,
57
enhanceError,
@@ -11,42 +13,82 @@ import {
1113
async function condition(
1214
el: WebdriverIO.Element,
1315
property: string,
14-
value: unknown,
16+
expectedValue: unknown,
1517
options: ExpectWebdriverIO.StringOptions = DEFAULT_OPTIONS
1618
) {
1719
const { asString = false } = options
1820

19-
let prop = await el.getProperty(property)
21+
let propertyValue = await el.getProperty(property)
2022

2123
// As specified in the w3c spec, cases where property does not exist
22-
if (prop === null || prop === undefined) {
23-
return { result: false, value: prop }
24+
if (propertyValue === null || propertyValue === undefined) {
25+
return { result: false, value: propertyValue }
2426
}
2527

2628
// As specified in the w3c spec, cases where property simply exists, missing undefined here?
27-
if (value === null) {
28-
return { result: true, value: prop }
29+
if (expectedValue === null || expectedValue === undefined) {
30+
return { result: true, value: propertyValue }
2931
}
3032

31-
if (!(value instanceof RegExp) && typeof prop !== 'string' && !asString) {
32-
return { result: prop === value, value: prop }
33+
if (!(expectedValue instanceof RegExp) && typeof propertyValue !== 'string' && !asString) {
34+
return { result: propertyValue === expectedValue, value: propertyValue }
3335
}
3436

35-
prop = prop.toString()
36-
return compareText(prop as string, value as string | RegExp | AsymmetricMatcher<string>, options)
37+
propertyValue = propertyValue.toString()
38+
return compareText(propertyValue as string, expectedValue as string | RegExp | AsymmetricMatcher<string>, options)
3739
}
3840

41+
/**
42+
* @deprecated since 5.6.10 Passing explicit `undefined` as a value is deprecated. Omit the third argument entirely or use `toHaveElementProperty(el, property, options)`.
43+
*/
3944
export async function toHaveElementProperty(
4045
received: WdioElementMaybePromise,
4146
property: string,
42-
value?: string | RegExp | AsymmetricMatcher<string> | null,
47+
value: undefined,
48+
options?: ExpectWebdriverIO.StringOptions
49+
): Promise<AsyncAssertionResult>
50+
51+
/**
52+
* When called with only the property name (and optional configuration options).
53+
*/
54+
export async function toHaveElementProperty(
55+
received: WdioElementMaybePromise,
56+
property: string,
57+
options?: ExpectWebdriverIO.StringOptions
58+
): Promise<AsyncAssertionResult>
59+
60+
/**
61+
* When called with an expected property name and value.
62+
*/
63+
export async function toHaveElementProperty(
64+
received: WdioElementMaybePromise,
65+
property: string,
66+
value: string | number | RegExp | AsymmetricMatcher<string> | null,
67+
options?: ExpectWebdriverIO.StringOptions
68+
): Promise<AsyncAssertionResult>
69+
70+
export async function toHaveElementProperty(
71+
received: WdioElementMaybePromise,
72+
property: string,
73+
valueOrOptions?: string | number | RegExp | AsymmetricMatcher<string> | null | ExpectWebdriverIO.StringOptions,
4374
options: ExpectWebdriverIO.StringOptions = DEFAULT_OPTIONS
44-
) {
75+
): Promise<AsyncAssertionResult> {
76+
let value: string | number | RegExp | AsymmetricMatcher<string> | null | undefined
77+
78+
// Determine if the third argument is actually options or the expected value
79+
if (isStringOptions(valueOrOptions)) {
80+
options = valueOrOptions
81+
value = undefined
82+
} else {
83+
value = valueOrOptions as string | number | RegExp | AsymmetricMatcher<string> | null
84+
}
85+
86+
const matcherName = 'toHaveElementProperty'
4587
const isNot = this.isNot
4688
const { expectation = 'property', verb = 'have' } = this
4789

4890
await options.beforeAssertion?.({
49-
matcherName: 'toHaveElementProperty',
91+
matcherName,
5092
expectedValue: [property, value],
5193
options,
5294
})
@@ -79,7 +121,7 @@ export async function toHaveElementProperty(
79121
}
80122

81123
await options.afterAssertion?.({
82-
matcherName: 'toHaveElementProperty',
124+
matcherName,
83125
expectedValue: [property, value],
84126
options,
85127
result

test-types/mocha/mocha.test-d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,10 @@ describe('WebDriverIO Expect Type Assertions under Mocha', () => {
481481
expectTypeOf(expect(element).toHaveElementProperty('prop', 'val')).toEqualTypeOf<Promise<void>>()
482482

483483
expectTypeOf(expect(element).toHaveElementProperty('prop', expect.stringContaining('val'))).toEqualTypeOf<Promise<void>>()
484+
485+
// Deprecated matchers
486+
expectTypeOf(expect(element).toHaveElementProperty('prop', undefined)).toEqualTypeOf<Promise<void>>()
487+
expectTypeOf(expect(element).toHaveElementProperty('prop', undefined, { wait: 1 })).toEqualTypeOf<Promise<void>>()
484488
})
485489
})
486490

0 commit comments

Comments
 (0)