Skip to content

Commit a2818dd

Browse files
authored
Merge pull request #24 from rober710/wait_page_load
Added command to wait until page is fully loaded.
2 parents f3f95f9 + af20e14 commit a2818dd

File tree

6 files changed

+228
-0
lines changed

6 files changed

+228
-0
lines changed

docs/waitForDocumentLoaded.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
3+
<!-- Start es6/commands/waitForDocumentLoaded.js -->
4+
5+
## WaitForDocumentLoaded
6+
7+
This custom command allows us to wait until the page is fully loaded. It checks document.readyState
8+
every 100ms until its value is "complete" or the timeout is reached.
9+
Nightwatch uses the Node.js EventEmitter pattern to handle asynchronous code so this command is also an EventEmitter.
10+
### Examples:
11+
12+
browser.waitForDocumentLoaded();
13+
browser.waitForDocumentLoaded(5000, 'Document fully loaded!');
14+
15+
Author: rober710
16+
17+
### Params:
18+
19+
* **Integer** *[timeoutInMilliseconds]* - timeout of this wait commands in milliseconds
20+
* **String** *[message]* - message to display
21+
22+
<!-- End es6/commands/waitForDocumentLoaded.js -->
23+
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import events from 'events';
2+
3+
/**
4+
* This custom command allows us to wait until the page is fully loaded. It checks document.readyState
5+
* every 100ms until its value is "complete" or the timeout is reached.
6+
* Nightwatch uses the Node.js EventEmitter pattern to handle asynchronous code so this command is also an EventEmitter.
7+
*
8+
* h3 Examples:
9+
*
10+
* browser.waitForDocumentLoaded();
11+
* browser.waitForDocumentLoaded(5000, 'Document fully loaded!');
12+
*
13+
* @author rober710
14+
* @param {Integer} [timeoutInMilliseconds] - timeout of this wait commands in milliseconds
15+
* @param {String} [message] - message to display
16+
*/
17+
18+
class WaitForDocumentLoaded extends events.EventEmitter {
19+
constructor() {
20+
super();
21+
this.timeoutRetryInMilliseconds = 100;
22+
this.defaultTimeoutInMilliseconds = 5000;
23+
this.startTimeInMilliseconds = null;
24+
}
25+
26+
command(timeoutInMilliseconds, message) {
27+
this.startTimeInMilliseconds = new Date().getTime();
28+
29+
if (typeof timeoutInMilliseconds !== 'number') {
30+
if (typeof this.api.globals.waitForConditionTimeout === 'number') {
31+
timeoutInMilliseconds = this.api.globals.waitForConditionTimeout;
32+
} else {
33+
timeoutInMilliseconds = this.defaultTimeoutInMilliseconds;
34+
}
35+
}
36+
37+
if (message && typeof message !== 'string') {
38+
this.emit('error', "defaultMessage is not a string");
39+
return;
40+
}
41+
42+
this.check((pageLoaded, loadedTimeInMilliseconds, readyState) => {
43+
let messageToShow;
44+
if (message) {
45+
messageToShow = message;
46+
} else if (pageLoaded) {
47+
messageToShow = `waitForDocumentLoaded: document fully loaded after ${loadedTimeInMilliseconds - this.startTimeInMilliseconds} ms.`;
48+
} else {
49+
messageToShow = `waitForDocumentLoaded: document not loaded after ${timeoutInMilliseconds} ms.`;
50+
}
51+
52+
this.client.assertion(pageLoaded, readyState, 'complete', messageToShow, true);
53+
return this.emit('complete');
54+
}, timeoutInMilliseconds);
55+
}
56+
57+
check(callback, maxTimeInMilliseconds) {
58+
return this.api.execute(function () {
59+
return document.readyState;
60+
}, [], result => {
61+
let now = new Date().getTime();
62+
if (result.status === 0 && result.value === 'complete') {
63+
return callback(true, now, result.value);
64+
} else if (now - this.startTimeInMilliseconds < maxTimeInMilliseconds) {
65+
return setTimeout(() => {
66+
this.check(callback, maxTimeInMilliseconds);
67+
}, this.timeoutRetryInMilliseconds);
68+
} else {
69+
return callback(false, now, result.value);
70+
}
71+
});
72+
}
73+
}
74+
75+
export default WaitForDocumentLoaded;
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
'use strict';
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
7+
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
8+
9+
var _events = require('events');
10+
11+
var _events2 = _interopRequireDefault(_events);
12+
13+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14+
15+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
16+
17+
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
18+
19+
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
20+
21+
/**
22+
* This custom command allows us to wait until the page is fully loaded. It checks document.readyState
23+
* every 100ms until its value is "complete" or the timeout is reached.
24+
* Nightwatch uses the Node.js EventEmitter pattern to handle asynchronous code so this command is also an EventEmitter.
25+
*
26+
* h3 Examples:
27+
*
28+
* browser.waitForDocumentLoaded();
29+
* browser.waitForDocumentLoaded(5000, 'Document fully loaded!');
30+
*
31+
* @author rober710
32+
* @param {Integer} [timeoutInMilliseconds] - timeout of this wait commands in milliseconds
33+
* @param {String} [message] - message to display
34+
*/
35+
36+
var WaitForDocumentLoaded = function (_events$EventEmitter) {
37+
_inherits(WaitForDocumentLoaded, _events$EventEmitter);
38+
39+
function WaitForDocumentLoaded() {
40+
_classCallCheck(this, WaitForDocumentLoaded);
41+
42+
var _this = _possibleConstructorReturn(this, (WaitForDocumentLoaded.__proto__ || Object.getPrototypeOf(WaitForDocumentLoaded)).call(this));
43+
44+
_this.timeoutRetryInMilliseconds = 100;
45+
_this.defaultTimeoutInMilliseconds = 5000;
46+
_this.startTimeInMilliseconds = null;
47+
return _this;
48+
}
49+
50+
_createClass(WaitForDocumentLoaded, [{
51+
key: 'command',
52+
value: function command(timeoutInMilliseconds, message) {
53+
var _this2 = this;
54+
55+
this.startTimeInMilliseconds = new Date().getTime();
56+
57+
if (typeof timeoutInMilliseconds !== 'number') {
58+
if (typeof this.api.globals.waitForConditionTimeout === 'number') {
59+
timeoutInMilliseconds = this.api.globals.waitForConditionTimeout;
60+
} else {
61+
timeoutInMilliseconds = this.defaultTimeoutInMilliseconds;
62+
}
63+
}
64+
65+
if (message && typeof message !== 'string') {
66+
this.emit('error', "defaultMessage is not a string");
67+
return;
68+
}
69+
70+
this.check(function (pageLoaded, loadedTimeInMilliseconds, readyState) {
71+
var messageToShow = void 0;
72+
if (message) {
73+
messageToShow = message;
74+
} else if (pageLoaded) {
75+
messageToShow = 'waitForDocumentLoaded: document fully loaded after ' + (loadedTimeInMilliseconds - _this2.startTimeInMilliseconds) + ' ms.';
76+
} else {
77+
messageToShow = 'waitForDocumentLoaded: document not loaded after ' + timeoutInMilliseconds + ' ms.';
78+
}
79+
80+
_this2.client.assertion(pageLoaded, readyState, 'complete', messageToShow, true);
81+
return _this2.emit('complete');
82+
}, timeoutInMilliseconds);
83+
}
84+
}, {
85+
key: 'check',
86+
value: function check(callback, maxTimeInMilliseconds) {
87+
var _this3 = this;
88+
89+
return this.api.execute(function () {
90+
return document.readyState;
91+
}, [], function (result) {
92+
var now = new Date().getTime();
93+
if (result.status === 0 && result.value === 'complete') {
94+
return callback(true, now, result.value);
95+
} else if (now - _this3.startTimeInMilliseconds < maxTimeInMilliseconds) {
96+
return setTimeout(function () {
97+
_this3.check(callback, maxTimeInMilliseconds);
98+
}, _this3.timeoutRetryInMilliseconds);
99+
} else {
100+
return callback(false, now, result.value);
101+
}
102+
});
103+
}
104+
}]);
105+
106+
return WaitForDocumentLoaded;
107+
}(_events2.default.EventEmitter);
108+
109+
exports.default = WaitForDocumentLoaded;
110+
module.exports = exports['default'];
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Test wait for document loaded</title>
6+
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
7+
</head>
8+
<body>
9+
<img src="https://imgs.xkcd.com/comics/im_an_idiot.png" id="xkcd-img">
10+
</body>
11+
</html>

tests/runTests.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,4 +241,12 @@ module.exports = {
241241
.assert.containsText("#div", "something else")
242242
.end();
243243
},
244+
245+
"test waitForDocumentLoaded": function (browser) {
246+
return browser
247+
.url(baseurl + "/waitForDocumentLoaded")
248+
.waitForDocumentLoaded(5000)
249+
.assert.visible("#xkcd-img")
250+
.end();
251+
},
244252
};

tests/setMocks.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,4 @@ monkeyPatchedMSC.mockHTMLResponse('/waitForAjaxRequest', "html/ajax.html");
6565
monkeyPatchedMSC.mockHTMLResponse('/delayedAjax', "html/ajax.json", {
6666
delay: 3000
6767
});
68+
monkeyPatchedMSC.mockHTMLResponse('/waitForDocumentLoaded', "html/waitForDocumentLoaded.html");

0 commit comments

Comments
 (0)