expect-webdriverio 4.3.0 → 4.4.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.
@@ -0,0 +1,26 @@
1
+ import { waitUntil, enhanceError, compareText, compareTextWithArray, executeCommand, wrapExpectedWithArray, updateElementsArray, } from '../../utils.js';
2
+ async function condition(el, label, options) {
3
+ const actualLabel = await el.getComputedLabel();
4
+ if (Array.isArray(label)) {
5
+ return compareTextWithArray(actualLabel, label, options);
6
+ }
7
+ return compareText(actualLabel, label, options);
8
+ }
9
+ export async function toHaveComputedLabel(received, label, options = {}) {
10
+ const isNot = this.isNot;
11
+ const { expectation = 'computed label', verb = 'have' } = this;
12
+ let el = await received;
13
+ let actualLabel;
14
+ const pass = await waitUntil(async () => {
15
+ const result = await executeCommand.call(this, el, condition, options, [label, options]);
16
+ el = result.el;
17
+ actualLabel = result.values;
18
+ return result.success;
19
+ }, isNot, options);
20
+ updateElementsArray(pass, received, el);
21
+ const message = enhanceError(el, wrapExpectedWithArray(el, actualLabel, label), actualLabel, this, verb, expectation, '', options);
22
+ return {
23
+ pass,
24
+ message: () => message,
25
+ };
26
+ }
@@ -0,0 +1,7 @@
1
+ import { toHaveComputedLabel } from './toHaveComputedLabel.js';
2
+ export function toHaveComputedLabelContaining(el, label, options = {}) {
3
+ return toHaveComputedLabel.call(this, el, label, {
4
+ ...options,
5
+ containing: true
6
+ });
7
+ }
@@ -0,0 +1,26 @@
1
+ import { waitUntil, enhanceError, compareText, compareTextWithArray, executeCommand, wrapExpectedWithArray, updateElementsArray, } from '../../utils.js';
2
+ async function condition(el, role, options) {
3
+ const actualRole = await el.getComputedRole();
4
+ if (Array.isArray(role)) {
5
+ return compareTextWithArray(actualRole, role, options);
6
+ }
7
+ return compareText(actualRole, role, options);
8
+ }
9
+ export async function toHaveComputedRole(received, role, options = {}) {
10
+ const isNot = this.isNot;
11
+ const { expectation = 'computed role', verb = 'have' } = this;
12
+ let el = await received;
13
+ let actualRole;
14
+ const pass = await waitUntil(async () => {
15
+ const result = await executeCommand.call(this, el, condition, options, [role, options]);
16
+ el = result.el;
17
+ actualRole = result.values;
18
+ return result.success;
19
+ }, isNot, options);
20
+ updateElementsArray(pass, received, el);
21
+ const message = enhanceError(el, wrapExpectedWithArray(el, actualRole, role), actualRole, this, verb, expectation, '', options);
22
+ return {
23
+ pass,
24
+ message: () => message,
25
+ };
26
+ }
@@ -0,0 +1,7 @@
1
+ import { toHaveComputedRole } from './toHaveComputedRole.js';
2
+ export function toHaveComputedRoleContaining(el, role, options = {}) {
3
+ return toHaveComputedRole.call(this, el, role, {
4
+ ...options,
5
+ containing: true
6
+ });
7
+ }
@@ -0,0 +1,26 @@
1
+ import { waitUntil, enhanceError, compareText, compareTextWithArray, executeCommand, wrapExpectedWithArray, updateElementsArray } from '../../utils.js';
2
+ async function condition(el, html, options) {
3
+ const actualHTML = await el.getHTML(options.includeSelectorTag);
4
+ if (Array.isArray(html)) {
5
+ return compareTextWithArray(actualHTML, html, options);
6
+ }
7
+ return compareText(actualHTML, html, options);
8
+ }
9
+ export async function toHaveHTML(received, html, options = {}) {
10
+ const isNot = this.isNot;
11
+ const { expectation = 'HTML', verb = 'have' } = this;
12
+ let el = await received;
13
+ let actualHTML;
14
+ const pass = await waitUntil(async () => {
15
+ const result = await executeCommand.call(this, el, condition, options, [html, options]);
16
+ el = result.el;
17
+ actualHTML = result.values;
18
+ return result.success;
19
+ }, isNot, options);
20
+ updateElementsArray(pass, received, el);
21
+ const message = enhanceError(el, wrapExpectedWithArray(el, actualHTML, html), actualHTML, this, verb, expectation, '', options);
22
+ return {
23
+ pass,
24
+ message: () => message
25
+ };
26
+ }
@@ -0,0 +1,7 @@
1
+ import { toHaveHTML } from './toHaveHTML.js';
2
+ export function toHaveHTMLContaining(el, html, options = {}) {
3
+ return toHaveHTML.call(this, el, html, {
4
+ ...options,
5
+ containing: true
6
+ });
7
+ }
@@ -0,0 +1,26 @@
1
+ import { waitUntil, enhanceError, executeCommand, wrapExpectedWithArray, updateElementsArray, } from '../../utils.js';
2
+ async function condition(el, height) {
3
+ const actualHeight = await el.getSize('height');
4
+ return {
5
+ value: actualHeight,
6
+ result: actualHeight === height,
7
+ };
8
+ }
9
+ export async function toHaveHeight(received, height, options = {}) {
10
+ const isNot = this.isNot;
11
+ const { expectation = 'height', verb = 'have' } = this;
12
+ let el = await received;
13
+ let actualHeight;
14
+ const pass = await waitUntil(async () => {
15
+ const result = await executeCommand.call(this, el, condition, options, [height, options]);
16
+ el = result.el;
17
+ actualHeight = result.values;
18
+ return result.success;
19
+ }, isNot, options);
20
+ updateElementsArray(pass, received, el);
21
+ const message = enhanceError(el, wrapExpectedWithArray(el, actualHeight, height), actualHeight, this, verb, expectation, '', options);
22
+ return {
23
+ pass,
24
+ message: () => message,
25
+ };
26
+ }
@@ -0,0 +1,23 @@
1
+ import { waitUntil, enhanceError, executeCommand, wrapExpectedWithArray, updateElementsArray, compareObject, } from '../../utils.js';
2
+ async function condition(el, size) {
3
+ const actualSize = await el.getSize();
4
+ return compareObject(actualSize, size);
5
+ }
6
+ export async function toHaveSize(received, size, options = {}) {
7
+ const isNot = this.isNot;
8
+ const { expectation = 'size', verb = 'have' } = this;
9
+ let el = await received;
10
+ let actualSize;
11
+ const pass = await waitUntil(async () => {
12
+ const result = await executeCommand.call(this, el, condition, options, [size, options]);
13
+ el = result.el;
14
+ actualSize = result.values;
15
+ return result.success;
16
+ }, isNot, options);
17
+ updateElementsArray(pass, received, el);
18
+ const message = enhanceError(el, wrapExpectedWithArray(el, actualSize, size), actualSize, this, verb, expectation, '', options);
19
+ return {
20
+ pass,
21
+ message: () => message,
22
+ };
23
+ }
@@ -0,0 +1,26 @@
1
+ import { waitUntil, enhanceError, executeCommand, wrapExpectedWithArray, updateElementsArray, } from '../../utils.js';
2
+ async function condition(el, width) {
3
+ const actualWidth = await el.getSize('width');
4
+ return {
5
+ value: actualWidth,
6
+ result: actualWidth === width,
7
+ };
8
+ }
9
+ export async function toHaveWidth(received, width, options = {}) {
10
+ const isNot = this.isNot;
11
+ const { expectation = 'width', verb = 'have' } = this;
12
+ let el = await received;
13
+ let actualWidth;
14
+ const pass = await waitUntil(async () => {
15
+ const result = await executeCommand.call(this, el, condition, options, [width, options]);
16
+ el = result.el;
17
+ actualWidth = result.values;
18
+ return result.success;
19
+ }, isNot, options);
20
+ updateElementsArray(pass, received, el);
21
+ const message = enhanceError(el, wrapExpectedWithArray(el, actualWidth, width), actualWidth, this, verb, expectation, '', options);
22
+ return {
23
+ pass,
24
+ message: () => message,
25
+ };
26
+ }
package/lib/utils.js CHANGED
@@ -1,3 +1,4 @@
1
+ import isEqual from 'lodash.isequal';
1
2
  import { executeCommand } from './util/executeCommand.js';
