expect-webdriverio 5.7.0 → 6.0.1

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.
Files changed (41) hide show
  1. package/README.md +16 -14
  2. package/lib/constants.js +4 -0
  3. package/lib/index.js +30 -18
  4. package/lib/matchers/asymmetrics/asymmetricsUtils.js +24 -0
  5. package/lib/matchers/asymmetrics/oneOf.js +51 -0
  6. package/lib/matchers/browser/toHaveClipboardText.js +8 -9
  7. package/lib/matchers/browser/toHaveLocalStorageItem.js +22 -14
  8. package/lib/matchers/browser/toHaveTitle.js +9 -10
  9. package/lib/matchers/browser/toHaveUrl.js +8 -9
  10. package/lib/matchers/element/toBeExisting.js +8 -3
  11. package/lib/matchers/element/toBeSelected.js +6 -13
  12. package/lib/matchers/element/toHaveAttribute.js +46 -45
  13. package/lib/matchers/element/toHaveChildren.js +30 -32
  14. package/lib/matchers/element/toHaveComputedLabel.js +21 -20
  15. package/lib/matchers/element/toHaveComputedRole.js +21 -20
  16. package/lib/matchers/element/toHaveElementClass.js +57 -0
  17. package/lib/matchers/element/toHaveElementProperty.js +40 -32
  18. package/lib/matchers/element/toHaveHTML.js +22 -23
  19. package/lib/matchers/element/toHaveHeight.js +23 -28
  20. package/lib/matchers/element/toHaveSize.js +16 -14
  21. package/lib/matchers/element/toHaveStyle.js +20 -14
  22. package/lib/matchers/element/toHaveText.js +26 -44
  23. package/lib/matchers/element/toHaveWidth.js +23 -28
  24. package/lib/matchers/elements/toBeElementsArrayOfSize.js +25 -30
  25. package/lib/matchers/mock/toBeRequestedTimes.js +12 -17
  26. package/lib/matchers/mock/toBeRequestedWith.js +8 -9
  27. package/lib/matchers/modifiers/some.js +15 -0
  28. package/lib/matchers.js +1 -1
  29. package/lib/tsconfig.build.tsbuildinfo +1 -1
  30. package/lib/util/commandOptionsUtils.js +6 -0
  31. package/lib/util/elementsUtil.js +74 -4
  32. package/lib/util/executeCommand.js +94 -6
  33. package/lib/util/formatMessage.js +87 -32
  34. package/lib/util/numberOptionsUtil.js +92 -0
  35. package/lib/util/refetchElements.js +30 -5
  36. package/lib/util/stringUtil.js +12 -0
  37. package/lib/util/waitUntil.js +44 -0
  38. package/lib/utils.js +84 -91
  39. package/package.json +11 -10
  40. package/types/expect-webdriverio.d.ts +587 -134
  41. package/lib/matchers/element/toHaveClass.js +0 -61
@@ -1,35 +1,36 @@
1
1
  import { DEFAULT_OPTIONS } from '../../constants.js';
