codeceptjs 3.6.2-beta.1 → 3.6.2

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.
package/README.md CHANGED
@@ -46,7 +46,7 @@ CodeceptJS uses **Helper** modules to provide actions to `I` object. Currently,
46
46
 
47
47
  * [**Playwright**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/Playwright.md) - is a Node library to automate the Chromium, WebKit and Firefox browsers with a single API.
48
48
  * [**Puppeteer**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/Puppeteer.md) - uses Google Chrome's Puppeteer for fast headless testing.
49
- * [**WebDriver**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/WebDriver.md) - uses [webdriverio](http://webdriver.io/) to run tests via WebDriver protocol.
49
+ * [**WebDriver**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/WebDriver.md) - uses [webdriverio](http://webdriver.io/) to run tests via WebDriver or Devtools protocol.
50
50
  * [**TestCafe**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/TestCafe.md) - cheap and fast cross-browser test automation.
51
51
  * [**Appium**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/Appium.md) - for **mobile testing** with Appium
52
52
  * [**Detox**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/Detox.md) - This is a wrapper on top of Detox library, aimed to unify testing experience for CodeceptJS framework. Detox provides a grey box testing for mobile applications, playing especially well for React Native apps.
@@ -3115,8 +3115,6 @@ class Playwright extends Helper {
3115
3115
  /**
3116
3116
  * Returns full URL of request matching parameter "urlMatch".
3117
3117
  *
3118
- * @param {string|RegExp} urlMatch Expected URL of request in network traffic. Can be a string or a regular expression.
3119
- *
3120
3118
  * Examples:
3121
3119
  *
3122
3120
  * ```js
@@ -3124,6 +3122,7 @@ class Playwright extends Helper {
3124
3122
  * I.grabTrafficUrl(/session.*start/);
3125
3123
  * ```
3126
3124
  *
3125
+ * @param {string|RegExp} urlMatch Expected URL of request in network traffic. Can be a string or a regular expression.
3127
3126
  * @return {Promise<*>}
3128
3127
  */
3129
3128
  grabTrafficUrl(urlMatch) {
@@ -1,5 +1,6 @@
1
1
  const axios = require('axios').default;
2
2
  const Helper = require('@codeceptjs/helper');
3
+ const { Agent } = require('https');
3
4
  const Secret = require('../secret');
4
5
 
5
6
  const { beautify } = require('../utils');
@@ -13,6 +14,7 @@ const { beautify } = require('../utils');
13
14
  * @prop {boolean} [prettyPrintJson=false] - pretty print json for response/request on console logs
14
15
  * @prop {number} [timeout=1000] - timeout for requests in milliseconds. 10000ms by default
15
16
  * @prop {object} [defaultHeaders] - a list of default headers
17
+ * @prop {object} [httpAgent] - create an agent with SSL certificate
16
18
  * @prop {function} [onRequest] - a async function which can update request object.
17
19
  * @prop {function} [onResponse] - a async function which can update response object.
18
20
  * @prop {number} [maxUploadFileSize] - set the max content file size in MB when performing api calls.
@@ -40,6 +42,24 @@ const config = {};
40
42
  * }
41
43
  *}
42
44
  * ```
45
+ * With httpAgent
46
+ *
47
+ * ```js
48
+ * {
49
+ * helpers: {
50
+ * REST: {
51
+ * endpoint: 'http://site.com/api',
52
+ * prettyPrintJson: true,
53
+ * httpAgent: {
54
+ * key: fs.readFileSync(__dirname + '/path/to/keyfile.key'),
55
+ * cert: fs.readFileSync(__dirname + '/path/to/certfile.cert'),
56
+ * rejectUnauthorized: false,
57
+ * keepAlive: true
58
+ * }
59
+ * }
60
+ * }
61
+ * }
62
+ * ```
43
63
  *
44
64
  * ## Access From Helpers
45
65
  *
@@ -76,7 +96,14 @@ class REST extends Helper {
76
96
  this._setConfig(config);
77
97
 
78
98
  this.headers = { ...this.options.defaultHeaders };
79
- this.axios = axios.create();
99
+
100
+ // Create an agent with SSL certificate
101
+ if (this.options.httpAgent) {
102
+ if (!this.options.httpAgent.key || !this.options.httpAgent.cert) throw Error('Please recheck your httpAgent config!');
103
+ this.httpsAgent = new Agent(this.options.httpAgent);
104
+ }
105
+
106
+ this.axios = this.httpsAgent ? axios.create({ httpsAgent: this.httpsAgent }) : axios.create();
80
107
  // @ts-ignore
81
108
  this.axios.defaults.headers = this.options.defaultHeaders;
82
109
  }
@@ -1795,14 +1795,21 @@ class WebDriver extends Helper {
1795
1795
  * {{> saveScreenshot }}
1796
1796
  */
1797
1797
  async saveScreenshot(fileName, fullPage = false) {
1798
- const outputFile = screenshotOutputFolder(fileName);
1798
+ let outputFile = screenshotOutputFolder(fileName);
1799
1799
 
1800
1800
  if (this.activeSessionName) {
1801
1801
  const browser = this.sessionWindows[this.activeSessionName];
1802
1802
 
1803
- if (browser) {
1804
- this.debug(`Screenshot of ${this.activeSessionName} session has been saved to ${outputFile}`);
1805
- return browser.saveScreenshot(outputFile);
1803
+ for (const sessionName in this.sessionWindows) {
1804
+ const activeSessionPage = this.sessionWindows[sessionName];
1805
+ outputFile = screenshotOutputFolder(`${sessionName}_${fileName}`);
1806
+
1807
+ this.debug(`${sessionName} - Screenshot is saving to ${outputFile}`);
1808
+
1809
+ if (browser) {
1810
+ this.debug(`Screenshot of ${sessionName} session has been saved to ${outputFile}`);
1811
+ return browser.saveScreenshot(outputFile);
1812
+ }
1806
1813
  }
1807
1814
  }
1808
1815
 
package/lib/locator.js CHANGED
@@ -299,6 +299,15 @@ class Locator {
299
299
  return new Locator({ xpath });
300
300
  }
301
301
 
302
+ /**
303
+ * @param {String} text
304
+ * @returns {Locator}
305
+ */
306
+ withClassAttr(text) {
307
+ const xpath = sprintf('%s[%s]', this.toXPath(), `contains(@class, '${text}')`);
308
+ return new Locator({ xpath });
309
+ }
310
+
302
311
  /**
303
312
  * @param {string} output
304
313
  * @returns {Locator}
@@ -110,7 +110,8 @@ module.exports = function (config) {
110
110
  allureReporter.addAttachment('Main session - Last Seen Screenshot', fs.readFileSync(path.join(global.output_dir, fileName)), dataType);
111
111
 
112
112
  if (helper.activeSessionName) {
113
- for (const sessionName in helper.sessionPages) {
113
+ const sessions = helper.sessionPages || helper.sessionWindows;
114
+ for (const sessionName in sessions) {
114
115
  const screenshotFileName = `${sessionName}_${fileName}`;
115
116
  test.artifacts[`${sessionName.replace(/ /g, '_')}_screenshot`] = path.join(global.output_dir, screenshotFileName);
116
117
  allureReporter.addAttachment(`${sessionName} - Last Seen Screenshot`, fs.readFileSync(path.join(global.output_dir, screenshotFileName)), dataType);
@@ -112,11 +112,13 @@ module.exports = function (config) {
112
112
  });
113
113
 
114
114
  event.dispatcher.on(event.test.failed, (test, err) => {
115
+ // BeforeSuite/AfterSuite don't have any access to the browser, hence it could not take screenshot.
116
+ if (test.ctx._runnable.title.includes('hook: BeforeSuite')) return;
115
117
  persist(test, err);
116
118
  });
117
119
 
118
120
  event.dispatcher.on(event.all.result, () => {
119
- if (!Object.keys(slides).length) return;
121
+ if (Object.keys(recordedTests).length === 0 || !Object.keys(slides).length) return;
120
122
 
121
123
  let links = '';
122
124
 
@@ -148,7 +150,7 @@ module.exports = function (config) {
148
150
  stepNum++;
149
151
  slides[fileName] = step;
150
152
  try {
151
- await helper.saveScreenshot(path.relative(reportDir, path.join(dir, fileName)), config.fullPageScreenshots);
153
+ await helper.saveScreenshot(path.join(dir, fileName), config.fullPageScreenshots);
152
154
  } catch (err) {
153
155
  output.plugin(`Can't save step screenshot: ${err}`);
154
156
  error = err;
package/lib/utils.js CHANGED
@@ -291,7 +291,7 @@ module.exports.screenshotOutputFolder = function (fileName) {
291
291
  const fileSep = path.sep;
292
292
 
293
293
  if (!fileName.includes(fileSep) || fileName.includes('record_')) {
294
- return path.join(global.output_dir, fileName);
294
+ return path.resolve(global.output_dir, fileName);
295
295
  }
296
296
  return path.resolve(global.codecept_dir, fileName);
297
297
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "3.6.2-beta.1",
3
+ "version": "3.6.2",
4
4
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
5
5
  "keywords": [
6
6
  "acceptance",
@@ -98,7 +98,7 @@
98
98
  "glob": "6.0.1",
99
99
  "html-minifier-terser": "7.2.0",
100
100
  "inquirer": "6.5.2",
101
- "joi": "17.12.3",
101
+ "joi": "17.13.0",
102
102
  "js-beautify": "1.15.1",
103
103
  "lodash.clonedeep": "4.5.0",
104
104
  "lodash.merge": "4.6.2",
@@ -128,14 +128,14 @@
128
128
  "@types/node": "20.11.30",
129
129
  "@wdio/sauce-service": "8.35.1",
130
130
  "@wdio/selenium-standalone-service": "8.3.2",
131
- "@wdio/utils": "8.33.1",
131
+ "@wdio/utils": "8.36.1",
132
132
  "@xmldom/xmldom": "0.8.10",
133
133
  "apollo-server-express": "2.25.3",
134
134
  "chai-as-promised": "7.1.1",
135
135
  "chai-subset": "1.6.0",
136
136
  "contributor-faces": "1.1.0",
137
137
  "documentation": "12.3.0",
138
- "electron": "28.2.1",
138
+ "electron": "30.0.1",
139
139
  "eslint": "8.56.0",
140
140
  "eslint-config-airbnb-base": "15.0.0",
141
141
  "eslint-plugin-import": "2.29.1",
@@ -164,7 +164,7 @@
164
164
  "typedoc-plugin-markdown": "3.17.1",
165
165
  "typescript": "5.3.3",
166
166
  "wdio-docker-service": "1.5.0",
167
- "webdriverio": "8.35.1",
167
+ "webdriverio": "8.36.1",
168
168
  "xml2js": "0.6.2",
169
169
  "xpath": "0.0.34"
170
170
  },
@@ -179,4 +179,4 @@
179
179
  "strict": false
180
180
  }
181
181
  }
182
- }
182
+ }
@@ -1154,7 +1154,6 @@ declare namespace CodeceptJS {
1154
1154
  *
1155
1155
  * ## Methods
1156
1156
  */
1157
- // @ts-ignore
1158
1157
  class ExpectHelper {
1159
1158
  expectEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise<any>;
1160
1159
  expectNotEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise<any>;
@@ -1781,7 +1780,6 @@ declare namespace CodeceptJS {
1781
1780
  * @property [host = "0.0.0.0"] - Mock server host
1782
1781
  * @property [httpsOpts] - key & cert values are the paths to .key and .crt files
1783
1782
  */
1784
- // @ts-ignore
1785
1783
  type MockServerConfig = {
1786
1784
  port?: number;
1787
1785
  host?: string;
@@ -1906,7 +1904,6 @@ declare namespace CodeceptJS {
1906
1904
  *
1907
1905
  * ## Methods
1908
1906
  */
1909
- // @ts-ignore
1910
1907
  class MockServer {
1911
1908
  /**
1912
1909
  * Start the mock server
@@ -4828,7 +4825,6 @@ declare namespace CodeceptJS {
4828
4825
  stopRecordingTraffic(): Promise<any>;
4829
4826
  /**
4830
4827
  * Returns full URL of request matching parameter "urlMatch".
4831
- * @param urlMatch - Expected URL of request in network traffic. Can be a string or a regular expression.
4832
4828
  *
4833
4829
  * Examples:
4834
4830
  *
@@ -4836,6 +4832,7 @@ declare namespace CodeceptJS {
4836
4832
  * I.grabTrafficUrl('https://api.example.com/session');
4837
4833
  * I.grabTrafficUrl(/session.*start/);
4838
4834
  * ```
4835
+ * @param urlMatch - Expected URL of request in network traffic. Can be a string or a regular expression.
4839
4836
  */
4840
4837
  grabTrafficUrl(urlMatch: string | RegExp): Promise<any>;
4841
4838
  /**
@@ -8031,6 +8028,24 @@ declare namespace CodeceptJS {
8031
8028
  * }
8032
8029
  * }
8033
8030
  * ```
8031
+ * With httpAgent
8032
+ *
8033
+ * ```js
8034
+ * {
8035
+ * helpers: {
8036
+ * REST: {
8037
+ * endpoint: 'http://site.com/api',
8038
+ * prettyPrintJson: true,
8039
+ * httpAgent: {
8040
+ * key: fs.readFileSync(__dirname + '/path/to/keyfile.key'),
8041
+ * cert: fs.readFileSync(__dirname + '/path/to/certfile.cert'),
8042
+ * rejectUnauthorized: false,
8043
+ * keepAlive: true
8044
+ * }
8045
+ * }
8046
+ * }
8047
+ * }
8048
+ * ```
8034
8049
  *
8035
8050
  * ## Access From Helpers
8036
8051
  *
@@ -1178,7 +1178,6 @@ declare namespace CodeceptJS {
1178
1178
  *
1179
1179
  * ## Methods
1180
1180
  */
1181
- // @ts-ignore
1182
1181
  class ExpectHelper {
1183
1182
  expectEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): void;
1184
1183
  expectNotEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): void;
@@ -1808,7 +1807,6 @@ declare namespace CodeceptJS {
1808
1807
  * @property [host = "0.0.0.0"] - Mock server host
1809
1808
  * @property [httpsOpts] - key & cert values are the paths to .key and .crt files
1810
1809
  */
1811
- // @ts-ignore
1812
1810
  type MockServerConfig = {
1813
1811
  port?: number;
1814
1812
  host?: string;
@@ -1933,7 +1931,6 @@ declare namespace CodeceptJS {
1933
1931
  *
1934
1932
  * ## Methods
1935
1933
  */
1936
- // @ts-ignore
1937
1934
  class MockServer {
1938
1935
  /**
1939
1936
  * Start the mock server
@@ -5079,7 +5076,6 @@ declare namespace CodeceptJS {
5079
5076
  stopRecordingTraffic(): void;
5080
5077
  /**
5081
5078
  * Returns full URL of request matching parameter "urlMatch".
5082
- * @param urlMatch - Expected URL of request in network traffic. Can be a string or a regular expression.
5083
5079
  *
5084
5080
  * Examples:
5085
5081
  *
@@ -5087,6 +5083,7 @@ declare namespace CodeceptJS {
5087
5083
  * I.grabTrafficUrl('https://api.example.com/session');
5088
5084
  * I.grabTrafficUrl(/session.*start/);
5089
5085
  * ```
5086
+ * @param urlMatch - Expected URL of request in network traffic. Can be a string or a regular expression.
5090
5087
  */
5091
5088
  grabTrafficUrl(urlMatch: string | RegExp): Promise<any>;
5092
5089
  /**
@@ -8528,6 +8525,7 @@ declare namespace CodeceptJS {
8528
8525
  * @property [prettyPrintJson = false] - pretty print json for response/request on console logs
8529
8526
  * @property [timeout = 1000] - timeout for requests in milliseconds. 10000ms by default
8530
8527
  * @property [defaultHeaders] - a list of default headers
8528
+ * @property [httpAgent] - create an agent with SSL certificate
8531
8529
  * @property [onRequest] - a async function which can update request object.
8532
8530
  * @property [onResponse] - a async function which can update response object.
8533
8531
  * @property [maxUploadFileSize] - set the max content file size in MB when performing api calls.
@@ -8537,6 +8535,7 @@ declare namespace CodeceptJS {
8537
8535
  prettyPrintJson?: boolean;
8538
8536
  timeout?: number;
8539
8537
  defaultHeaders?: any;
8538
+ httpAgent?: any;
8540
8539
  onRequest?: (...params: any[]) => any;
8541
8540
  onResponse?: (...params: any[]) => any;
8542
8541
  maxUploadFileSize?: number;
@@ -8562,6 +8561,24 @@ declare namespace CodeceptJS {
8562
8561
  * }
8563
8562
  * }
8564
8563
  * ```
8564
+ * With httpAgent
8565
+ *
8566
+ * ```js
8567
+ * {
8568
+ * helpers: {
8569
+ * REST: {
8570
+ * endpoint: 'http://site.com/api',
8571
+ * prettyPrintJson: true,
8572
+ * httpAgent: {
8573
+ * key: fs.readFileSync(__dirname + '/path/to/keyfile.key'),
8574
+ * cert: fs.readFileSync(__dirname + '/path/to/certfile.cert'),
8575
+ * rejectUnauthorized: false,
8576
+ * keepAlive: true
8577
+ * }
8578
+ * }
8579
+ * }
8580
+ * }
8581
+ * ```
8565
8582
  *
8566
8583
  * ## Access From Helpers
8567
8584
  *
@@ -12158,6 +12175,7 @@ declare namespace CodeceptJS {
12158
12175
  withAttr(attributes: {
12159
12176
  [key: string]: string;
12160
12177
  }): Locator;
12178
+ withClassAttr(text: string): Locator;
12161
12179
  as(output: string): Locator;
12162
12180
  inside(locator: CodeceptJS.LocatorOrString): Locator;
12163
12181
  after(locator: CodeceptJS.LocatorOrString): Locator;