Skip to content

Commit 02ac40e

Browse files
committed
Merge branch 'master' of github.com:Codeception/CodeceptJS
2 parents 11df3e1 + 44b397d commit 02ac40e

16 files changed

+235
-73
lines changed

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,25 @@
1+
## 1.3.0
2+
3+
* Cucumber-style BDD Introduced. [Gherkin support](https://codecept.io/bdd).
4+
* Nested steps output enabled for page objects.
5+
* [Puppeteer] [Multiple sessions]((https://codecept.io/acceptance/#multiple-sessions) enabled. Requires Puppeteer >= 1.5
6+
* [Puppeteer] Stability improvement. Waits for for `load` event on page load. This strategy can be changed in config:
7+
* `waitForNavigation` config option introduced. Possible options: `load`, `domcontentloaded`, `networkidle0`, `networkidle2`. See [Puppeteer API](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitfornavigationoptions)
8+
* `getPageTimeout` config option to set maximum navigation time in milliseconds. Default is 30 seconds.
9+
* `waitForNavigation` method added. Explicitly waits for navigation to be finished.
10+
* [Puppeteer] Fixed `resizeWindow` by @sergejkaravajnij
11+
* [WebDriverIO][Protractor][Puppeteer][Nightmare] `grabTextFrom` unified. Return a text for single matched element and an array of texts for multiple elements.
12+
* [WebDriverIO][Protractor][Puppeteer][Nightmare] `waitForFunction` added. Waits for client-side JavaScript function to return true by @GREENpoint.
13+
* [Puppeteer] `waitUntil` deprecated in favor of `waitForFunction`.
14+
* Added `filter` function to DataTable.
15+
* Send non-nested array of files to custom parallel execution chunking by @mikecbrant.
16+
* Fixed invalid output directory path for run-multiple by @mikecbrant.
17+
* [WebDriverIO] `waitUntil` timeout accepts time in seconds (as all other wait* functions). Fix by @truesrc.
18+
* [Nightmare] Fixed grabNumberOfVisibleElements to work similarly to `seeElement`. Thx to @stefanschenk and Jinbo Jinboson.
19+
* [Protractor] Fixed alert handling error with message 'no such alert' by @truesrc.
20+
21+
22+
123
## 1.2.1
224

325
* Fixed running `I.retry()` on multiple steps.

docs/acceptance.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,6 @@ within({frame: [".content", "#editor"]}, () => {
265265

266266
## Multiple Sessions
267267

268-
*Note: Currently multiple sessions work only in WebDriverIO and Protractor*
269-
270268
CodeceptJS allows to run several browser sessions inside a test. This can be useful for testing communication between users inside a system, for instance in chats. To open another browser use `session()` function as shown in example:
271269

272270
```js

docs/puppeteer.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,21 @@ Make sure `Puppeteer` helper is enabled in `codecept.json` config:
5656

5757
Turn on the `show` option if you want to follow test progress in a window. This is very useful for debugging.
5858

59-
Sometimes test may run faster than application gets rendered. In this case it is **recommended to increase `waitForAction` config value**. It will wait for a small amount of time (100ms) by default after each user action taken.
59+
Puppeteer uses different strategies to detect if a page is loaded. In configuration use `waitForNavigation` option for that:
60+
61+
By default it is set to `domcontentloaded` which waits for `DOMContentLoaded` event being fired. However, for Single Page Applications it's more useful to set this value to `networkidle0` which waits for all network connections to be finished.
62+
63+
```js
64+
"helpers": {
65+
"Puppeteer": {
66+
"url": "http://localhost",
67+
"waitForNavigation": "networkidle0"
68+
}
69+
}
70+
```
71+
72+
WHen a test runs faster than application it is recommended to increase `waitForAction` config value.
73+
It will wait for a small amount of time (100ms) by default after each user action is taken.
6074

6175
*More options are listed in [helper reference](http://codecept.io/helpers/Puppeteer/).*
6276

docs/webapi/grabTextFrom.mustache

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ Resumes test execution, so **should be used inside async with `await`** operator
44
```js
55
let pin = await I.grabTextFrom('#pin');
66
```
7+
If multiple elements found returns an array of texts.
8+
79
@param locator element located by CSS|XPath|strict locator

docs/webapi/waitForFunction.mustache

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Waits for a function to return true (waits for 1 sec by default).
2+
Running in browser context.
3+
4+
```js
5+
I.waitForFunction(() => window.requests == 0);
6+
I.waitForFunction(() => window.requests == 0, 5); // waits for 5 sec
7+
```
8+
9+
@param function to be executed in browser context
10+
@param sec time seconds to wait, 1 by default

lib/helper/Nightmare.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -764,9 +764,15 @@ class Nightmare extends Helper {
764764
*/
765765
async grabTextFrom(locator) {
766766
locator = new Locator(locator, 'css');
767-
const el = await this.browser.findElement(locator.toStrict());
768-
assertElementExists(el, locator);
769-
return this.browser.evaluate(el => window.codeceptjs.fetchElement(el).innerText, el);
767+
const els = await this.browser.findElements(locator.toStrict());
768+
assertElementExists(els[0], locator);
769+
const texts = [];
770+
const getText = el => window.codeceptjs.fetchElement(el).innerText;
771+
for (const el of els) {
772+
texts.push(await this.browser.evaluate(getText, el));
773+
}
774+
if (texts.length === 1) return texts[0];
775+
return texts;
770776
}
771777

772778
/**

lib/helper/Protractor.js

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ class Protractor extends Helper {
140140
driver: 'hosted',
141141
capabilities: {},
142142
angular: true,
143+
restart: true,
143144
};
144145

145146
config = Object.assign(defaults, config);
@@ -148,6 +149,7 @@ class Protractor extends Helper {
148149
if (!config.scriptTimeout) config.scriptTimeout = config.scriptsTimeout;
149150
if (config.proxy) config.capabilities.proxy = config.proxy;
150151
if (config.browser) config.capabilities.browserName = config.browser;
152+
151153
config.waitForTimeout /= 1000; // convert to seconds
152154
return config;
153155
}
@@ -206,7 +208,6 @@ class Protractor extends Helper {
206208
this.browser = runner.createBrowser();
207209
await this.browser.ready;
208210
} catch (err) {
209-
console.log(err);
210211
if (err.toString().indexOf('ECONNREFUSED')) {
211212
throw new ConnectionRefused(err);
212213
}
@@ -218,20 +219,16 @@ class Protractor extends Helper {
218219
await this.amOutsideAngularApp();
219220
}
220221

221-
try {
222-
loadGlobals(this.browser);
222+
loadGlobals(this.browser);
223223

224-
if (this.options.windowSize === 'maximize') {
225-
await this.resizeWindow(this.options.windowSize);
226-
} else if (this.options.windowSize) {
227-
const size = this.options.windowSize.split('x');
228-
await this.resizeWindow(parseInt(size[0], 10), parseInt(size[1], 10));
229-
}
230-
this.context = this.options.rootElement;
231-
this.isRunning = true;
232-
} catch (err) {
233-
console.log(err);
224+
if (this.options.windowSize === 'maximize') {
225+
await this.resizeWindow(this.options.windowSize);
226+
} else if (this.options.windowSize) {
227+
const size = this.options.windowSize.split('x');
228+
await this.resizeWindow(parseInt(size[0], 10), parseInt(size[1], 10));
234229
}
230+
this.context = this.options.rootElement;
231+
this.isRunning = true;
235232
return this.browser.ready;
236233
}
237234

@@ -692,17 +689,20 @@ class Protractor extends Helper {
692689
async grabTextFrom(locator) {
693690
const els = await this._locate(locator);
694691
assertElementExists(els);
695-
return els[0].getText();
692+
const texts = [];
693+
for (const el of els) {
694+
texts.push(await el.getText());
695+
}
696+
if (texts.length === 1) return texts[0];
697+
return texts;
696698
}
697699

698700
/**
699701
* {{> ../webapi/grabHTMLFrom }}
700702
*/
701703
async grabHTMLFrom(locator) {
702704
const els = await this._locate(locator);
703-
if (!els) {
704-
return null;
705-
}
705+
assertElementExists(els);
706706

707707
const html = await Promise.all(els.map((el) => {
708708
return this.browser.executeScript('return arguments[0].innerHTML;', el);
@@ -1076,7 +1076,7 @@ class Protractor extends Helper {
10761076
return dialog.getText();
10771077
}
10781078
} catch (e) {
1079-
if (~e.message.indexOf('no alert open') || ~e.message.indexOf('no such alert')) {
1079+
if (e.message.indexOf('no alert open') || e.message.indexOf('no such alert')) {
10801080
// Don't throw an error
10811081
return null;
10821082
}
@@ -1226,7 +1226,6 @@ class Protractor extends Helper {
12261226
* {{> ../webapi/switchTo }}
12271227
*/
12281228
async switchTo(locator) {
1229-
// console.log('EC', EC);
12301229
if (Number.isInteger(locator)) {
12311230
return this.browser.switchTo().frame(locator);
12321231
} else if (!locator) {

0 commit comments

Comments
 (0)