2
- import { compareText, compareTextWithArray, enhanceError, executeCommand, waitUntil, wrapExpectedWithArray } from '../../utils.js';
3
- async function condition(el, label, options) {
4
- const actualLabel = await el.getComputedLabel();
5
- if (Array.isArray(label)) {
6
- return compareTextWithArray(actualLabel, label, options);
7
- }
8
- return compareText(actualLabel, label, options);
2
+ import { executeCommandWithStrategy } from '../../util/executeCommand.js';
3
+ import { compareTextOrArray, enhanceError, waitUntil, wrapExpectedWithArray } from '../../utils.js';
4
+ import { buildWdioAsymmetricMatchersWithOptions } from '../asymmetrics/asymmetricsUtils.js';
5
+ async function singleElementCompare(element, label, options) {
6
+ const actualLabel = await element.getComputedLabel();
7
+ return compareTextOrArray(actualLabel, label, options);
9
8
  }
10
9
  export async function toHaveComputedLabel(received, expectedValue, options = DEFAULT_OPTIONS) {
11
- const isNot = this.isNot;
12
- const { expectation = 'computed label', verb = 'have' } = this;
10
+ const { expectation = 'computed label', verb = 'have', isNot, matcherName = 'toHaveComputedLabel' } = this;
13
11
  await options.beforeAssertion?.({
14
- matcherName: 'toHaveComputedLabel',
12
+ matcherName,
15
13
  expectedValue,
16
14
  options,
17
15
  });
18
- let el = await received?.getElement();
19
- let actualLabel;
20
- const pass = await waitUntil(async () => {
21
- const result = await executeCommand.call(this, el, condition, options, [expectedValue, options]);
22
- el = result.el;
23
- actualLabel = result.values;
24
- return result.success;
25
- }, isNot, options);
26
- const message = enhanceError(el, wrapExpectedWithArray(el, actualLabel, expectedValue), actualLabel, this, verb, expectation, '', options);
16
+ expectedValue = buildWdioAsymmetricMatchersWithOptions(expectedValue, options);
17
+ const { success: pass, actual: actualLabel, subject: el, context: { isSome } = {} } = await waitUntil(async (iteration) => {
18
+ return await executeCommandWithStrategy({
19
+ unresolvedElements: received,
20
+ expectedValues: expectedValue,
21
+ singleElementCompare: (element, expectedValue) => singleElementCompare(element, expectedValue, options),
22
+ context: { isNot, iteration },
23
+ strategy: 'NewStrictMultipleElements',
24
+ strictConfiguration: { allowArrayWithSingleElement: true }
25
+ });
26
+ }, isNot, { wait: options.wait, interval: options.interval });
27
+ const message = enhanceError(el, wrapExpectedWithArray(el, actualLabel, expectedValue), actualLabel, { isNot, isSome }, verb, expectation, '', options);
27
28
  const result = {
28
29
  pass,
29
30
  message: () => message
30
31
  };
31
32
  await options.afterAssertion?.({
32
- matcherName: 'toHaveComputedLabel',
33
+ matcherName,
33
34
  expectedValue,
34
35
  options,
35
36
  result
@@ -1,35 +1,36 @@
1
1
  import { DEFAULT_OPTIONS } from '../../constants.js';
2
- import { compareText, compareTextWithArray, enhanceError, executeCommand, waitUntil, wrapExpectedWithArray } from '../../utils.js';
3
- async function condition(el, role, options) {
4
- const actualRole = await el.getComputedRole();
5
- if (Array.isArray(role)) {
6
- return compareTextWithArray(actualRole, role, options);
7
- }
8
- return compareText(actualRole, role, options);
2
+ import { executeCommandWithStrategy } from '../../util/executeCommand.js';
3
+ import { compareTextOrArray, enhanceError, waitUntil, wrapExpectedWithArray } from '../../utils.js';
4
+ import { buildWdioAsymmetricMatchersWithOptions } from '../asymmetrics/asymmetricsUtils.js';
5
+ async function singleElementCompare(element, role, options) {
6
+ const actualRole = await element.getComputedRole();
7
+ return compareTextOrArray(actualRole, role, options);
9
8
  }
10
9
  export async function toHaveComputedRole(received, expectedValue, options = DEFAULT_OPTIONS) {
11
- const isNot = this.isNot;
12
- const { expectation = 'computed role', verb = 'have' } = this;
10
+ const { expectation = 'computed role', verb = 'have', isNot, matcherName = 'toHaveComputedRole' } = this;
13
11
  await options.beforeAssertion?.({
14
- matcherName: 'toHaveComputedRole',
12
+ matcherName,
15
13
  expectedValue,
16
14
  options,
17
15
  });
18
- let el = await received?.getElement();
19
- let actualRole;
20
- const pass = await waitUntil(async () => {
21
- const result = await executeCommand.call(this, el, condition, options, [expectedValue, options]);
22
- el = result.el;
23
- actualRole = result.values;
24
- return result.success;
25
- }, isNot, options);
26
- const message = enhanceError(el, wrapExpectedWithArray(el, actualRole, expectedValue), actualRole, this, verb, expectation, '', options);
16
+ expectedValue = buildWdioAsymmetricMatchersWithOptions(expectedValue, options);
17
+ const { success: pass, actual: actualRole, subject: el, context: { isSome } = {} } = await waitUntil(async (iteration) => {
18
+ return await executeCommandWithStrategy({
19
+ unresolvedElements: received,
20
+ expectedValues: expectedValue,
21
+ singleElementCompare: (element, expectedValue) => singleElementCompare(element, expectedValue, options),
22
+ context: { isNot, iteration },
23
+ strategy: 'NewStrictMultipleElements',
24
+ strictConfiguration: { allowArrayWithSingleElement: true }
25
+ });
26
+ }, isNot, { wait: options.wait, interval: options.interval });
27
+ const message = enhanceError(el, wrapExpectedWithArray(el, actualRole, expectedValue), actualRole, { isNot, isSome }, verb, expectation, '', options);
27
28
  const result = {
28
29
  pass,
29
30
  message: () => message
30
31
  };
31
32
  await options.afterAssertion?.({
32
- matcherName: 'toHaveComputedRole',
33
+ matcherName,
33
34
  expectedValue,
34
35
  options,
35
36
  result
@@ -0,0 +1,57 @@
1
+ import { DEFAULT_OPTIONS } from '../../constants.js';
2
+ import { executeCommandWithStrategy } from '../../util/executeCommand.js';
3
+ import { compareText, compareTextOrArray, enhanceError, isAsymmetricMatcher, waitUntil, wrapExpectedWithArray } from '../../utils.js';
4
+ async function singleElementCompare(el, attribute, value, options) {
5
+ const actualClass = await el.getAttribute(attribute);
6
+ if (value === undefined) {
7
+ return { success: false, actual: actualClass };
8
+ }
9
+ if (typeof actualClass !== 'string') {
10
+ return { success: false, actual: actualClass };
11
+ }
12
+ if (isAsymmetricMatcher(value)) {
13
+ return compareText(actualClass, value, options);
14
+ }
15
+ const classes = actualClass.split(' ');
16
+ const isValueInClasses = classes.some((clazz) => {
17
+ return compareTextOrArray(clazz, value, options).success;
18
+ });
19
+ return {
20
+ success: isValueInClasses,
21
+ actual: actualClass
22
+ };
23
+ }
24
+ export function toHaveClass(...args) {
25
+ return toHaveElementClass.call(this || {}, ...args);
26
+ }
27
+ export async function toHaveElementClass(received, expectedValue, options = DEFAULT_OPTIONS) {
28
+ const { expectation = 'class', verb = 'have', isNot, matcherName = 'toHaveElementClass' } = this;
29
+ await options.beforeAssertion?.({
30
+ matcherName,
31
+ expectedValue,
32
+ options,
33
+ });
34
+ const attribute = 'class';
35
+ const { success: pass, actual: attr, subject: el, context: { isSome } = {} } = await waitUntil(async (iteration) => {
36
+ return await executeCommandWithStrategy({
37
+ unresolvedElements: received,
38
+ expectedValues: expectedValue,
39
+ singleElementCompare: (element, expectedValue) => singleElementCompare(element, attribute, expectedValue, options),
40
+ context: { isNot, iteration },
41
+ strategy: 'NewStrictMultipleElements',
42
+ strictConfiguration: { allowArrayWithSingleElement: true }
43
+ });
44
+ }, isNot, { wait: options.wait, interval: options.interval });
45
+ const message = enhanceError(el, wrapExpectedWithArray(el, attr, expectedValue), attr, { isNot, isSome }, verb, expectation, '', options);
46
+ const result = {
47
+ pass,
48
+ message: () => message
49
+ };
50
+ await options.afterAssertion?.({
51
+ matcherName,
52
+ expectedValue,
53
+ options,
54
+ result
55
+ });
56
+ return result;
57
+ }
@@ -1,50 +1,58 @@
1
1
  import { DEFAULT_OPTIONS } from '../../constants.js';
2
- import { compareText, enhanceError, executeCommand, waitUntil, wrapExpectedWithArray } from '../../utils.js';
3
- async function condition(el, property, value, options = DEFAULT_OPTIONS) {
2
+ import { executeCommandWithStrategy } from '../../util/executeCommand.js';
3
+ import { expect as wdioExpect } from '../../index.js';
4
+ import { compareText, enhanceError, isAsymmetricMatcher, waitUntil, wrapExpectedWithArray } from '../../utils.js';
5
+ import { buildWdioAsymmetricMatchersWithOptions } from '../asymmetrics/asymmetricsUtils.js';
6
+ import { OneOfMatcher } from '../asymmetrics/oneOf.js';
7
+ async function condition(el, property, expectedValue, options = DEFAULT_OPTIONS) {
4
8
  const { asString = false } = options;
5
- let prop = await el.getProperty(property);
6
- if (prop === null || prop === undefined) {
7
- return { result: false, value: prop };
9
+ const propertyValue = await el.getProperty(property);
10
+ if (propertyValue === null || propertyValue === undefined || (!(expectedValue instanceof RegExp) && typeof propertyValue !== 'string' && !asString)) {
11
+ if (isAsymmetricMatcher(expectedValue)) {
12
+ return { success: expectedValue.asymmetricMatch(propertyValue), actual: propertyValue };
13
+ }
14
+ return { success: propertyValue === expectedValue, actual: propertyValue };
8
15
  }
9
- if (value === null) {
10
- return { result: true, value: prop };
16
+ else if (expectedValue instanceof OneOfMatcher) {
17
+ return { success: expectedValue.asymmetricMatch(propertyValue), actual: propertyValue };
11
18
  }
12
- if (!(value instanceof RegExp) && typeof prop !== 'string' && !asString) {
13
- return { result: prop === value, value: prop };
14
- }
15
- prop = prop.toString();
16
- return compareText(prop, value, options);
19
+ return compareText(propertyValue.toString(), expectedValue, options);
17
20
  }
18
21
  export async function toHaveElementProperty(received, property, value, options = DEFAULT_OPTIONS) {
19
- const isNot = this.isNot;
20
- const { expectation = 'property', verb = 'have' } = this;
22
+ const { expectation = 'property', verb = 'have', isNot, matcherName = 'toHaveElementProperty' } = this;
23
+ const paramsCount = arguments.length;
24
+ if (value === undefined || value === null) {
25
+ if (paramsCount > 2) {
26
+ 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).');
27
+ }
28
+ value = wdioExpect.anything();
29
+ }
21
30
  await options.beforeAssertion?.({
22
- matcherName: 'toHaveElementProperty',
31
+ matcherName,
23
32
  expectedValue: [property, value],
24
33
  options,
25
34
  });
26
- let el = await received?.getElement();
27
- let prop;
28
- const pass = await waitUntil(async () => {
29
- const result = await executeCommand.call(this, el, condition, options, [property, value]);
30
- el = result.el;
31
- prop = result.values;
32
- return result.success;
33
- }, isNot, options);
34
- let message;
35
- if (value === undefined) {
36
- message = enhanceError(el, !isNot, pass, this, verb, expectation, property, options);
37
- }
38
- else {
39
- const expected = wrapExpectedWithArray(el, prop, value);
40
- message = enhanceError(el, expected, prop, this, verb, expectation, property, options);
41
- }
35
+ value = buildWdioAsymmetricMatchersWithOptions(value, options);
36
+ const { success: pass, actual: actualProppertyValue, subject: elements, context: { isSome } = {} } = await waitUntil(async (iteration) => {
37
+ return await executeCommandWithStrategy({
38
+ unresolvedElements: received,
39
+ expectedValues: value,
40
+ singleElementCompare: (element, expectedValue) => {
41
+ return condition(element, property, expectedValue, options);
42
+ },
43
+ context: { isNot, iteration },
44
+ strategy: 'NewStrictMultipleElements',
45
+ strictConfiguration: { allowArrayWithSingleElement: false }
46
+ });
47
+ }, isNot, { wait: options.wait, interval: options.interval });
48
+ const expected = wrapExpectedWithArray(elements, actualProppertyValue, value);
49
+ const message = enhanceError(elements, expected, actualProppertyValue, { isNot, isSome }, verb, expectation, property, options);
42
50
  const result = {
43
51
  pass,
44
52
  message: () => message
45
53
  };
46
54
  await options.afterAssertion?.({
47
- matcherName: 'toHaveElementProperty',
55
+ matcherName,
48
56
  expectedValue: [property, value],
49
57
  options,
50
58
  result
@@ -1,39 +1,38 @@
1
1
  import { DEFAULT_OPTIONS } from '../../constants.js';
2
- import { compareText, compareTextWithArray, enhanceError, executeCommand, waitUntil, wrapExpectedWithArray } from '../../utils.js';
3
- async function condition(el, html, options) {
2
+ import { compareTextOrArray, enhanceError, waitUntil, wrapExpectedWithArray } from '../../utils.js';
3
+ import { executeCommandWithStrategy } from '../../util/executeCommand.js';
4
+ import { buildWdioAsymmetricMatchersWithOptions } from '../asymmetrics/asymmetricsUtils.js';
5
+ async function singleElementCompare(el, html, options) {
4
6
  const actualHTML = await el.getHTML(options);
5
- if (Array.isArray(html)) {
6
- return compareTextWithArray(actualHTML, html, options);
7
- }
8
- return compareText(actualHTML, html, options);
7
+ return compareTextOrArray(actualHTML, html, options);
9
8
  }
10
9
  export async function toHaveHTML(received, expectedValue, options = DEFAULT_OPTIONS) {
11
- const isNot = this.isNot;
12
- const { expectation = 'HTML', verb = 'have' } = this;
10
+ const { expectation = 'HTML', verb = 'have', isNot, matcherName = 'toHaveHTML' } = this;
11
+ expectedValue = buildWdioAsymmetricMatchersWithOptions(expectedValue, options);
13
12
  await options.beforeAssertion?.({
14
- matcherName: 'toHaveHTML',
13
+ matcherName,
15
14
  expectedValue,
16
15
  options,
17
16
  });
18
- let el = 'getElement' in received
19
- ? await received?.getElement()
20
- : 'getElements' in received
21
- ? await received?.getElements()
22
- : received;
23
- let actualHTML;
24
- const pass = await waitUntil(async () => {
25
- const result = await executeCommand.call(this, el, condition, options, [expectedValue, options]);
26
- el = result.el;
27
- actualHTML = result.values;
28
- return result.success;
29
- }, isNot, options);
30
- const message = enhanceError(el, wrapExpectedWithArray(el, actualHTML, expectedValue), actualHTML, this, verb, expectation, '', options);
17
+ const { success: pass, actual: actualHTML, subject: elements, context: { isSome } = {} } = await waitUntil(async (iteration) => {
18
+ const result = await executeCommandWithStrategy({
19
+ unresolvedElements: received,
20
+ expectedValues: expectedValue,
21
+ singleElementCompare: (element, expectedValue) => singleElementCompare(element, expectedValue, options),
22
+ context: { isNot, iteration },
23
+ strategy: 'NewStrictMultipleElements',
24
+ strictConfiguration: { allowArrayWithSingleElement: true }
25
+ });
26
+ return result;
27
+ }, isNot, { wait: options.wait, interval: options.interval });
28
+ const expectedValues = wrapExpectedWithArray(elements, actualHTML, expectedValue);
29
+ const message = enhanceError(elements, expectedValues, actualHTML, { isNot, isSome }, verb, expectation, '', options);
31
30
  const result = {
32
31
  pass,
33
32
  message: () => message
34
33
  };
35
34
  await options.afterAssertion?.({
36
- matcherName: 'toHaveHTML',
35
+ matcherName,
37
36
  expectedValue,
38
37
  options,
39
38
  result
@@ -1,46 +1,41 @@
1
1
  import { DEFAULT_OPTIONS } from '../../constants.js';
2
- import { compareNumbers, enhanceError, executeCommand, numberError, waitUntil, } from '../../utils.js';
3
- async function condition(el, height, options) {
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 actualHeight = await el.getSize('height');
5
8
  return {
6
- result: compareNumbers(actualHeight, options),
7
- value: actualHeight
9
+ success: expectedNumber?.asymmetricMatch(actualHeight) ?? false,
10
+ actual: actualHeight
8
11
  };
9
12
  }
10
13
  export async function toHaveHeight(received, expectedValue, options = DEFAULT_OPTIONS) {
11
- const isNot = this.isNot;
12
- const { expectation = 'height', verb = 'have' } = this;
14
+ const { expectation = 'height', verb = 'have', isNot, matcherName = 'toHaveHeight' } = this;
13
15
  await options.beforeAssertion?.({
14
- matcherName: 'toHaveHeight',
16
+ matcherName,
15
17
  expectedValue,
16
18
  options,
17
19
  });
18
- let numberOptions;
19
- if (typeof expectedValue === 'number') {
20
- numberOptions = { eq: expectedValue };
21
- }
22
- else if (!expectedValue || (typeof expectedValue.eq !== 'number' && typeof expectedValue.gte !== 'number' && typeof expectedValue.lte !== 'number')) {
23
- throw new Error('Invalid params passed to toHaveHeight.');
24
- }
25
- else {
26
- numberOptions = expectedValue;
27
- }
28
- let el = await received?.getElement();
29
- let actualHeight;
30
- const pass = await waitUntil(async () => {
31
- const result = await executeCommand.call(this, el, condition, numberOptions, [expectedValue, numberOptions]);
32
- el = result.el;
33
- actualHeight = result.values;
34
- return result.success;
35
- }, isNot, { ...numberOptions, ...options });
36
- const error = numberError(numberOptions);
37
- const message = enhanceError(el, error, actualHeight, this, verb, expectation, '', options);
20
+ const { numberMatcher: expectedNumber, commandOptions } = validateNumberArrayAndExtractOptions(expectedValue, options);
21
+ const { success: pass, actual: actualHeight, 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, actualHeight, expectedNumber);
32
+ const message = enhanceError(elements, expectedValues, actualHeight, { 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: 'toHaveHeight',
38
+ matcherName,
44
39
  expectedValue,
45
40
  options,
46
41
  result
@@ -1,32 +1,34 @@
1
1
  import { DEFAULT_OPTIONS } from '../../constants.js';
2
- import { compareObject, enhanceError, executeCommand, waitUntil, wrapExpectedWithArray, } from '../../utils.js';
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.isNot;
9
- const { expectation = 'size', verb = 'have' } = this;
9
+ const { expectation = 'size', verb = 'have', isNot, matcherName = 'toHaveSize' } = this;
10
10
  await options.beforeAssertion?.({
11
- matcherName: 'toHaveSize',
11
+ matcherName,
12
12
  expectedValue,
13
13
  options,
14
14
  });
15
- let el = await received?.getElement();
16
- let actualSize;
17
- const pass = await waitUntil(async () => {
18
- const result = await executeCommand.call(this, el, condition, options, [expectedValue, options]);
19
- el = result.el;
20
- actualSize = result.values;
21
- return result.success;
22
- }, isNot, options);
23
- const message = enhanceError(el, wrapExpectedWithArray(el, actualSize, expectedValue), actualSize, this, verb, expectation, '', options);
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: 'toHaveSize',
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 { compareStyle, enhanceError, executeCommand, waitUntil, wrapExpectedWithArray } from '../../utils.js';
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.isNot;
8
- const { expectation = 'style', verb = 'have' } = this;
11
+ const { expectation = 'style', verb = 'have', isNot, matcherName = 'toHaveStyle' } = this;
9
12
  await options.beforeAssertion?.({
10
- matcherName: 'toHaveStyle',
13
+ matcherName,
11
14
  expectedValue,
12
15
  options,
13
16
  });
14
- let el = await received?.getElement();
15
- let actualStyle;
16
- const pass = await waitUntil(async () => {
17
- const result = await executeCommand.call(this, el, condition, options, [expectedValue, options]);
18
- el = result.el;
19
- actualStyle = result.values;
20
- return result.success;
21
- }, isNot, options);
22
- const message = enhanceError(el, wrapExpectedWithArray(el, actualStyle, expectedValue), actualStyle, this, verb, expectation, '', options);
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: 'toHaveStyle',
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 { compareText, compareTextWithArray, enhanceError, executeCommand, waitUntil, wrapExpectedWithArray } from '../../utils.js';
3
- async function condition(el, text, options) {
4
- const actualTextArray = [];
5
- const resultArray = [];
6
- let checkAllValuesMatchCondition;
7
- if (Array.isArray(el)) {
8
- for (const element of el) {
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.isNot;
32
- const { expectation = 'text', verb = 'have' } = this;
11
+ const { expectation = 'text', verb = 'have', isNot, matcherName = 'toHaveText' } = this;
33
12
  await options.beforeAssertion?.({
34
- matcherName: 'toHaveText',
13
+ matcherName,
35
14
  expectedValue,
36
15
  options,
37
16
  });
38
- let el = 'getElement' in received
39
- ? await received?.getElement()
40
- : 'getElements' in received
41
- ? await received?.getElements()
42
- : received;
43
- let actualText;
44
- const pass = await waitUntil(async () => {
45
- const result = await executeCommand.call(this, el, condition, options, [expectedValue, options]);
46
- el = result.el;
47
- actualText = result.values;
48
- return result.success;
49
- }, isNot, options);
50
- const message = enhanceError(el, wrapExpectedWithArray(el, actualText, expectedValue), actualText, this, verb, expectation, '', options);
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: 'toHaveText',
38
+ matcherName,
57
39
  expectedValue,
58
40
  options,
59
41
  result