2
3
  import { wrapExpectedWithArray, updateElementsArray } from './util/elementsUtil.js';
3
4
  import { enhanceError, enhanceErrorBe, numberError } from './util/formatMessage.js';
@@ -11,12 +12,12 @@ const waitUntil = async (condition, isNot = false, { wait = DEFAULT_OPTIONS.wait
11
12
  let error;
12
13
  const start = Date.now();
13
14
  while (true) {
14
- if ((Date.now() - start) > wait) {
15
+ if (Date.now() - start > wait) {
15
16
  throw new Error('timeout');
16
17
  }
17
18
  error = undefined;
18
19
  try {
19
- const result = isNot !== await condition();
20
+ const result = isNot !== (await condition());
20
21
  if (result) {
21
22
  break;
22
23
  }
@@ -49,7 +50,7 @@ async function executeCommandBe(received, command, options) {
49
50
  const message = enhanceErrorBe(el, pass, this, verb, expectation, options);
50
51
  return {
51
52
  pass,
52
- message: () => message
53
+ message: () => message,
53
54
  };
54
55
  }
55
56
  const compareNumbers = (actual, options = {}) => {
@@ -67,11 +68,11 @@ const compareNumbers = (actual, options = {}) => {
67
68
  }
68
69
  return false;
69
70
  };
70
- export const compareText = (actual, expected, { ignoreCase = false, trim = true, containing = false, atStart = false, atEnd = false, atIndex, replace }) => {
71
+ export const compareText = (actual, expected, { ignoreCase = false, trim = true, containing = false, atStart = false, atEnd = false, atIndex, replace, }) => {
71
72
  if (typeof actual !== 'string') {
72
73
  return {
73
74
  value: actual,
74
- result: false
75
+ result: false,
75
76
  };
76
77
  }
77
78
  if (trim) {
@@ -89,43 +90,43 @@ export const compareText = (actual, expected, { ignoreCase = false, trim = true,
89
90
  if (expected instanceof RegExp) {
90
91
  return {
91
92
  value: actual,
92
- result: !!actual.match(expected)
93
+ result: !!actual.match(expected),
93
94
  };
94
95
  }
95
96
  if (containing) {
96
97
  return {
97
98
  value: actual,
98
- result: actual.includes(expected)
99
+ result: actual.includes(expected),
99
100
  };
100
101
  }
101
102
  if (atStart) {
102
103
  return {
103
104
  value: actual,
104
- result: actual.startsWith(expected)
105
+ result: actual.startsWith(expected),
105
106
  };
106
107
  }
107
108
  if (atEnd) {
108
109
  return {
109
110
  value: actual,
110
- result: actual.endsWith(expected)
111
+ result: actual.endsWith(expected),
111
112
  };
112
113
  }
113
114
  if (atIndex) {
114
115
  return {
115
116
  value: actual,
116
- result: actual.substring(atIndex, actual.length).startsWith(expected)
117
+ result: actual.substring(atIndex, actual.length).startsWith(expected),
117
118
  };
118
119
  }
119
120
  return {
120
121
  value: actual,
121
- result: actual === expected
122
+ result: actual === expected,
122
123
  };
123
124
  };
124
- export const compareTextWithArray = (actual, expectedArray, { ignoreCase = false, trim = false, containing = false, atStart = false, atEnd = false, atIndex, replace }) => {
125
+ export const compareTextWithArray = (actual, expectedArray, { ignoreCase = false, trim = false, containing = false, atStart = false, atEnd = false, atIndex, replace, }) => {
125
126
  if (typeof actual !== 'string') {
126
127
  return {
127
128
  value: actual,
128
- result: false
129
+ result: false,
129
130
  };
130
131
  }
131
132
  if (trim) {
@@ -136,7 +137,7 @@ export const compareTextWithArray = (actual, expectedArray, { ignoreCase = false
136
137
  }
137
138
  if (ignoreCase) {
138
139
  actual = actual.toLowerCase();
139
- expectedArray = expectedArray.map(item => (item instanceof RegExp) ? item : item.toLowerCase());
140
+ expectedArray = expectedArray.map((item) => (item instanceof RegExp ? item : item.toLowerCase()));
140
141
  }
141
142
  const textInArray = expectedArray.some((expected) => {
142
143
  if (expected instanceof RegExp) {
@@ -158,7 +159,19 @@ export const compareTextWithArray = (actual, expectedArray, { ignoreCase = false
158
159
  });
159
160
  return {
160
161
  value: actual,
161
- result: textInArray
162
+ result: textInArray,
163
+ };
164
+ };
165
+ export const compareObject = (actual, expected) => {
166
+ if (typeof actual !== 'object' || Array.isArray(actual)) {
167
+ return {
168
+ value: actual,
169
+ result: false,
170
+ };
171
+ }
172
+ return {
173
+ value: actual,
174
+ result: isEqual(actual, expected),
162
175
  };
163
176
  };
164
177
  export const compareStyle = async (actualEl, style, { ignoreCase = true, trim = false }) => {
@@ -181,21 +194,21 @@ export const compareStyle = async (actualEl, style, { ignoreCase = true, trim =
181
194
  }
182
195
  return {
183
196
  value: actual,
184
- result
197
+ result,
185
198
  };
186
199
  };
187
- function aliasFn(fn, { verb, expectation } = {}, ...args) {
200
+ function aliasFn(fn, { verb, expectation, } = {}, ...args) {
188
201
  this.verb = verb;
189
202
  this.expectation = expectation;
190
203
  return fn.apply(this, args);
191
204
  }
192
- export { updateElementsArray, wrapExpectedWithArray, enhanceError, numberError, executeCommand, executeCommandBe, waitUntil, compareNumbers, aliasFn };
205
+ export { updateElementsArray, wrapExpectedWithArray, enhanceError, numberError, executeCommand, executeCommandBe, waitUntil, compareNumbers, aliasFn, };
193
206
  function replaceActual(replace, actual) {
194
- const hasMultipleReplacers = replace.every(r => Array.isArray(r));
207
+ const hasMultipleReplacers = replace.every((r) => Array.isArray(r));
195
208
  const replacers = hasMultipleReplacers
196
209
  ? replace
197
210
  : [replace];
198
- if (replacers.some(r => Array.isArray(r) && r.length !== 2)) {
211
+ if (replacers.some((r) => Array.isArray(r) && r.length !== 2)) {
199
212
  throw new Error('Replacers need to have a searchValue and a replaceValue');
200
213
  }
201
214
  for (const replacer of replacers) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expect-webdriverio",
3
- "version": "4.3.0",
3
+ "version": "4.4.1",
4
4
  "author": "Mykola Grybyk <mykola.grybyk@gmail.com>",
5
5
  "description": "WebdriverIO Assertion Library",
6
6
  "license": "MIT",
@@ -60,6 +60,7 @@
60
60
  "devDependencies": {
61
61
  "@types/debug": "^4.1.8",
62
62
  "@types/jest": "^29.5.4",
63
+ "@types/lodash.isequal": "^4.5.6",
63
64
  "@types/node": "^20.6.0",
64
65
  "@typescript-eslint/eslint-plugin": "^6.7.0",
65
66
  "@typescript-eslint/parser": "^6.7.0",
@@ -75,7 +76,7 @@
75
76
  "rimraf": "^5.0.1",
76
77
  "shelljs": "^0.8.5",
77
78
  "typescript": "^5.2.2",
78
- "vitest": "0.34.5",
79
+ "vitest": "0.34.6",
79
80
  "webdriverio": "^8.16.7"
80
81
  },
81
82
  "optionalDependencies": {
@@ -84,6 +85,7 @@
84
85
  },
85
86
  "dependencies": {
86
87
  "expect": "^29.7.0",
87
- "jest-matcher-utils": "^29.7.0"
88
+ "jest-matcher-utils": "^29.7.0",
89
+ "lodash.isequal": "^4.5.0"
88
90
  }
89
91
  }
@@ -1,7 +1,3 @@
1
- type searchValue = string | RegExp
2
- type replaceValue = string | ((substring: string, ...args: any[]) => string)
3
- type Replacer = [searchValue, replaceValue]
4
-
5
1
  declare namespace ExpectWebdriverIO {
6
2
  function expect<T = unknown, R extends void | Promise<void> = void | Promise<void>>(
7
3
  actual: T
@@ -38,6 +34,13 @@ declare namespace ExpectWebdriverIO {
38
34
  message?: string
39
35
  }
40
36
 
37
+ interface HTMLOptions extends StringOptions {
38
+ /**
39
+ * return the HTML with the selector tag included
40
+ */
41
+ includeSelectorTag?: boolean
42
+ }
43
+
41
44
  interface StringOptions extends CommandOptions {
42
45
  /**
43
46
  * apply `toLowerCase` to both actual and expected values
@@ -77,7 +80,7 @@ declare namespace ExpectWebdriverIO {
77
80
  * replace the actual value (example: strip newlines from the value) and expect it to match the expected value
78
81
  * Otherwise strict equal
79
82
  */
80
- replace?: Replacer | Replacer[]
83
+ replace?: [string | RegExp, string | Function] | Array<[string | RegExp, string | Function]>
81
84
 
82
85
  /**
83
86
  * might be helpful to force converting property value to string
@@ -268,6 +271,7 @@ declare namespace ExpectWebdriverIO {
268
271
 
269
272
  /**
270
273
  * `WebdriverIO.Element` -> `getText`
274
+ * Element's text equals the text provided
271
275
  */
272
276
  toHaveText(
273
277
  text: string | RegExp | Array<string | RegExp>,
@@ -282,6 +286,72 @@ declare namespace ExpectWebdriverIO {
282
286
  options?: ExpectWebdriverIO.StringOptions
283
287
  ): R
284
288
 
289
+ /**
290
+ * `WebdriverIO.Element` -> `getHTML`
291
+ * Element's html equals the html provided
292
+ */
293
+ toHaveHTML(html: string | RegExp | Array<string | RegExp>, options?: ExpectWebdriverIO.HTMLOptions): R
294
+ /**
295
+ * `WebdriverIO.Element` -> `getHTML`
296
+ * Element's html includes the html provided
297
+ */
298
+ toHaveHTMLContaining(
299
+ html: string | RegExp | Array<string | RegExp>,
300
+ options?: ExpectWebdriverIO.HTMLOptions
301
+ ): R
302
+
303
+ /**
304
+ * `WebdriverIO.Element` -> `getComputedLabel`
305
+ * Element's computed label equals the computed label provided
306
+ */
307
+ toHaveComputedLabel(
308
+ computedLabel: string | RegExp | Array<string | RegExp>,
309
+ options?: ExpectWebdriverIO.StringOptions
310
+ ): R
311
+ /**
312
+ * `WebdriverIO.Element` -> `getComputedLabel`
313
+ * Element's computed label includes the computed label provided
314
+ */
315
+ toHaveComputedLabelContaining(
316
+ computedLabel: string | RegExp | Array<string | RegExp>,
317
+ options?: ExpectWebdriverIO.StringOptions
318
+ ): R
319
+
320
+ /**
321
+ * `WebdriverIO.Element` -> `getComputedRole`
322
+ * Element's computed role equals the computed role provided
323
+ */
324
+ toHaveComputedRole(
325
+ computedRole: string | RegExp | Array<string | RegExp>,
326
+ options?: ExpectWebdriverIO.StringOptions
327
+ ): R
328
+ /**
329
+ * `WebdriverIO.Element` -> `getComputedRole`
330
+ * Element's computed role includes the computed role provided
331
+ */
332
+ toHaveComputedRoleContaining(
333
+ computedRole: string | RegExp | Array<string | RegExp>,
334
+ options?: ExpectWebdriverIO.StringOptions
335
+ ): R
336
+
337
+ /**
338
+ * `WebdriverIO.Element` -> `getSize('width')`
339
+ * Element's width equals the width provided
340
+ */
341
+ toHaveWidth(width: number, options?: ExpectWebdriverIO.CommandOptions): R
342
+
343
+ /**
344
+ * `WebdriverIO.Element` -> `getSize('height')`
345
+ * Element's height equals the height provided
346
+ */
347
+ toHaveHeight(height: number, options?: ExpectWebdriverIO.CommandOptions): R
348
+
349
+ /**
350
+ * `WebdriverIO.Element` -> `getSize()`
351
+ * Element's size equals the size provided
352
+ */
353
+ toHaveHeight(size: { height: number; width: number }, options?: ExpectWebdriverIO.CommandOptions): R
354
+
285
355
  /**
286
356
  * `WebdriverIO.Element` -> `getAttribute("style")`
287
357
  */