Skip to content

Commit 764c67c

Browse files
committed
added waitForJqueryElement
1 parent f92e155 commit 764c67c

File tree

6 files changed

+205
-3
lines changed

6 files changed

+205
-3
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
events = require('events');
2+
3+
###*
4+
* This custom command allows us to locate an HTML element on the page and then wait until the value of a
5+
* specified attribute matches the provided expression (aka. the 'checker' function).
6+
* It retries executing the checker function every 100ms until either it evaluates to true or it reaches
7+
* maxTimeInMilliseconds (which fails the test). Nightwatch uses the Node.js EventEmitter pattern to handle
8+
* asynchronous code so this command is also an EventEmitter.
9+
*
10+
* h3 Examples:
11+
*
12+
* browser.waitForAttribute("img", "src", function(imageSource) {
13+
* return imageSource === "img/header.jpg";
14+
* });
15+
*
16+
* @author maxgalbu
17+
* @param {String} elementSelector - jquery selector for the element
18+
* @param {Integer} [timeoutInMilliseconds] - timeout of this wait commands in milliseconds
19+
###
20+
21+
class WaitForJqueryElement extends events.EventEmitter
22+
timeoutRetryInMilliseconds: 100
23+
defaultTimeoutInMilliseconds: 5000
24+
25+
constructor: ->
26+
super;
27+
@startTimeInMilliseconds = null;
28+
29+
command: (elementSelector, timeoutInMilliseconds) ->
30+
@startTimeInMilliseconds = new Date().getTime();
31+
32+
if typeof timeoutInMilliseconds != 'number'
33+
timeoutInMilliseconds = @api.globals.waitForConditionTimeout;
34+
if typeof timeoutInMilliseconds != 'number'
35+
timeoutInMilliseconds = @defaultTimeoutInMilliseconds;
36+
37+
@check(elementSelector, (result, loadedTimeInMilliseconds) =>
38+
if result
39+
message = "WaitForJqueryElement: #{elementSelector}.
40+
Expression was true after #{loadedTimeInMilliseconds - @startTimeInMilliseconds}.";
41+
else
42+
message = "WaitForJqueryElement: #{elementSelector}.
43+
Expression wasn't true in #{timeoutInMilliseconds} ms.";
44+
45+
@client.assertion(result, 'expression false', 'expression true', message, true);
46+
@emit('complete');
47+
, timeoutInMilliseconds);
48+
49+
return this;
50+
51+
check: (elementSelector, callback, maxTimeInMilliseconds) ->
52+
@api.jqueryElement(elementSelector, (result) =>
53+
now = new Date().getTime();
54+
if result
55+
callback(true, now);
56+
else if now - @startTimeInMilliseconds < maxTimeInMilliseconds
57+
setTimeout(=>
58+
@check(elementSelector, callback, maxTimeInMilliseconds);
59+
, @timeoutRetryInMilliseconds);
60+
else
61+
callback(false);
62+
);
63+
64+
module.exports = WaitForJqueryElement;

