expect-webdriverio 5.6.9 → 6.0.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 +16 -14
- package/jasmine-wdio-expect-async.d.ts +58 -18
- package/jasmine.d.ts +9 -16
- package/lib/constants.js +4 -0
- package/lib/index.js +30 -18
- package/lib/jasmineUtils.js +3 -2
- package/lib/matchers/asymmetrics/asymmetricsUtils.js +24 -0
- package/lib/matchers/asymmetrics/oneOf.js +51 -0
- package/lib/matchers/browser/toHaveClipboardText.js +8 -9
- package/lib/matchers/browser/toHaveLocalStorageItem.js +22 -14
- package/lib/matchers/browser/toHaveTitle.js +9 -10
- package/lib/matchers/browser/toHaveUrl.js +8 -9
- package/lib/matchers/element/toBeExisting.js +8 -3
- package/lib/matchers/element/toBeSelected.js +6 -13
- package/lib/matchers/element/toHaveAttribute.js +46 -45
- package/lib/matchers/element/toHaveChildren.js +30 -32
- package/lib/matchers/element/toHaveComputedLabel.js +21 -20
- package/lib/matchers/element/toHaveComputedRole.js +21 -20
- package/lib/matchers/element/toHaveElementClass.js +57 -0
- package/lib/matchers/element/toHaveElementProperty.js +40 -32
- package/lib/matchers/element/toHaveHTML.js +22 -23
- package/lib/matchers/element/toHaveHeight.js +23 -28
- package/lib/matchers/element/toHaveSize.js +16 -14
- package/lib/matchers/element/toHaveStyle.js +20 -14
- package/lib/matchers/element/toHaveText.js +26 -44
- package/lib/matchers/element/toHaveWidth.js +23 -28
- package/lib/matchers/elements/toBeElementsArrayOfSize.js +25 -30
- package/lib/matchers/mock/toBeRequestedTimes.js +12 -17
- package/lib/matchers/mock/toBeRequestedWith.js +13 -23
- package/lib/matchers/modifiers/some.js +15 -0
- package/lib/matchers.js +1 -1
- package/lib/tsconfig.build.tsbuildinfo +1 -1
- package/lib/util/commandOptionsUtils.js +6 -0
- package/lib/util/elementsUtil.js +74 -4
- package/lib/util/executeCommand.js +94 -6
- package/lib/util/formatMessage.js +87 -32
- package/lib/util/numberOptionsUtil.js +92 -0
- package/lib/util/refetchElements.js +30 -5
- package/lib/util/stringUtil.js +12 -0
- package/lib/util/waitUntil.js +44 -0
- package/lib/utils.js +128 -105
- package/package.json +13 -11
- package/types/expect-global.d.ts +2 -1
- package/types/expect-webdriverio.d.ts +628 -136
- package/lib/matchers/element/toHaveClass.js +0 -61
|
@@ -1,32 +1,34 @@
|
|
|
1
1
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
2
|
-
import {
|
|
2
|
+
import { executeCommandWithStrategy } from '../../util/executeCommand.js';
|
|
3
|
+
import { compareObject, enhanceError, waitUntil, wrapExpectedWithArray, } from '../../utils.js';
|
|
3
4
|
async function condition(el, size) {
|
|
4
5
|
const actualSize = await el.getSize();
|
|
5
6
|
return compareObject(actualSize, size);
|
|
6
7
|
}
|
|
7
8
|
export async function toHaveSize(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
8
|
-
const isNot = this
|
|
9
|
-
const { expectation = 'size', verb = 'have' } = this;
|
|
9
|
+
const { expectation = 'size', verb = 'have', isNot, matcherName = 'toHaveSize' } = this;
|
|
10
10
|
await options.beforeAssertion?.({
|
|
11
|
-
matcherName
|
|
11
|
+
matcherName,
|
|
12
12
|
expectedValue,
|
|
13
13
|
options,
|
|
14
14
|
});
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
const { success: pass, actual: actualSize, subject: el, context: { isSome } = {} } = await waitUntil(async (iteration) => {
|
|
16
|
+
return await executeCommandWithStrategy({
|
|
17
|
+
unresolvedElements: received,
|
|
18
|
+
expectedValues: expectedValue,
|
|
19
|
+
singleElementCompare: (element, expectedSize) => condition(element, expectedSize),
|
|
20
|
+
context: { isNot, iteration },
|
|
21
|
+
strategy: 'NewStrictMultipleElements',
|
|
22
|
+
strictConfiguration: { allowArrayWithSingleElement: false }
|
|
23
|
+
});
|
|
24
|
+
}, isNot, { wait: options.wait, interval: options.interval });
|
|
25
|
+
const message = enhanceError(el, wrapExpectedWithArray(el, actualSize, expectedValue), actualSize, { isNot, isSome }, verb, expectation, '', options);
|
|
24
26
|
const result = {
|
|
25
27
|
pass,
|
|
26
28
|
message: () => message
|
|
27
29
|
};
|
|
28
30
|
await options.afterAssertion?.({
|
|
29
|
-
matcherName
|
|
31
|
+
matcherName,
|
|
30
32
|
expectedValue,
|
|
31
33
|
options,
|
|
32
34
|
result
|
|
@@ -1,31 +1,37 @@
|
|
|
1
1
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
2
|
-
import {
|
|
2
|
+
import { executeCommandWithStrategy } from '../../util/executeCommand.js';
|
|
3
|
+
import { compareStyle, enhanceError, waitUntil, wrapExpectedWithArray } from '../../utils.js';
|
|
3
4
|
async function condition(el, style, options) {
|
|
5
|
+
if (style === undefined) {
|
|
6
|
+
return { success: false, actual: undefined };
|
|
7
|
+
}
|
|
4
8
|
return compareStyle(el, style, options);
|
|
5
9
|
}
|
|
6
10
|
export async function toHaveStyle(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
7
|
-
const isNot = this
|
|
8
|
-
const { expectation = 'style', verb = 'have' } = this;
|
|
11
|
+
const { expectation = 'style', verb = 'have', isNot, matcherName = 'toHaveStyle' } = this;
|
|
9
12
|
await options.beforeAssertion?.({
|
|
10
|
-
matcherName
|
|
13
|
+
matcherName,
|
|
11
14
|
expectedValue,
|
|
12
15
|
options,
|
|
13
16
|
});
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
const { success: pass, actual: actualStyle, subject: el, context: { isSome } = {} } = await waitUntil(async (iteration) => {
|
|
18
|
+
return await executeCommandWithStrategy({
|
|
19
|
+
unresolvedElements: received,
|
|
20
|
+
expectedValues: expectedValue,
|
|
21
|
+
singleElementCompare: (element, expectedValues) => condition(element, expectedValues, options),
|
|
22
|
+
context: { isNot, iteration },
|
|
23
|
+
strategy: 'NewStrictMultipleElements',
|
|
24
|
+
strictConfiguration: { allowArrayWithSingleElement: false }
|
|
25
|
+
});
|
|
26
|
+
}, isNot, { wait: options.wait, interval: options.interval });
|
|
27
|
+
const expected = wrapExpectedWithArray(el, actualStyle, expectedValue);
|
|
28
|
+
const message = enhanceError(el, expected, actualStyle, { isNot, isSome }, verb, expectation, '', options);
|
|
23
29
|
const result = {
|
|
24
30
|
pass,
|
|
25
31
|
message: () => message
|
|
26
32
|
};
|
|
27
33
|
await options.afterAssertion?.({
|
|
28
|
-
matcherName
|
|
34
|
+
matcherName,
|
|
29
35
|
expectedValue,
|
|
30
36
|
options,
|
|
31
37
|
result
|
|
@@ -1,59 +1,41 @@
|
|
|
1
1
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const actualText = await element.getText();
|
|
10
|
-
actualTextArray.push(actualText);
|
|
11
|
-
const result = Array.isArray(text)
|
|
12
|
-
? compareTextWithArray(actualText, text, options).result
|
|
13
|
-
: compareText(actualText, text, options).result;
|
|
14
|
-
resultArray.push(result);
|
|
15
|
-
}
|
|
16
|
-
checkAllValuesMatchCondition = resultArray.every(Boolean);
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
const actualText = await el.getText();
|
|
20
|
-
actualTextArray.push(actualText);
|
|
21
|
-
checkAllValuesMatchCondition = Array.isArray(text)
|
|
22
|
-
? compareTextWithArray(actualText, text, options).result
|
|
23
|
-
: compareText(actualText, text, options).result;
|
|
24
|
-
}
|
|
25
|
-
return {
|
|
26
|
-
value: actualTextArray.length === 1 ? actualTextArray[0] : actualTextArray,
|
|
27
|
-
result: checkAllValuesMatchCondition
|
|
28
|
-
};
|
|
2
|
+
import { compareTextOrArray, enhanceError, getFeatureFlagValue, waitUntil, } from '../../utils.js';
|
|
3
|
+
import { executeCommandWithStrategy } from '../../util/executeCommand.js';
|
|
4
|
+
import { fillSingleExpectedForElementArray } from '../../util/elementsUtil.js';
|
|
5
|
+
import { buildWdioAsymmetricMatchersWithOptions } from '../asymmetrics/asymmetricsUtils.js';
|
|
6
|
+
async function compareElement(el, expectedText, options) {
|
|
7
|
+
const actualText = await el.getText();
|
|
8
|
+
return compareTextOrArray(actualText, expectedText, options);
|
|
29
9
|
}
|
|
30
10
|
export async function toHaveText(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
31
|
-
const isNot = this
|
|
32
|
-
const { expectation = 'text', verb = 'have' } = this;
|
|
11
|
+
const { expectation = 'text', verb = 'have', isNot, matcherName = 'toHaveText' } = this;
|
|
33
12
|
await options.beforeAssertion?.({
|
|
34
|
-
matcherName
|
|
13
|
+
matcherName,
|
|
35
14
|
expectedValue,
|
|
36
15
|
options,
|
|
37
16
|
});
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
: received
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
17
|
+
expectedValue = buildWdioAsymmetricMatchersWithOptions(expectedValue, options);
|
|
18
|
+
const isNewStrictCompare = getFeatureFlagValue(options, 'useToHaveTextStrictMultiElementsCompareStrategy');
|
|
19
|
+
const { success: pass, actual: actualText, subject: subject, context: { isSome } = {} } = await waitUntil(async (iteration) => {
|
|
20
|
+
return await executeCommandWithStrategy({
|
|
21
|
+
unresolvedElements: received,
|
|
22
|
+
expectedValues: expectedValue,
|
|
23
|
+
singleElementCompare: (element, values) => {
|
|
24
|
+
return compareElement(element, values, options);
|
|
25
|
+
},
|
|
26
|
+
context: { isNot, iteration },
|
|
27
|
+
strategy: isNewStrictCompare ? 'NewStrictMultipleElements' : 'LegacyLooseMultipleElements',
|
|
28
|
+
strictConfiguration: { allowArrayWithSingleElement: true }
|
|
29
|
+
});
|
|
30
|
+
}, isNot, { wait: options.wait, interval: options.interval });
|
|
31
|
+
const expected = fillSingleExpectedForElementArray(subject, expectedValue);
|
|
32
|
+
const message = enhanceError(subject, expected, actualText, { isNot, isSome }, verb, expectation, '', options);
|
|
51
33
|
const result = {
|
|
52
34
|
pass,
|
|
53
35
|
message: () => message
|
|
54
36
|
};
|
|
55
37
|
await options.afterAssertion?.({
|
|
56
|
-
matcherName
|
|
38
|
+
matcherName,
|
|
57
39
|
expectedValue,
|
|
58
40
|
options,
|
|
59
41
|
result
|
|
@@ -1,46 +1,41 @@
|
|
|
1
1
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { wrapExpectedWithArray } from '../../util/elementsUtil.js';
|
|
3
|
+
import { executeCommandWithStrategy } from '../../util/executeCommand.js';
|
|
4
|
+
import { validateNumberArrayAndExtractOptions } from '../../util/numberOptionsUtil.js';
|
|
5
|
+
import { enhanceError, waitUntil, } from '../../utils.js';
|
|
6
|
+
async function condition(el, expectedNumber) {
|
|
4
7
|
const actualWidth = await el.getSize('width');
|
|
5
8
|
return {
|
|
6
|
-
|
|
7
|
-
|
|
9
|
+
success: expectedNumber?.asymmetricMatch(actualWidth) ?? false,
|
|
10
|
+
actual: actualWidth
|
|
8
11
|
};
|
|
9
12
|
}
|
|
10
13
|
export async function toHaveWidth(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
11
|
-
const isNot = this
|
|
12
|
-
const { expectation = 'width', verb = 'have' } = this;
|
|
14
|
+
const { expectation = 'width', verb = 'have', isNot, matcherName = 'toHaveWidth' } = this;
|
|
13
15
|
await options.beforeAssertion?.({
|
|
14
|
-
matcherName
|
|
16
|
+
matcherName,
|
|
15
17
|
expectedValue,
|
|
16
18
|
options,
|
|
17
19
|
});
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
const result = await executeCommand.call(this, el, condition, numberOptions, [expectedValue, numberOptions]);
|
|
32
|
-
el = result.el;
|
|
33
|
-
actualWidth = result.values;
|
|
34
|
-
return result.success;
|
|
35
|
-
}, isNot, { ...numberOptions, ...options });
|
|
36
|
-
const error = numberError(numberOptions);
|
|
37
|
-
const message = enhanceError(el, error, actualWidth, this, verb, expectation, '', options);
|
|
20
|
+
const { numberMatcher: expectedNumber, commandOptions } = validateNumberArrayAndExtractOptions(expectedValue, options);
|
|
21
|
+
const { success: pass, actual: actualWidth, subject: elements, context: { isSome } = {} } = await waitUntil(async (iteration) => {
|
|
22
|
+
return await executeCommandWithStrategy({
|
|
23
|
+
unresolvedElements: received,
|
|
24
|
+
expectedValues: expectedNumber,
|
|
25
|
+
singleElementCompare: (element, expectedNumber) => condition(element, expectedNumber),
|
|
26
|
+
context: { isNot, iteration },
|
|
27
|
+
strategy: 'NewStrictMultipleElements',
|
|
28
|
+
strictConfiguration: { allowArrayWithSingleElement: false }
|
|
29
|
+
});
|
|
30
|
+
}, isNot, { wait: commandOptions.wait, interval: commandOptions.interval });
|
|
31
|
+
const expectedValues = wrapExpectedWithArray(elements, actualWidth, expectedNumber);
|
|
32
|
+
const message = enhanceError(elements, expectedValues, actualWidth, { isNot, isSome }, verb, expectation, '', commandOptions);
|
|
38
33
|
const result = {
|
|
39
34
|
pass,
|
|
40
35
|
message: () => message
|
|
41
36
|
};
|
|
42
37
|
await options.afterAssertion?.({
|
|
43
|
-
matcherName
|
|
38
|
+
matcherName,
|
|
44
39
|
expectedValue,
|
|
45
40
|
options,
|
|
46
41
|
result
|
|
@@ -1,47 +1,42 @@
|
|
|
1
|
-
import { waitUntil, enhanceError,
|
|
2
|
-
import { refetchElements } from '../../util/refetchElements.js';
|
|
1
|
+
import { waitUntil, enhanceError, } from '../../utils.js';
|
|
2
|
+
import { refetchElements, syncronizeElements } from '../../util/refetchElements.js';
|
|
3
3
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
4
|
+
import { validateNumberAndExtractOptions } from '../../util/numberOptionsUtil.js';
|
|
5
|
+
import { awaitElementArray, isStrictlyElementArray } from '../../util/elementsUtil.js';
|
|
4
6
|
export async function toBeElementsArrayOfSize(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
5
|
-
const isNot = this
|
|
6
|
-
const { expectation = 'elements array of size', verb = 'be' } = this;
|
|
7
|
+
const { expectation = 'elements array of size', verb = 'be', isNot, matcherName = 'toBeElementsArrayOfSize' } = this;
|
|
7
8
|
await options.beforeAssertion?.({
|
|
8
|
-
matcherName
|
|
9
|
+
matcherName,
|
|
9
10
|
expectedValue,
|
|
10
11
|
options,
|
|
11
12
|
});
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
let elements = await received;
|
|
23
|
-
const originalLength = elements.length;
|
|
24
|
-
const pass = await waitUntil(async () => {
|
|
25
|
-
const isPassing = compareNumbers(elements.length, numberOptions);
|
|
26
|
-
if (isPassing) {
|
|
27
|
-
return isPassing;
|
|
13
|
+
const { numberMatcher: expectedNumber, commandOptions } = validateNumberAndExtractOptions(expectedValue, options);
|
|
14
|
+
let { elements, other } = await awaitElementArray(received);
|
|
15
|
+
const originalLength = elements ? elements.length : undefined;
|
|
16
|
+
const { success: pass } = await waitUntil(async (iteration) => {
|
|
17
|
+
if (!elements) {
|
|
18
|
+
return { success: false, subject: elements, actual: undefined, abort: true };
|
|
19
|
+
}
|
|
20
|
+
else if (iteration > 0) {
|
|
21
|
+
elements = await refetchElements(elements);
|
|
28
22
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (Array.isArray(received) && pass) {
|
|
33
|
-
for (let index = originalLength; index < elements.length; index++) {
|
|
34
|
-
received.push(elements[index]);
|
|
23
|
+
const isPassing = expectedNumber.asymmetricMatch(elements.length);
|
|
24
|
+
if (isPassing) {
|
|
25
|
+
return { success: isPassing, subject: elements, actual: elements.length };
|
|
35
26
|
}
|
|
27
|
+
return { success: false, subject: elements, actual: elements.length };
|
|
28
|
+
}, isNot, { wait: commandOptions.wait, interval: commandOptions.interval });
|
|
29
|
+
if (pass && originalLength !== undefined && elements !== received && (isStrictlyElementArray(received) || received instanceof Promise) && isStrictlyElementArray(elements)) {
|
|
30
|
+
await syncronizeElements(received, elements);
|
|
36
31
|
}
|
|
37
|
-
const
|
|
38
|
-
const message = enhanceError(elements,
|
|
32
|
+
const actual = originalLength;
|
|
33
|
+
const message = enhanceError(elements ?? other, expectedNumber, actual, this, verb, expectation, '', commandOptions);
|
|
39
34
|
const result = {
|
|
40
35
|
pass,
|
|
41
36
|
message: () => message
|
|
42
37
|
};
|
|
43
38
|
await options.afterAssertion?.({
|
|
44
|
-
matcherName
|
|
39
|
+
matcherName,
|
|
45
40
|
expectedValue,
|
|
46
41
|
options,
|
|
47
42
|
result
|
|
@@ -1,30 +1,25 @@
|
|
|
1
|
-
import { waitUntil, enhanceError
|
|
2
|
-
import { numberError } from '../../util/formatMessage.js';
|
|
1
|
+
import { waitUntil, enhanceError } from '../../utils.js';
|
|
3
2
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const { expectation = `called${typeof expectedValue === 'number' ? ' ' + expectedValue : ''} time${expectedValue !== 1 ? 's' : ''}`,
|
|
3
|
+
import { validateNumberAndExtractOptions } from '../../util/numberOptionsUtil.js';
|
|
4
|
+
export async function toBeRequestedTimes(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
5
|
+
const { verb = 'be', isNot, matcherName = 'toBeRequestedTimes', expectation = `called${typeof expectedValue === 'number' ? ' ' + expectedValue : ''} time${expectedValue !== 1 ? 's' : ''}`, } = this;
|
|
7
6
|
await options.beforeAssertion?.({
|
|
8
|
-
matcherName
|
|
7
|
+
matcherName,
|
|
9
8
|
expectedValue,
|
|
10
9
|
options,
|
|
11
10
|
});
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return compareNumbers(actual, numberOptions);
|
|
19
|
-
}, isNot, { ...numberOptions, ...options });
|
|
20
|
-
const error = numberError(numberOptions);
|
|
21
|
-
const message = enhanceError('mock', error, actual, this, verb, expectation, '', numberOptions);
|
|
11
|
+
const { numberMatcher: expectedNumber, commandOptions } = validateNumberAndExtractOptions(expectedValue, options);
|
|
12
|
+
const { success: pass, actual } = await waitUntil(async () => {
|
|
13
|
+
const actual = received.calls.length;
|
|
14
|
+
return { success: expectedNumber.asymmetricMatch(actual), subject: received, actual };
|
|
15
|
+
}, isNot, { wait: commandOptions.wait, interval: commandOptions.interval });
|
|
16
|
+
const message = enhanceError('mock', expectedNumber, actual, this, verb, expectation, '', commandOptions);
|
|
22
17
|
const result = {
|
|
23
18
|
pass,
|
|
24
19
|
message: () => message
|
|
25
20
|
};
|
|
26
21
|
await options.afterAssertion?.({
|
|
27
|
-
matcherName
|
|
22
|
+
matcherName,
|
|
28
23
|
expectedValue,
|
|
29
24
|
options,
|
|
30
25
|
result
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { waitUntil, enhanceError } from '../../utils.js';
|
|
1
|
+
import { waitUntil, enhanceError, isAsymmetricMatcher, getAsymmetricMatcherValue } from '../../utils.js';
|
|
2
2
|
import { equals } from '../../jasmineUtils.js';
|
|
3
3
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
4
4
|
const STR_LIMIT = 80;
|
|
@@ -10,26 +10,25 @@ function reduceHeaders(headers) {
|
|
|
10
10
|
}, {});
|
|
11
11
|
}
|
|
12
12
|
export async function toBeRequestedWith(received, expectedValue = {}, options = DEFAULT_OPTIONS) {
|
|
13
|
-
const
|
|
14
|
-
const { expectation = 'called with', verb = 'be' } = this;
|
|
13
|
+
const { expectation = 'called with', verb = 'be', isNot, matcherName = 'toBeRequestedWith' } = this;
|
|
15
14
|
await options.beforeAssertion?.({
|
|
16
|
-
matcherName
|
|
15
|
+
matcherName,
|
|
17
16
|
expectedValue,
|
|
18
17
|
options,
|
|
19
18
|
});
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
const { success: pass, actual } = await waitUntil(async () => {
|
|
20
|
+
let lastCall;
|
|
22
21
|
for (const call of received.calls) {
|
|
23
|
-
|
|
22
|
+
lastCall = call;
|
|
24
23
|
if (methodMatcher(call.request.method, expectedValue.method) &&
|
|
25
24
|
statusCodeMatcher(call.response.status, expectedValue.statusCode) &&
|
|
26
25
|
urlMatcher(call.request.url, expectedValue.url) &&
|
|
27
26
|
headersMatcher(reduceHeaders(call.request.headers), expectedValue.requestHeaders) &&
|
|
28
27
|
headersMatcher(reduceHeaders(call.response.headers), expectedValue.responseHeaders)) {
|
|
29
|
-
return true;
|
|
28
|
+
return { success: true, subject: call, actual: call };
|
|
30
29
|
}
|
|
31
30
|
}
|
|
32
|
-
return false;
|
|
31
|
+
return { success: false, subject: lastCall, actual: lastCall };
|
|
33
32
|
}, isNot, { ...options, wait: isNot ? 0 : options.wait });
|
|
34
33
|
const message = enhanceError('mock', minifyRequestedWith(expectedValue), minifyRequestMock(actual, expectedValue) || 'was not called', this, verb, expectation, '', options);
|
|
35
34
|
const result = {
|
|
@@ -37,7 +36,7 @@ export async function toBeRequestedWith(received, expectedValue = {}, options =
|
|
|
37
36
|
message: () => message
|
|
38
37
|
};
|
|
39
38
|
await options.afterAssertion?.({
|
|
40
|
-
matcherName
|
|
39
|
+
matcherName,
|
|
41
40
|
expectedValue,
|
|
42
41
|
options,
|
|
43
42
|
result
|
|
@@ -88,15 +87,6 @@ const headersMatcher = (headers, expected) => {
|
|
|
88
87
|
}
|
|
89
88
|
return equals(headers, expected);
|
|
90
89
|
};
|
|
91
|
-
const isMatcher = (filter) => {
|
|
92
|
-
const proto = Object.getPrototypeOf(filter);
|
|
93
|
-
return (typeof filter === 'object' &&
|
|
94
|
-
filter !== null &&
|
|
95
|
-
typeof proto === 'object' &&
|
|
96
|
-
proto &&
|
|
97
|
-
'asymmetricMatch' in proto &&
|
|
98
|
-
typeof proto.asymmetricMatch === 'function');
|
|
99
|
-
};
|
|
100
90
|
const minifyRequestMock = (requestMock, requestedWith) => {
|
|
101
91
|
if (requestMock === undefined) {
|
|
102
92
|
return requestMock;
|
|
@@ -129,10 +119,10 @@ const requestedWithParamToString = (param, transformFn) => {
|
|
|
129
119
|
if (typeof param === 'function') {
|
|
130
120
|
param = param.toString();
|
|
131
121
|
}
|
|
132
|
-
else if (
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
122
|
+
else if (isAsymmetricMatcher(param)) {
|
|
123
|
+
const sample = getAsymmetricMatcherValue(param);
|
|
124
|
+
const sampleString = typeof sample === 'string' ? sample : sample instanceof RegExp ? sample.toString() : JSON.stringify(sample) || sample?.toString();
|
|
125
|
+
return `${param.constructor.name} ${sampleString || ''}`;
|
|
136
126
|
}
|
|
137
127
|
else if (transformFn && typeof param === 'object' && param !== null) {
|
|
138
128
|
param = transformFn(param);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const SOME_TAG = 'expect-webdriverio.some';
|
|
2
|
+
const SOME_SYMBOL = Symbol.for(SOME_TAG);
|
|
3
|
+
export class SomeElementsWrapper {
|
|
4
|
+
elements;
|
|
5
|
+
[SOME_SYMBOL] = true;
|
|
6
|
+
constructor(elements) {
|
|
7
|
+
this.elements = elements;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export function some(elements) {
|
|
11
|
+
return new SomeElementsWrapper(elements);
|
|
12
|
+
}
|
|
13
|
+
export function isSomeWrapper(value) {
|
|
14
|
+
return value instanceof SomeElementsWrapper;
|
|
15
|
+
}
|
package/lib/matchers.js
CHANGED
|
@@ -12,9 +12,9 @@ export * from './matchers/element/toBeFocused.js';
|
|
|
12
12
|
export * from './matchers/element/toBeSelected.js';
|
|
13
13
|
export * from './matchers/element/toHaveAttribute.js';
|
|
14
14
|
export * from './matchers/element/toHaveChildren.js';
|
|
15
|
-
export * from './matchers/element/toHaveClass.js';
|
|
16
15
|
export * from './matchers/element/toHaveComputedLabel.js';
|
|
17
16
|
export * from './matchers/element/toHaveComputedRole.js';
|
|
17
|
+
export * from './matchers/element/toHaveElementClass.js';
|
|
18
18
|
export * from './matchers/element/toHaveElementProperty.js';
|
|
19
19
|
export * from './matchers/element/toHaveHeight.js';
|
|
20
20
|
export * from './matchers/element/toHaveHref.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/constants.ts","../src/index.ts","../src/jasmineUtils.ts","../src/matchers.ts","../src/snapshot.ts","../src/softAssert.ts","../src/softAssertService.ts","../src/softExpect.ts","../src/types.ts","../src/utils.ts","../src/matchers/snapshot.ts","../src/matchers/browser/toHaveClipboardText.ts","../src/matchers/browser/toHaveLocalStorageItem.ts","../src/matchers/browser/toHaveTitle.ts","../src/matchers/browser/toHaveUrl.ts","../src/matchers/element/toBeClickable.ts","../src/matchers/element/toBeDisabled.ts","../src/matchers/element/toBeDisplayed.ts","../src/matchers/element/toBeDisplayedInViewport.ts","../src/matchers/element/toBeEnabled.ts","../src/matchers/element/toBeExisting.ts","../src/matchers/element/toBeFocused.ts","../src/matchers/element/toBeSelected.ts","../src/matchers/element/toHaveAttribute.ts","../src/matchers/element/toHaveChildren.ts","../src/matchers/element/
|
|
1
|
+
{"root":["../src/constants.ts","../src/index.ts","../src/jasmineUtils.ts","../src/matchers.ts","../src/snapshot.ts","../src/softAssert.ts","../src/softAssertService.ts","../src/softExpect.ts","../src/types.ts","../src/utils.ts","../src/matchers/snapshot.ts","../src/matchers/asymmetrics/asymmetricsUtils.ts","../src/matchers/asymmetrics/oneOf.ts","../src/matchers/browser/toHaveClipboardText.ts","../src/matchers/browser/toHaveLocalStorageItem.ts","../src/matchers/browser/toHaveTitle.ts","../src/matchers/browser/toHaveUrl.ts","../src/matchers/element/toBeClickable.ts","../src/matchers/element/toBeDisabled.ts","../src/matchers/element/toBeDisplayed.ts","../src/matchers/element/toBeDisplayedInViewport.ts","../src/matchers/element/toBeEnabled.ts","../src/matchers/element/toBeExisting.ts","../src/matchers/element/toBeFocused.ts","../src/matchers/element/toBeSelected.ts","../src/matchers/element/toHaveAttribute.ts","../src/matchers/element/toHaveChildren.ts","../src/matchers/element/toHaveComputedLabel.ts","../src/matchers/element/toHaveComputedRole.ts","../src/matchers/element/toHaveElementClass.ts","../src/matchers/element/toHaveElementProperty.ts","../src/matchers/element/toHaveHTML.ts","../src/matchers/element/toHaveHeight.ts","../src/matchers/element/toHaveHref.ts","../src/matchers/element/toHaveId.ts","../src/matchers/element/toHaveSize.ts","../src/matchers/element/toHaveStyle.ts","../src/matchers/element/toHaveText.ts","../src/matchers/element/toHaveValue.ts","../src/matchers/element/toHaveWidth.ts","../src/matchers/elements/toBeElementsArrayOfSize.ts","../src/matchers/mock/toBeRequested.ts","../src/matchers/mock/toBeRequestedTimes.ts","../src/matchers/mock/toBeRequestedWith.ts","../src/matchers/modifiers/some.ts","../src/util/commandOptionsUtils.ts","../src/util/elementsUtil.ts","../src/util/executeCommand.ts","../src/util/formatMessage.ts","../src/util/numberOptionsUtil.ts","../src/util/refetchElements.ts","../src/util/stringUtil.ts","../src/util/waitUntil.ts"],"version":"5.9.3"}
|
package/lib/util/elementsUtil.js
CHANGED
|
@@ -1,9 +1,79 @@
|
|
|
1
|
-
export const wrapExpectedWithArray = (
|
|
2
|
-
if (Array.isArray(
|
|
3
|
-
expected =
|
|
1
|
+
export const wrapExpectedWithArray = (elements, actual, expected) => {
|
|
2
|
+
if (Array.isArray(elements) && Array.isArray(actual) && !Array.isArray(expected)) {
|
|
3
|
+
expected = Array(actual.length).fill(expected);
|
|
4
4
|
}
|
|
5
5
|
return expected;
|
|
6
6
|
};
|
|
7
|
+
export const fillSingleExpectedForElementArray = (subject, value) => {
|
|
8
|
+
if (isElementArrayLike(subject) && !Array.isArray(value)) {
|
|
9
|
+
const fillerlength = subject.length > 0 ? subject.length : 1;
|
|
10
|
+
return Array(fillerlength).fill(value);
|
|
11
|
+
}
|
|
12
|
+
return value;
|
|
13
|
+
};
|
|
14
|
+
export const isArray = (obj) => {
|
|
15
|
+
return Array.isArray(obj);
|
|
16
|
+
};
|
|
17
|
+
export const isSelector = (obj) => {
|
|
18
|
+
return !!obj
|
|
19
|
+
&& typeof obj === 'object'
|
|
20
|
+
&& 'selector' in obj
|
|
21
|
+
&& 'parent' in obj;
|
|
22
|
+
};
|
|
7
23
|
export const isElementArray = (obj) => {
|
|
8
|
-
return obj
|
|
24
|
+
return isSelector(obj)
|
|
25
|
+
&& 'foundWith' in obj;
|
|
26
|
+
};
|
|
27
|
+
export const isStrictlyElementArray = (obj) => {
|
|
28
|
+
return isElementArray(obj)
|
|
29
|
+
&& Array.isArray(obj)
|
|
30
|
+
&& 'getElements' in obj;
|
|
31
|
+
};
|
|
32
|
+
export const isElement = (obj) => {
|
|
33
|
+
return isSelector(obj)
|
|
34
|
+
&& !Array.isArray(obj)
|
|
35
|
+
&& 'getElement' in obj;
|
|
36
|
+
};
|
|
37
|
+
export const isElementArrayLike = (obj) => {
|
|
38
|
+
return !!obj && (isStrictlyElementArray(obj) || (Array.isArray(obj) && obj.every(isElement)));
|
|
39
|
+
};
|
|
40
|
+
export const isArrayOfElement = (obj) => {
|
|
41
|
+
return Array.isArray(obj) && obj.every(isElement);
|
|
42
|
+
};
|
|
43
|
+
export const isElementOrArrayLike = (obj) => {
|
|
44
|
+
return !!obj && (isElement(obj) || isElementArrayLike(obj));
|
|
45
|
+
};
|
|
46
|
+
export const awaitElementOrArray = async (received) => {
|
|
47
|
+
if (!received || typeof received !== 'object') {
|
|
48
|
+
return { other: received };
|
|
49
|
+
}
|
|
50
|
+
let awaitedElements = received;
|
|
51
|
+
if (awaitedElements instanceof Promise) {
|
|
52
|
+
awaitedElements = await awaitedElements;
|
|
53
|
+
}
|
|
54
|
+
if (!isElementOrArrayLike(awaitedElements)) {
|
|
55
|
+
return { other: awaitedElements };
|
|
56
|
+
}
|
|
57
|
+
if ('getElement' in awaitedElements) {
|
|
58
|
+
const element = await awaitedElements.getElement();
|
|
59
|
+
return { selector: element, element };
|
|
60
|
+
}
|
|
61
|
+
if ('getElements' in awaitedElements) {
|
|
62
|
+
const elements = await awaitedElements.getElements();
|
|
63
|
+
return { selector: elements, elements, isEmptyElements: elements.length === 0 };
|
|
64
|
+
}
|
|
65
|
+
return { selector: awaitedElements, elements: awaitedElements, isEmptyElements: awaitedElements.length === 0 };
|
|
66
|
+
};
|
|
67
|
+
export const awaitElementArray = async (received) => {
|
|
68
|
+
let awaitedElements = received;
|
|
69
|
+
if (awaitedElements instanceof Promise) {
|
|
70
|
+
awaitedElements = await awaitedElements;
|
|
71
|
+
}
|
|
72
|
+
if (!isElementArrayLike(awaitedElements)) {
|
|
73
|
+
return { other: awaitedElements };
|
|
74
|
+
}
|
|
75
|
+
if ('getElements' in awaitedElements) {
|
|
76
|
+
return { elements: await awaitedElements.getElements() };
|
|
77
|
+
}
|
|
78
|
+
return { elements: awaitedElements };
|
|
9
79
|
};
|