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,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
@@ -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, width, 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 actualWidth = await el.getSize('width');
5
8
  return {
6
- result: compareNumbers(actualWidth, options),
7
- value: actualWidth
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.isNot;
12
- const { expectation = 'width', verb = 'have' } = this;
14
+ const { expectation = 'width', verb = 'have', isNot, matcherName = 'toHaveWidth' } = this;
13
15
  await options.beforeAssertion?.({
14
- matcherName: 'toHaveWidth',
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 actualWidth;
30
- const pass = await waitUntil(async () => {
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: 'toHaveWidth',
38
+ matcherName,
44
39
  expectedValue,
45
40
  options,
46
41
  result
@@ -1,47 +1,42 @@
1
- import { waitUntil, enhanceError, compareNumbers, numberError } from '../../utils.js';
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.isNot;
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: 'toBeElementsArrayOfSize',
9
+ matcherName,
9
10
  expectedValue,
10
11
  options,
11
12
  });
12
- let numberOptions;
13
- if (typeof expectedValue === 'number') {
14
- numberOptions = { eq: expectedValue };
15
- }
16
- else if (!expectedValue || (typeof expectedValue.eq !== 'number' && typeof expectedValue.gte !== 'number' && typeof expectedValue.lte !== 'number')) {
17
- throw new Error('Invalid params passed to toBeElementsArrayOfSize.');
18
- }
19
- else {
20
- numberOptions = expectedValue;
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
- elements = await refetchElements(elements, numberOptions.wait, true);
30
- return false;
31
- }, isNot, { ...numberOptions, ...options });
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 error = numberError(numberOptions);
38
- const message = enhanceError(elements, error, originalLength, this, verb, expectation, '', numberOptions);
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: 'toBeElementsArrayOfSize',
39
+ matcherName,
45
40
  expectedValue,
46
41
  options,
47
42
  result
@@ -1,30 +1,25 @@
1
- import { waitUntil, enhanceError, compareNumbers } from '../../utils.js';
2
- import { numberError } from '../../util/formatMessage.js';
1
+ import { waitUntil, enhanceError } from '../../utils.js';
3
2
  import { DEFAULT_OPTIONS } from '../../constants.js';
4
- export async function toBeRequestedTimes(received, expectedValue = {}, options = DEFAULT_OPTIONS) {
5
- const isNot = this.isNot || false;
6
- const { expectation = `called${typeof expectedValue === 'number' ? ' ' + expectedValue : ''} time${expectedValue !== 1 ? 's' : ''}`, verb = 'be' } = this;
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: 'toBeRequestedTimes',
7
+ matcherName,
9
8
  expectedValue,
10
9
  options,
11
10
  });
12
- const numberOptions = typeof expectedValue === 'number'
13
- ? { eq: expectedValue }
14
- : expectedValue || {};
15
- let actual;
16
- const pass = await waitUntil(async () => {
17
- actual = received.calls.length;
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: 'toBeRequestedTimes',
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 isNot = this.isNot || false;
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: 'toBeRequestedWith',
15
+ matcherName,
17
16
  expectedValue,
18
17
  options,
19
18
  });
20
- let actual;
21
- const pass = await waitUntil(async () => {
19
+ const { success: pass, actual } = await waitUntil(async () => {
20
+ let lastCall;
22
21
  for (const call of received.calls) {
23
- actual = call;
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: 'toBeRequestedWith',
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 (isMatcher(param)) {
133
- return (param.constructor.name +
134
- ' ' +
135
- (JSON.stringify(param.sample) || ''));
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/toHaveClass.ts","../src/matchers/element/toHaveComputedLabel.ts","../src/matchers/element/toHaveComputedRole.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/util/elementsUtil.ts","../src/util/executeCommand.ts","../src/util/formatMessage.ts","../src/util/refetchElements.ts"],"version":"5.9.3"}
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"}
@@ -0,0 +1,6 @@
1
+ export const isDefinedPlainObject = (obj) => {
2
+ if (typeof obj === 'object' && obj !== null && !Array.isArray(obj)) {
3
+ return true;
4
+ }
5
+ return false;
6
+ };
@@ -1,9 +1,79 @@
1
- export const wrapExpectedWithArray = (el, actual, expected) => {
2
- if (Array.isArray(el) && el.length > 1 && Array.isArray(actual)) {
3
- expected = [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 !== null && typeof obj === 'object' && 'selector' in obj && 'foundWith' in obj && 'parent' in 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
  };