codeceptjs 2.4.3 → 2.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/CHANGELOG.md +117 -0
- package/README.md +32 -7
- package/bin/codecept.js +3 -0
- package/docs/basics.md +11 -5
- package/docs/bdd.md +4 -4
- package/docs/build/MockRequest.js +3 -0
- package/docs/build/Nightmare.js +10 -2
- package/docs/build/Playwright.js +3187 -0
- package/docs/build/Protractor.js +16 -2
- package/docs/build/Puppeteer.js +126 -19
- package/docs/build/REST.js +3 -1
- package/docs/build/TestCafe.js +11 -3
- package/docs/build/WebDriver.js +361 -28
- package/docs/changelog.md +116 -0
- package/docs/configuration.md +2 -2
- package/docs/custom-helpers.md +55 -10
- package/docs/helpers/Appium.md +81 -1
- package/docs/helpers/MockRequest.md +281 -38
- package/docs/helpers/Nightmare.md +10 -2
- package/docs/helpers/Playwright.md +1770 -0
- package/docs/helpers/Protractor.md +15 -3
- package/docs/helpers/Puppeteer-firefox.md +32 -1
- package/docs/helpers/Puppeteer.md +126 -76
- package/docs/helpers/TestCafe.md +10 -2
- package/docs/helpers/WebDriver.md +208 -118
- package/docs/locators.md +2 -0
- package/docs/playwright.md +306 -0
- package/docs/plugins.md +103 -0
- package/docs/reports.md +12 -0
- package/docs/shadow.md +68 -0
- package/docs/visual.md +0 -73
- package/docs/webapi/forceClick.mustache +27 -0
- package/docs/webapi/seeInPopup.mustache +7 -0
- package/docs/webapi/setCookie.mustache +10 -2
- package/docs/webapi/type.mustache +12 -0
- package/docs/webdriver.md +7 -3
- package/lib/codecept.js +1 -1
- package/lib/command/definitions.js +2 -2
- package/lib/command/generate.js +4 -4
- package/lib/command/gherkin/snippets.js +4 -4
- package/lib/command/init.js +1 -1
- package/lib/command/interactive.js +3 -0
- package/lib/command/run-multiple.js +2 -2
- package/lib/command/run-rerun.js +2 -0
- package/lib/command/run-workers.js +22 -8
- package/lib/command/run.js +2 -0
- package/lib/command/workers/runTests.js +1 -0
- package/lib/container.js +1 -1
- package/lib/event.js +2 -0
- package/lib/helper/MockRequest.js +3 -0
- package/lib/helper/Playwright.js +2422 -0
- package/lib/helper/Protractor.js +1 -2
- package/lib/helper/Puppeteer.js +84 -19
- package/lib/helper/REST.js +3 -1
- package/lib/helper/TestCafe.js +1 -1
- package/lib/helper/WebDriver.js +313 -26
- package/lib/helper/extras/PlaywrightPropEngine.js +53 -0
- package/lib/helper/scripts/isElementClickable.js +54 -14
- package/lib/interfaces/gherkin.js +1 -1
- package/lib/listener/helpers.js +3 -0
- package/lib/locator.js +5 -0
- package/lib/mochaFactory.js +12 -10
- package/lib/plugin/allure.js +8 -1
- package/lib/plugin/autoDelay.js +1 -8
- package/lib/plugin/commentStep.js +133 -0
- package/lib/plugin/screenshotOnFail.js +3 -10
- package/lib/plugin/selenoid.js +2 -2
- package/lib/plugin/standardActingHelpers.js +13 -0
- package/lib/plugin/stepByStepReport.js +1 -8
- package/lib/plugin/wdio.js +10 -1
- package/lib/reporter/cli.js +30 -1
- package/lib/session.js +7 -4
- package/package.json +13 -10
- package/typings/Mocha.d.ts +567 -16
- package/typings/index.d.ts +9 -5
- package/typings/types.d.ts +1634 -74
|
@@ -1,24 +1,64 @@
|
|
|
1
|
-
function isElementClickable(
|
|
2
|
-
if (!
|
|
1
|
+
function isElementClickable(element) {
|
|
2
|
+
if (!element.getBoundingClientRect || !element.scrollIntoView || !element.contains || !element.getClientRects || !document.elementFromPoint) {
|
|
3
3
|
return false;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
6
|
+
const getOverlappingElement = (element, context = document) => {
|
|
7
|
+
const elemDimension = element.getBoundingClientRect();
|
|
8
|
+
const x = elemDimension.left + (element.clientWidth / 2);
|
|
9
|
+
const y = elemDimension.top + (element.clientHeight / 2);
|
|
10
|
+
|
|
11
|
+
return context.elementFromPoint(x, y);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const getOverlappingRects = (element, context = document) => {
|
|
15
|
+
const rects = element.getClientRects();
|
|
16
|
+
const rect = rects[0];
|
|
17
|
+
const x = rect.left + (rect.width / 2);
|
|
18
|
+
const y = rect.top + (rect.height / 2);
|
|
19
|
+
|
|
20
|
+
return context.elementFromPoint(x, y);
|
|
11
21
|
};
|
|
12
22
|
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
23
|
+
const getOverlappingElements = (element, context) => {
|
|
24
|
+
return [getOverlappingElement(element, context), getOverlappingRects(element, context)];
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const isOverlappingElementMatch = (elementsFromPoint, element) => {
|
|
28
|
+
if (elementsFromPoint.some(elementFromPoint => elementFromPoint === element || element.contains(elementFromPoint))) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let elementsWithShadowRoot = [...new Set(elementsFromPoint)];
|
|
33
|
+
elementsWithShadowRoot = elementsWithShadowRoot.filter(elem => elem && elem.shadowRoot && elem.shadowRoot.elementFromPoint);
|
|
34
|
+
|
|
35
|
+
let shadowElementsFromPoint = [];
|
|
36
|
+
for (const shadowElement of elementsWithShadowRoot) {
|
|
37
|
+
shadowElementsFromPoint.push(...getOverlappingElements(element, shadowElement.shadowRoot));
|
|
38
|
+
}
|
|
39
|
+
shadowElementsFromPoint = [...new Set(shadowElementsFromPoint)];
|
|
40
|
+
shadowElementsFromPoint = shadowElementsFromPoint.filter(element => !elementsFromPoint.includes(element));
|
|
41
|
+
|
|
42
|
+
if (shadowElementsFromPoint.length === 0) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return isOverlappingElementMatch(shadowElementsFromPoint, element);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const isElementInViewport = (element) => {
|
|
50
|
+
const rect = element.getBoundingClientRect();
|
|
51
|
+
|
|
52
|
+
const windowHeight = (window.innerHeight || document.documentElement.clientHeight);
|
|
53
|
+
const windowWidth = (window.innerWidth || document.documentElement.clientWidth);
|
|
54
|
+
|
|
55
|
+
const vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) > 0);
|
|
56
|
+
const horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) > 0);
|
|
57
|
+
|
|
58
|
+
return (vertInView && horInView);
|
|
18
59
|
};
|
|
19
60
|
|
|
20
|
-
|
|
21
|
-
return isClickable(elem);
|
|
61
|
+
return element.disabled !== true && isElementInViewport(element) && isOverlappingElementMatch(getOverlappingElements(element), element);
|
|
22
62
|
}
|
|
23
63
|
|
|
24
64
|
module.exports = isElementClickable;
|
|
@@ -74,7 +74,7 @@ module.exports = (text) => {
|
|
|
74
74
|
return step;
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
|
-
const tags = child.tags.map(t => t.name);
|
|
77
|
+
const tags = child.tags.map(t => t.name).concat(examples.tags.map(t => t.name));
|
|
78
78
|
const title = `${child.name} ${JSON.stringify(current)} ${tags.join(' ')}`.trim();
|
|
79
79
|
const test = new Test(title, async () => runSteps(addExampleInTable(exampleSteps, current)));
|
|
80
80
|
test.tags = suite.tags.concat(tags);
|
package/lib/listener/helpers.js
CHANGED
package/lib/locator.js
CHANGED
|
@@ -3,6 +3,7 @@ const sprintf = require('sprintf-js').sprintf;
|
|
|
3
3
|
|
|
4
4
|
const xpathLocator = require('./utils').xpathLocator;
|
|
5
5
|
|
|
6
|
+
const locatorTypes = ['css', 'by', 'xpath', 'id', 'name', 'fuzzy', 'frame'];
|
|
6
7
|
/** @class */
|
|
7
8
|
class Locator {
|
|
8
9
|
/**
|
|
@@ -96,6 +97,10 @@ class Locator {
|
|
|
96
97
|
return this.type === 'xpath';
|
|
97
98
|
}
|
|
98
99
|
|
|
100
|
+
isCustom() {
|
|
101
|
+
return this.type && !locatorTypes.includes(this.type);
|
|
102
|
+
}
|
|
103
|
+
|
|
99
104
|
isStrict() {
|
|
100
105
|
return this.strict;
|
|
101
106
|
}
|
package/lib/mochaFactory.js
CHANGED
|
@@ -38,19 +38,21 @@ class MochaFactory {
|
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
mocha.loadFiles = (fn) => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
.
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
if (mocha.suite.suites.length === 0) {
|
|
42
|
+
// load features
|
|
43
|
+
mocha.files
|
|
44
|
+
.filter(file => file.match(/\.feature$/))
|
|
45
|
+
.map(file => fs.readFileSync(file, 'utf8'))
|
|
46
|
+
.forEach(content => mocha.suite.addSuite(gherkinParser(content)));
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
// remove feature files
|
|
49
|
+
mocha.files = mocha.files.filter(file => !file.match(/\.feature$/));
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
Mocha.prototype.loadFiles.call(mocha, fn);
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
// add ids for each test
|
|
54
|
+
mocha.suite.eachTest(test => test.id = genTestId(test));
|
|
55
|
+
}
|
|
54
56
|
};
|
|
55
57
|
|
|
56
58
|
// use standard reporter
|
package/lib/plugin/allure.js
CHANGED
|
@@ -72,6 +72,7 @@ const defaultConfig = {
|
|
|
72
72
|
*
|
|
73
73
|
*/
|
|
74
74
|
module.exports = (config) => {
|
|
75
|
+
defaultConfig.outputDir = global.output_dir;
|
|
75
76
|
config = Object.assign(defaultConfig, config);
|
|
76
77
|
|
|
77
78
|
const plugin = {};
|
|
@@ -215,7 +216,13 @@ module.exports = (config) => {
|
|
|
215
216
|
}
|
|
216
217
|
|
|
217
218
|
err.message = err.message.replace(ansiRegExp(), '');
|
|
218
|
-
reporter.
|
|
219
|
+
if (reporter.getCurrentTest()) {
|
|
220
|
+
reporter.endCase('failed', err);
|
|
221
|
+
} else {
|
|
222
|
+
// this means before suite failed, we should report this.
|
|
223
|
+
reporter.startCase(`BeforeSuite of suite ${reporter.getCurrentSuite().name} failed.`);
|
|
224
|
+
reporter.endCase('failed', err);
|
|
225
|
+
}
|
|
219
226
|
});
|
|
220
227
|
|
|
221
228
|
event.dispatcher.on(event.test.passed, () => {
|
package/lib/plugin/autoDelay.js
CHANGED
|
@@ -4,14 +4,7 @@ const recorder = require('../recorder');
|
|
|
4
4
|
const event = require('../event');
|
|
5
5
|
const log = require('../output').log;
|
|
6
6
|
|
|
7
|
-
const supportedHelpers =
|
|
8
|
-
'WebDriver',
|
|
9
|
-
'WebDriverIO',
|
|
10
|
-
'Protractor',
|
|
11
|
-
'Appium',
|
|
12
|
-
'Nightmare',
|
|
13
|
-
'Puppeteer',
|
|
14
|
-
];
|
|
7
|
+
const supportedHelpers = require('./standardActingHelpers');
|
|
15
8
|
|
|
16
9
|
const methodsToDelay = [
|
|
17
10
|
'click',
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
const event = require('../event');
|
|
2
|
+
const recorder = require('../recorder');
|
|
3
|
+
const { MetaStep } = require('../step');
|
|
4
|
+
|
|
5
|
+
let currentCommentStep;
|
|
6
|
+
|
|
7
|
+
const defaultGlobalName = '__';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Add descriptive nested steps for your tests:
|
|
11
|
+
*
|
|
12
|
+
* ```js
|
|
13
|
+
* Scenario('project update test', async (I) => {
|
|
14
|
+
* __`Given`;
|
|
15
|
+
* const projectId = await I.have('project');
|
|
16
|
+
*
|
|
17
|
+
* __`When`;
|
|
18
|
+
* projectPage.update(projectId, { title: 'new title' });
|
|
19
|
+
*
|
|
20
|
+
* __`Then`;
|
|
21
|
+
* projectPage.open(projectId);
|
|
22
|
+
* I.see('new title', 'h1');
|
|
23
|
+
* })
|
|
24
|
+
* ```
|
|
25
|
+
* Steps prefixed with `__` will be printed as nested steps in `--steps` output:
|
|
26
|
+
*
|
|
27
|
+
* ```
|
|
28
|
+
* Given
|
|
29
|
+
* I have "project"
|
|
30
|
+
* When
|
|
31
|
+
* projectPage update
|
|
32
|
+
* Then
|
|
33
|
+
* projectPage open
|
|
34
|
+
* I see "new title", "h1"
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* Also those steps will be exported to allure reports.
|
|
38
|
+
*
|
|
39
|
+
* This plugin can be used
|
|
40
|
+
*
|
|
41
|
+
* ### Config
|
|
42
|
+
*
|
|
43
|
+
* * `enabled` - (default: false) enable a plugin
|
|
44
|
+
* * `regusterGlobal` - (default: false) register `__` template literal function globally. You can override function global name by providing a name as a value.
|
|
45
|
+
*
|
|
46
|
+
* ### Examples
|
|
47
|
+
*
|
|
48
|
+
* Registering `__` globally:
|
|
49
|
+
*
|
|
50
|
+
* ```js
|
|
51
|
+
* plugins: {
|
|
52
|
+
* commentStep: {
|
|
53
|
+
* enabled: true,
|
|
54
|
+
* registerGlobal: true
|
|
55
|
+
* }
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* Registering `Step` globally:
|
|
60
|
+
* ```js
|
|
61
|
+
* plugins: {
|
|
62
|
+
* commentStep: {
|
|
63
|
+
* enabled: true,
|
|
64
|
+
* registerGlobal: 'Step'
|
|
65
|
+
* }
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* Using only local function names:
|
|
70
|
+
* ```js
|
|
71
|
+
* plugins: {
|
|
72
|
+
* commentStep: {
|
|
73
|
+
* enabled: true
|
|
74
|
+
* }
|
|
75
|
+
* }
|
|
76
|
+
* ```
|
|
77
|
+
* Then inside a test import a comment function from a plugin.
|
|
78
|
+
* For instance, you can prepare Given/When/Then functions to use them inside tests:
|
|
79
|
+
*
|
|
80
|
+
* ```js
|
|
81
|
+
* // inside a test
|
|
82
|
+
* const step = codeceptjs.container.plugins('commentStep');
|
|
83
|
+
*
|
|
84
|
+
* const Given = () => step`Given`;
|
|
85
|
+
* const When = () => step`When`;
|
|
86
|
+
* const Then = () => step`Then`;
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* Scenario('project update test', async (I) => {
|
|
90
|
+
* Given();
|
|
91
|
+
* const projectId = await I.have('project');
|
|
92
|
+
*
|
|
93
|
+
* When();
|
|
94
|
+
* projectPage.update(projectId, { title: 'new title' });
|
|
95
|
+
*
|
|
96
|
+
* Then();
|
|
97
|
+
* projectPage.open(projectId);
|
|
98
|
+
* I.see('new title', 'h1');
|
|
99
|
+
* });
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
module.exports = function (config) {
|
|
103
|
+
event.dispatcher.on(event.test.started, (test) => {
|
|
104
|
+
currentCommentStep = null;
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
event.dispatcher.on(event.step.started, (step) => {
|
|
108
|
+
if (currentCommentStep) {
|
|
109
|
+
const metaStep = getRootMetaStep(step);
|
|
110
|
+
metaStep.metaStep = currentCommentStep;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (config.registerGlobal) {
|
|
115
|
+
if (config.registerGlobal === true) {
|
|
116
|
+
config.registerGlobal = defaultGlobalName;
|
|
117
|
+
}
|
|
118
|
+
global[config.registerGlobal] = setCommentString;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return setCommentString;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
function getRootMetaStep(step) {
|
|
125
|
+
if (step.metaStep) return getRootMetaStep(step.metaStep);
|
|
126
|
+
return step;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function setCommentString(string) {
|
|
130
|
+
recorder.add('set comment metastep', () => {
|
|
131
|
+
currentCommentStep = new MetaStep(String.raw(string), '');
|
|
132
|
+
});
|
|
133
|
+
}
|
|
@@ -14,15 +14,7 @@ const defaultConfig = {
|
|
|
14
14
|
fullPageScreenshots: false,
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
const supportedHelpers =
|
|
18
|
-
'Mochawesome',
|
|
19
|
-
'WebDriverIO',
|
|
20
|
-
'WebDriver',
|
|
21
|
-
'Protractor',
|
|
22
|
-
'Appium',
|
|
23
|
-
'Nightmare',
|
|
24
|
-
'Puppeteer',
|
|
25
|
-
];
|
|
17
|
+
const supportedHelpers = require('./standardActingHelpers');
|
|
26
18
|
|
|
27
19
|
/**
|
|
28
20
|
* Creates screenshot on failure. Screenshot is saved into `output` directory.
|
|
@@ -126,6 +118,7 @@ module.exports = function (config) {
|
|
|
126
118
|
|| err.message.indexOf('no such window: target window already closed') > -1
|
|
127
119
|
)
|
|
128
120
|
) {
|
|
121
|
+
output.log(`Can't make screenshot, ${err}`);
|
|
129
122
|
helper.isRunning = false;
|
|
130
123
|
}
|
|
131
124
|
}
|
|
@@ -137,7 +130,7 @@ module.exports = function (config) {
|
|
|
137
130
|
return test.uuid;
|
|
138
131
|
}
|
|
139
132
|
|
|
140
|
-
if (test.ctx) {
|
|
133
|
+
if (test.ctx && test.ctx.test.uuid) {
|
|
141
134
|
return test.ctx.test.uuid;
|
|
142
135
|
}
|
|
143
136
|
|
package/lib/plugin/selenoid.js
CHANGED
|
@@ -3,7 +3,7 @@ const path = require('path');
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const axios = require('axios').default;
|
|
5
5
|
const exec = util.promisify(require('child_process').exec);
|
|
6
|
-
const { clearString } = require('../utils');
|
|
6
|
+
const { clearString, deepMerge } = require('../utils');
|
|
7
7
|
const {
|
|
8
8
|
container, event, recorder, output,
|
|
9
9
|
} = require('../index');
|
|
@@ -336,7 +336,7 @@ function deletePassedTests(passedTests) {
|
|
|
336
336
|
|
|
337
337
|
function setOptionsForWebdriver(config) {
|
|
338
338
|
const WebDriver = container.helpers('WebDriver');
|
|
339
|
-
WebDriver._setConfig(
|
|
339
|
+
WebDriver._setConfig(deepMerge(WebDriver.options, {
|
|
340
340
|
capabilities: { 'selenoid:options': config },
|
|
341
341
|
}));
|
|
342
342
|
}
|
|
@@ -11,14 +11,7 @@ const event = require('../event');
|
|
|
11
11
|
const output = require('../output');
|
|
12
12
|
const { template, deleteDir } = require('../utils');
|
|
13
13
|
|
|
14
|
-
const supportedHelpers =
|
|
15
|
-
'WebDriverIO',
|
|
16
|
-
'WebDriver',
|
|
17
|
-
'Protractor',
|
|
18
|
-
'Appium',
|
|
19
|
-
'Nightmare',
|
|
20
|
-
'Puppeteer',
|
|
21
|
-
];
|
|
14
|
+
const supportedHelpers = require('./standardActingHelpers');
|
|
22
15
|
|
|
23
16
|
const defaultConfig = {
|
|
24
17
|
deleteSuccessful: true,
|
package/lib/plugin/wdio.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const debug = require('debug')('codeceptjs:plugin:wdio');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
2
4
|
|
|
3
5
|
const container = require('../container');
|
|
4
6
|
const mainConfig = require('../config');
|
|
@@ -99,7 +101,14 @@ module.exports = (config) => {
|
|
|
99
101
|
if (Service) {
|
|
100
102
|
if (Service.launcher && typeof Service.launcher === 'function') {
|
|
101
103
|
const Launcher = Service.launcher;
|
|
102
|
-
|
|
104
|
+
|
|
105
|
+
const version = JSON.parse(fs.readFileSync(path.join(require.resolve('webdriverio'), '/../../', 'package.json')).toString()).version;
|
|
106
|
+
if (version.indexOf('5') === 0) {
|
|
107
|
+
launchers.push(new Launcher(config));
|
|
108
|
+
} else {
|
|
109
|
+
const options = { logPath: global.output_dir, installArgs: {}, args: {} };
|
|
110
|
+
launchers.push(new Launcher(options, [config.capabilities], config));
|
|
111
|
+
}
|
|
103
112
|
}
|
|
104
113
|
if (typeof Service === 'function') {
|
|
105
114
|
services.push(new Service(config, config.capabilities));
|
package/lib/reporter/cli.js
CHANGED
|
@@ -11,11 +11,11 @@ class Cli extends Base {
|
|
|
11
11
|
constructor(runner, opts) {
|
|
12
12
|
super(runner);
|
|
13
13
|
let level = 0;
|
|
14
|
+
this.failedTests = [];
|
|
14
15
|
opts = opts.reporterOptions || opts;
|
|
15
16
|
if (opts.steps) level = 1;
|
|
16
17
|
if (opts.debug) level = 2;
|
|
17
18
|
if (opts.verbose) level = 3;
|
|
18
|
-
|
|
19
19
|
output.level(level);
|
|
20
20
|
output.print(`CodeceptJS v${require('../codecept').version()}`);
|
|
21
21
|
output.print(`Using test root "${global.codecept_dir}"`);
|
|
@@ -42,6 +42,9 @@ class Cli extends Base {
|
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
runner.on('fail', (test, err) => {
|
|
45
|
+
if (test.ctx.currentTest) {
|
|
46
|
+
this.failedTests.push(test.ctx.currentTest.id);
|
|
47
|
+
}
|
|
45
48
|
if (showSteps && test.steps) {
|
|
46
49
|
return output.scenario.failed(test);
|
|
47
50
|
}
|
|
@@ -90,6 +93,24 @@ class Cli extends Base {
|
|
|
90
93
|
});
|
|
91
94
|
}
|
|
92
95
|
|
|
96
|
+
runner.on('suite end', suite => {
|
|
97
|
+
let skippedCount = 0;
|
|
98
|
+
const grep = runner._grep;
|
|
99
|
+
for (const test of suite.tests) {
|
|
100
|
+
if (!test.state && !this.failedTests.includes(test.id)) {
|
|
101
|
+
if (matchTest(grep, test.title)) {
|
|
102
|
+
event.emit(event.test.skipped, test);
|
|
103
|
+
test.state = 'skipped';
|
|
104
|
+
output.test.skipped(test);
|
|
105
|
+
skippedCount += 1;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
this.stats.pending += skippedCount;
|
|
111
|
+
this.stats.tests += skippedCount;
|
|
112
|
+
});
|
|
113
|
+
|
|
93
114
|
runner.on('end', this.result.bind(this));
|
|
94
115
|
}
|
|
95
116
|
|
|
@@ -129,6 +150,14 @@ class Cli extends Base {
|
|
|
129
150
|
output.result(stats.passes, stats.failures, stats.pending, ms(stats.duration));
|
|
130
151
|
}
|
|
131
152
|
}
|
|
153
|
+
|
|
154
|
+
function matchTest(grep, test) {
|
|
155
|
+
if (grep) {
|
|
156
|
+
return grep.test(test);
|
|
157
|
+
}
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
|
|
132
161
|
module.exports = function (runner, opts) {
|
|
133
162
|
return new Cli(runner, opts);
|
|
134
163
|
};
|
package/lib/session.js
CHANGED
|
@@ -58,14 +58,16 @@ function session(sessionName, config, fn) {
|
|
|
58
58
|
delete savedSessions[sessionName];
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
-
event.dispatcher.once(event.test.
|
|
61
|
+
event.dispatcher.once(event.test.after, () => {
|
|
62
|
+
recorder.add('close session browsers', closeBrowsers);
|
|
63
|
+
});
|
|
62
64
|
|
|
63
65
|
if (!savedSessions[sessionName]) {
|
|
64
66
|
throw new Error('Configured helpers do not support starting sessions. Please use a helper with session support.');
|
|
65
67
|
}
|
|
66
68
|
|
|
67
69
|
recorder.add('save vars', async () => {
|
|
68
|
-
savedSessions[sessionName].vars = await savedSessions[sessionName].start(config);
|
|
70
|
+
savedSessions[sessionName].vars = await savedSessions[sessionName].start(sessionName, config);
|
|
69
71
|
});
|
|
70
72
|
}
|
|
71
73
|
|
|
@@ -97,13 +99,14 @@ function session(sessionName, config, fn) {
|
|
|
97
99
|
});
|
|
98
100
|
};
|
|
99
101
|
|
|
102
|
+
// Indicate when executing this function that we are in a session
|
|
100
103
|
if (isAsyncFunction(fn)) {
|
|
101
104
|
return fn.apply(null).then((res) => {
|
|
102
105
|
finalize();
|
|
103
106
|
return recorder.promise().then(() => res);
|
|
104
107
|
}).catch((e) => {
|
|
105
108
|
output.stepShift = 0;
|
|
106
|
-
session.restoreVars();
|
|
109
|
+
session.restoreVars(sessionName);
|
|
107
110
|
event.dispatcher.removeListener(event.step.after, addContextToStep);
|
|
108
111
|
recorder.throw(e);
|
|
109
112
|
return recorder.promise();
|
|
@@ -117,7 +120,7 @@ function session(sessionName, config, fn) {
|
|
|
117
120
|
recorder.throw(err);
|
|
118
121
|
} finally {
|
|
119
122
|
recorder.catch((e) => {
|
|
120
|
-
session.restoreVars();
|
|
123
|
+
session.restoreVars(sessionName);
|
|
121
124
|
output.stepShift = 0;
|
|
122
125
|
event.dispatcher.removeListener(event.step.after, addContextToStep);
|
|
123
126
|
throw e;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeceptjs",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.2",
|
|
4
4
|
"description": "Supercharged End 2 End Testing Framework for NodeJS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"acceptance",
|
|
@@ -46,11 +46,11 @@
|
|
|
46
46
|
"test": "npm run test:unit && npm run test:runner",
|
|
47
47
|
"def": "./runio.js def",
|
|
48
48
|
"dev:graphql": "nodemon test/data/graphql/index.js",
|
|
49
|
-
"publish:site": "./runio.js publish:site"
|
|
49
|
+
"publish:site": "./runio.js publish:site",
|
|
50
|
+
"update-contributor-faces": "contributor-faces ."
|
|
50
51
|
},
|
|
51
52
|
"dependencies": {
|
|
52
53
|
"@codeceptjs/configure": "^0.4.0",
|
|
53
|
-
"@types/mocha": "^5.2.7",
|
|
54
54
|
"allure-js-commons": "^1.3.2",
|
|
55
55
|
"arrify": "^2.0.1",
|
|
56
56
|
"axios": "^0.19.1",
|
|
@@ -69,19 +69,20 @@
|
|
|
69
69
|
"js-beautify": "^1.10.2",
|
|
70
70
|
"lodash.clonedeep": "^4.5.0",
|
|
71
71
|
"lodash.merge": "^4.6.2",
|
|
72
|
-
"mkdirp": "^0.
|
|
72
|
+
"mkdirp": "^1.0.3",
|
|
73
73
|
"mocha": "^6.2.2",
|
|
74
74
|
"mocha-junit-reporter": "^1.23.1",
|
|
75
75
|
"ms": "^2.1.2",
|
|
76
76
|
"parse-function": "^5.5.0",
|
|
77
77
|
"promise-retry": "^1.1.1",
|
|
78
|
-
"requireg": "^0.
|
|
78
|
+
"requireg": "^0.2.2",
|
|
79
79
|
"resq": "^1.7.0",
|
|
80
80
|
"semver": "^6.2.0",
|
|
81
81
|
"sprintf-js": "^1.1.1"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@codeceptjs/detox-helper": "^1.0.2",
|
|
85
|
+
"@codeceptjs/mock-request": "^0.3.0",
|
|
85
86
|
"@pollyjs/adapter-puppeteer": "^2.6.3",
|
|
86
87
|
"@pollyjs/core": "^2.6.3",
|
|
87
88
|
"@types/inquirer": "^0.0.35",
|
|
@@ -93,6 +94,7 @@
|
|
|
93
94
|
"chai": "^3.4.1",
|
|
94
95
|
"chai-as-promised": "^5.2.0",
|
|
95
96
|
"chai-subset": "^1.6.0",
|
|
97
|
+
"contributor-faces": "^1.0.3",
|
|
96
98
|
"documentation": "^12.1.4",
|
|
97
99
|
"eslint": "^6.8.0",
|
|
98
100
|
"eslint-config-airbnb-base": "^14.0.0",
|
|
@@ -105,10 +107,12 @@
|
|
|
105
107
|
"jsdoc": "^3.6.2",
|
|
106
108
|
"jsdoc-typeof-plugin": "^1.0.0",
|
|
107
109
|
"json-server": "^0.10.1",
|
|
110
|
+
"mocha-parallel-tests": "^2.2.2",
|
|
108
111
|
"nightmare": "^3.0.2",
|
|
109
112
|
"nodemon": "^1.19.4",
|
|
113
|
+
"playwright": "^0.14.0",
|
|
110
114
|
"protractor": "^5.4.1",
|
|
111
|
-
"puppeteer": "^
|
|
115
|
+
"puppeteer": "^3.0.0",
|
|
112
116
|
"qrcode-terminal": "^0.12.0",
|
|
113
117
|
"rosie": "^1.6.0",
|
|
114
118
|
"runio.js": "^1.0.20",
|
|
@@ -119,10 +123,9 @@
|
|
|
119
123
|
"tsd-jsdoc": "^2.3.0",
|
|
120
124
|
"typescript": "^2.9.2",
|
|
121
125
|
"wdio-docker-service": "^1.5.0",
|
|
122
|
-
"webdriverio": "^
|
|
126
|
+
"webdriverio": "^6.0.4",
|
|
123
127
|
"xmldom": "^0.1.31",
|
|
124
|
-
"xpath": "0.0.27"
|
|
125
|
-
"mocha-parallel-tests": "^2.2.2"
|
|
128
|
+
"xpath": "0.0.27"
|
|
126
129
|
},
|
|
127
130
|
"engines": {
|
|
128
131
|
"node": ">=8.9.1",
|
|
@@ -132,7 +135,7 @@
|
|
|
132
135
|
"husky": {
|
|
133
136
|
"hooks": {
|
|
134
137
|
"pre-commit": "npm run lint",
|
|
135
|
-
"pre-push": "npm run lint && npm run test"
|
|
138
|
+
"pre-push": "npm run lint && npm run test:unit"
|
|
136
139
|
}
|
|
137
140
|
}
|
|
138
141
|
}
|