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.
Files changed (45) hide show
  1. package/README.md +16 -14
  2. package/jasmine-wdio-expect-async.d.ts +58 -18
  3. package/jasmine.d.ts +9 -16
  4. package/lib/constants.js +4 -0
  5. package/lib/index.js +30 -18
  6. package/lib/jasmineUtils.js +3 -2
  7. package/lib/matchers/asymmetrics/asymmetricsUtils.js +24 -0
  8. package/lib/matchers/asymmetrics/oneOf.js +51 -0
  9. package/lib/matchers/browser/toHaveClipboardText.js +8 -9
  10. package/lib/matchers/browser/toHaveLocalStorageItem.js +22 -14
  11. package/lib/matchers/browser/toHaveTitle.js +9 -10
  12. package/lib/matchers/browser/toHaveUrl.js +8 -9
  13. package/lib/matchers/element/toBeExisting.js +8 -3
  14. package/lib/matchers/element/toBeSelected.js +6 -13
  15. package/lib/matchers/element/toHaveAttribute.js +46 -45
  16. package/lib/matchers/element/toHaveChildren.js +30 -32
  17. package/lib/matchers/element/toHaveComputedLabel.js +21 -20
  18. package/lib/matchers/element/toHaveComputedRole.js +21 -20
  19. package/lib/matchers/element/toHaveElementClass.js +57 -0
  20. package/lib/matchers/element/toHaveElementProperty.js +40 -32
  21. package/lib/matchers/element/toHaveHTML.js +22 -23
  22. package/lib/matchers/element/toHaveHeight.js +23 -28
  23. package/lib/matchers/element/toHaveSize.js +16 -14
  24. package/lib/matchers/element/toHaveStyle.js +20 -14
  25. package/lib/matchers/element/toHaveText.js +26 -44
  26. package/lib/matchers/element/toHaveWidth.js +23 -28
  27. package/lib/matchers/elements/toBeElementsArrayOfSize.js +25 -30
  28. package/lib/matchers/mock/toBeRequestedTimes.js +12 -17
  29. package/lib/matchers/mock/toBeRequestedWith.js +13 -23
  30. package/lib/matchers/modifiers/some.js +15 -0
  31. package/lib/matchers.js +1 -1
  32. package/lib/tsconfig.build.tsbuildinfo +1 -1
  33. package/lib/util/commandOptionsUtils.js +6 -0
  34. package/lib/util/elementsUtil.js +74 -4
  35. package/lib/util/executeCommand.js +94 -6
  36. package/lib/util/formatMessage.js +87 -32
  37. package/lib/util/numberOptionsUtil.js +92 -0
  38. package/lib/util/refetchElements.js +30 -5
  39. package/lib/util/stringUtil.js +12 -0
  40. package/lib/util/waitUntil.js +44 -0
  41. package/lib/utils.js +128 -105
  42. package/package.json +13 -11
  43. package/types/expect-global.d.ts +2 -1
  44. package/types/expect-webdriverio.d.ts +628 -136
  45. package/lib/matchers/element/toHaveClass.js +0 -61
@@ -1,63 +1,64 @@
1
1
  import { DEFAULT_OPTIONS } from '../../constants.js';
