Skip to content

Commit a79a725

Browse files
APshenkinDavertMik
authored andcommitted
Fix work with promise chains (#568)
* Run after block after test fails * fix interface test * fix formatting * refactor work with chains * fix typo * remove second after * correct chain order * fix formatting * Add compliting _after _afterSuite if after hooks failed * fix formatting * Add new hook finishTest * fix formatting * return recorder back * fix formatting * add closing tabs for Protractor and selenium * fix formatting * fix uppercase * fix hooks * clear localstorage and close tabs with keepCookies flag * fix formatting * Fixes * remove defenition * add step execution time in Verbose mode * fix formatting * Add step execution time to output * fix formatting * fixes after review * fix formatting * fix typo * fix tests with generator * fix formatting * add mochaFile override * add report file name in override config for junit reporter
1 parent ba92e1b commit a79a725

16 files changed

Lines changed: 216 additions & 64 deletions

File tree

‎lib/actor.js‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,17 @@ function recordStep(step, args) {
6161
val = step.run.apply(step, args);
6262
});
6363

64+
// ensure step result is passed to next step
65+
recorder.add('return step result', () => val);
66+
67+
//return execution time for logging
68+
recorder.add(`return execution time`, () => {
69+
output.stepExecutionTime(step, global.suiteDetails);
70+
return val;
71+
});
72+
6473
// run async after step hooks
6574
event.emit(event.step.after, step);
6675

67-
// ensure step result is passed to next step
68-
recorder.add('return step result', () => val);
6976
return recorder.promise();
7077
}

