codeceptjs 3.5.12-beta.3 → 3.5.12-beta.6

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.
@@ -47,6 +47,9 @@ const {
47
47
  setRestartStrategy, restartsSession, restartsContext, restartsBrowser,
48
48
  } = require('./extras/PlaywrightRestartOpts');
49
49
  const { createValueEngine, createDisabledEngine } = require('./extras/PlaywrightPropEngine');
50
+ const {
51
+ seeElementError, dontSeeElementError, dontSeeElementInDOMError, seeElementInDOMError,
52
+ } = require('./errors/ElementAssertion');
50
53
 
51
54
  const pathSeparator = path.sep;
52
55
 
@@ -1451,7 +1454,11 @@ class Playwright extends Helper {
1451
1454
  async seeElement(locator) {
1452
1455
  let els = await this._locate(locator);
1453
1456
  els = await Promise.all(els.map(el => el.isVisible()));
1454
- return empty('visible elements').negate(els.filter(v => v).fill('ELEMENT'));
1457
+ try {
1458
+ return empty('visible elements').negate(els.filter(v => v).fill('ELEMENT'));
1459
+ } catch (e) {
1460
+ dontSeeElementError(locator);
1461
+ }
1455
1462
  }
1456
1463
 
1457
1464
  /**
@@ -1461,7 +1468,11 @@ class Playwright extends Helper {
1461
1468
  async dontSeeElement(locator) {
1462
1469
  let els = await this._locate(locator);
1463
1470
  els = await Promise.all(els.map(el => el.isVisible()));
1464
- return empty('visible elements').assert(els.filter(v => v).fill('ELEMENT'));
1471
+ try {
1472
+ return empty('visible elements').assert(els.filter(v => v).fill('ELEMENT'));
1473
+ } catch (e) {
1474
+ seeElementError(locator);
1475
+ }
1465
1476
  }
1466
1477
 
1467
1478
  /**
@@ -1469,7 +1480,11 @@ class Playwright extends Helper {
1469
1480
  */
1470
1481
  async seeElementInDOM(locator) {
1471
1482
  const els = await this._locate(locator);
1472
- return empty('elements on page').negate(els.filter(v => v).fill('ELEMENT'));
1483
+ try {
1484
+ return empty('elements on page').negate(els.filter(v => v).fill('ELEMENT'));
1485
+ } catch (e) {
1486
+ dontSeeElementInDOMError(locator);
1487
+ }
1473
1488
  }
1474
1489
 
1475
1490
  /**
@@ -1477,7 +1492,11 @@ class Playwright extends Helper {
1477
1492
  */
1478
1493
  async dontSeeElementInDOM(locator) {
1479
1494
  const els = await this._locate(locator);
1480
- return empty('elements on a page').assert(els.filter(v => v).fill('ELEMENT'));
1495
+ try {
1496
+ return empty('elements on a page').assert(els.filter(v => v).fill('ELEMENT'));
1497
+ } catch (e) {
1498
+ seeElementInDOMError(locator);
1499
+ }
1481
1500
  }
1482
1501
 
1483
1502
  /**
@@ -2974,27 +2993,27 @@ class Playwright extends Helper {
2974
2993
  throw new Error('Failure in test automation. You use "I.grabRecordedNetworkTraffics", but "I.startRecordingTraffic" was never called before.');
2975
2994
  }
2976
2995
 
2977
- const requests = await this.requests;
2978
- const promises = requests.map(async (request) => request.response.then(
2979
- async (response) => {
2980
- let body;
2981
- try {
2982
- // There's no 'body' for some requests (redirect etc...)
2983
- body = JSON.parse((await response.body()).toString());
2984
- } catch (e) {
2985
- // only interested in JSON, not HTML responses.
2986
- }
2996
+ const promises = this.requests.map(async (request) => {
2997
+ const resp = await request.response;
2998
+ let body;
2999
+ try {
3000
+ // There's no 'body' for some requests (redirect etc...)
3001
+ body = JSON.parse((await resp.body()).toString());
3002
+ } catch (e) {
3003
+ // only interested in JSON, not HTML responses.
3004
+ }
2987
3005
 
2988
- request.response = {
2989
- status: response.status(),
2990
- statusText: response.statusText(),
3006
+ return {
3007
+ url: resp.url(),
3008
+ response: {
3009
+ status: resp.status(),
3010
+ statusText: resp.statusText(),
2991
3011
  body,
2992
- };
2993
- },
2994
- ));
2995
- await Promise.all(promises);
3012
+ },
3013
+ };
3014
+ });
2996
3015
 
2997
- return this.requests;
3016
+ return Promise.all(promises);
2998
3017
  }
2999
3018
 
3000
3019
  /**
@@ -39,6 +39,9 @@ const findReact = require('./extras/React');
39
39
  const { highlightElement } = require('./scripts/highlightElement');
40
40
  const { blurElement } = require('./scripts/blurElement');
41
41
  const { focusElement } = require('./scripts/focusElement');
42
+ const {
43
+ dontSeeElementError, seeElementError, dontSeeElementInDOMError, seeElementInDOMError,
44
+ } = require('./errors/ElementAssertion');
42
45
 
43
46
  let puppeteer;
44
47
  let perfTiming;
@@ -1038,8 +1041,11 @@ class Puppeteer extends Helper {
1038
1041
  els = (await Promise.all(els.map(el => el.boundingBox() && el))).filter(v => v);
1039
1042
  // Puppeteer visibility was ignored? | Remove when Puppeteer is fixed
1040
1043
  els = await Promise.all(els.map(async el => (await el.evaluate(node => window.getComputedStyle(node).visibility !== 'hidden' && window.getComputedStyle(node).display !== 'none')) && el));
1041
-
1042
- return empty('visible elements').negate(els.filter(v => v).fill('ELEMENT'));
1044
+ try {
1045
+ return empty('visible elements').negate(els.filter(v => v).fill('ELEMENT'));
1046
+ } catch (e) {
1047
+ dontSeeElementError(locator);
1048
+ }
1043
1049
  }
1044
1050
 
1045
1051
  /**
@@ -1051,8 +1057,11 @@ class Puppeteer extends Helper {
1051
1057
  els = (await Promise.all(els.map(el => el.boundingBox() && el))).filter(v => v);
1052
1058
  // Puppeteer visibility was ignored? | Remove when Puppeteer is fixed
1053
1059
  els = await Promise.all(els.map(async el => (await el.evaluate(node => window.getComputedStyle(node).visibility !== 'hidden' && window.getComputedStyle(node).display !== 'none')) && el));
1054
-
1055
- return empty('visible elements').assert(els.filter(v => v).fill('ELEMENT'));
1060
+ try {
1061
+ return empty('visible elements').assert(els.filter(v => v).fill('ELEMENT'));
1062
+ } catch (e) {
1063
+ seeElementError(locator);
1064
+ }
1056
1065
  }
1057
1066
 
1058
1067
  /**
@@ -1060,7 +1069,11 @@ class Puppeteer extends Helper {
1060
1069
  */
1061
1070
  async seeElementInDOM(locator) {
1062
1071
  const els = await this._locate(locator);
1063
- return empty('elements on page').negate(els.filter(v => v).fill('ELEMENT'));
1072
+ try {
1073
+ return empty('elements on page').negate(els.filter(v => v).fill('ELEMENT'));
1074
+ } catch (e) {
1075
+ dontSeeElementInDOMError(locator);
1076
+ }
1064
1077
  }
1065
1078
 
1066
1079
  /**
@@ -1068,7 +1081,11 @@ class Puppeteer extends Helper {
1068
1081
  */
1069
1082
  async dontSeeElementInDOM(locator) {
1070
1083
  const els = await this._locate(locator);
1071
- return empty('elements on a page').assert(els.filter(v => v).fill('ELEMENT'));
1084
+ try {
1085
+ return empty('elements on a page').assert(els.filter(v => v).fill('ELEMENT'));
1086
+ } catch (e) {
1087
+ seeElementInDOMError(locator);
1088
+ }
1072
1089
  }
1073
1090
 
1074
1091
  /**
@@ -32,6 +32,9 @@ const { highlightElement } = require('./scripts/highlightElement');
32
32
  const store = require('../store');
33
33
  const { focusElement } = require('./scripts/focusElement');
34
34
  const { blurElement } = require('./scripts/blurElement');
35
+ const {
36
+ dontSeeElementError, seeElementError, seeElementInDOMError, dontSeeElementInDOMError,
37
+ } = require('./errors/ElementAssertion');
35
38
 
36
39
  const SHADOW = 'shadow';
37
40
  const webRoot = 'body';
@@ -1461,7 +1464,11 @@ class WebDriver extends Helper {
1461
1464
  const res = await this._locate(locator, true);
1462
1465
  assertElementExists(res, locator);
1463
1466
  const selected = await forEachAsync(res, async el => el.isDisplayed());
1464
- return truth(`elements of ${(new Locator(locator))}`, 'to be seen').assert(selected);
1467
+ try {
1468
+ return truth(`elements of ${(new Locator(locator))}`, 'to be seen').assert(selected);
1469
+ } catch (e) {
1470
+ dontSeeElementError(locator);
1471
+ }
1465
1472
  }
1466
1473
 
1467
1474
  /**
@@ -1474,7 +1481,11 @@ class WebDriver extends Helper {
1474
1481
  return truth(`elements of ${(new Locator(locator))}`, 'to be seen').negate(false);
1475
1482
  }
1476
1483
  const selected = await forEachAsync(res, async el => el.isDisplayed());
1477
- return truth(`elements of ${(new Locator(locator))}`, 'to be seen').negate(selected);
1484
+ try {
1485
+ return truth(`elements of ${(new Locator(locator))}`, 'to be seen').negate(selected);
1486
+ } catch (e) {
1487
+ seeElementError(locator);
1488
+ }
1478
1489
  }
1479
1490
 
1480
1491
  /**
@@ -1483,7 +1494,11 @@ class WebDriver extends Helper {
1483
1494
  */
1484
1495
  async seeElementInDOM(locator) {
1485
1496
  const res = await this._res(locator);
1486
- return empty('elements').negate(res);
1497
+ try {
1498
+ return empty('elements').negate(res);
1499
+ } catch (e) {
1500
+ dontSeeElementInDOMError(locator);
1501
+ }
1487
1502
  }
1488
1503
 
1489
1504
  /**
@@ -1492,7 +1507,11 @@ class WebDriver extends Helper {
1492
1507
  */
1493
1508
  async dontSeeElementInDOM(locator) {
1494
1509
  const res = await this._res(locator);
1495
- return empty('elements').assert(res);
1510
+ try {
1511
+ return empty('elements').assert(res);
1512
+ } catch (e) {
1513
+ seeElementInDOMError(locator);
1514
+ }
1496
1515
  }
1497
1516
 
1498
1517
  /**
@@ -0,0 +1,38 @@
1
+ const Locator = require('../../locator');
2
+
3
+ const prefixMessage = 'Element';
4
+
5
+ function seeElementError(locator) {
6
+ if (typeof locator === 'object') {
7
+ locator = JSON.stringify(locator);
8
+ }
9
+ throw new Error(`${prefixMessage} "${(new Locator(locator))}" is still visible on page.`);
10
+ }
11
+
12
+ function seeElementInDOMError(locator) {
13
+ if (typeof locator === 'object') {
14
+ locator = JSON.stringify(locator);
15
+ }
16
+ throw new Error(`${prefixMessage} "${(new Locator(locator))}" is still seen in DOM.`);
17
+ }
18
+
19
+ function dontSeeElementError(locator) {
20
+ if (typeof locator === 'object') {
21
+ locator = JSON.stringify(locator);
22
+ }
23
+ throw new Error(`${prefixMessage} "${(new Locator(locator))}" is not visible on page.`);
24
+ }
25
+
26
+ function dontSeeElementInDOMError(locator) {
27
+ if (typeof locator === 'object') {
28
+ locator = JSON.stringify(locator);
29
+ }
30
+ throw new Error(`${prefixMessage} "${(new Locator(locator))}" is not seen in DOM.`);
31
+ }
32
+
33
+ module.exports = {
34
+ seeElementError,
35
+ dontSeeElementError,
36
+ seeElementInDOMError,
37
+ dontSeeElementInDOMError,
38
+ };
package/lib/locator.js CHANGED
@@ -1,4 +1,4 @@
1
- let cssToXPath;
1
+ const cssToXPath = require('csstoxpath');
2
2
  const { sprintf } = require('sprintf-js');
3
3
 
4
4
  const { xpathLocator } = require('./utils');
@@ -162,17 +162,8 @@ class Locator {
162
162
  * @returns {string}
163
163
  */
164
164
  toXPath(pseudoSelector = '') {
165
- const locator = `${this.value}${pseudoSelector}`;
166
- const limitation = [':nth-of-type', ':first-of-type', ':last-of-type', ':nth-last-child', ':nth-last-of-type', ':checked', ':disabled', ':enabled', ':required', ':lang'];
167
-
168
- if (limitation.some(item => locator.includes(item))) {
169
- cssToXPath = require('css-to-xpath');
170
- } else {
171
- cssToXPath = require('csstoxpath');
172
- }
173
-
174
165
  if (this.isXPath()) return this.value;
175
- if (this.isCSS()) return cssToXPath(locator);
166
+ if (this.isCSS()) return cssToXPath(`${this.value}${pseudoSelector}`);
176
167
 
177
168
  throw new Error('Can\'t be converted to XPath');
178
169
  }
@@ -259,7 +250,7 @@ class Locator {
259
250
  */
260
251
  withText(text) {
261
252
  text = xpathLocator.literal(text);
262
- const xpath = sprintf('%s[%s]', this.toXPath(), `contains(., ${text})`);
253
+ const xpath = this.toXPath(`:text-contains-case(${text})`);
263
254
  return new Locator({ xpath });
264
255
  }
265
256
 
@@ -270,7 +261,7 @@ class Locator {
270
261
  */
271
262
  withTextEquals(text) {
272
263
  text = xpathLocator.literal(text);
273
- const xpath = sprintf('%s[%s]', this.toXPath(), `.= ${text}`);
264
+ const xpath = this.toXPath(`:text-case(${text})`);
274
265
  return new Locator({ xpath });
275
266
  }
276
267
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "3.5.12-beta.3",
3
+ "version": "3.5.12-beta.6",
4
4
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
5
5
  "keywords": [
6
6
  "acceptance",
@@ -76,15 +76,14 @@
76
76
  "axios": "1.6.3",
77
77
  "chai": "4.3.8",
78
78
  "chai-deep-match": "1.2.1",
79
- "chai-exclude": "2.1.0",
80
- "chai-json-schema": "1.5.1",
81
- "chai-json-schema-ajv": "5.2.4",
82
- "chai-match-pattern": "1.3.0",
83
- "chai-string": "1.5.0",
79
+ "chai-exclude": "^2.1.0",
80
+ "chai-json-schema": "^1.5.1",
81
+ "chai-json-schema-ajv": "^5.2.4",
82
+ "chai-match-pattern": "^1.3.0",
83
+ "chai-string": "^1.5.0",
84
84
  "chalk": "4.1.2",
85
85
  "commander": "11.1.0",
86
86
  "cross-spawn": "7.0.3",
87
- "css-to-xpath": "0.1.0",
88
87
  "csstoxpath": "1.6.0",
89
88
  "devtools": "8.27.2",
90
89
  "envinfo": "7.11.0",
@@ -93,7 +92,7 @@
93
92
  "fn-args": "4.0.0",
94
93
  "fs-extra": "11.2.0",
95
94
  "glob": "6.0.1",
96
- "html-minifier-terser": "7.2.0",
95
+ "html-minifier-terser": "^7.2.0",
97
96
  "inquirer": "6.5.2",
98
97
  "joi": "17.11.0",
99
98
  "js-beautify": "1.14.11",
@@ -119,7 +118,7 @@
119
118
  "@faker-js/faker": "7.6.0",
120
119
  "@pollyjs/adapter-puppeteer": "6.0.6",
121
120
  "@pollyjs/core": "5.1.0",
122
- "@types/chai": "4.3.7",
121
+ "@types/chai": "^4.3.7",
123
122
  "@types/inquirer": "9.0.3",
124
123
  "@types/node": "20.10.7",
125
124
  "@wdio/sauce-service": "8.27.0",