2
- import { compareText, enhanceError, executeCommand, waitUntil, wrapExpectedWithArray } from '../../utils.js';
3
- async function conditionAttr(el, attribute) {
4
- const attr = await el.getAttribute(attribute);
5
- if (typeof attr !== 'string') {
6
- return { result: false, value: attr };
2
+ import { executeCommandWithStrategy } from '../../util/executeCommand.js';
3
+ import { compareText, enhanceError, isAsymmetricMatcher, waitUntil, wrapExpectedWithArray } from '../../utils.js';
4
+ import { expect as wdioExpect } from '../../index.js';
5
+ import { buildWdioAsymmetricMatchersWithOptions } from '../asymmetrics/asymmetricsUtils.js';
6
+ import { OneOfMatcher } from '../asymmetrics/oneOf.js';
7
+ async function conditionAttributeValueMatchWithExpected(el, attribute, expectedValue, options) {
8
+ const attributeValue = await el.getAttribute(attribute);
9
+ if (typeof attributeValue !== 'string' || expectedValue === undefined || expectedValue === null) {
10
+ if (isAsymmetricMatcher(expectedValue)) {
11
+ return { success: expectedValue.asymmetricMatch(attributeValue), actual: attributeValue };
12
+ }
13
+ return { success: attributeValue === expectedValue, actual: attributeValue };
7
14
  }
8
- return { result: true, value: attr };
9
- }
10
- async function conditionAttrAndValue(el, attribute, value, options) {
11
- const attr = await el.getAttribute(attribute);
12
- if (typeof attr !== 'string') {
13
- return { result: false, value: attr };
15
+ else if (expectedValue instanceof OneOfMatcher) {
16
+ return { success: expectedValue.asymmetricMatch(attributeValue), actual: attributeValue };
14
17
  }
15
- return compareText(attr, value, options);
16
- }
17
- export async function toHaveAttributeAndValue(received, attribute, value, options = DEFAULT_OPTIONS) {
18
- const isNot = this.isNot;
19
- const { expectation = 'attribute', verb = 'have' } = this;
20
- let el = await received?.getElement();
21
- let attr;
22
- const pass = await waitUntil(async () => {
23
- const result = await executeCommand.call(this, el, conditionAttrAndValue, options, [attribute, value, options]);
24
- el = result.el;
25
- attr = result.values;
26
- return result.success;
27
- }, isNot, options);
28
- const expected = wrapExpectedWithArray(el, attr, value);
29
- const message = enhanceError(el, expected, attr, this, verb, expectation, attribute, options);
30
- return {
31
- pass,
32
- message: () => message
33
- };
18
+ return compareText(attributeValue, expectedValue, options);
34
19
  }
35
- async function toHaveAttributeFn(received, attribute) {
36
- const isNot = this.isNot;
37
- const { expectation = 'attribute', verb = 'have' } = this;
38
- let el = await received?.getElement();
39
- const pass = await waitUntil(async () => {
40
- const result = await executeCommand.call(this, el, conditionAttr, {}, [attribute]);
41
- el = result.el;
42
- return result.success;
43
- }, isNot, {});
44
- const message = enhanceError(el, !isNot, pass, this, verb, expectation, attribute, {});
20
+ export async function toHaveAttributeAndValue(received, attribute, expectedValue, options = DEFAULT_OPTIONS) {
21
+ const { expectation = 'attribute', verb = 'have', isNot } = this;
22
+ expectedValue = buildWdioAsymmetricMatchersWithOptions(expectedValue, options);
23
+ const { success: pass, actual: attr, subject: el, context: { isSome } = {} } = await waitUntil(async (iteration) => {
24
+ return await executeCommandWithStrategy({
25
+ unresolvedElements: received,
26
+ expectedValues: expectedValue,
27
+ singleElementCompare: (element, values) => {
28
+ return conditionAttributeValueMatchWithExpected(element, attribute, values, options);
29
+ },
30
+ context: { isNot, iteration },
31
+ strategy: 'NewStrictMultipleElements',
32
+ });
33
+ }, isNot, { wait: options.wait, interval: options.interval });
34
+ const expected = wrapExpectedWithArray(el, attr, expectedValue);
35
+ const message = enhanceError(el, expected, attr, { isNot, isSome }, verb, expectation, attribute, options);
45
36
  return {
46
37
  pass,
47
38
  message: () => message
48
39
  };
49
40
  }
50
41
  export async function toHaveAttribute(received, attribute, value, options = DEFAULT_OPTIONS) {
42
+ const matcherName = 'toHaveAttribute';
43
+ const paramsCount = arguments.length;
51
44
  await options.beforeAssertion?.({
52
- matcherName: 'toHaveAttribute',
45
+ matcherName,
53
46
  expectedValue: [attribute, value],
54
47
  options,
55
48
  });
56
- const result = value !== undefined
57
- ? await toHaveAttributeAndValue.call(this, received, attribute, value, options)
58
- : await toHaveAttributeFn.call(this, received, attribute);
49
+ let expectedValue;
50
+ if (value === undefined) {
51
+ if (paramsCount > 2) {
52
+ 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).');
53
+ }
54
+ expectedValue = wdioExpect.anything();
55
+ }
56
+ else {
57
+ expectedValue = value;
58
+ }
59
+ const result = await toHaveAttributeAndValue.call(this, received, attribute, expectedValue, options);
59
60
  await options.afterAssertion?.({
60
- matcherName: 'toHaveAttribute',
61
+ matcherName,
61
62
  expectedValue: [attribute, value],
62
63
  options,
63
64
  result
@@ -1,49 +1,47 @@
1
1
  import { DEFAULT_OPTIONS } from '../../constants.js';
2
- import { compareNumbers, enhanceError, executeCommand, numberError, waitUntil, wrapExpectedWithArray } from '../../utils.js';
3
- async function condition(el, options) {
2
+ import { executeCommandWithStrategy } from '../../util/executeCommand.js';
3
+ import { isEmptyOrLegacyNumberOptions, validateNumberArrayAndExtractOptions } from '../../util/numberOptionsUtil.js';
4
+ import { enhanceError, waitUntil, wrapExpectedWithArray } from '../../utils.js';
5
+ async function condition(el, expectedValue) {
4
6
  const children = await el.$$('./*').getElements();
5
- if (typeof options.lte !== 'number' &&
6
- typeof options.gte !== 'number' &&
7
- typeof options.eq !== 'number') {
8
- return {
9
- result: children.length > 0,
10
- value: children?.length
11
- };
7
+ if (expectedValue === undefined) {
8
+ return { success: false, actual: children?.length };
12
9
  }
13
10
  return {
14
- result: compareNumbers(children?.length, options),
15
- value: children?.length
11
+ success: expectedValue?.asymmetricMatch(children?.length) ?? false,
12
+ actual: children?.length
16
13
  };
17
14
  }
18
- export async function toHaveChildren(received, expectedValue, options = DEFAULT_OPTIONS) {
19
- const isNot = this.isNot;
20
- const { expectation = 'children', verb = 'have' } = this;
15
+ export async function toHaveChildren(received, expectedValueOrOptions, options = DEFAULT_OPTIONS) {
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
21
  await options.beforeAssertion?.({
22
- matcherName: 'toHaveChildren',
23
- expectedValue,
22
+ matcherName,
23
+ expectedValue: expectedValueOrOptions,
24
24
  options,
25
25
  });
26
- const numberOptions = typeof expectedValue === 'number'
27
- ? { eq: expectedValue }
28
- : expectedValue || {};
29
- let el = await received?.getElement();
30
- let children;
31
- const pass = await waitUntil(async () => {
32
- const result = await executeCommand.call(this, el, condition, numberOptions, [numberOptions]);
33
- el = result.el;
34
- children = result.values;
35
- return result.success;
36
- }, isNot, { ...numberOptions, ...options });
37
- const error = numberError(numberOptions);
38
- const expectedArray = wrapExpectedWithArray(el, children, error);
39
- const message = enhanceError(el, expectedArray, children, this, verb, expectation, '', numberOptions);
26
+ const { numberMatcher: expectedNumber, commandOptions } = validateNumberArrayAndExtractOptions(expectedValueOrOptions, options, { supportDefaultAsGteThen1: true });
27
+ const { success: pass, actual: children, subject, context: { isSome } = {} } = await waitUntil(async (iteration) => {
28
+ return await executeCommandWithStrategy({
29
+ unresolvedElements: received,
30
+ expectedValues: expectedNumber,
31
+ singleElementCompare: (element, expectedValue) => condition(element, expectedValue),
32
+ context: { isNot, iteration },
33
+ strategy: 'NewStrictMultipleElements',
34
+ });
35
+ }, isNot, { wait: commandOptions.wait, interval: commandOptions.interval });
36
+ const expectedArray = wrapExpectedWithArray(subject, children, expectedNumber);
37
+ const message = enhanceError(subject, expectedArray, children, { isNot, isSome }, verb, expectation, '', commandOptions);
40
38
  const result = {
41
39
  pass,
42
40
  message: () => message
43
41
  };
44
42
  await options.afterAssertion?.({
45
- matcherName: 'toHaveChildren',
46
- expectedValue,
43
+ matcherName,
44
+ expectedValue: expectedValueOrOptions,
47
45
  options,
48
46
  result
49
47
  });
@@ -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