Skip to content
This repository was archived by the owner on Aug 5, 2020. It is now read-only.

Commit 3f7b7c6

Browse files
author
Marlow Payne
authored
Merge pull request #62 from mobify/release
Release 1.7.0
2 parents 03852e7 + 8f95a88 commit 3f7b7c6

File tree

11 files changed

+307
-139
lines changed

11 files changed

+307
-139
lines changed

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Status: **Ready for Review** or **Open for Visibility**
22
Owner:
3-
Reviewers: @ellenmobify @marlowpayne @mobify-derrick
3+
Reviewers: @ellenmobify @marlowpayne @mikenikles
44

55
## Changes
66
- (change1)

CHANGELOG

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
1.7.0
2+
- Introduces 'waitForContextsReady' command.
3+
1.6.3
4+
- Fixes a bug in `waitForAjaxCompleted` in cases where `$` is not bound to jQuery.
15
1.6.2
26
- Update `preview` command to accept `site.js` files under `/system/site.js`
37
1.6.1

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,26 @@ this.demoTest = function (browser) {
328328
};
329329
```
330330

331+
#### waitForContextsReady(expectedContextsCount, milliseconds, timeout, messages, callback)
332+
333+
The `waitForContextsReady` command receives a number of expected contexts to check for, waits for a maximum time before timing out, and polls at a specified time interval. Used with Appium when testing hybrid mobile web apps. See http://nightwatchjs.org/api/contexts.html
334+
335+
Parameter Name | Parameter Type | Description
336+
------------- | -------------- | -----------
337+
expectedContextsCount | Number | The condition to check against.
338+
milliSeconds | Number | _optional_ The number of milliseconds to poll before timeout.
339+
timeout | Number | _optional_ The number of milliseconds between each poll.
340+
message | String | _optional_ The message to output.
341+
callback | Function | _optional_ A function to call after the current command finishes execution.
342+
343+
```
344+
this.demoTest = function (browser) {
345+
browser.waitForContextsReady(3, 8000);
346+
// At this point, it is safe to switch the context to either the NATIVE
347+
// context or any of the WEBVIEW_* contexts.
348+
};
349+
```
350+
331351
#### waitForUrl(url, milliseconds, timeout, messages, callback)
332352

333353
The `waitForUrl` command waits until the page URL is equal to the specified `url`.

commands/waitForAjaxCompleted.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ exports.command = function(callback) {
33

44
// Uses waitForCondition to run code within the client browser
55
//
6-
return client.waitForCondition('return $.active;', 8000, function(result) {
6+
return client.waitForCondition('return jQuery.active;', 8000, function(result) {
77
if (typeof callback === 'function') {
88
callback.call(client, result);
99
}

commands/waitForContextsReady.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
var util = require('util'),
2+
events = require('events');
3+
4+
var CommandAction = function() {
5+
events.EventEmitter.call(this);
6+
this.startTimer = null;
7+
this.cb = null;
8+
this.ms = null;
9+
this.selector = null;
10+
this.protocol = require('nightwatch/lib/api/protocol.js')(this.client);
11+
};
12+
13+
util.inherits(CommandAction, events.EventEmitter);
14+
15+
CommandAction.prototype.command = function(expectedContextsCount, milliseconds, timeout, messages, callback) {
16+
17+
if (milliseconds && typeof milliseconds !== 'number') {
18+
throw new Error('waitForContextsReady expects second parameter to be number; ' + typeof (milliseconds) + ' given');
19+
}
20+
21+
var lastArgument = Array.prototype.slice.call(arguments, 0).pop();
22+
if (typeof (lastArgument) === 'function') {
23+
callback = lastArgument;
24+
}
25+
26+
if (!messages || typeof messages !== 'object') {
27+
messages = {
28+
success: 'All contexts found after ',
29+
timeout: 'Timed out while waiting for contexts after '
30+
};
31+
}
32+
33+
timeout = timeout && typeof (timeout) !== 'function' && typeof (timeout) !== 'object' ? timeout : 0;
34+
35+
this.startTimer = new Date().getTime();
36+
this.cb = callback || function() {};
37+
this.ms = milliseconds || 1000;
38+
this.timeout = timeout;
39+
this.messages = messages;
40+
this.check(expectedContextsCount);
41+
return this;
42+
};
43+
44+
CommandAction.prototype.check = function(expectedContextsCount) {
45+
var self = this;
46+
47+
this.protocol.contexts(function(result) {
48+
var now = new Date().getTime();
49+
var contextsCount = result.value ? result.value.length : -1;
50+
51+
if (expectedContextsCount === contextsCount) {
52+
setTimeout(function() {
53+
var msg = self.messages.success + (now - self.startTimer) + ' milliseconds.';
54+
self.cb.call(self.client.api, result.value);
55+
self.client.assertion(true, !!result.value, false, msg, true);
56+
return self.emit('complete');
57+
}, self.timeout);
58+
} else if (now - self.startTimer < self.ms) {
59+
setTimeout(function() {
60+
self.check(expectedContextsCount);
61+
}, 500);
62+
} else {
63+
var msg = self.messages.timeout + self.ms + ' milliseconds.';
64+
self.cb.call(self.client.api, false);
65+
self.client.assertion(false, false, false, msg, true);
66+
return self.emit('complete');
67+
}
68+
});
69+
};
70+
71+
module.exports = CommandAction;

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nightwatch-commands",
3-
"version": "1.6.2",
3+
"version": "1.7.0",
44
"description": "A set of Mobify specific custom commands for Nightwatch.js",
55
"repository": {
66
"type": "git",
@@ -11,15 +11,16 @@
1111
"url": "https://github.com/mobify/nightwatch-commands/issues"
1212
},
1313
"devDependencies": {
14-
"nightwatch": "0.8.6",
14+
"nightwatch": "0.9.1",
1515
"nodeunit": "~0.8.4",
1616
"grunt": "0.4.5",
17+
"grunt-cli": "~0.1.13",
1718
"grunt-eslint": "^17.0.0",
1819
"mobify-code-style": "^2.3.6"
1920
},
2021
"scripts": {
2122
"install": "node selenium/installation/install.js",
22-
"test": "grunt lint"
23+
"test": "./node_modules/.bin/grunt lint; ./node_modules/.bin/grunt test"
2324
},
2425
"homepage": "https://github.com/mobify/nightwatch-commands",
2526
"dependencies": {

tests/mocks.json

Lines changed: 69 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,89 @@
11
{
2-
"port" : 10195,
3-
"mocks" : [
4-
{
5-
"url" : "/wd/hub/session",
6-
"postdata" : "{\"desiredCapabilities\":{\"browserName\":\"firefox\",\"javascriptEnabled\":true,\"acceptSslCerts\":true,\"platform\":\"ANY\"},\"sessionId\":null}",
7-
"response" : "{\"status\": 0, \"sessionId\": \"1352110219202\", \"value\": { \"javascriptEnabled\": true, \"browserName\": \"firefox\"}, \"state\": null}",
8-
"responseHeaders" : {
9-
},
10-
"statusCode" : 200,
11-
"method": "POST"
12-
},
13-
{
2+
"port": 10195,
3+
"mocks": [{
4+
"url": "/wd/hub/session",
5+
"postdata": "",
6+
"response": "{\"status\": 0, \"sessionId\": \"1352110219202\", \"value\": { \"javascriptEnabled\": true, \"browserName\": \"firefox\", \"version\": \"TEST\", \"platform\": \"TEST\"}, \"state\": null}",
7+
"responseHeaders": {},
8+
"statusCode": 201,
9+
"method": "POST"
10+
}, {
1411
"url" : "/wd/hub/session/1352110219202",
15-
"method": "DELETE"
16-
},
17-
{
12+
"postdata" : "",
13+
"response" : "{\"status\":0,\"value\":true}"
14+
}, {
15+
"url" : "/wd/hub/session/1352110219202",
16+
"postdata" : "",
17+
"response" : "{\"status\":0,\"value\":false}"
18+
}, {
19+
"url" : "/wd/hub/session/1352110219202",
20+
"method": "DELETE",
21+
"postdata" : "",
22+
"response" : "{\"status\":0,\"value\":false}"
23+
}, {
24+
"url" : "/wd/hub/session/1352110219202/url",
25+
"method": "GET",
26+
"postdata" : ""
27+
}, {
1828
"url" : "/wd/hub/session/1352110219202/url",
29+
"method": "POST",
1930
"postdata" : "{\"url\":\"http://localhost\"}"
20-
},
21-
{
22-
"url" : "/wd/hub/test",
23-
"response" : "{\"status\":0}"
24-
},
25-
{
26-
"url" : "/wd/hub/test_error",
27-
"response" : "{\"status\":7,\"value\":{\"screen\":\"screenshot_data\"}}",
28-
"statusCode" : 500
29-
},
30-
{
31-
"url" : "/wd/hub/session/1352110219202/element",
32-
"postdata" : "{\"using\":\"css selector\",\"value\":\"body\"}",
33-
"response" : "{\"sessionId\":\"1352110219202\",\"status\":0,\"value\":{\"ELEMENT\":\"0\"},\"class\":\"org.openqa.selenium.remote.Response\",\"hCode\":604376696}"
34-
},
35-
{
36-
"url" : "/wd/hub/session/1352110219202/element",
37-
"postdata" : "{\"using\":\"css selector\",\"value\":\"#weblogin\"}",
38-
"response" : "{\"sessionId\":\"1352110219202\",\"status\":0,\"value\":{\"ELEMENT\":\"0\"},\"class\":\"org.openqa.selenium.remote.Response\",\"hCode\":604376696}"
39-
},
40-
{
41-
"url" : "/wd/hub/session/1352110219202/buttondown",
42-
"postdata" : "{\"button\":0}",
43-
"response" : "{\"sessionId\":\"1352110219202\",\"status\":0,\"class\":\"org.openqa.selenium.remote.Response\",\"hCode\":604376696}"
44-
},
45-
{
31+
}, {
32+
"url" : "/wd/hub/session/1352110219202/url",
33+
"method": "GET",
34+
"postdata" : "",
35+
"response" : "{\"value\":\"http://localhost/\",\"status\":0}"
36+
}, {
37+
"url" : "/wd/hub/session/null/url",
38+
"method": "GET",
39+
"postdata" : ""
40+
}, {
4641
"url" : "/wd/hub/session/1352110219202/execute",
4742
"postdata" : "{\"script\":\"return true;\",\"args\":[]}",
4843
"response" : "{\"status\":0,\"value\":true}"
49-
},
50-
{
44+
}, {
45+
"url" : "/wd/hub/session/1352110219202/execute",
46+
"postdata" : "{\"script\":\"return false\",\"args\":[]}",
47+
"response" : "{\"status\":0,\"value\":false}"
48+
}, {
5149
"url" : "/wd/hub/session/1352110219202/execute",
5250
"postdata" : "{\"script\":\"return Mobify.evaluatedData;\",\"args\":[]}",
5351
"response" : "{\"status\":0,\"value\":true}"
54-
},
55-
{
56-
"url" : "/wd/hub/session/1352110219202/execute",
57-
"postdata" : "{\"script\":\"var passedArgs = Array.prototype.slice.call(arguments,0); return function (sel, t) { var event = new MouseEvent(t || 'click', { 'view': window, 'bubbles': true, 'cancelable': true }); var el = document.querySelector(sel); el.dispatchEvent(event); return true; }.apply(window, passedArgs);\",\"args\":[\".clickMe\",null]}",
52+
}, {
53+
"url" : "/wd/hub/session/null/execute",
54+
"method": "POST",
55+
"postdata": "{\"script\":\"var passedArgs = Array.prototype.slice.call(arguments,0); return function () {\\n var framework = Mobify || Adaptive;\\n return !!framework;\\n }.apply(window, passedArgs);\",\"args\":[]}",
5856
"response" : "{\"status\":0,\"value\":true}"
59-
},
60-
{
57+
}, {
6158
"url" : "/wd/hub/session/1352110219202/execute",
62-
"postdata" : "{\"script\":\"var passedArgs = Array.prototype.slice.call(arguments,0); return function (sel, t) { var event = new MouseEvent(t || 'click', { 'view': window, 'bubbles': true, 'cancelable': true }); var el = document.querySelector(sel); el.dispatchEvent(event); return true; }.apply(window, passedArgs);\",\"args\":[\".clickMe\",\"click\"]}",
59+
"method": "POST",
60+
"postdata": "{\"script\":\"var passedArgs = Array.prototype.slice.call(arguments,0); return function () {\\n var framework = Mobify || Adaptive;\\n return !!framework;\\n }.apply(window, passedArgs);\",\"args\":[]}",
6361
"response" : "{\"status\":0,\"value\":true}"
64-
},
65-
{
62+
}, {
6663
"url" : "/wd/hub/session/1352110219202/execute",
64+
"method": "POST",
6765
"postdata": "{\"script\":\"var passedArgs = Array.prototype.slice.call(arguments,0); return function (){ var framework = Mobify || Adaptive; return !!framework; }.apply(window, passedArgs);\",\"args\":[]}",
6866
"response" : "{\"status\":0,\"value\":true}"
69-
},
70-
{
67+
}, {
68+
"url" : "/wd/hub/session/1352110219202/execute",
69+
"postdata": "{\"script\":\"var passedArgs = Array.prototype.slice.call(arguments,0); return function () {\\n var framework = Mobify || Adaptive;\\n return framework ? framework.evaluatedData : null;\\n }.apply(window, passedArgs);\",\"args\":[]}",
70+
"response" : "{\"status\":0,\"value\":true}"
71+
}, {
72+
"url" : "/wd/hub/session/1352110219202/execute",
73+
"postdata" : "{\"script\":\"var passedArgs = Array.prototype.slice.call(arguments,0); return function (sel, t) {\\n var event = new MouseEvent(t || 'click', {\\n 'view': window,\\n 'bubbles': true,\\n 'cancelable': true\\n });\\n var el = document.querySelector(sel);\\n el.dispatchEvent(event);\\n return true;\\n }.apply(window, passedArgs);\",\"args\":[\".clickMe\",\"click\"]}",
74+
"response" : "{\"status\":0,\"value\":true}"
75+
}, {
76+
"url" : "/wd/hub/session/1352110219202/execute",
77+
"postdata" : "{\"script\":\"var passedArgs = Array.prototype.slice.call(arguments,0); return function (sel, t) {\\n var event = new MouseEvent(t || 'click', {\\n 'view': window,\\n 'bubbles': true,\\n 'cancelable': true\\n });\\n var el = document.querySelector(sel);\\n el.dispatchEvent(event);\\n return true;\\n }.apply(window, passedArgs);\",\"args\":[\".clickMe\",null]}",
78+
"response" : "{\"status\":0,\"value\":true}"
79+
}, {
7180
"url" : "/wd/hub/session/1352110219202/execute",
7281
"postdata" : "{\"script\":\"return $.active;\",\"args\":[]}",
7382
"response" : "{\"status\":0,\"value\":0}"
74-
}
75-
]
83+
}, {
84+
"url" : "/wd/hub/session/1352110219202/contexts",
85+
"method": "GET",
86+
"postdata" : "",
87+
"response" : "{\"status\":0,\"value\":[\"NATIVE\", \"WEBVIEW_1\", \"WEBVIEW_2\"]}"
88+
}]
7689
}

tests/nightwatch.js

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,40 @@
11
var nightwatch = require('../node_modules/nightwatch');
22

33
module.exports = {
4-
init : function(callback) {
5-
return nightwatch.client({
6-
// desiredCapabilities: {
7-
// browserName: 'chrome'
8-
// },
4+
init: function(options, callback) {
5+
var opts = {
6+
seleniumPort: 10195,
7+
silent: true,
8+
output: false,
9+
globals: {
10+
myGlobal: 'test'
11+
},
12+
desiredCapabilities: {
13+
browserName: 'chrome'
14+
},
915
/* eslint-disable camelcase */
1016
custom_commands_path: '../commands',
11-
custom_assertions_path: '../assertions',
12-
selenium_port : 10195,
17+
custom_assertions_path: '../assertions'
1318
/* eslint-enable camelcase */
14-
silent : true,
15-
output : false
16-
}).start().once('error', function() {
19+
};
20+
21+
if (options) {
22+
for (var prop in options) {
23+
if (options.hasOwnProperty(prop)) {
24+
opts[prop] = options[prop];
25+
}
26+
}
27+
}
28+
29+
return nightwatch.client(opts).on('selenium:session_create', function() {
30+
if (callback) {
31+
callback();
32+
}
33+
}).once('error', function() {
1734
if (callback) {
1835
callback();
1936
}
2037
process.exit();
21-
});
38+
}).start();
2239
}
2340
};

0 commit comments

Comments
 (0)