‎lib/command/run-multiple.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ function runSuite(suite, suiteConf, browser) {
9393
// tweaking default output directories and for mochawesome
9494
overriddenConfig = replaceValue(overriddenConfig, 'output', path.join(config.output, outputDir));
9595
overriddenConfig = replaceValue(overriddenConfig, 'reportDir', path.join(config.output, outputDir));
96+
overriddenConfig = replaceValue(overriddenConfig, 'mochaFile', path.join(config.output, outputDir, 'report.xml'));
9697

9798
// override grep param and collect all params
9899
let params = ['run',

‎lib/event.js‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ module.exports = {
1111
passed: 'test.passed',
1212
failed: 'test.failed',
1313
},
14+
hook: {
15+
afterSuite: {
16+
failed: 'afterSuiteHook.failed',
17+
},
18+
after: {
19+
failed: 'afterTestHook.failed'
20+
}
21+
},
1422
suite: {
1523
before: 'suite.before',
1624
after: 'suite.after'

‎lib/helper.js‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,15 @@ class Helper {
105105

106106
}
107107

108+
/**
109+
* Hook executed after all tests are executed
110+
*
111+
* @param suite
112+
*/
113+
_finishTest() {
114+
115+
}
116+
108117
/**
109118
* Access another configured helper: `this.helpers['AnotherHelper']`
110119
*/

‎lib/helper/Appium.js‎

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -133,16 +133,6 @@ class Appium extends WebdriverIO {
133133
return this.browser;
134134
}
135135

136-
_after() {
137-
if (this.options.restart) return this.browser.end();
138-
if (this.options.desiredCapabilities.browserName) {
139-
this.debugSection('Session', 'cleaning cookies and localStorage');
140-
return this.browser.execute('localStorage.clear();').then(() => {
141-
return this.browser.deleteCookie();
142-
});
143-
}
144-
}
145-
146136
/**
147137
* Check if an app is installed.
148138
*

‎lib/helper/Nightmare.js‎

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ class Nightmare extends Helper {
5555
js_errors: null
5656
};
5757

58+
this.isRunning = false;
59+
5860
// override defaults with config
5961
Object.assign(this.options, config);
6062

@@ -172,7 +174,8 @@ class Nightmare extends Helper {
172174
}
173175

174176
_beforeSuite() {
175-
if (!this.options.restart) {
177+
if (!this.options.restart && !this.isRunning) {
178+
this.isRunning = true;
176179
return this._startBrowser();
177180
}
178181
}
@@ -189,10 +192,13 @@ class Nightmare extends Helper {
189192
return this._stopBrowser();
190193
}
191194
if (this.options.keepCookies) return;
192-
return this.browser.cookies.clearAll();
195+
return Promise.all([this.browser.cookies.clearAll(), this.executeScript('localStorage.clear();')]);
193196
}
194197

195198
_afterSuite() {
199+
}
200+
201+
_finishTest() {
196202
if (!this.options.restart) {
197203
this._stopBrowser();
198204
}
@@ -822,9 +828,9 @@ class Nightmare extends Helper {
822828
}, lctype(locator), lcval(locator));
823829
}
824830

825-
/**
826-
* {{> ../webapi/saveScreenshot }}
827-
*/
831+
/**
832+
* {{> ../webapi/saveScreenshot }}
833+
*/
828834
saveScreenshot(fileName, fullPage = this.options.fullPageScreenshots) {
829835
let outputFile = path.join(global.output_dir, fileName);
830836
this.debug('Screenshot is saving to ' + outputFile);
@@ -837,9 +843,9 @@ class Nightmare extends Helper {
837843
height: document.body.scrollHeight,
838844
width: document.body.scrollWidth
839845
})).then(({
840-
width,
841-
height
842-
}) => {
846+
width,
847+
height
848+
}) => {
843849
this.browser.viewport(width, height);
844850
return this.browser.screenshot(outputFile);
845851
});
@@ -907,7 +913,7 @@ function *proceedSeeInField(assertType, field, value) {
907913
let fieldVal = yield this.browser.evaluate(function (el) {
908914
return codeceptjs.fetchElement(el).value;
909915
}
910-
, el);
916+
, el);
911917
if (tag == 'select') {
912918
// locate option by values and check them
913919
let text = yield this.browser.evaluate(function (el, val) {

‎lib/helper/SeleniumWebdriver.js‎

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ class SeleniumWebdriver extends Helper {
7878
manualStart: false,
7979
capabilities: {}
8080
};
81+
82+
this.isRunning = false;
83+
8184
if (this.options.waitforTimeout) {
8285
console.log(`waitforTimeout is deprecated in favor of waitForTimeout, please update config`);
8386
this.options.waitForTimeout = this.options.waitforTimeout;
@@ -132,8 +135,9 @@ class SeleniumWebdriver extends Helper {
132135
}
133136

134137
_beforeSuite() {
135-
if (!this.options.restart && !this.options.manualStart) {
138+
if (!this.options.restart && !this.options.manualStart && !this.isRunning) {
136139
this.debugSection('Session', 'Starting singleton browser session');
140+
this.isRunning = true;
137141
return this._startBrowser();
138142
}
139143
}
@@ -146,13 +150,16 @@ class SeleniumWebdriver extends Helper {
146150

147151
_after() {
148152
if (this.options.restart) return this.browser.quit();
149-
if (this.options.keepCookies) return;
153+
if (this.options.keepCookies) return Promise.all([this.browser.executeScript('localStorage.clear();'), this.closeOtherTabs()]);
150154
// if browser should not be restarted
151155
this.debugSection('Session', 'cleaning cookies and localStorage');
152-
return Promise.all([this.browser.manage().deleteAllCookies(), this.browser.executeScript('localStorage.clear();')]);
156+
return Promise.all([this.browser.manage().deleteAllCookies(), this.browser.executeScript('localStorage.clear();'), this.closeOtherTabs()]);
153157
}
154158

155159
_afterSuite() {
160+
}
161+
162+
_finishTest() {
156163
if (!this.options.restart) return this.browser.quit();
157164
}
158165

@@ -667,6 +674,27 @@ class SeleniumWebdriver extends Helper {
667674
return this.browser.manage().window().setSize(width, height);
668675
}
669676

677+
/**
678+
* Close all tabs expect for one.
679+
*
680+
* ```js
681+
* I.closeOtherTabs();
682+
* ```
683+
*/
684+
closeOtherTabs() {
685+
let client = this.browser;
686+
687+
return client.getAllWindowHandles().then(function (handles){
688+
for (var i = 1; i < handles.length; i++) {
689+
client.switchTo().window(handles[i]).then(function (){
690+
client.close();
691+
});
692+
}
693+
return client.switchTo().window(handles[0]);
694+
});
695+
}
696+
697+
670698
/**
671699
* {{> ../webapi/wait }}
672700
*/

‎lib/helper/WebDriverIO.js‎

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ class WebDriverIO extends Helper {
210210
}
211211
};
212212

213+
this.isRunning = false;
214+
213215
// override defaults with config
214216
Object.assign(this.options, config);
215217

@@ -256,8 +258,9 @@ class WebDriverIO extends Helper {
256258
}
257259

258260
_beforeSuite() {
259-
if (!this.options.restart && !this.options.manualStart) {
261+
if (!this.options.restart && !this.options.manualStart && !this.isRunning) {
260262
this.debugSection('Session', 'Starting singleton browser session');
263+
this.isRunning = true;
261264
return this._startBrowser();
262265
}
263266
}
@@ -295,12 +298,17 @@ class WebDriverIO extends Helper {
295298

296299
_after() {
297300
if (this.options.restart) return this.browser.end();
298-
if (this.options.keepCookies) return;
299-
this.debugSection('Session', 'cleaning cookies and localStorage');
300-
return Promise.all([this.browser.deleteCookie(), this.browser.execute('localStorage.clear();')]);
301+
if (this.options.keepCookies) return Promise.all([this.browser.execute('localStorage.clear();'), this.closeOtherTabs()]);
302+
if (this.options.desiredCapabilities.browserName) {
303+
this.debugSection('Session', 'cleaning cookies and localStorage');
304+
return Promise.all([this.browser.deleteCookie(), this.browser.execute('localStorage.clear();'), this.closeOtherTabs()]);
305+
}
301306
}
302307

303308
_afterSuite() {
309+
}
310+
311+
_finishTest() {
304312
if (!this.options.restart) return this.browser.end();
305313
}
306314

@@ -1088,6 +1096,24 @@ class WebDriverIO extends Helper {
10881096
);
10891097
}
10901098

1099+
/**
1100+
* Close all tabs expect for one.
1101+
* Appium: support web test
1102+
*
1103+
* ```js
1104+
* I.closeOtherTabs();
1105+
* ```
1106+
*/
1107+
closeOtherTabs() {
1108+
let client = this.browser;
1109+
return client.getTabIds().then(function (handles) {
1110+
for (var i = 1; i < handles.length; i++) {
1111+
this.close(handles[i]);
1112+
}
1113+
return this.switchTab();
1114+
});
1115+
}
1116+
10911117
/**
10921118
* {{> ../webapi/wait }}
10931119
* Appium: support

‎lib/interfaces/bdd.js‎

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ var escapeRe = require('escape-string-regexp');
2424
module.exports = function (suite) {
2525
var suites = [suite];
2626
suite.timeout(0);
27+
var afterAllHooks, afterEachHooks, afterAllHooksAreLoaded, afterEachHooksAreLoaded;
2728

2829
suite.on('pre-require', function (context, file, mocha) {
2930
var common = require('mocha/lib/interfaces/common')(suites, context);
@@ -45,6 +46,12 @@ module.exports = function (suite) {
4546
suites.shift();
4647
}
4748
if (!opts) opts = {};
49+
50+
afterAllHooks = [];
51+
afterEachHooks = [];
52+
afterAllHooksAreLoaded = false;
53+
afterEachHooksAreLoaded = false;
54+
4855
var suite = Suite.create(suites[0], title);
4956
suite.timeout(0);
5057

@@ -54,28 +61,28 @@ module.exports = function (suite) {
5461
suite.file = file;
5562
suites.unshift(suite);
5663
suite.beforeEach('codeceptjs.before', scenario.setup);
57-
suite.afterEach('finialize codeceptjs', scenario.teardown);
64+
afterEachHooks.push(['finialize codeceptjs', scenario.teardown]);
5865

5966
suite.beforeAll('codeceptjs.beforeSuite', () => scenario.suiteSetup(suite));
60-
suite.afterAll('codeceptjs.afterSuite', () => scenario.suiteTeardown(suite));
67+
afterAllHooks.push(['codeceptjs.afterSuite', () => scenario.suiteTeardown(suite)]);
6168

6269
return suite;
6370
};
6471

6572
context.BeforeSuite = function (fn) {
66-
suites[0].beforeAll('BeforeSuite', scenario.injected(fn, suites[0]));
73+
suites[0].beforeAll('BeforeSuite', scenario.injected(fn, suites[0], 'beforeSuite'));
6774
};
6875

6976
context.AfterSuite = function (fn) {
70-
suites[0].afterAll('AfterSuite', scenario.injected(fn, suites[0]));
77+
afterAllHooks.unshift(['AfterSuite', scenario.injected(fn, suites[0], 'afterSuite')]);
7178
};
7279

7380
context.Background = context.Before = function (fn) {
74-
suites[0].beforeEach('Before', scenario.injected(fn, suites[0]));
81+
suites[0].beforeEach('Before', scenario.injected(fn, suites[0], 'before'));
7582
};
7683

7784
context.After = function (fn) {
78-
suites[0].afterEach('After', scenario.injected(fn, suites[0]));
85+
afterEachHooks.unshift(['After', scenario.injected(fn, suites[0]), 'after']);
7986
};
8087

8188
/**
@@ -88,7 +95,22 @@ module.exports = function (suite) {
8895
fn = opts;
8996
opts = {};
9097
}
91-
98+
/**
99+
* load hooks from arrays to suite to prevent reordering
100+
*
101+
*/
102+
if (!afterAllHooksAreLoaded) {
103+
afterAllHooks.forEach(function (hook) {
104+
suites[0].afterAll(hook[0], hook[1]);
105+
});
106+
afterAllHooksAreLoaded = true;
107+
}
108+
if (!afterEachHooksAreLoaded) {
109+
afterEachHooks.forEach(function (hook) {
110+
suites[0].afterEach(hook[0], hook[1]);
111+
});
112+
afterEachHooksAreLoaded = true;
113+
}
92114
var suite = suites[0];
93115
if (suite.pending) {
94116
fn = null;

‎lib/listener/helpers.js‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ module.exports = function () {
3636
runAsyncHelpersHook('_afterSuite', suite, true);
3737
});
3838

39+
event.dispatcher.on(event.hook.after.failed, function (suite) {
40+
runAsyncHelpersHook('_after', suite, true);
41+
});
42+
43+
event.dispatcher.on(event.hook.afterSuite.failed, function (suite) {
44+
runAsyncHelpersHook('_afterSuite', suite, true);
45+
});
46+
3947
event.dispatcher.on(event.test.started, function (test) {
4048
runHelpersHook('_test', test);
4149
recorder.catch((e) => error(e));
@@ -48,7 +56,7 @@ module.exports = function () {
4856
event.dispatcher.on(event.test.failed, function (test) {
4957
runAsyncHelpersHook('_failed', test, true);
5058
// should not fail test execution, so errors should be catched
51-
recorder.catch((e) => error(e));
59+
recorder.catchWithoutStop((e) => error(e));
5260
});
5361

5462
event.dispatcher.on(event.test.after, function () {
@@ -62,4 +70,8 @@ module.exports = function () {
6270
event.dispatcher.on(event.step.after, function (step) {
6371
runAsyncHelpersHook('_afterStep', step);
6472
});
73+
74+
event.dispatcher.on(event.all.result, function () {
75+
runAsyncHelpersHook('_finishTest', {}, true);
76+
});
6577
};

0 commit comments

Comments
 (0)