Skip to content

Commit f527ddd

Browse files
authored
Merge pull request #627 from Codeception/multi-reports
Multi reports and Mochawesome helper
2 parents 8310dfb + f4a5eef commit f527ddd

22 files changed

+276
-35
lines changed

CHANGELOG.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Next notable feature is **[SmartWait](http://codecept.io/acceptance/#smartwait)*
4141

4242
* Read more about [SmartWait](http://codecept.io/acceptance/#smartwait)
4343

44-
#### Changelog
44+
**Changelog**
4545

4646
* Minimal NodeJS version is 6.11.1 LTS
4747
* Use `within` command with generators.
@@ -486,4 +486,4 @@ Whenever you need to create `I` object (in page objects, custom steps, but not i
486486
* [WebDriverIO] proxy configuration added by @petehouston
487487
* [WebDriverIO] fixed `waitForText` method by @roadhump. Fixes #11
488488
* Fixed creating output dir when it already exists on init by @alfirin
489-
* Fixed loading of custom helpers
489+
* Fixed loading of custom helpers

docs/helpers/Appium.md

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ This helper should be configured in codecept.json or codecept.conf.js
2323

2424
- `port`: Appium port
2525
- `restart`: restart browser or app between tests (default: true), if set to false cookies will be cleaned but browser window will be kept and for apps nothing will be changed.
26+
- `disableScreenshots` (optional, default: false) - don't save screenshot on failure
27+
- `uniqueScreenshotNames` (optional, default: false) - option to prevent screenshot override if you have scenarios with the same name in different suites
2628
- `desiredCapabilities`: [], Appium capabilities, see below
2729
- `platformName` - Which mobile OS platform to use
2830
- `appPackage` - Java package of the Android app you want to run

docs/helpers/Nightmare.md

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ This helper should be configured in codecept.json
1313

1414
- `url` - base url of website to be tested
1515
- `restart` (optional, default: true) - restart browser between tests.
16+
- `disableScreenshots` (optional, default: false) - don't save screenshot on failure
17+
- `uniqueScreenshotNames` (optional, default: false) - option to prevent screenshot override if you have scenarios with the same name in different suites
18+
- `keepBrowserState` (optional, default: false) - keep browser state between tests when `restart` set to false.
1619
- `keepCookies` (optional, default: false) - keep cookies between tests when `restart` set to false.
1720
- `waitForAction`: (optional) how long to wait after click, doubleClick or PressKey actions in ms. Default: 500
1821
- `waitForTimeout`: (optional) default wait* timeout

docs/helpers/Protractor.md

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ This helper should be configured in codecept.json
2525
- `driver` - which protrator driver to use (local, direct, session, hosted, sauce, browserstack). By default set to 'hosted' which requires selenium server to be started.
2626
- `restart` (optional, default: true) - restart browser between tests.
2727
- `smartWait`: (optional) **enables [SmartWait](http://codecept.io/acceptance/#smartwait)**; wait for additional milliseconds for element to appear. Enable for 5 secs: "smartWait": 5000
28+
- `disableScreenshots` (optional, default: false) - don't save screenshot on failure
29+
- `uniqueScreenshotNames` (optional, default: false) - option to prevent screenshot override if you have scenarios with the same name in different suites
30+
- `keepBrowserState` (optional, default: false) - keep browser state between tests when `restart` set to false.
31+
- `keepCookies` (optional, default: false) - keep cookies between tests when `restart` set to false.*
2832
- `seleniumAddress` - Selenium address to connect (default: <http://localhost:4444/wd/hub>)
2933
- `rootElement` - Root element of AngularJS application (default: body)
3034
- `waitForTimeout`: (optional) sets default wait time in _ms_ for all `wait*` functions. 1000 by default.

docs/helpers/SeleniumWebdriver.md

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ This helper should be configured in codecept.json
2626
- `driver` - which protrator driver to use (local, direct, session, hosted, sauce, browserstack). By default set to 'hosted' which requires selenium server to be started.
2727
- `restart` - restart browser between tests (default: true).
2828
- `smartWait`: (optional) **enables SmartWait**; wait for additional milliseconds for element to appear. Enable for 5 secs: "smartWait": 5000
29+
- `disableScreenshots` (optional, default: false) - don't save screenshot on failure
30+
- `uniqueScreenshotNames` (optional, default: false) - option to prevent screenshot override if you have scenarios with the same name in different suites
31+
- `keepBrowserState` (optional, default: false) - keep browser state between tests when `restart` set to false.
2932
- `keepCookies` (optional, default: false) - keep cookies between tests when `restart` set to false.*
3033
- `seleniumAddress` - Selenium address to connect (default: <http://localhost:4444/wd/hub>)
3134
- `waitForTimeout`: (optional) sets default wait time in _ms_ for all `wait*` functions. 1000 by default;

docs/helpers/WebDriverIO.md

+3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ This helper should be configured in codecept.json
2727
- `browser` - browser in which perform testing
2828
- `restart` (optional, default: true) - restart browser between tests.
2929
- `smartWait`: (optional) **enables [SmartWait](http://codecept.io/acceptance/#smartwait)**; wait for additional milliseconds for element to appear. Enable for 5 secs: "smartWait": 5000
30+
- `disableScreenshots` (optional, default: false) - don't save screenshot on failure
31+
- `uniqueScreenshotNames` (optional, default: false) - option to prevent screenshot override if you have scenarios with the same name in different suites
32+
- `keepBrowserState` (optional, default: false) - keep browser state between tests when `restart` set to false.
3033
- `keepCookies` (optional, default: false) - keep cookies between tests when `restart` set to false.
3134
- `windowSize`: (optional) default window size. Set to `maximize` or a dimension in the format `640x480`.
3235
- `waitForTimeout`: (option) sets default wait time in _ms_ for all `wait*` functions. 1000 by default;

docs/pageobjects.md

+42
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,48 @@ Scenario('login', (I, loginPage) => {
6868
});
6969
```
7070

71+
Also you can use generators inside PageObject:
72+
```js
73+
'use strict';
74+
let I;
75+
76+
module.exports = {
77+
78+
_init() {
79+
I = actor();
80+
},
81+
82+
// setting locators
83+
container: "//div[@class = 'numbers']",
84+
mainItem: {
85+
number: ".//div[contains(@class, 'numbers__main-number')]",
86+
title: ".//div[contains(@class, 'numbers__main-title-block')]"
87+
},
88+
89+
// introducing methods
90+
openMainArticle: function* () {
91+
I.waitForVisible(this.container)
92+
let _this = this
93+
let title;
94+
yield within(this.container, function*(){
95+
title = yield I.grabTextFrom(_this.mainItem.number);
96+
let subtitle = yield I.grabTextFrom(_this.mainItem.title);
97+
title = title + " " + subtitle.charAt(0).toLowerCase() + subtitle.slice(1);
98+
yield I.click(_this.mainItem.title)
99+
})
100+
return title;
101+
}
102+
}
103+
```
104+
105+
and use them in your tests:
106+
```js
107+
Scenario('login2', (I, loginPage, basePage) => {
108+
let title = yield* mainPage.openMainArticle()
109+
basePage.pageShouldBeOpened(title)
110+
});
111+
```
112+
71113
## Page Fragments
72114

73115
In a similar manner CodeceptJS allows you to generate **PageFragments** and any other are abstraction

docs/reports.md

+77
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,80 @@ codeceptjs run --reporter mochawesome
141141

142142
Result will be located at `output/index.html` file.
143143

144+
### Advanced usage
145+
Want to have screenshots for failed tests?
146+
Then add Mochawesome helper to your config:
147+
```json
148+
"helpers": {
149+
"Mochawesome": {
150+
"uniqueScreenshotNames": "true"
151+
}
152+
},
153+
```
154+
Then tests with failure will have screenshots.
155+
156+
### Configuration
157+
158+
This helper should be configured in codecept.json
159+
160+
- `uniqueScreenshotNames` (optional, default: false) - option to prevent screenshot override if you have scenarios with the same name in different suites. This option should be the same as in common helper.
161+
- `disableScreenshots` (optional, default: false) - don't save screenshot on failure. This option should be the same as in common helper.
162+
163+
Also if you will add Mochawesome helper, then you will able to add custom context in report:
164+
#### addMochawesomeContext
165+
166+
Adds context to executed test in HTML report:
167+
168+
```js
169+
I.addMochawesomeContext('simple string');
170+
I.addMochawesomeContext('http://www.url.com/pathname');
171+
I.addMochawesomeContext('http://www.url.com/screenshot-maybe.jpg');
172+
I.addMochawesomeContext({title: 'expected output',
173+
value: {
174+
a: 1,
175+
b: '2',
176+
c: 'd'
177+
}
178+
});
179+
```
180+
181+
**Parameters**
182+
183+
- `context` string, url, path to screenshot, object. See [this](https://www.npmjs.com/package/mochawesome#adding-test-context)
184+
185+
## Multi Reports
186+
Want to use several reporters in the same time? Try to use [mocha-multi](https://www.npmjs.com/package/mocha-multi) reporter
187+
188+
Install it via NPM:
189+
190+
```
191+
npm i mocha-multi
192+
```
193+
194+
Configure mocha-multi with reports that you want:
195+
```json
196+
"mocha": {
197+
"reporterOptions": {
198+
"codeceptjs-cli-reporter": {
199+
"stdout": "-",
200+
"options": {
201+
"verbose": true,
202+
"steps": true,
203+
}
204+
},
205+
"mochawesome": {
206+
"stdout": "./output/console.log",
207+
"options": {
208+
"reportDir": "./output",
209+
"reportFilename": "report"
210+
}
211+
}
212+
}
213+
```
214+
Execute CodeceptJS with mocha-multi reporter:
215+
216+
```
217+
codeceptjs run --reporter mocha-multi
218+
```
219+
220+
This will give you cli with steps in console and HTML report in `output` directory

lib/actor.js

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ function recordStep(step, args) {
7070
});
7171

7272
recorder.catchWithoutStop((err) => {
73+
step.status = 'failed';
7374
step.endTime = Date.now();
7475
event.emit(event.step.failed, step);
7576
throw err;

lib/codecept.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class Codecept {
109109
if (test) {
110110
mocha.files = mocha.files.filter((t) => fsPath.basename(t, '_test.js') === test || fsPath.basename(t, '.js') === test || fsPath.basename(t) === test);
111111
}
112-
mocha.run().on('end', () => {
112+
mocha.run(() => {
113113
let done = () => {
114114
event.emit(event.all.result, this);
115115
};

lib/helper/Appium.js

+7-6
Original file line numberDiff line numberDiff line change
@@ -168,25 +168,26 @@ class Appium extends WebdriverIO {
168168
this.browser = webdriverio.remote(this.options).init();
169169
}
170170

171+
let promisesList = [];
171172
if (this.options.timeouts && this.isWeb) {
172-
this.defineTimeout(this.options.timeouts);
173+
promisesList.push(this.defineTimeout(this.options.timeouts));
173174
}
174175

175176
if (this.options.windowSize === 'maximize' && !this.platform) {
176-
this.browser.execute('return [screen.width, screen.height]').then((res) => {
177+
promisesList.push(this.browser.execute('return [screen.width, screen.height]').then((res) => {
177178
return this.browser.windowHandleSize({
178179
width: res.value[0],
179180
height: res.value[1]
180181
});
181-
});
182+
}));
182183
} else if (this.options.windowSize && this.options.windowSize.indexOf('x') > 0 && !this.platform) {
183184
let dimensions = this.options.windowSize.split('x');
184-
this.browser.windowHandleSize({
185+
promisesList.push(this.browser.windowHandleSize({
185186
width: dimensions[0],
186187
height: dimensions[1]
187-
});
188+
}));
188189
}
189-
return this.browser;
190+
return this.browser.then(() => Promise.all(promisesList));
190191
}
191192

192193
_after() {

lib/helper/Mochawesome.js

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
'use strict';
2+
let addMochawesomeContext;
3+
let currentTest;
4+
let currentSuite;
5+
const Helper = require('../helper');
6+
const hashCode = require('../utils').hashCode;
7+
const clearString = require('../utils').clearString;
8+
const requireg = require('requireg');
9+
const path = require('path');
10+
11+
12+
class Mochawesome extends Helper {
13+
14+
constructor(config) {
15+
super(config);
16+
addMochawesomeContext = requireg('mochawesome/addContext');
17+
this._createConfig(config);
18+
}
19+
20+
_createConfig(config) {
21+
22+
// set defaults
23+
24+
this.options = {
25+
uniqueScreenshotNames: false,
26+
disableScreenshots: false
27+
};
28+
29+
// override defaults with config
30+
Object.assign(this.options, config);
31+
}
32+
33+
_beforeSuite(suite) {
34+
currentSuite = suite;
35+
}
36+
37+
_before() {
38+
currentTest = {test: currentSuite.ctx.currentTest};
39+
}
40+
41+
_test(test) {
42+
currentTest = {test: test};
43+
}
44+
45+
46+
_failed(test) {
47+
if (this.options.disableScreenshots) return;
48+
let fileName = clearString(test.title);
49+
if (this.options.uniqueScreenshotNames) {
50+
fileName =
51+
fileName.substring(0, 10) + '-' + hashCode(test.title) + '-' +
52+
hashCode(test.file);
53+
}
54+
if (test._retries < 1 || test._retries == test.retryNum) {
55+
fileName = `${fileName}.failed.png`;
56+
return addMochawesomeContext(currentTest, path.join(global.output_dir, fileName));
57+
}
58+
}
59+
60+
addMochawesomeContext(context) {
61+
return addMochawesomeContext(currentTest, context);
62+
}
63+
64+
}
65+
66+
module.exports = Mochawesome;

lib/helper/Nightmare.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ let withinStatus = false;
3434
*
3535
* * `url` - base url of website to be tested
3636
* * `restart` (optional, default: true) - restart browser between tests.
37+
* * `disableScreenshots` (optional, default: false) - don't save screenshot on failure
38+
* * `uniqueScreenshotNames` (optional, default: false) - option to prevent screenshot override if you have scenarios with the same name in different suites
39+
* * `keepBrowserState` (optional, default: false) - keep browser state between tests when `restart` set to false.
3740
* * `keepCookies` (optional, default: false) - keep cookies between tests when `restart` set to false.
3841
* * `waitForAction`: (optional) how long to wait after click, doubleClick or PressKey actions in ms. Default: 500
3942
* * `waitForTimeout`: (optional) default wait* timeout
@@ -56,6 +59,7 @@ class Nightmare extends Helper {
5659
uniqueScreenshotNames: false,
5760
rootElement: 'body',
5861
restart: true,
62+
keepBrowserState: false,
5963
keepCookies: false,
6064
js_errors: null
6165
};
@@ -196,7 +200,12 @@ class Nightmare extends Helper {
196200
if (this.options.restart) {
197201
return this._stopBrowser();
198202
}
199-
if (this.options.keepCookies) return;
203+
if (this.options.keepBrowserState) return;
204+
if (this.options.keepCookies) {
205+
return Promise.all([this.executeScript(function () {
206+
return localStorage.clear();
207+
})]);
208+
}
200209
return Promise.all([this.browser.cookies.clearAll(), this.executeScript(function () {
201210
return localStorage.clear();
202211
})]);

0 commit comments

Comments
 (0)