docs/waitForJqueryElement.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
2+
3+
<!-- Start coffee/commands/waitForJqueryElement.coffee -->
4+
5+
This custom command allows us to locate an HTML element on the page and then wait until the value of a
6+
specified attribute matches the provided expression (aka. the 'checker' function).
7+
It retries executing the checker function every 100ms until either it evaluates to true or it reaches
8+
maxTimeInMilliseconds (which fails the test). Nightwatch uses the Node.js EventEmitter pattern to handle
9+
asynchronous code so this command is also an EventEmitter.
10+
### Examples:
11+
12+
browser.waitForAttribute("img", "src", function(imageSource) {
13+
return imageSource === "img/header.jpg";
14+
});
15+
16+
Author: maxgalbu
17+
18+
### Params:
19+
20+
* **String** *elementSelector* - jquery selector for the element
21+
* **Integer** *[timeoutInMilliseconds]* - timeout of this wait commands in milliseconds
22+
23+
<!-- End coffee/commands/waitForJqueryElement.coffee -->
24+
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
var WaitForJqueryElement, events,
2+
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
3+
hasProp = {}.hasOwnProperty;
4+
5+
events = require('events');
6+
7+
8+
/**
9+
* This custom command allows us to locate an HTML element on the page and then wait until the value of a
10+
* specified attribute matches the provided expression (aka. the 'checker' function).
11+
* It retries executing the checker function every 100ms until either it evaluates to true or it reaches
12+
* maxTimeInMilliseconds (which fails the test). Nightwatch uses the Node.js EventEmitter pattern to handle
13+
* asynchronous code so this command is also an EventEmitter.
14+
*
15+
* h3 Examples:
16+
*
17+
* browser.waitForAttribute("img", "src", function(imageSource) {
18+
* return imageSource === "img/header.jpg";
19+
* });
20+
*
21+
* @author maxgalbu
22+
* @param {String} elementSelector - jquery selector for the element
23+
* @param {Integer} [timeoutInMilliseconds] - timeout of this wait commands in milliseconds
24+
*/
25+
26+
WaitForJqueryElement = (function(superClass) {
27+
extend(WaitForJqueryElement, superClass);
28+
29+
WaitForJqueryElement.prototype.timeoutRetryInMilliseconds = 100;
30+
31+
WaitForJqueryElement.prototype.defaultTimeoutInMilliseconds = 5000;
32+
33+
function WaitForJqueryElement() {
34+
WaitForJqueryElement.__super__.constructor.apply(this, arguments);
35+
this.startTimeInMilliseconds = null;
36+
}
37+
38+
WaitForJqueryElement.prototype.command = function(elementSelector, timeoutInMilliseconds) {
39+
this.startTimeInMilliseconds = new Date().getTime();
40+
if (typeof timeoutInMilliseconds !== 'number') {
41+
timeoutInMilliseconds = this.api.globals.waitForConditionTimeout;
42+
}
43+
if (typeof timeoutInMilliseconds !== 'number') {
44+
timeoutInMilliseconds = this.defaultTimeoutInMilliseconds;
45+
}
46+
this.check(elementSelector, (function(_this) {
47+
return function(result, loadedTimeInMilliseconds) {
48+
var message;
49+
if (result) {
50+
message = "WaitForJqueryElement: " + elementSelector + ". Expression was true after " + (loadedTimeInMilliseconds - _this.startTimeInMilliseconds) + ".";
51+
} else {
52+
message = "WaitForJqueryElement: " + elementSelector + ". Expression wasn't true in " + timeoutInMilliseconds + " ms.";
53+
}
54+
_this.client.assertion(result, 'expression false', 'expression true', message, true);
55+
return _this.emit('complete');
56+
};
57+
})(this), timeoutInMilliseconds);
58+
return this;
59+
};
60+
61+
WaitForJqueryElement.prototype.check = function(elementSelector, callback, maxTimeInMilliseconds) {
62+
return this.api.jqueryElement(elementSelector, (function(_this) {
63+
return function(result) {
64+
var now;
65+
now = new Date().getTime();
66+
if (result) {
67+
return callback(true, now);
68+
} else if (now - _this.startTimeInMilliseconds < maxTimeInMilliseconds) {
69+
return setTimeout(function() {
70+
return _this.check(elementSelector, callback, maxTimeInMilliseconds);
71+
}, _this.timeoutRetryInMilliseconds);
72+
} else {
73+
return callback(false);
74+
}
75+
};
76+
})(this));
77+
};
78+
79+
return WaitForJqueryElement;
80+
81+
})(events.EventEmitter);
82+
83+
module.exports = WaitForJqueryElement;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<html>
2+
<head>
3+
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
4+
<script type="text/javascript">
5+
$(document).ready(function() {
6+
setTimeout(function() {
7+
$("#div").show();
8+
}, 1000);
9+
});
10+
</script>
11+
</head>
12+
<body>
13+
<div class="myclass"></div>
14+
<div class="myclass"></div>
15+
<div class="myclass">
16+
<div id="div" style="display:none">invisible</div>
17+
</div>
18+
</body>
19+
</html>

tests/runTests.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ var easyimg = require("easyimage");
33
var baseurl = "http://localhost:9999";
44

55
module.exports = {
6-
"test elementHasChildren": function(browser) {
6+
/*"test elementHasChildren": function(browser) {
77
return browser
88
.url(baseurl+"/children")
99
.assert.elementHasChildren(".myclass")
@@ -33,9 +33,20 @@ module.exports = {
3333
});
3434
})
3535
.end();
36+
},*/
37+
38+
"test waitForJqueryElement": function(browser) {
39+
browser.globals.waitForConditionTimeout = 5000;
40+
41+
return browser
42+
.url(baseurl+"/waitForJqueryElement")
43+
.waitForJqueryElement(".myclass:eq(2) > #div:visible", function() {
44+
client.assert.equal(true, true, "waitForJqueryElement works");
45+
})
46+
.end();
3647
},
3748

38-
"test waitForAttribute": function(browser) {
49+
/*"test waitForAttribute": function(browser) {
3950
browser.globals.waitForConditionTimeout = 5000;
4051
4152
return browser
@@ -136,5 +147,5 @@ module.exports = {
136147
.pause(200)
137148
.assert.visible("#div")
138149
.end();
139-
},
150+
},*/
140151
};

tests/setMocks.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ monkeyPatchedMSC.mockHTMLResponse('/jqueryElementPresent', "html/jqueryElement.h
3838
monkeyPatchedMSC.mockHTMLResponse('/setSelect2Data', "html/select2.html");
3939
monkeyPatchedMSC.mockHTMLResponse('/setSelect2Value', "html/select2.html");
4040
monkeyPatchedMSC.mockHTMLResponse('/setValueAndTrigger', "html/input.html");
41+
monkeyPatchedMSC.mockHTMLResponse('/waitForJqueryElement', "html/waitForJqueryElement.html");
4142
monkeyPatchedMSC.mockHTMLResponse('/waitForAttribute', "html/attribute.html");
4243
monkeyPatchedMSC.mockHTMLResponse('/waitForText', "html/text.html");
4344
monkeyPatchedMSC.mockHTMLResponse('/waitForTitle', "html/title.html");

0 commit comments

Comments
 (0)