expect-webdriverio 6.1.0 → 8.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -7
- package/jasmine-wdio-expect-async.d.ts +1 -1
- package/jest.d.ts +4 -2
- package/lib/api/index.js +2 -0
- package/lib/constants.js +0 -6
- package/lib/index.js +3 -13
- package/lib/jasmineUtils.js +2 -2
- package/lib/matchers/asymmetrics/asymmetricsUtils.js +10 -0
- package/lib/matchers/asymmetrics/multiRemote.js +36 -0
- package/lib/matchers/asymmetrics/oneOf.js +2 -2
- package/lib/matchers/browser/toHaveClipboardText.js +24 -10
- package/lib/matchers/browser/toHaveLocalStorageItem.js +23 -22
- package/lib/matchers/browser/toHaveTitle.js +16 -6
- package/lib/matchers/browser/toHaveUrl.js +16 -6
- package/lib/matchers/element/toBeClickable.js +3 -2
- package/lib/matchers/element/toBeDisabled.js +3 -2
- package/lib/matchers/element/toBeDisplayed.js +3 -2
- package/lib/matchers/element/toBeDisplayedInViewport.js +3 -2
- package/lib/matchers/element/toBeEnabled.js +3 -2
- package/lib/matchers/element/toBeExisting.js +5 -2
- package/lib/matchers/element/toBeFocused.js +3 -2
- package/lib/matchers/element/toBeSelected.js +4 -4
- package/lib/matchers/element/toHaveAttribute.js +4 -16
- package/lib/matchers/element/toHaveChildren.js +9 -14
- package/lib/matchers/element/toHaveComputedLabel.js +4 -6
- package/lib/matchers/element/toHaveComputedRole.js +4 -6
- package/lib/matchers/element/toHaveElementClass.js +5 -10
- package/lib/matchers/element/toHaveElementProperty.js +4 -9
- package/lib/matchers/element/toHaveHTML.js +6 -8
- package/lib/matchers/element/toHaveHeight.js +6 -7
- package/lib/matchers/element/toHaveHref.js +6 -3
- package/lib/matchers/element/toHaveId.js +3 -2
- package/lib/matchers/element/toHaveSize.js +3 -4
- package/lib/matchers/element/toHaveStyle.js +3 -4
- package/lib/matchers/element/toHaveText.js +5 -8
- package/lib/matchers/element/toHaveValue.js +1 -1
- package/lib/matchers/element/toHaveWidth.js +6 -7
- package/lib/matchers/elements/toBeElementsArrayOfSize.js +71 -6
- package/lib/matchers/mock/toBeRequested.js +1 -1
- package/lib/matchers/mock/toBeRequestedTimes.js +30 -7
- package/lib/matchers/mock/toBeRequestedWith.js +40 -15
- package/lib/matchers/snapshot.js +38 -7
- package/lib/matchers.js +32 -32
- package/lib/snapshot.js +1 -8
- package/lib/tsconfig.build.tsbuildinfo +1 -1
- package/lib/util/elementsUtil.js +35 -6
- package/lib/util/executeBrowserCommand.js +37 -0
- package/lib/util/executeCommand.js +101 -52
- package/lib/util/formatMessage.js +81 -7
- package/lib/util/multiRemoteUtils.js +93 -0
- package/lib/util/numberOptionsUtil.js +19 -24
- package/lib/util/refetchElements.js +24 -2
- package/lib/utils.js +16 -111
- package/package.json +37 -40
- package/types/expect-global.d.ts +1 -2
- package/types/expect-webdriverio.d.ts +386 -232
|
@@ -20,7 +20,7 @@ async function conditionAttributeValueMatchWithExpected(el, attribute, expectedV
|
|
|
20
20
|
export async function toHaveAttributeAndValue(received, attribute, expectedValue, options = DEFAULT_OPTIONS) {
|
|
21
21
|
const { expectation = 'attribute', verb = 'have', isNot } = this;
|
|
22
22
|
expectedValue = buildWdioAsymmetricMatchersWithOptions(expectedValue, options);
|
|
23
|
-
const { success: pass, actual: attr, subject: el, context: { isSome } = {} } = await waitUntil(async (iteration) => {
|
|
23
|
+
const { success: pass, actual: attr, subject: el, context: { isSome } = {}, expected: expectedValues } = await waitUntil(async (iteration) => {
|
|
24
24
|
return await executeCommandWithStrategy({
|
|
25
25
|
unresolvedElements: received,
|
|
26
26
|
supportsArrayContaining: true,
|
|
@@ -29,10 +29,9 @@ export async function toHaveAttributeAndValue(received, attribute, expectedValue
|
|
|
29
29
|
return conditionAttributeValueMatchWithExpected(element, attribute, values, options);
|
|
30
30
|
},
|
|
31
31
|
context: { isNot, iteration },
|
|
32
|
-
strategy: 'NewStrictMultipleElements',
|
|
33
32
|
});
|
|
34
33
|
}, isNot, { wait: options.wait, interval: options.interval });
|
|
35
|
-
const expected = wrapExpectedWithArray(el, attr, expectedValue);
|
|
34
|
+
const expected = expectedValues ?? wrapExpectedWithArray(el, attr, expectedValue);
|
|
36
35
|
const message = enhanceError(el, expected, attr, { isNot, isSome }, verb, expectation, attribute, options);
|
|
37
36
|
return {
|
|
38
37
|
pass,
|
|
@@ -40,23 +39,13 @@ export async function toHaveAttributeAndValue(received, attribute, expectedValue
|
|
|
40
39
|
};
|
|
41
40
|
}
|
|
42
41
|
export async function toHaveAttribute(received, attribute, value, options = DEFAULT_OPTIONS) {
|
|
43
|
-
const matcherName = 'toHaveAttribute';
|
|
44
|
-
const paramsCount = arguments.length;
|
|
42
|
+
const { matcherName = 'toHaveAttribute' } = this;
|
|
45
43
|
await options.beforeAssertion?.({
|
|
46
44
|
matcherName,
|
|
47
45
|
expectedValue: [attribute, value],
|
|
48
46
|
options,
|
|
49
47
|
});
|
|
50
|
-
|
|
51
|
-
if (value === undefined) {
|
|
52
|
-
if (paramsCount > 2) {
|
|
53
|
-
console.warn('Using undefined or null as value for toHaveAttribute is deprecated and will be removed in v6.0.0. Please omit the third argument entirely or use toHaveAttribute(el, attribute, wdioExpect.anything(), options).');
|
|
54
|
-
}
|
|
55
|
-
expectedValue = expect.anything();
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
expectedValue = value;
|
|
59
|
-
}
|
|
48
|
+
const expectedValue = value ?? expect.anything();
|
|
60
49
|
const result = await toHaveAttributeAndValue.call(this, received, attribute, expectedValue, options);
|
|
61
50
|
await options.afterAssertion?.({
|
|
62
51
|
matcherName,
|
|
@@ -66,4 +55,3 @@ export async function toHaveAttribute(received, attribute, value, options = DEFA
|
|
|
66
55
|
});
|
|
67
56
|
return result;
|
|
68
57
|
}
|
|
69
|
-
export const toHaveAttr = toHaveAttribute;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
2
2
|
import { executeCommandWithStrategy } from '../../util/executeCommand.js';
|
|
3
|
-
import {
|
|
3
|
+
import { validateNumberMatcherArray } from '../../util/numberOptionsUtil.js';
|
|
4
4
|
import { enhanceError, waitUntil, wrapExpectedWithArray } from '../../utils.js';
|
|
5
5
|
async function condition(el, expectedValue) {
|
|
6
6
|
const children = await el.$$('./*').getElements();
|
|
@@ -12,36 +12,31 @@ async function condition(el, expectedValue) {
|
|
|
12
12
|
actual: children?.length
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
|
-
export async function toHaveChildren(received,
|
|
15
|
+
export async function toHaveChildren(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
16
16
|
const { expectation = 'children', verb = 'have', isNot, matcherName = 'toHaveChildren' } = this;
|
|
17
|
-
const paramsCount = arguments.length;
|
|
18
|
-
if (paramsCount > 1 && (expectedValueOrOptions === undefined || isEmptyOrLegacyNumberOptions(expectedValueOrOptions))) {
|
|
19
|
-
console.warn('Passing undefined or NumberOptions as the second argument to toHaveChildren is deprecated. Use a NumberMatcher instead. For example, `expect(el).toHaveChildren({ gte: 1 }, options)`');
|
|
20
|
-
}
|
|
21
17
|
await options.beforeAssertion?.({
|
|
22
18
|
matcherName,
|
|
23
|
-
expectedValue
|
|
19
|
+
expectedValue,
|
|
24
20
|
options,
|
|
25
21
|
});
|
|
26
|
-
const
|
|
27
|
-
const { success: pass, actual: children, subject, context: { isSome } = {} } = await waitUntil(async (iteration) => {
|
|
22
|
+
const expectedNumber = validateNumberMatcherArray(expectedValue, { supportDefaultAsGteThen1: true });
|
|
23
|
+
const { success: pass, actual: children, subject, context: { isSome } = {}, expected } = await waitUntil(async (iteration) => {
|
|
28
24
|
return await executeCommandWithStrategy({
|
|
29
25
|
unresolvedElements: received,
|
|
30
26
|
expectedValues: expectedNumber,
|
|
31
27
|
singleElementCompare: (element, expectedValue) => condition(element, expectedValue),
|
|
32
28
|
context: { isNot, iteration },
|
|
33
|
-
strategy: 'NewStrictMultipleElements',
|
|
34
29
|
});
|
|
35
|
-
}, isNot, { wait:
|
|
36
|
-
const expectedArray = wrapExpectedWithArray(subject, children, expectedNumber);
|
|
37
|
-
const message = enhanceError(subject, expectedArray, children, { isNot, isSome }, verb, expectation, '',
|
|
30
|
+
}, isNot, { wait: options.wait, interval: options.interval });
|
|
31
|
+
const expectedArray = expected ?? wrapExpectedWithArray(subject, children, expectedNumber);
|
|
32
|
+
const message = enhanceError(subject, expectedArray, children, { isNot, isSome }, verb, expectation, '', options);
|
|
38
33
|
const result = {
|
|
39
34
|
pass,
|
|
40
35
|
message: () => message
|
|
41
36
|
};
|
|
42
37
|
await options.afterAssertion?.({
|
|
43
38
|
matcherName,
|
|
44
|
-
expectedValue
|
|
39
|
+
expectedValue,
|
|
45
40
|
options,
|
|
46
41
|
result
|
|
47
42
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
2
2
|
import { executeCommandWithStrategy } from '../../util/executeCommand.js';
|
|
3
|
-
import {
|
|
3
|
+
import { compareTextOrOneOf, enhanceError, waitUntil, wrapExpectedWithArray } from '../../utils.js';
|
|
4
4
|
import { buildWdioAsymmetricMatchersWithOptions } from '../asymmetrics/asymmetricsUtils.js';
|
|
5
5
|
async function singleElementCompare(element, label, options) {
|
|
6
6
|
const actualLabel = await element.getComputedLabel();
|
|
7
|
-
return
|
|
7
|
+
return compareTextOrOneOf(actualLabel, label, options);
|
|
8
8
|
}
|
|
9
9
|
export async function toHaveComputedLabel(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
10
10
|
const { expectation = 'computed label', verb = 'have', isNot, matcherName = 'toHaveComputedLabel' } = this;
|
|
@@ -14,18 +14,16 @@ export async function toHaveComputedLabel(received, expectedValue, options = DEF
|
|
|
14
14
|
options,
|
|
15
15
|
});
|
|
16
16
|
expectedValue = buildWdioAsymmetricMatchersWithOptions(expectedValue, options);
|
|
17
|
-
const { success: pass, actual: actualLabel, subject: el, context: { isSome } = {} } = await waitUntil(async (iteration) => {
|
|
17
|
+
const { success: pass, actual: actualLabel, subject: el, context: { isSome } = {}, expected } = await waitUntil(async (iteration) => {
|
|
18
18
|
return await executeCommandWithStrategy({
|
|
19
19
|
unresolvedElements: received,
|
|
20
20
|
supportsArrayContaining: true,
|
|
21
21
|
expectedValues: expectedValue,
|
|
22
22
|
singleElementCompare: (element, expectedValue) => singleElementCompare(element, expectedValue, options),
|
|
23
23
|
context: { isNot, iteration },
|
|
24
|
-
strategy: 'NewStrictMultipleElements',
|
|
25
|
-
strictConfiguration: { allowArrayWithSingleElement: true }
|
|
26
24
|
});
|
|
27
25
|
}, isNot, { wait: options.wait, interval: options.interval });
|
|
28
|
-
const message = enhanceError(el, wrapExpectedWithArray(el, actualLabel, expectedValue), actualLabel, { isNot, isSome }, verb, expectation, '', options);
|
|
26
|
+
const message = enhanceError(el, expected ?? wrapExpectedWithArray(el, actualLabel, expectedValue), actualLabel, { isNot, isSome }, verb, expectation, '', options);
|
|
29
27
|
const result = {
|
|
30
28
|
pass,
|
|
31
29
|
message: () => message
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
2
2
|
import { executeCommandWithStrategy } from '../../util/executeCommand.js';
|
|
3
|
-
import {
|
|
3
|
+
import { compareTextOrOneOf, enhanceError, waitUntil, wrapExpectedWithArray } from '../../utils.js';
|
|
4
4
|
import { buildWdioAsymmetricMatchersWithOptions } from '../asymmetrics/asymmetricsUtils.js';
|
|
5
5
|
async function singleElementCompare(element, role, options) {
|
|
6
6
|
const actualRole = await element.getComputedRole();
|
|
7
|
-
return
|
|
7
|
+
return compareTextOrOneOf(actualRole, role, options);
|
|
8
8
|
}
|
|
9
9
|
export async function toHaveComputedRole(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
10
10
|
const { expectation = 'computed role', verb = 'have', isNot, matcherName = 'toHaveComputedRole' } = this;
|
|
@@ -14,18 +14,16 @@ export async function toHaveComputedRole(received, expectedValue, options = DEFA
|
|
|
14
14
|
options,
|
|
15
15
|
});
|
|
16
16
|
expectedValue = buildWdioAsymmetricMatchersWithOptions(expectedValue, options);
|
|
17
|
-
const { success: pass, actual: actualRole, subject: el, context: { isSome } = {} } = await waitUntil(async (iteration) => {
|
|
17
|
+
const { success: pass, actual: actualRole, subject: el, context: { isSome } = {}, expected } = await waitUntil(async (iteration) => {
|
|
18
18
|
return await executeCommandWithStrategy({
|
|
19
19
|
unresolvedElements: received,
|
|
20
20
|
supportsArrayContaining: true,
|
|
21
21
|
expectedValues: expectedValue,
|
|
22
22
|
singleElementCompare: (element, expectedValue) => singleElementCompare(element, expectedValue, options),
|
|
23
23
|
context: { isNot, iteration },
|
|
24
|
-
strategy: 'NewStrictMultipleElements',
|
|
25
|
-
strictConfiguration: { allowArrayWithSingleElement: true }
|
|
26
24
|
});
|
|
27
25
|
}, isNot, { wait: options.wait, interval: options.interval });
|
|
28
|
-
const message = enhanceError(el, wrapExpectedWithArray(el, actualRole, expectedValue), actualRole, { isNot, isSome }, verb, expectation, '', options);
|
|
26
|
+
const message = enhanceError(el, expected ?? wrapExpectedWithArray(el, actualRole, expectedValue), actualRole, { isNot, isSome }, verb, expectation, '', options);
|
|
29
27
|
const result = {
|
|
30
28
|
pass,
|
|
31
29
|
message: () => message
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
2
2
|
import { executeCommandWithStrategy } from '../../util/executeCommand.js';
|
|
3
|
-
import { compareText,
|
|
3
|
+
import { compareText, enhanceError, isAsymmetricMatcher, waitUntil, wrapExpectedWithArray } from '../../utils.js';
|
|
4
4
|
async function singleElementCompare(el, attribute, value, options) {
|
|
5
5
|
const actualClass = await el.getAttribute(attribute);
|
|
6
6
|
if (value === undefined) {
|
|
@@ -13,17 +13,13 @@ async function singleElementCompare(el, attribute, value, options) {
|
|
|
13
13
|
return compareText(actualClass, value, options);
|
|
14
14
|
}
|
|
15
15
|
const classes = actualClass.split(' ');
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
});
|
|
16
|
+
const values = Array.isArray(value) ? value : [value];
|
|
17
|
+
const isValueInClasses = classes.some((clazz) => values.some((expected) => compareText(clazz, expected, options).success));
|
|
19
18
|
return {
|
|
20
19
|
success: isValueInClasses,
|
|
21
20
|
actual: actualClass
|
|
22
21
|
};
|
|
23
22
|
}
|
|
24
|
-
export function toHaveClass(...args) {
|
|
25
|
-
return toHaveElementClass.call(this || {}, ...args);
|
|
26
|
-
}
|
|
27
23
|
export async function toHaveElementClass(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
28
24
|
const { expectation = 'class', verb = 'have', isNot, matcherName = 'toHaveElementClass' } = this;
|
|
29
25
|
await options.beforeAssertion?.({
|
|
@@ -32,18 +28,17 @@ export async function toHaveElementClass(received, expectedValue, options = DEFA
|
|
|
32
28
|
options,
|
|
33
29
|
});
|
|
34
30
|
const attribute = 'class';
|
|
35
|
-
const { success: pass, actual: attr, subject: el, context: { isSome } = {} } = await waitUntil(async (iteration) => {
|
|
31
|
+
const { success: pass, actual: attr, subject: el, context: { isSome } = {}, expected } = await waitUntil(async (iteration) => {
|
|
36
32
|
return await executeCommandWithStrategy({
|
|
37
33
|
unresolvedElements: received,
|
|
38
34
|
supportsArrayContaining: true,
|
|
39
35
|
expectedValues: expectedValue,
|
|
40
36
|
singleElementCompare: (element, expectedValue) => singleElementCompare(element, attribute, expectedValue, options),
|
|
41
37
|
context: { isNot, iteration },
|
|
42
|
-
strategy: 'NewStrictMultipleElements',
|
|
43
38
|
strictConfiguration: { allowArrayWithSingleElement: true }
|
|
44
39
|
});
|
|
45
40
|
}, isNot, { wait: options.wait, interval: options.interval });
|
|
46
|
-
const message = enhanceError(el, wrapExpectedWithArray(el, attr, expectedValue), attr, { isNot, isSome }, verb, expectation, '', options);
|
|
41
|
+
const message = enhanceError(el, expected ?? wrapExpectedWithArray(el, attr, expectedValue), attr, { isNot, isSome }, verb, expectation, '', options);
|
|
47
42
|
const result = {
|
|
48
43
|
pass,
|
|
49
44
|
message: () => message
|
|
@@ -20,12 +20,8 @@ async function condition(el, property, expectedValue, options = DEFAULT_OPTIONS)
|
|
|
20
20
|
return compareText(propertyValue.toString(), expectedValue, options);
|
|
21
21
|
}
|
|
22
22
|
export async function toHaveElementProperty(received, property, value, options = DEFAULT_OPTIONS) {
|
|
23
|
-
const { expectation = 'property', verb = 'have', isNot, matcherName = 'toHaveElementProperty' } = this;
|
|
24
|
-
const paramsCount = arguments.length;
|
|
23
|
+
const { expectation = 'property', verb = 'have', isNot, matcherName = 'toHaveElementProperty', allowObjectExpectedValue = true } = this;
|
|
25
24
|
if (value === undefined || value === null) {
|
|
26
|
-
if (paramsCount > 2) {
|
|
27
|
-
console.warn('Using undefined or null as value for toHaveElementProperty is deprecated and will be removed in v6.0.0. Please omit the third argument entirely or use toHaveElementProperty(el, property, object.anything(), options).');
|
|
28
|
-
}
|
|
29
25
|
value = expect.anything();
|
|
30
26
|
}
|
|
31
27
|
await options.beforeAssertion?.({
|
|
@@ -34,7 +30,7 @@ export async function toHaveElementProperty(received, property, value, options =
|
|
|
34
30
|
options,
|
|
35
31
|
});
|
|
36
32
|
value = buildWdioAsymmetricMatchersWithOptions(value, options);
|
|
37
|
-
const { success: pass, actual: actualProppertyValue, subject: elements, context: { isSome } = {} } = await waitUntil(async (iteration) => {
|
|
33
|
+
const { success: pass, actual: actualProppertyValue, subject: elements, context: { isSome } = {}, expected: expectedValues } = await waitUntil(async (iteration) => {
|
|
38
34
|
return await executeCommandWithStrategy({
|
|
39
35
|
unresolvedElements: received,
|
|
40
36
|
supportsArrayContaining: true,
|
|
@@ -43,11 +39,10 @@ export async function toHaveElementProperty(received, property, value, options =
|
|
|
43
39
|
return condition(element, property, expectedValue, options);
|
|
44
40
|
},
|
|
45
41
|
context: { isNot, iteration },
|
|
46
|
-
|
|
47
|
-
strictConfiguration: { allowArrayWithSingleElement: false }
|
|
42
|
+
strictConfiguration: { allowArrayWithSingleElement: false, allowObjectExpectedValue }
|
|
48
43
|
});
|
|
49
44
|
}, isNot, { wait: options.wait, interval: options.interval });
|
|
50
|
-
const expected = wrapExpectedWithArray(elements, actualProppertyValue, value);
|
|
45
|
+
const expected = expectedValues ?? wrapExpectedWithArray(elements, actualProppertyValue, value);
|
|
51
46
|
const message = enhanceError(elements, expected, actualProppertyValue, { isNot, isSome }, verb, expectation, property, options);
|
|
52
47
|
const result = {
|
|
53
48
|
pass,
|
|
@@ -1,32 +1,30 @@
|
|
|
1
1
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
2
|
-
import {
|
|
2
|
+
import { compareTextOrOneOf, enhanceError, waitUntil, wrapExpectedWithArray } from '../../utils.js';
|
|
3
3
|
import { executeCommandWithStrategy } from '../../util/executeCommand.js';
|
|
4
4
|
import { buildWdioAsymmetricMatchersWithOptions } from '../asymmetrics/asymmetricsUtils.js';
|
|
5
5
|
async function singleElementCompare(el, html, options) {
|
|
6
6
|
const actualHTML = await el.getHTML(options);
|
|
7
|
-
return
|
|
7
|
+
return compareTextOrOneOf(actualHTML, html, options);
|
|
8
8
|
}
|
|
9
9
|
export async function toHaveHTML(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
10
10
|
const { expectation = 'HTML', verb = 'have', isNot, matcherName = 'toHaveHTML' } = this;
|
|
11
|
-
expectedValue = buildWdioAsymmetricMatchersWithOptions(expectedValue, options);
|
|
12
11
|
await options.beforeAssertion?.({
|
|
13
12
|
matcherName,
|
|
14
13
|
expectedValue,
|
|
15
14
|
options,
|
|
16
15
|
});
|
|
17
|
-
const
|
|
16
|
+
const expectedWithOptions = buildWdioAsymmetricMatchersWithOptions(expectedValue, options);
|
|
17
|
+
const { success: pass, actual: actualHTML, subject: elements, context: { isSome } = {}, expected } = await waitUntil(async (iteration) => {
|
|
18
18
|
const result = await executeCommandWithStrategy({
|
|
19
19
|
unresolvedElements: received,
|
|
20
20
|
supportsArrayContaining: true,
|
|
21
|
-
expectedValues:
|
|
21
|
+
expectedValues: expectedWithOptions,
|
|
22
22
|
singleElementCompare: (element, expectedValue) => singleElementCompare(element, expectedValue, options),
|
|
23
23
|
context: { isNot, iteration },
|
|
24
|
-
strategy: 'NewStrictMultipleElements',
|
|
25
|
-
strictConfiguration: { allowArrayWithSingleElement: true }
|
|
26
24
|
});
|
|
27
25
|
return result;
|
|
28
26
|
}, isNot, { wait: options.wait, interval: options.interval });
|
|
29
|
-
const expectedValues = wrapExpectedWithArray(elements, actualHTML,
|
|
27
|
+
const expectedValues = expected ?? wrapExpectedWithArray(elements, actualHTML, expectedWithOptions);
|
|
30
28
|
const message = enhanceError(elements, expectedValues, actualHTML, { isNot, isSome }, verb, expectation, '', options);
|
|
31
29
|
const result = {
|
|
32
30
|
pass,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
2
2
|
import { wrapExpectedWithArray } from '../../util/elementsUtil.js';
|
|
3
3
|
import { executeCommandWithStrategy } from '../../util/executeCommand.js';
|
|
4
|
-
import {
|
|
4
|
+
import { validateNumberMatcherArray } from '../../util/numberOptionsUtil.js';
|
|
5
5
|
import { enhanceError, waitUntil, } from '../../utils.js';
|
|
6
6
|
async function condition(el, expectedNumber) {
|
|
7
7
|
const actualHeight = await el.getSize('height');
|
|
@@ -17,19 +17,18 @@ export async function toHaveHeight(received, expectedValue, options = DEFAULT_OP
|
|
|
17
17
|
expectedValue,
|
|
18
18
|
options,
|
|
19
19
|
});
|
|
20
|
-
const
|
|
21
|
-
const { success: pass, actual: actualHeight, subject: elements, context: { isSome } = {} } = await waitUntil(async (iteration) => {
|
|
20
|
+
const expectedNumber = validateNumberMatcherArray(expectedValue);
|
|
21
|
+
const { success: pass, actual: actualHeight, subject: elements, context: { isSome } = {}, expected } = await waitUntil(async (iteration) => {
|
|
22
22
|
return await executeCommandWithStrategy({
|
|
23
23
|
unresolvedElements: received,
|
|
24
24
|
expectedValues: expectedNumber,
|
|
25
25
|
singleElementCompare: (element, expectedNumber) => condition(element, expectedNumber),
|
|
26
26
|
context: { isNot, iteration },
|
|
27
|
-
strategy: 'NewStrictMultipleElements',
|
|
28
27
|
strictConfiguration: { allowArrayWithSingleElement: false }
|
|
29
28
|
});
|
|
30
|
-
}, isNot, { wait:
|
|
31
|
-
const expectedValues = wrapExpectedWithArray(elements, actualHeight, expectedNumber);
|
|
32
|
-
const message = enhanceError(elements, expectedValues, actualHeight, { isNot, isSome }, verb, expectation, '',
|
|
29
|
+
}, isNot, { wait: options.wait, interval: options.interval });
|
|
30
|
+
const expectedValues = expected ?? wrapExpectedWithArray(elements, actualHeight, expectedNumber);
|
|
31
|
+
const message = enhanceError(elements, expectedValues, actualHeight, { isNot, isSome }, verb, expectation, '', options);
|
|
33
32
|
const result = {
|
|
34
33
|
pass,
|
|
35
34
|
message: () => message
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { toHaveAttributeAndValue } from './toHaveAttribute.js';
|
|
2
2
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
3
3
|
export async function toHaveHref(el, expectedValue, options = DEFAULT_OPTIONS) {
|
|
4
|
+
const { matcherName = 'toHaveHref' } = this;
|
|
4
5
|
await options.beforeAssertion?.({
|
|
5
|
-
matcherName
|
|
6
|
+
matcherName,
|
|
6
7
|
expectedValue,
|
|
7
8
|
options,
|
|
8
9
|
});
|
|
9
10
|
const result = await toHaveAttributeAndValue.call(this, el, 'href', expectedValue, options);
|
|
10
11
|
await options.afterAssertion?.({
|
|
11
|
-
matcherName
|
|
12
|
+
matcherName,
|
|
12
13
|
expectedValue,
|
|
13
14
|
options,
|
|
14
15
|
result
|
|
15
16
|
});
|
|
16
17
|
return result;
|
|
17
18
|
}
|
|
18
|
-
export const toHaveLink =
|
|
19
|
+
export const toHaveLink = function toHaveLink(...args) {
|
|
20
|
+
return toHaveHref.call({ matcherName: 'toHaveLink', ...this }, ...args);
|
|
21
|
+
};
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { toHaveAttributeAndValue } from './toHaveAttribute.js';
|
|
2
2
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
3
3
|
export async function toHaveId(el, expectedValue, options = DEFAULT_OPTIONS) {
|
|
4
|
+
const { matcherName = 'toHaveId' } = this;
|
|
4
5
|
await options.beforeAssertion?.({
|
|
5
|
-
matcherName
|
|
6
|
+
matcherName,
|
|
6
7
|
expectedValue,
|
|
7
8
|
options,
|
|
8
9
|
});
|
|
9
10
|
const result = await toHaveAttributeAndValue.call(this, el, 'id', expectedValue, options);
|
|
10
11
|
await options.afterAssertion?.({
|
|
11
|
-
matcherName
|
|
12
|
+
matcherName,
|
|
12
13
|
expectedValue,
|
|
13
14
|
options,
|
|
14
15
|
result
|
|
@@ -12,17 +12,16 @@ export async function toHaveSize(received, expectedValue, options = DEFAULT_OPTI
|
|
|
12
12
|
expectedValue,
|
|
13
13
|
options,
|
|
14
14
|
});
|
|
15
|
-
const { success: pass, actual: actualSize, subject: el, context: { isSome } = {} } = await waitUntil(async (iteration) => {
|
|
15
|
+
const { success: pass, actual: actualSize, subject: el, context: { isSome } = {}, expected } = await waitUntil(async (iteration) => {
|
|
16
16
|
return await executeCommandWithStrategy({
|
|
17
17
|
unresolvedElements: received,
|
|
18
18
|
expectedValues: expectedValue,
|
|
19
19
|
singleElementCompare: (element, expectedSize) => condition(element, expectedSize),
|
|
20
20
|
context: { isNot, iteration },
|
|
21
|
-
|
|
22
|
-
strictConfiguration: { allowArrayWithSingleElement: false }
|
|
21
|
+
strictConfiguration: { allowArrayWithSingleElement: false, allowObjectExpectedValue: true }
|
|
23
22
|
});
|
|
24
23
|
}, isNot, { wait: options.wait, interval: options.interval });
|
|
25
|
-
const message = enhanceError(el, wrapExpectedWithArray(el, actualSize, expectedValue), actualSize, { isNot, isSome }, verb, expectation, '', options);
|
|
24
|
+
const message = enhanceError(el, expected ?? wrapExpectedWithArray(el, actualSize, expectedValue), actualSize, { isNot, isSome }, verb, expectation, '', options);
|
|
26
25
|
const result = {
|
|
27
26
|
pass,
|
|
28
27
|
message: () => message
|
|
@@ -14,17 +14,16 @@ export async function toHaveStyle(received, expectedValue, options = DEFAULT_OPT
|
|
|
14
14
|
expectedValue,
|
|
15
15
|
options,
|
|
16
16
|
});
|
|
17
|
-
const { success: pass, actual: actualStyle, subject: el, context: { isSome } = {} } = await waitUntil(async (iteration) => {
|
|
17
|
+
const { success: pass, actual: actualStyle, subject: el, context: { isSome } = {}, expected: expectedValues } = await waitUntil(async (iteration) => {
|
|
18
18
|
return await executeCommandWithStrategy({
|
|
19
19
|
unresolvedElements: received,
|
|
20
20
|
expectedValues: expectedValue,
|
|
21
21
|
singleElementCompare: (element, expectedValues) => condition(element, expectedValues, options),
|
|
22
22
|
context: { isNot, iteration },
|
|
23
|
-
|
|
24
|
-
strictConfiguration: { allowArrayWithSingleElement: false }
|
|
23
|
+
strictConfiguration: { allowArrayWithSingleElement: false, allowObjectExpectedValue: true }
|
|
25
24
|
});
|
|
26
25
|
}, isNot, { wait: options.wait, interval: options.interval });
|
|
27
|
-
const expected = wrapExpectedWithArray(el, actualStyle, expectedValue);
|
|
26
|
+
const expected = expectedValues ?? wrapExpectedWithArray(el, actualStyle, expectedValue);
|
|
28
27
|
const message = enhanceError(el, expected, actualStyle, { isNot, isSome }, verb, expectation, '', options);
|
|
29
28
|
const result = {
|
|
30
29
|
pass,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
2
|
-
import {
|
|
2
|
+
import { compareTextOrOneOf, enhanceError, isArrayContainingMatcher, waitUntil, } from '../../utils.js';
|
|
3
3
|
import { executeCommandWithStrategy } from '../../util/executeCommand.js';
|
|
4
4
|
import { fillSingleExpectedForElementArray } from '../../util/elementsUtil.js';
|
|
5
5
|
import { buildWdioAsymmetricMatchersWithOptions } from '../asymmetrics/asymmetricsUtils.js';
|
|
6
6
|
async function compareElement(el, expectedText, options) {
|
|
7
7
|
const actualText = await el.getText();
|
|
8
|
-
return
|
|
8
|
+
return compareTextOrOneOf(actualText, expectedText, options);
|
|
9
9
|
}
|
|
10
10
|
export async function toHaveText(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
11
11
|
const { expectation = 'text', verb = 'have', isNot, matcherName = 'toHaveText' } = this;
|
|
@@ -15,8 +15,7 @@ export async function toHaveText(received, expectedValue, options = DEFAULT_OPTI
|
|
|
15
15
|
options,
|
|
16
16
|
});
|
|
17
17
|
expectedValue = buildWdioAsymmetricMatchersWithOptions(expectedValue, options);
|
|
18
|
-
const
|
|
19
|
-
const { success: pass, actual: actualText, subject: subject, context: { isSome } = {} } = await waitUntil(async (iteration) => {
|
|
18
|
+
const { success: pass, actual: actualText, subject, context: { isSome } = {}, expected } = await waitUntil(async (iteration) => {
|
|
20
19
|
return await executeCommandWithStrategy({
|
|
21
20
|
unresolvedElements: received,
|
|
22
21
|
expectedValues: expectedValue,
|
|
@@ -25,15 +24,13 @@ export async function toHaveText(received, expectedValue, options = DEFAULT_OPTI
|
|
|
25
24
|
return compareElement(element, values, options);
|
|
26
25
|
},
|
|
27
26
|
context: { isNot, iteration },
|
|
28
|
-
strategy: isNewStrictCompare ? 'NewStrictMultipleElements' : 'LegacyLooseMultipleElements',
|
|
29
|
-
strictConfiguration: { allowArrayWithSingleElement: true }
|
|
30
27
|
});
|
|
31
28
|
}, isNot, { wait: options.wait, interval: options.interval });
|
|
32
29
|
if (isArrayContainingMatcher(expectedValue) && actualText === undefined) {
|
|
33
30
|
throw new Error('toHaveText with arrayContaining requires an array of elements');
|
|
34
31
|
}
|
|
35
|
-
const
|
|
36
|
-
const message = enhanceError(subject,
|
|
32
|
+
const finalExpected = expected ?? fillSingleExpectedForElementArray(subject, expectedValue);
|
|
33
|
+
const message = enhanceError(subject, finalExpected, actualText, { isNot, isSome }, verb, expectation, '', options);
|
|
37
34
|
const result = {
|
|
38
35
|
pass,
|
|
39
36
|
message: () => message
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { toHaveElementProperty } from './toHaveElementProperty.js';
|
|
2
2
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
3
3
|
export function toHaveValue(el, value, options = DEFAULT_OPTIONS) {
|
|
4
|
-
return toHaveElementProperty.call(this, el, 'value', value, options);
|
|
4
|
+
return toHaveElementProperty.call({ matcherName: 'toHaveValue', ...this, allowObjectExpectedValue: false }, el, 'value', value, options);
|
|
5
5
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
2
2
|
import { wrapExpectedWithArray } from '../../util/elementsUtil.js';
|
|
3
3
|
import { executeCommandWithStrategy } from '../../util/executeCommand.js';
|
|
4
|
-
import {
|
|
4
|
+
import { validateNumberMatcherArray } from '../../util/numberOptionsUtil.js';
|
|
5
5
|
import { enhanceError, waitUntil, } from '../../utils.js';
|
|
6
6
|
async function condition(el, expectedNumber) {
|
|
7
7
|
const actualWidth = await el.getSize('width');
|
|
@@ -17,19 +17,18 @@ export async function toHaveWidth(received, expectedValue, options = DEFAULT_OPT
|
|
|
17
17
|
expectedValue,
|
|
18
18
|
options,
|
|
19
19
|
});
|
|
20
|
-
const
|
|
21
|
-
const { success: pass, actual: actualWidth, subject: elements, context: { isSome } = {} } = await waitUntil(async (iteration) => {
|
|
20
|
+
const expectedNumber = validateNumberMatcherArray(expectedValue);
|
|
21
|
+
const { success: pass, actual: actualWidth, subject: elements, context: { isSome } = {}, expected } = await waitUntil(async (iteration) => {
|
|
22
22
|
return await executeCommandWithStrategy({
|
|
23
23
|
unresolvedElements: received,
|
|
24
24
|
expectedValues: expectedNumber,
|
|
25
25
|
singleElementCompare: (element, expectedNumber) => condition(element, expectedNumber),
|
|
26
26
|
context: { isNot, iteration },
|
|
27
|
-
strategy: 'NewStrictMultipleElements',
|
|
28
27
|
strictConfiguration: { allowArrayWithSingleElement: false }
|
|
29
28
|
});
|
|
30
|
-
}, isNot, { wait:
|
|
31
|
-
const expectedValues = wrapExpectedWithArray(elements, actualWidth, expectedNumber);
|
|
32
|
-
const message = enhanceError(elements, expectedValues, actualWidth, { isNot, isSome }, verb, expectation, '',
|
|
29
|
+
}, isNot, { wait: options.wait, interval: options.interval });
|
|
30
|
+
const expectedValues = expected ?? wrapExpectedWithArray(elements, actualWidth, expectedNumber);
|
|
31
|
+
const message = enhanceError(elements, expectedValues, actualWidth, { isNot, isSome }, verb, expectation, '', options);
|
|
33
32
|
const result = {
|
|
34
33
|
pass,
|
|
35
34
|
message: () => message
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { waitUntil, enhanceError, } from '../../utils.js';
|
|
2
|
-
import { refetchElements, syncronizeElements } from '../../util/refetchElements.js';
|
|
2
|
+
import { refetchElements, synchronizeElementArray, syncronizeElements } from '../../util/refetchElements.js';
|
|
3
3
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
4
|
-
import {
|
|
5
|
-
import { awaitElementArray, isStrictlyElementArray } from '../../util/elementsUtil.js';
|
|
4
|
+
import { validateNumberMatcher } from '../../util/numberOptionsUtil.js';
|
|
5
|
+
import { awaitElementArray, isMultiRemoteElementArray, isMultiRemoteElements, isMultiRemoteElementsLike, isStrictlyElementArray } from '../../util/elementsUtil.js';
|
|
6
|
+
import { getElementsPerInstance, getGlobalMultiRemoteInstanceNames, hasSameInstanceNames, isGlobalBrowserSingleRemote, isMultiRemoteMatcher } from '../../util/multiRemoteUtils.js';
|
|
6
7
|
export async function toBeElementsArrayOfSize(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
7
8
|
const { expectation = 'elements array of size', verb = 'be', isNot, matcherName = 'toBeElementsArrayOfSize' } = this;
|
|
8
9
|
await options.beforeAssertion?.({
|
|
@@ -10,8 +11,17 @@ export async function toBeElementsArrayOfSize(received, expectedValue, options =
|
|
|
10
11
|
expectedValue,
|
|
11
12
|
options,
|
|
12
13
|
});
|
|
13
|
-
const { numberMatcher: expectedNumber, commandOptions } = validateNumberAndExtractOptions(expectedValue, options);
|
|
14
14
|
let { elements, other } = await awaitElementArray(received);
|
|
15
|
+
const awaitedMultiRemote = other ?? elements;
|
|
16
|
+
const isEmptyWithPerInstanceSizes = Array.isArray(awaitedMultiRemote) && awaitedMultiRemote.length === 0
|
|
17
|
+
&& !isStrictlyElementArray(awaitedMultiRemote) && !isGlobalBrowserSingleRemote()
|
|
18
|
+
&& getPerInstanceSizes(expectedValue) !== undefined;
|
|
19
|
+
if (isMultiRemoteElementsLike(awaitedMultiRemote) || isEmptyWithPerInstanceSizes) {
|
|
20
|
+
const result = await multiRemoteElementsArrayOfSize(awaitedMultiRemote, expectedValue, options, { context: this, verb, expectation });
|
|
21
|
+
await options.afterAssertion?.({ matcherName, expectedValue, options, result });
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
const expectedNumber = validateNumberMatcher(expectedValue);
|
|
15
25
|
const originalLength = elements ? elements.length : undefined;
|
|
16
26
|
const { success: pass } = await waitUntil(async (iteration) => {
|
|
17
27
|
if (!elements) {
|
|
@@ -25,12 +35,12 @@ export async function toBeElementsArrayOfSize(received, expectedValue, options =
|
|
|
25
35
|
return { success: isPassing, subject: elements, actual: elements.length };
|
|
26
36
|
}
|
|
27
37
|
return { success: false, subject: elements, actual: elements.length };
|
|
28
|
-
}, isNot, { wait:
|
|
38
|
+
}, isNot, { wait: options.wait, interval: options.interval });
|
|
29
39
|
if (pass && originalLength !== undefined && elements !== received && (isStrictlyElementArray(received) || received instanceof Promise) && isStrictlyElementArray(elements)) {
|
|
30
40
|
await syncronizeElements(received, elements);
|
|
31
41
|
}
|
|
32
42
|
const actual = originalLength;
|
|
33
|
-
const message = enhanceError(elements ?? other, expectedNumber, actual, this, verb, expectation, '',
|
|
43
|
+
const message = enhanceError(elements ?? other, expectedNumber, actual, this, verb, expectation, '', options);
|
|
34
44
|
const result = {
|
|
35
45
|
pass,
|
|
36
46
|
message: () => message
|
|
@@ -43,3 +53,58 @@ export async function toBeElementsArrayOfSize(received, expectedValue, options =
|
|
|
43
53
|
});
|
|
44
54
|
return result;
|
|
45
55
|
}
|
|
56
|
+
const multiRemoteElementsArrayOfSize = async (received, expectedValue, options, { context, verb, expectation }) => {
|
|
57
|
+
const { isNot } = context;
|
|
58
|
+
const perInstanceSizes = getPerInstanceSizes(expectedValue);
|
|
59
|
+
const instances = getMultiRemoteInstanceNames(received)
|
|
60
|
+
?? getGlobalMultiRemoteInstanceNames()
|
|
61
|
+
?? (perInstanceSizes ? Object.keys(perInstanceSizes) : []);
|
|
62
|
+
let expected;
|
|
63
|
+
let instanceMismatch = false;
|
|
64
|
+
if (perInstanceSizes) {
|
|
65
|
+
instanceMismatch = !hasSameInstanceNames(perInstanceSizes, instances);
|
|
66
|
+
expected = Object.fromEntries(Object.entries(perInstanceSizes).map(([name, value]) => [name, validateNumberMatcher(value)]));
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
const numberMatcher = validateNumberMatcher(expectedValue);
|
|
70
|
+
expected = Object.fromEntries(instances.map((name) => [name, numberMatcher]));
|
|
71
|
+
}
|
|
72
|
+
let refetchSource = received;
|
|
73
|
+
let elements = received;
|
|
74
|
+
let actual = countElementsPerInstance(elements, instances);
|
|
75
|
+
const { success: pass } = await waitUntil(async (iteration) => {
|
|
76
|
+
if (iteration > 0) {
|
|
77
|
+
elements = await refetchElements(refetchSource);
|
|
78
|
+
if (elements.length > 0 || !isMultiRemoteElements(refetchSource)) {
|
|
79
|
+
refetchSource = elements;
|
|
80
|
+
}
|
|
81
|
+
actual = countElementsPerInstance(elements, instances);
|
|
82
|
+
}
|
|
83
|
+
if (instanceMismatch) {
|
|
84
|
+
return { success: !!isNot, subject: refetchSource, actual, abort: true };
|
|
85
|
+
}
|
|
86
|
+
const matches = (name) => expected[name].asymmetricMatch(actual[name]);
|
|
87
|
+
const success = isNot ? instances.some(matches) : instances.every(matches);
|
|
88
|
+
return { success, subject: refetchSource, actual };
|
|
89
|
+
}, isNot, { wait: options.wait, interval: options.interval });
|
|
90
|
+
if (pass && elements !== received) {
|
|
91
|
+
synchronizeElementArray(received, elements);
|
|
92
|
+
}
|
|
93
|
+
const message = enhanceError(refetchSource, expected, actual, { isNot }, verb, expectation, '', options);
|
|
94
|
+
return { pass, message: () => message };
|
|
95
|
+
};
|
|
96
|
+
const getPerInstanceSizes = (value) => {
|
|
97
|
+
return isMultiRemoteMatcher(value) ? value.sample : undefined;
|
|
98
|
+
};
|
|
99
|
+
const getMultiRemoteInstanceNames = (elements) => {
|
|
100
|
+
const first = elements[0];
|
|
101
|
+
if (first) {
|
|
102
|
+
return first.instances;
|
|
103
|
+
}
|
|
104
|
+
const parent = isMultiRemoteElementArray(elements) ? elements.parent : undefined;
|
|
105
|
+
return parent?.instances;
|
|
106
|
+
};
|
|
107
|
+
const countElementsPerInstance = (elements, instances) => {
|
|
108
|
+
const elementsPerInstance = getElementsPerInstance(elements, instances);
|
|
109
|
+
return Object.fromEntries(instances.map((name) => [name, elementsPerInstance[name].length]));
|
|
110
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { toBeRequestedTimes } from './toBeRequestedTimes.js';
|
|
2
2
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
3
3
|
export function toBeRequested(received, options = DEFAULT_OPTIONS) {
|
|
4
|
-
return toBeRequestedTimes.call({ ...(this || {}), expectation: 'called' }, received, { gte: 1 }, options);
|
|
4
|
+
return toBeRequestedTimes.call({ matcherName: 'toBeRequested', ...(this || {}), expectation: 'called' }, received, { gte: 1 }, options);
|
|
5
5
|
}
|