refactor app directory structure and add tests

This commit is contained in:
s2
2016-11-10 16:27:26 +01:00
parent 204834ce28
commit dd88218c0e
1844 changed files with 263520 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
/**
* Checks if the given attribute of an element contains the expected value.
*
* ```
* this.demoTest = function (client) {
* browser.assert.attributeContains('#someElement', 'href', 'google.com');
* };
* ```
*
* @method attributeContains
* @param {string} selector The selector (CSS / Xpath) used to locate the element.
* @param {string} attribute The attribute name
* @param {string} expected The expected contained value of the attribute to check.
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
* @api assertions
*/
var util = require('util');
exports.assertion = function(selector, attribute, expected, msg) {
var DEFAULT_MSG = 'Testing if attribute %s of <%s> contains "%s".';
var MSG_ELEMENT_NOT_FOUND = DEFAULT_MSG + ' ' + 'Element could not be located.';
var MSG_ATTR_NOT_FOUND = DEFAULT_MSG + ' ' + 'Element does not have a ' + attribute + ' attribute.';
this.message = msg || util.format(DEFAULT_MSG, attribute, selector, expected);
this.expected = function() {
return expected;
};
this.pass = function(value) {
return value.indexOf(expected) > -1;
};
this.failure = function(result) {
var failed = (result === false) ||
// no such element
result && (result.status === -1 || result.value === null);
if (failed) {
var defaultMsg = MSG_ELEMENT_NOT_FOUND;
if (result && result.value === null) {
defaultMsg = MSG_ATTR_NOT_FOUND;
}
this.message = msg || util.format(defaultMsg, attribute, selector, expected);
}
return failed;
};
this.value = function(result) {
return result.value;
};
this.command = function(callback) {
return this.api.getAttribute(selector, attribute, callback);
};
};

View File

@@ -0,0 +1,57 @@
/**
* Checks if the given attribute of an element has the expected value.
*
* ```
* this.demoTest = function (client) {
* browser.assert.attributeEquals('body', 'data-attr', 'some value');
* };
* ```
*
* @method attributeEquals
* @param {string} selector The selector (CSS / Xpath) used to locate the element.
* @param {string} attribute The attribute name
* @param {string} expected The expected value of the attribute to check.
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
* @api assertions
*/
var util = require('util');
exports.assertion = function(selector, attribute, expected, msg) {
var DEFAULT_MSG = 'Testing if attribute %s of <%s> equals "%s".';
var MSG_ELEMENT_NOT_FOUND = DEFAULT_MSG + ' ' + 'Element could not be located.';
var MSG_ATTR_NOT_FOUND = DEFAULT_MSG + ' ' + 'Element does not have a ' + attribute + ' attribute.';
this.message = msg || util.format(DEFAULT_MSG, attribute, selector, expected);
this.expected = function() {
return expected;
};
this.pass = function(value) {
return value === expected;
};
this.failure = function(result) {
var failed = (result === false) ||
// no such element
result && (result.status === -1 || result.value === null);
if (failed) {
var defaultMsg = MSG_ELEMENT_NOT_FOUND;
if (result && result.value === null) {
defaultMsg = MSG_ATTR_NOT_FOUND;
}
this.message = msg || util.format(defaultMsg, attribute, selector, expected);
}
return failed;
};
this.value = function(result) {
return result.value;
};
this.command = function(callback) {
return this.api.getAttribute(selector, attribute, callback);
};
};

View File

@@ -0,0 +1,49 @@
/**
* Checks if the given element contains the specified text.
*
* ```
* this.demoTest = function (client) {
* browser.assert.containsText('#main', 'The Night Watch');
* };
* ```
*
* @method containsText
* @param {string} selector The selector (CSS / Xpath) used to locate the element.
* @param {string} expectedText The text to look for.
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
* @api assertions
*/
var util = require('util');
exports.assertion = function(selector, expectedText, msg) {
var MSG_ELEMENT_NOT_FOUND = 'Testing if element <%s> contains text: "%s". ' +
'Element could not be located.';
this.message = msg || util.format('Testing if element <%s> contains text: "%s".', selector, expectedText);
this.expected = function() {
return expectedText;
};
this.pass = function(value) {
return value.indexOf(expectedText) > -1;
};
this.failure = function(result) {
var failed = result === false || result && result.status === -1;
if (failed) {
this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, selector, expectedText);
}
return failed;
};
this.value = function(result) {
return result.value;
};
this.command = function(callback) {
return this.api.getText(selector, callback);
};
};

View File

@@ -0,0 +1,50 @@
/**
* Checks if the given element does not have the specified CSS class.
*
* ```
* this.demoTest = function (client) {
* browser.assert.cssClassNotPresent('#main', 'container');
* };
* ```
*
* @method cssClassNotPresent
* @param {string} selector The selector (CSS / Xpath) used to locate the element.
* @param {string} className The CSS class to look for.
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
* @api assertions
*/
var util = require('util');
exports.assertion = function(selector, className, msg) {
var MSG_ELEMENT_NOT_FOUND = 'Testing if element <%s> does not have css class: "%s". ' +
'Element could not be located.';
this.message = msg || util.format('Testing if element <%s> does not have css class: "%s".', selector, className);
this.expected = function() {
return 'without ' + className;
};
this.pass = function(value) {
var classes = value.split(' ');
return classes.indexOf(className) === -1;
};
this.failure = function(result) {
var failed = result === false || result && result.status === -1;
if (failed) {
this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, selector, className);
}
return failed;
};
this.value = function(result) {
return result.value;
};
this.command = function(callback) {
return this.api.getAttribute(selector, 'class', callback);
};
};

View File

@@ -0,0 +1,50 @@
/**
* Checks if the given element has the specified CSS class.
*
* ```
* this.demoTest = function (client) {
* browser.assert.cssClassPresent('#main', 'container');
* };
* ```
*
* @method cssClassPresent
* @param {string} selector The selector (CSS / Xpath) used to locate the element.
* @param {string} className The CSS class to look for.
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
* @api assertions
*/
var util = require('util');
exports.assertion = function(selector, className, msg) {
var MSG_ELEMENT_NOT_FOUND = 'Testing if element <%s> has css class: "%s". ' +
'Element could not be located.';
this.message = msg || util.format('Testing if element <%s> has css class: "%s".', selector, className);
this.expected = function() {
return 'has ' + className;
};
this.pass = function(value) {
var classes = value.split(' ');
return classes.indexOf(className) > -1;
};
this.failure = function(result) {
var failed = result === false || result && result.status === -1;
if (failed) {
this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, selector, className);
}
return failed;
};
this.value = function(result) {
return result.value;
};
this.command = function(callback) {
return this.api.getAttribute(selector, 'class', callback);
};
};

View File

@@ -0,0 +1,47 @@
/**
* Checks if the specified css property of a given element has the expected value.
*
* ```
* this.demoTest = function (client) {
* browser.assert.cssProperty('#main', 'display', 'block');
* };
* ```
*
* @method cssProperty
* @param {string} selector The selector (CSS / Xpath) used to locate the element.
* @param {string} cssProperty The CSS property.
* @param {string} expected The expected value of the css property to check.
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
* @api assertions
*/
var util = require('util');
exports.assertion = function(selector, cssProperty, expected, msg) {
var MSG_ELEMENT_NOT_FOUND = 'Testing if element <%s> has css property %s. ' +
'Element or attribute could not be located.';
this.message = msg || util.format('Testing if element <%s> has css property "%s: %s".', selector, cssProperty, expected);
this.expected = expected;
this.pass = function(value) {
return value === expected;
};
this.failure = function(result) {
var failed = result === false || result && result.status === -1;
if (failed) {
this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, selector, cssProperty);
}
return failed;
};
this.value = function(result) {
return result.value;
};
this.command = function(callback) {
return this.api.getCssProperty(selector, cssProperty, callback);
};
};

View File

@@ -0,0 +1,34 @@
/**
* Checks if the given element exists in the DOM.
*
* ```
* this.demoTest = function (client) {
* browser.assert.elementNotPresent(".should_not_exist");
* };
* ```
*
* @method elementNotPresent
* @param {string} selector The selector (CSS / Xpath) used to locate the element.
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
* @api assertions
*/
var util = require('util');
exports.assertion = function(selector, msg) {
this.message = msg || util.format('Testing if element <%s> is not present.', selector);
this.expected = 'not present';
this.pass = function(value) {
return value === 'not present';
};
this.value = function(result) {
return (result.status !== 0 || result.value.length === 0) ? 'not present' : 'present';
};
this.command = function(callback) {
return this.api.elements(this.client.locateStrategy, selector, callback);
};
};

View File

@@ -0,0 +1,34 @@
/**
* Checks if the given element exists in the DOM.
*
* ```
* this.demoTest = function (client) {
* browser.assert.elementPresent("#main");
* };
* ```
*
* @method elementPresent
* @param {string} selector The selector (CSS / Xpath) used to locate the element.
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
* @api assertions
*/
var util = require('util');
exports.assertion = function(selector, msg) {
this.message = msg || util.format('Testing if element <%s> is present.', selector);
this.expected = 'present';
this.pass = function(value) {
return value == 'present';
};
this.value = function(result) {
return (result.status !== 0 || result.value.length === 0) ? 'not present' : 'present';
};
this.command = function(callback) {
return this.api.elements(this.client.locateStrategy, selector, callback);
};
};

View File

@@ -0,0 +1,45 @@
/**
* Checks if the given element is not visible on the page.
*
* ```
* this.demoTest = function (client) {
* browser.assert.hidden(".should_not_be_visible");
* };
* ```
*
* @method hidden
* @param {string} selector The selector (CSS / Xpath) used to locate the element.
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
* @api assertions
*/
var util = require('util');
exports.assertion = function(selector, msg) {
var MSG_ELEMENT_NOT_FOUND = 'Testing if element <%s> is hidden. ' +
'Element could not be located.';
this.message = msg || util.format('Testing if element <%s> is hidden.', selector);
this.expected = true;
this.pass = function(value) {
return value === this.expected;
};
this.failure = function(result) {
var failed = result === false || result && result.status === -1;
if (failed) {
this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, selector);
}
return failed;
};
this.value = function(result) {
return !result.value;
};
this.command = function(callback) {
return this.api.isVisible(selector, callback);
};
};

View File

@@ -0,0 +1,35 @@
/**
* Checks if the page title equals the given value.
*
* ```
* this.demoTest = function (client) {
* browser.assert.title("Nightwatch.js");
* };
* ```
*
* @method title
* @param {string} expected The expected page title.
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
* @api assertions
*/
var util = require('util');
exports.assertion = function(expected, msg) {
this.message = msg || util.format('Testing if the page title equals "%s".', expected);
this.expected = expected;
this.pass = function(value) {
return value === this.expected;
};
this.value = function(result) {
return result.value;
};
this.command = function(callback) {
this.api.title(callback);
return this;
};
};

View File

@@ -0,0 +1,35 @@
/**
* Checks if the current URL contains the given value.
*
* ```
* this.demoTest = function (client) {
* browser.assert.urlContains('google');
* };
* ```
*
* @method urlContains
* @param {string} expected The value expected to exist within the current URL.
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
* @api assertions
*/
var util = require('util');
exports.assertion = function(expected, msg) {
this.message = msg || util.format('Testing if the URL contains "%s".', expected);
this.expected = expected;
this.pass = function(value) {
return value.indexOf(this.expected) > -1;
};
this.value = function(result) {
return result.value;
};
this.command = function(callback) {
this.api.url(callback);
return this;
};
};

View File

@@ -0,0 +1,35 @@
/**
* Checks if the current url equals the given value.
*
* ```
* this.demoTest = function (client) {
* browser.assert.urlEquals('http://www.google.com');
* };
* ```
*
* @method urlEquals
* @param {string} expected The expected url.
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
* @api assertions
*/
var util = require('util');
exports.assertion = function(expected, msg) {
this.message = msg || util.format('Testing if the URL equals "%s".', expected);
this.expected = expected;
this.pass = function(value) {
return value === this.expected;
};
this.value = function(result) {
return result.value;
};
this.command = function(callback) {
this.api.url(callback);
return this;
};
};

View File

@@ -0,0 +1,50 @@
/**
* Checks if the given form element's value equals the expected value.
*
* ```
* this.demoTest = function (client) {
* browser.assert.value("form.login input[type=text]", "username");
* };
* ```
*
* @method value
* @param {string} selector The selector (CSS / Xpath) used to locate the element.
* @param {string} expectedText The expected text.
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
* @api assertions
*/
var util = require('util');
exports.assertion = function(selector, expected, msg) {
var MSG_ELEMENT_NOT_FOUND = 'Testing if value of <%s> equals: "%s". ' +
'Element or attribute could not be located.';
this.message = msg || util.format('Testing if value of <%s> equals: "%s".', selector, expected);
this.expected = expected;
this.pass = function(value) {
return value === this.expected;
};
this.failure = function(result) {
var failed = (result === false) ||
// no such element
result && result.status === -1 ||
// element doesn't have a value attribute
result && result.value === null;
if (failed) {
this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, selector, expected);
}
return failed;
};
this.value = function(result) {
return result.value;
};
this.command = function(callback) {
return this.api.getValue(selector, callback);
};
};

View File

@@ -0,0 +1,53 @@
/**
* Checks if the given form element's value contains the expected value.
*
* ```
* this.demoTest = function (client) {
* browser.assert.valueContains("form.login input[type=text]", "username");
* };
* ```
*
* @method valueContains
* @param {string} selector The selector (CSS / Xpath) used to locate the element.
* @param {string} expectedText The expected text.
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
* @api assertions
*/
var util = require('util');
exports.assertion = function(selector, expected, msg) {
var DEFAULT_MSG = 'Testing if value of <%s> contains: "%s".';
var MSG_ELEMENT_NOT_FOUND = DEFAULT_MSG + ' ' + 'Element could not be located.';
var VALUE_ATTR_NOT_FOUND = DEFAULT_MSG + ' ' + 'Element does not have a value attribute.';
this.message = msg || util.format(DEFAULT_MSG, selector, expected);
this.expected = true;
this.pass = function(value) {
return value.indexOf(expected) > -1;
};
this.failure = function(result) {
var failed = (result === false) ||
// no such element
result && (result.status === -1 || result.value === null);
if (failed) {
var defaultMsg = MSG_ELEMENT_NOT_FOUND;
if (result && result.value === null) {
defaultMsg = VALUE_ATTR_NOT_FOUND;
}
this.message = msg || util.format(defaultMsg, selector, expected);
}
return failed;
};
this.value = function(result) {
return result.value;
};
this.command = function(callback) {
return this.api.getValue(selector, callback);
};
};

View File

@@ -0,0 +1,45 @@
/**
* Checks if the given element is visible on the page.
*
* ```
* this.demoTest = function (client) {
* browser.assert.visible(".should_be_visible");
* };
* ```
*
* @method visible
* @param {string} selector The selector (CSS / Xpath) used to locate the element.
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
* @api assertions
*/
var util = require('util');
exports.assertion = function(selector, msg) {
var MSG_ELEMENT_NOT_FOUND = 'Testing if element <%s> is visible. ' +
'Element could not be located.';
this.message = msg || util.format('Testing if element <%s> is visible.', selector);
this.expected = true;
this.pass = function(value) {
return value === this.expected;
};
this.failure = function(result) {
var failed = result === false || result && result.status === -1;
if (failed) {
this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, selector);
}
return failed;
};
this.value = function(result) {
return result.value;
};
this.command = function(callback) {
return this.api.isVisible(selector, callback);
};
};

View File

@@ -0,0 +1,509 @@
var events = require('events');
module.exports = function(client) {
return {
/**
* Change focus to another window. The window to change focus to may be specified by its server assigned window handle, or by the value of its name attribute.
*
* To find out the window handle use `window_handles` protocol action
*
* ```
* this.demoTest = function (browser) {
* browser.window_handles(function(result) {
* var handle = result.value[0];
* browser.switchWindow(handle);
* });
* };
* ```
*
* @method switchWindow
* @param {string} handleOrName The server assigned window handle or the name attribute.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see window
* @since v0.3.0
* @api commands
*/
switchWindow : function(handleOrName, callback) {
var self = this;
this.window('POST', handleOrName, function(result) {
if (typeof callback === 'function') {
callback.call(self, result);
}
});
return this;
},
/**
* Resizes the current window.
*
* ```
* this.demoTest = function (browser) {
* browser.resizeWindow(1000, 800);
* };
* ```
*
* @method resizeWindow
* @param {number} width The new window width.
* @param {number} height The new window height.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see windowSize
* @since v0.3.0
* @api commands
*/
resizeWindow : function(width, height, callback) {
var self = this;
return this.windowSize('current', width, height, function(result) {
if (typeof callback === 'function') {
callback.call(self, result);
}
});
},
/**
* Sets the current window position.
*
* ```
* this.demoTest = function (browser) {
* browser.setWindowPosition(0, 0);
* };
* ```
*
* @method setWindowPosition
* @param {number} offsetX The new window offset x-position.
* @param {number} offsetY The new window offset y-position.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see windowPosition
* @since v0.8.18
* @api commands
*/
setWindowPosition : function(offsetX, offsetY, callback) {
var self = this;
return this.windowPosition('current', offsetX, offsetY, function(result) {
if (typeof callback === 'function') {
callback.call(self, result);
}
});
},
/**
* Maximizes the current window.
*
* ```
* this.demoTest = function (browser) {
* browser.maximizeWindow();
* };
* ```
*
* @method maximizeWindow
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see windowMaximize
* @since v0.5.13
* @api commands
*/
maximizeWindow: function(callback) {
var self = this;
return this.windowMaximize('current', function(result) {
if (typeof callback === 'function') {
callback.call(self, result);
}
});
},
/**
* Take a screenshot of the current page and saves it as the given filename.
*
* ```
* this.demoTest = function (browser) {
* browser.saveScreenshot('/path/to/fileName.png');
* };
* ```
*
* @method saveScreenshot
* @param {string} fileName The complete path to the file name where the screenshot should be saved.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see screenshot
* @api commands
*/
saveScreenshot : function(fileName, callback) {
var self = this;
return this.screenshot(client.api.options.log_screenshot_data, function(result) {
client.saveScreenshotToFile(fileName, result.value, function(err) {
if (typeof callback === 'function') {
callback.call(self, result, err);
}
});
});
},
/**
* Returns the title of the current page. Uses title protocol command.
*
* ```
* this.demoTest = function (browser) {
* browser.getTitle(function(title) {
* this.assert.equal(typeof title, 'string');
* this.assert.equal(title, 'Nightwatch.js');
* });
* };
* ```
*
* @method getTitle
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see title
* @returns {string} The page title.
* @api commands
*/
getTitle : function(callback) {
var self = this;
return this.title(function(result) {
callback.call(self, result.value);
});
},
/**
* Close the current window. This can be useful when you're working with multiple windows open (e.g. an OAuth login).
* Uses `window` protocol command.
*
* ```
* this.demoTest = function (client) {
* client.closeWindow();
* };
* ```
*
* @method closeWindow
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see window
* @since v0.3.0
* @api commands
*/
closeWindow : function(callback) {
var self = this;
return this.window('DELETE', function(result) {
if (typeof callback === 'function') {
callback.call(self, result);
}
});
},
/**
* This command is an alias to url and also a convenience method when called without any arguments in the sense that it performs a call to .url() with passing the value of `launch_url` field from the settings file.
* Uses `url` protocol command.
*
* ```
* this.demoTest = function (client) {
* client.init();
* };
* ```
*
* @method init
* @param {string} [url] Url to navigate to.
* @see url
* @since v0.4.0
* @api commands
*/
init : function(url) {
if (url) {
return this.url(url);
}
if (!this.launchUrl) {
return this;
}
return this.url(this.launchUrl);
},
/**
* Convenience method that adds the specified hash (i.e. url fragment) to the current value of the `launch_url` as set in `nightwatch.json`.
*
* ```
* this.demoTest = function (client) {
* client.urlHash('#hashvalue');
* // or
* client.urlHash('hashvalue');
* };
* ```
*
* @method urlHash
* @param {string} hash The hash to add/replace to the current url (i.e. the value set in the launch_url property in nightwatch.json).
* @see url
* @since v0.4.0
* @api commands
*/
urlHash : function(hash) {
if (hash.charAt(0) === '#') {
hash = hash.substring(1);
}
return this.url(this.launchUrl + '#' + hash);
},
/**
* Retrieve all cookies visible to the current page. The cookies are returned as an array of cookie JSON object, as defined [here](https://code.google.com/p/selenium/wiki/JsonWireProtocol#Cookie_JSON_Object).
*
* Uses `cookie` protocol command.
*
* ```
* this.demoTest = function(browser) {
* browser.getCookies(function callback(result) {
* this.assert.equal(result.value.length, 1);
* this.assert.equals(result.value[0].name, 'test_cookie');
* });
* }
* ```
*
* @method getCookies
* @param {function} callback The callback function which will receive the response as an argument.
* @api commands
* @since v0.4.0
* @see cookie
* @returns {Array.<object>} A list of cookies.
*/
getCookies : function(callback) {
return this.cookie('GET', callback);
},
/**
* Retrieve a single cookie visible to the current page. The cookie is returned as a cookie JSON object, as defined [here](https://code.google.com/p/selenium/wiki/JsonWireProtocol#Cookie_JSON_Object).
*
* Uses `cookie` protocol command.
*
* ```
* this.demoTest = function(browser) {
* browser.getCookie(name, function callback(result) {
* this.assert.equal(result.value, '123456');
* this.assert.equals(result.name, 'test_cookie');
* });
* }
* ```
*
* @method getCookie
* @param {string} name The cookie name.
* @param {function} callback The callback function which will receive the response as an argument.
* @api commands
* @since v0.4.0
* @see cookie
* @returns {object|null} The cookie object as a selenium cookie JSON object or null if the cookie wasn't found.
*/
getCookie : function(name, callback) {
var self = this;
return this.cookie('GET', function(result) {
if (!result.value || result.value.length === 0) {
callback.call(self, null);
return;
}
var cookie = null;
for (var i = 0; i < result.value.length; i++) {
if (result.value[i].name === name) {
cookie = result.value[i];
break;
}
}
callback.call(self, cookie);
});
},
/**
* Set a cookie, specified as a cookie JSON object, as defined [here](https://code.google.com/p/selenium/wiki/JsonWireProtocol#Cookie_JSON_Object).
*
* Uses `cookie` protocol command.
*
* ```
* this.demoTest = function(browser) {
* browser.setCookie({
* name : "test_cookie",
* value : "test_value",
* path : "/", (Optional)
* domain : "example.org", (Optional)
* secure : false, (Optional)
* httpOnly : false, // (Optional)
* expiry : 1395002765 // (Optional) time in seconds since midnight, January 1, 1970 UTC
* });
* }
* ```
*
* @method setCookie
* @param {object} cookie The cookie object.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @api commands
* @since v0.4.0
* @see cookie
*/
setCookie : function(cookie, callback) {
return this.cookie('POST', cookie, callback);
},
/**
* Delete the cookie with the given name. This command is a no-op if there is no such cookie visible to the current page.
*
* ```
* this.demoTest = function(browser) {
* browser.deleteCookie("test_cookie", function() {
* // do something more in here
* });
* }
* ```
*
* @method deleteCookie
* @param cookieName The name of the cookie to delete.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @api commands
* @since v0.4.0
* @see cookie
*/
deleteCookie : function(cookieName, callback) {
return this.cookie('DELETE', cookieName, callback);
},
/**
* Delete all cookies visible to the current page.
*
* ```
* this.demoTest = function(browser) {
* browser.deleteCookies(function() {
* // do something more in here
* });
* }
* ```
*
* @method deleteCookies
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @api commands
* @since v0.4.0
* @see cookie
*/
deleteCookies : function(callback) {
return this.cookie('DELETE', callback);
},
/**
* Utility command to load an external script into the page specified by url.
*
* ```
* this.demoTest = function(client) {
* this.injectScript('http://example.org/js/utility.js', function() {
* // we're all done here.
* });
* };
* ```
*
* @method injectScript
* @param {string} scriptUrl The script file url
* @param {string} [id] Dom element id to be set on the script tag.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @api commands
* @since v0.4.0
* @returns {HTMLScriptElement} The newly created script tag.
*/
injectScript : function(scriptUrl, id, callback) {
var args = [scriptUrl];
if (arguments.length == 2 && typeof arguments[1] == 'function') {
callback = arguments[1];
} else if (typeof id == 'string') {
args.push(id);
}
return this.execute(function(u,i) {/* jshint browser:true */return (function(d){var e=d.createElement('script');var m=d.getElementsByTagName('head')[0];e.src=u;if(i){e.id=i;}m.appendChild(e);return e;})(document);}, args, callback);
},
/**
* Gets the available log types
*
* ```
* this.demoTest = function(client) {
* this.getLogTypes(function(typesArray) {
*
* });
* };
* ```
*
* @method getLogTypes
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @api commands
* @see logTypes
*/
getLogTypes: function(callback) {
var self = this;
return this.sessionLogTypes(function(response) {
if (callback) {
callback.call(self, response.value);
}
});
},
/**
* Gets a log from selenium
*
* ```
* this.demoTest = function(client) {
* this.getLog('browser', function(logEntriesArray) {
* console.log('Log length: ' + logEntriesArray.length);
* logEntriesArray.forEach(function(log) {
* console.log('[' + log.level + '] ' + log.timestamp + ' : ' + log.message);
* });
* });
* };
* ```
*
* @method getLog
* @param {string|function} typeString Log type to request
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @api commands
* @see log
*/
getLog: function(typeString, callback) {
var self = this;
if (typeof typeString !== 'string') {
if (typeof typeString === 'function') {
callback = typeString;
}
typeString = 'browser';
}
return this.sessionLog(typeString, function (response) {
if (callback) {
callback.call(self, response.value);
}
});
},
/**
* Utility command to test if the log type is available
*
* ```
* this.demoTest = function(browser) {
* browser.isLogAvailable('browser', function(isAvailable) {
* // do something more in here
* });
* }
* ```
*
* @method isLogAvailable
* @param {string|function} typeString Type of log to test
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @api commands
* @see getLogTypes
*/
isLogAvailable: function(typeString, callback) {
var self = this;
if (typeof typeString !== 'string') {
if (typeof typeString === 'function') {
callback = typeString;
}
typeString = 'browser';
}
return this.getLogTypes(function (types) {
var isAvailable;
try {
isAvailable = Array.isArray(types) && types.indexOf(typeString) >= 0;
} catch (err) {
isAvailable = false;
}
if (callback) {
callback.call(self, isAvailable);
}
});
}
};
};

View File

@@ -0,0 +1,24 @@
var util = require('util');
var events = require('events');
function Command() {
events.EventEmitter.call(this);
}
util.inherits(Command, events.EventEmitter);
Command.prototype.command = function(callback) {
var self = this;
this.client.locateStrategy = this.strategy;
process.nextTick(function() {
if (typeof callback == 'function') {
callback.call(self.client.api);
}
self.emit('complete');
});
return this;
};
module.exports = Command;

View File

@@ -0,0 +1,70 @@
var util = require('util');
var events = require('events');
var Utils = require('../../util/utils.js');
var Logger = require('../../util/logger.js');
/**
* Ends the session. Uses session protocol command.
*
* ```
* this.demoTest = function (browser) {
* browser.end();
* };
* ```
*
* @method end
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see session
* @api commands
*/
function End() {
events.EventEmitter.call(this);
}
util.inherits(End, events.EventEmitter);
End.prototype.command = function(callback) {
var self = this;
var client = this.client;
if (client.sessionId) {
if (this.testFailuresExist() && this.shouldTakeScreenshot()) {
var fileNamePath = Utils.getScreenshotFileName(client.api.currentTest, false, client.options.screenshots.path);
Logger.info('We have failures in "' + client.api.currentTest.name + '". Taking screenshot...');
client.api.saveScreenshot(fileNamePath, function(result, err) {
if (err || result.status !== 0) {
Logger.warn('Error saving screenshot...', err || result);
}
});
}
client.api.session('delete', function(result) {
client.sessionId = client.api.sessionId = null;
self.complete(callback, result);
});
} else {
setImmediate(function() {
self.complete(callback, null);
});
}
return this.client.api;
};
End.prototype.testFailuresExist = function() {
return this.client.results.errors > 0 || this.client.results.failed > 0;
};
End.prototype.shouldTakeScreenshot = function() {
return this.client.options.screenshots.enabled && this.client.options.screenshots.on_failure;
};
End.prototype.complete = function(callback, result) {
if (typeof callback === 'function') {
callback.call(this, result);
}
this.emit('complete');
};
module.exports = End;

View File

@@ -0,0 +1,46 @@
var util = require('util');
var events = require('events');
/**
* Suspends the test for the given time in milliseconds. If the milliseconds argument is missing it will suspend the test indefinitely
*
* ```
* this.demoTest = function (browser) {
* browser.pause(1000);
* // or suspend indefinitely
* browser.pause();
* };
* ```
*
* @method pause
* @param {number} ms The number of milliseconds to wait.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @api commands
*/
function Pause() {
events.EventEmitter.call(this);
}
util.inherits(Pause, events.EventEmitter);
Pause.prototype.command = function(ms, cb) {
var self = this;
// If we don't pass the milliseconds, the client will
// be suspended indefinitely
if (!ms) {
return this;
}
setTimeout(function() {
// if we have a callback, call it right before the complete event
if (cb) {
cb.call(self.client.api);
}
self.emit('complete');
}, ms);
return this;
};
module.exports = Pause;

View File

@@ -0,0 +1,81 @@
/**
* A simple perform command which allows access to the "api" in a callback.
* Can be useful if you want to read variables set by other commands.
*
* ```
* this.demoTest = function (browser) {
* var elementValue;
* browser
* .getValue('.some-element', function(result) {
* elementValue = result.value;
* })
* // other stuff going on ...
*
* // self-completing callback
* .perform(function() {
* console.log('elementValue', elementValue);
* // without any defined parameters, perform
* // completes immediately (synchronously)
* })
*
* // asynchronous completion
* .perform(function(done) {
* console.log('elementValue', elementValue);
* // potentially other async stuff going on
* // on finished, call the done callback
* done();
* })
*
* // asynchronous completion including api (client)
* .perform(function(client, done) {
* console.log('elementValue', elementValue);
* // similar to before, but now with client
* // potentially other async stuff going on
* // on finished, call the done callback
* done();
* });
* };
* ```
*
* @method perform
* @param {function} callback The function to run as part of the queue. Its signature can have up to two parameters. No parameters: callback runs and perform completes immediately at the end of the execution of the callback. One parameter: allows for asynchronous execution within the callback providing a done callback function for completion as the first argument. Two parameters: allows for asynchronous execution with the "api" object passed in as the first argument, followed by the done callback.
* @api commands
*/
var util = require('util');
var events = require('events');
function Perform() {
events.EventEmitter.call(this);
}
util.inherits(Perform, events.EventEmitter);
Perform.prototype.command = function(callback) {
var self = this;
var doneCallback;
if (callback.length === 0) {
callback.call(self, self.client.api);
doneCallback = function() {
self.emit('complete');
};
} else {
doneCallback = function() {
var args = [function() {
self.emit('complete');
}];
if (callback.length > 1) {
args.unshift(self.client.api);
}
callback.apply(self, args);
};
}
process.nextTick(doneCallback);
return this;
};
module.exports = Perform;

View File

@@ -0,0 +1,27 @@
var util = require('util');
var locateStrategy = require('./_locateStrategy.js');
/**
* Sets the locate strategy for selectors to `css selector`, therefore every following selector needs to be specified as css.
*
* ```
* this.demoTest = function (browser) {
* browser
* .useCss() // we're back to CSS now
* .setValue('input[type=text]', 'nightwatch');
* };
* ```
*
* @method useCss
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @api commands
*/
function Command() {
this.strategy = 'css selector';
locateStrategy.call(this);
}
util.inherits(Command, locateStrategy);
module.exports = Command;

View File

@@ -0,0 +1,20 @@
var util = require('util');
var locateStrategy = require('./_locateStrategy.js');
/**
* Sets the locate strategy for selectors to `recursion`, therefore every following selector needs to be an array of element objects
* This is used internally for sections of page objects which require element nesting
*
* @method useRecursion
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @api commands
*/
function Command() {
this.strategy = 'recursion';
locateStrategy.call(this);
}
util.inherits(Command, locateStrategy);
module.exports = Command;

View File

@@ -0,0 +1,27 @@
var util = require('util');
var locateStrategy = require('./_locateStrategy.js');
/**
* Sets the locate strategy for selectors to xpath, therefore every following selector needs to be specified as xpath.
*
* ```
* this.demoTest = function (browser) {
* browser
* .useXpath() // every selector now must be xpath
* .click("//tr[@data-recordid]/span[text()='Search Text']");
* };
* ```
*
* @method useXpath
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @api commands
*/
function Command() {
this.strategy = 'xpath';
locateStrategy.call(this);
}
util.inherits(Command, locateStrategy);
module.exports = Command;

View File

@@ -0,0 +1,388 @@
var util = require('util');
var events = require('events');
var Logger = require('../util/logger.js');
var Utils = require('../util/utils.js');
module.exports = function(client) {
var Protocol = require('./protocol.js')(client);
var returnValue = {};
var elementCommands = {};
/**
* Simulates a click event on the given DOM element. Uses `elementIdClick` protocol command.
*
* ```
* this.demoTest = function (client) {
* client.click("#main ul li a.first");
* };
* ```
*
* @method click
* @param {string} selector The CSS/Xpath selector used to locate the element.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see elementIdClick
* @api commands
*/
elementCommands.click = 'elementIdClick';
/**
* Clear a textarea or a text input element's value. Uses `elementIdValue` protocol command.
*
* ```
* this.demoTest = function (client) {
* client.clearValue('input[type=text]');
* };
* ```
*
* @method clearValue
* @param {string} selector The CSS/Xpath selector used to locate the element.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see elementIdClear
* @api commands
*/
elementCommands.clearValue = 'elementIdClear';
/**
* Retrieve the value of an attribute for a given DOM element. Uses `elementIdAttribute` protocol command.
*
* ```
* this.demoTest = function (client) {
* client.getAttribute("#main ul li a.first", "href", function(result) {
* this.assert.equal(typeof result, "object");
* this.assert.equal(result.status, 0);
* this.assert.equal(result.value, "#home");
* });
* };
* ```
*
* @method getAttribute
* @param {string} selector The CSS/Xpath selector used to locate the element.
* @param {string} attribute The attribute name to inspect.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see elementIdAttribute
* @returns {*} The value of the attribute
* @api commands
*/
elementCommands.getAttribute = ['elementIdAttribute', 1];
/**
* Retrieve the value of a css property for a given DOM element. Uses `elementIdCssProperty` protocol command.
*
* ```
* this.demoTest = function (client) {
* client.getCssProperty("#main ul li a.first", "display", function(result) {
* this.assert.equal(typeof result, "object");
* this.assert.equal(result.status, 0);
* this.assert.equal(result.value, 'inline');
* });
* };
* ```
*
* @method getCssProperty
* @param {string} selector The CSS/Xpath selector used to locate the element.
* @param {string} cssProperty The CSS property to inspect.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see elementIdCssProperty
* @returns {*} The value of the css property
* @api commands
*/
elementCommands.getCssProperty = ['elementIdCssProperty', 1];
/**
* Determine an element's size in pixels. Uses `elementIdSize` protocol command.
*
* ```
* this.demoTest = function (client) {
* client.getElementSize("#main ul li a.first", function(result) {
* this.assert.equal(typeof result, "object");
* this.assert.equal(result.status, 0);
* this.assert.equal(result.value.width, 500);
* this.assert.equal(result.value.height, 20);
* });
* };
* ```
*
* @method getElementSize
* @param {string} selector The CSS/Xpath selector used to locate the element.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see elementIdSize
* @returns {{width: number, height: number}} The width and height of the element in pixels
* @api commands
*/
elementCommands.getElementSize = 'elementIdSize';
/**
* Determine an element's location on the page. The point (0, 0) refers to the upper-left corner of the page.
*
* The element's coordinates are returned as a JSON object with x and y properties. Uses `elementIdLocation` protocol command.
*
* ```
* this.demoTest = function (client) {
* client.getLocation("#main ul li a.first", function(result) {
* this.assert.equal(typeof result, "object");
* this.assert.equal(result.status, 0);
* this.assert.equal(result.value.x, 200);
* this.assert.equal(result.value.y, 200);
* });
* };
* ```
*
* @method getLocation
* @param {string} selector The CSS/Xpath selector used to locate the element.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see elementIdLocation
* @returns {x:number, y:number} The X and Y coordinates for the element on the page.
* @api commands
*/
elementCommands.getLocation = 'elementIdLocation';
/**
* Determine an element's location on the screen once it has been scrolled into view. Uses `elementIdLocationInView` protocol command.
*
* ```
* this.demoTest = function (browser) {
* browser.getLocationInView("#main ul li a.first", function(result) {
* this.assert.equal(typeof result, "object");
* this.assert.equal(result.status, 0);
* this.assert.equal(result.value.x, 200);
* this.assert.equal(result.value.y, 200);
* });
* };
* ```
*
* @method getLocationInView
* @param {string} selector The CSS/Xpath selector used to locate the element.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see elementIdLocationInView
* @returns {x: number, y: number} The X and Y coordinates for the element on the page.
* @api commands
*/
elementCommands.getLocationInView = 'elementIdLocationInView';
/**
* Query for an element's tag name. Uses `elementIdName` protocol command.
*
* ```
* this.demoTest = function (client) {
* client.getTagName("#main ul li .first", function(result) {
* this.assert.equal(typeof result, "object");
* this.assert.equal(result.status, 0);
* this.assert.equal(result.value, "a");
* });
* };
* ```
*
* @method getTagName
* @param {string} selector The CSS/Xpath selector used to locate the element.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see elementIdName
* @returns {number} The element's tag name, as a lowercase string.
* @api commands
*/
elementCommands.getTagName = 'elementIdName';
/**
* Returns the visible text for the element. Uses `elementIdText` protocol command.
*
* ```
* this.demoTest = function (browser) {
* browser.getText("#main ul li a.first", function(result) {
* this.assert.equal(typeof result, "object");
* this.assert.equal(result.status, 0);
* this.assert.equal(result.value, "nightwatchjs.org");
* });
* };
* ```
*
* @method getText
* @param {string} selector The CSS/Xpath selector used to locate the element.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see elementIdText
* @returns {string} The element's visible text.
* @api commands
*/
elementCommands.getText = 'elementIdText';
/**
* Returns a form element current value. Uses `elementIdValue` protocol command.
*
* ```
* this.demoTest = function (browser) {
* browser.getValue("form.login input[type=text]", function(result) {
* this.assert.equal(typeof result, "object");
* this.assert.equal(result.status, 0);
* this.assert.equal(result.value, "enter username");
* });
* };
* ```
*
* @method getValue
* @param {string} selector The CSS/Xpath selector used to locate the element.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see elementIdValue
* @returns {string} The element's value.
* @api commands
*/
elementCommands.getValue = 'elementIdValue';
/**
* Determine if an element is currently displayed. Uses `elementIdDisplayed` protocol command.
*
* ```
* this.demoTest = function (browser) {
* browser.isVisible('#main', function(result) {
* this.assert.equal(typeof result, "object");
* this.assert.equal(result.status, 0);
* this.assert.equal(result.value, true);
* });
* };
* ```
*
* @method isVisible
* @param {string} selector The CSS/Xpath selector used to locate the element.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see elementIdDisplayed
* @api commands
*/
elementCommands.isVisible = 'elementIdDisplayed';
/**
* Move the mouse by an offset of the specified element. Uses `moveTo` protocol command.
*
* ```
* this.demoTest = function (browser) {
* browser.moveToElement('#main', 10, 10);
* };
* ```
*
* @method moveToElement
* @param {string} selector The CSS/Xpath selector used to locate the element.
* @param {number} xoffset X offset to move to, relative to the top-left corner of the element.
* @param {number} yoffset Y offset to move to, relative to the top-left corner of the element.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see moveTo
* @api commands
*/
elementCommands.moveToElement = ['moveTo', 2];
/**
* Sends some text to an element. Can be used to set the value of a form element or to send a sequence of key strokes to an element. Any UTF-8 character may be specified.
*
* An object map with available keys and their respective UTF-8 characters, as defined on [W3C WebDriver draft spec](http://www.w3.org/TR/webdriver/#character-types), is loaded onto the main Nightwatch instance as `client.Keys`.
*
* ```
* // send some simple text to an input
* this.demoTest = function (browser) {
* browser.setValue('input[type=text]', 'nightwatch');
* };
* //
* // send some text to an input and hit enter.
* this.demoTest = function (browser) {
* browser.setValue('input[type=text]', ['nightwatch', browser.Keys.ENTER]);
* };
* ```
*
* @link /session/:sessionId/element/:id/value
* @method setValue
* @param {string} selector The CSS/Xpath selector used to locate the element.
* @param {string|array} value The text to send to the element or key strokes.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see elementIdValue
* @api commands
*/
elementCommands.setValue = ['elementIdValue', 1];
/**
* Submit a FORM element. The submit command may also be applied to any element that is a descendant of a FORM element. Uses `submit` protocol command.
*
* ```
* this.demoTest = function (browser) {
* browser.submitForm('form.login');
* };
* ```
*
* @method submitForm
* @param {string} selector The CSS/Xpath selector used to locate the element.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @see submit
* @api commands
*/
elementCommands.submitForm = 'submit';
function addElementCommand(protocolAction, extraArgs) {
extraArgs = extraArgs || 0;
var expectedArgs = 3 + extraArgs;
return function commandActionFn() {
var originalStackTrace = commandActionFn.stackTrace;
var noopFn = function() {};
var args = Array.prototype.slice.call(arguments, 0);
if (typeof args[args.length-1] !== 'function') {
args.push(noopFn);
}
var defaultUsing = client.locateStrategy || 'css selector';
if (expectedArgs - args.length === 1) {
args.unshift(defaultUsing);
}
if (args.length < expectedArgs - 1 || args.length > expectedArgs) {
throw new Error(protocolAction + ' method expects ' + (expectedArgs - 1) + ' or ' + expectedArgs + ' arguments - ' + args.length + ' given.');
}
var using = args.shift();
var value = args.shift();
var callback = args.pop();
return new CommandAction(using, value, protocolAction, args, callback, originalStackTrace);
};
}
function CommandAction(using, value, protocolAction, args, callback, originalStackTrace) {
events.EventEmitter.call(this);
var $this = this;
var el = Protocol.element(using, value, function(result) {
if (result.status !== 0) {
callback.call(client.api, result);
var errorMessage = 'ERROR: Unable to locate element: "' + value + '" using: ' + using;
var stack = originalStackTrace.split('\n');
stack.shift();
Utils.showStackTraceWithHeadline(errorMessage, stack);
client.results.errors++;
client.errors.push(errorMessage + '\n' + stack.join('\n'));
$this.emit('complete', el, $this);
} else {
result = result.value.ELEMENT;
args.push(function(r) {
callback.call(client.api, r);
});
args.unshift(result);
var c = Protocol[protocolAction].apply(Protocol, args).once('complete', function() {
$this.emit('complete', c, $this);
});
}
});
}
util.inherits(CommandAction, events.EventEmitter);
Object.keys(elementCommands).forEach(function(commandName) {
var args = elementCommands[commandName];
if (!Array.isArray(args)) {
args = [args];
}
returnValue[commandName] = addElementCommand.apply(client.api, args);
});
// alias
returnValue.sendKeys = returnValue.setValue;
return returnValue;
};

View File

@@ -0,0 +1,43 @@
var util = require('util');
var events = require('events');
/**
* Search for an element on the page, starting with the first element of the array, and where each element in the passed array is nested under the previous one. The located element will be returned as a WebElement JSON object.
*
* @param {Array} elements An array of ancestor element objects containing selector and locateStrategy properties
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @api protocol
*/
function ElementByRecursion(client) {
events.EventEmitter.call(this);
this.protocol = require('../protocol.js')(client);
}
util.inherits(ElementByRecursion, events.EventEmitter);
ElementByRecursion.prototype.command = function(elements, callback) {
var self = this;
var allElements = elements.slice();
var topElement = allElements.shift();
var el = this.protocol.element(topElement.locateStrategy, topElement.selector, function checkResult(result) {
if (result.status !== 0) {
callback(result);
self.emit('complete', el, self);
} else {
var nextElement = allElements.shift();
var parentId = result.value.ELEMENT;
if (nextElement) {
self.protocol.elementIdElement(parentId, nextElement.locateStrategy, nextElement.selector, checkResult);
} else {
callback(result);
self.emit('complete', el, self);
}
}
});
return this;
};
module.exports = ElementByRecursion;

View File

@@ -0,0 +1,94 @@
var util = require('util');
var events = require('events');
var Q = require('q');
/**
* Search for multiple elements on the page, starting with the first element of the array, and where each element in the passed array is nested under the previous one. The located element will be returned as a WebElement JSON objects.
*
* @param {Array} elements An array of ancestor element objects containing selector and locateStrategy properties
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @api protocol
*/
function ElementsByRecursion(client) {
events.EventEmitter.call(this);
this.protocol = require('../protocol.js')(client);
}
util.inherits(ElementsByRecursion, events.EventEmitter);
ElementsByRecursion.prototype.command = function(elements, callback) {
var self = this;
function deferredElementIdElements(el, using, value) {
var deferred = Q.defer();
var req = self.protocol.elementIdElements(el, using, value, function(result) {
deferred.resolve(result);
});
req.on('error', function() {
deferred.reject();
});
return deferred.promise;
}
function createResult(result, foundElements) {
return {
status: 0,
sessionId: result.sessionId,
value: foundElements.map(function(e) {
return {
ELEMENT: e
};
}),
class: result.class,
hCode: result.hCode
};
}
function aggregateResults(results) {
var result;
var foundElements = [];
for (var i = 0; i < results.length; i++) {
result = results[i];
if (result.status === 0 && result.value && result.value.length) {
result.value.forEach(function(e) {
if (foundElements.indexOf(e.ELEMENT) <= -1) {
// In case we have multiple matches on the same element, only add once
foundElements.push(e.ELEMENT);
}
});
}
}
return createResult(result, foundElements);
}
var allElements = elements.slice();
var topElement = allElements.shift();
var el = this.protocol.elements(topElement.locateStrategy, topElement.selector, function checkResult() {
var result = aggregateResults(arguments);
if (result.value.length === 0) {
callback(result);
self.emit('complete', el, self);
return;
}
var nextElement = allElements.shift();
if (nextElement) {
var promises = [];
result.value.forEach(function(el) {
var p = deferredElementIdElements(el.ELEMENT, nextElement.locateStrategy, nextElement.selector, checkResult);
promises.push(p);
});
Q.all(promises).spread(checkResult);
} else {
callback(result);
self.emit('complete', el, self);
}
});
return this;
};
module.exports = ElementsByRecursion;

View File

@@ -0,0 +1,280 @@
var util = require('util');
var events = require('events');
var Logger = require('../../util/logger.js');
var Utils = require('../../util/utils.js');
/*!
* Base class for waitForElement commands. It provides a command
* method and element* methods to be overwritten by subclasses
*
* @constructor
*/
function WaitForElement() {
events.EventEmitter.call(this);
this.startTimer = null;
this.cb = null;
this.ms = null;
this.element = null;
this.abortOnFailure = typeof this.client.api.globals.abortOnAssertionFailure == 'undefined' || this.client.api.globals.abortOnAssertionFailure;
this.selector = null;
this.locateStrategy = this.client.locateStrategy || 'css selector';
this.rescheduleInterval = this.client.api.globals.waitForConditionPollInterval || this.client.options.waitForConditionPollInterval || 500; //ms
this.throwOnMultipleElementsReturned = this.client.api.globals.throwOnMultipleElementsReturned || this.client.options.throwOnMultipleElementsReturned || false;
this.protocol = require('../protocol.js')(this.client);
}
util.inherits(WaitForElement, events.EventEmitter);
/*!
* The public command function which will be called by the test runner. Arguments can be passed in a variety of ways.
*
* The custom message always is last and the callback is always before the message or last if a message is not passed.
*
* The second argument is always the time in milliseconds. The third argument can be either of:
* - abortOnFailure: this can overwrite the default behaviour of aborting the test if the condition is not met within the specified time
* - rescheduleInterval: this can overwrite the default polling interval (currently 500ms)
* The above can be supplied also together, in which case the rescheduleInterval is specified before the abortOnFailure.
*
* Some of the multiple usage possibilities:
* ---------------------------------------------------------------------------
* - with no arguments; in this case a global default timeout is expected
* waitForElement('body');
*
* - with a global default timeout and a callback
* waitForElement('body', function() {});
*
* - with a global default timeout, a callback and a custom message
* waitForElement('body', function() {}, 'test message');
*
* - with only the timeout
* waitForElement('body', 500);
*
* - with a timeout and a custom message
* waitForElement('body', 500, 'test message);
*
* - with a timeout and a callback
* waitForElement('body', 500, function() { .. });
*
* - with a timeout and a custom abortOnFailure
* waitForElement('body', 500, true);
*
* - with a timeout, a custom abortOnFailure and a custom message
* waitForElement('body', 500, true, 'test message');
*
* - with a timeout, a custom abortOnFailure and a callback
* waitForElement('body', 500, true, function() { .. });
*
* - with a timeout, a custom abortOnFailure, a callback and a custom message
* waitForElement('body', 500, true, function() { .. }, 'test message');
*
* - with a timeout, a custom reschedule interval and a callback
* waitForElement('body', 500, 100, function() { .. });
*
* - with a timeout, a custom rescheduleInterval and a custom abortOnFailure
* waitForElement('body', 500, 100, false);
*
*
* @param {string} selector
* @param {number|function|string} milliseconds
* @param {function|boolean|string|number} callbackOrAbort
* @returns {WaitForElement}
*/
WaitForElement.prototype.command = function commandFn(selector, milliseconds, callbackOrAbort) {
this.startTimer = new Date().getTime();
this.ms = this.setMilliseconds(milliseconds);
this._stackTrace = commandFn.stackTrace;
if (typeof arguments[1] === 'function') {
////////////////////////////////////////////////
// The command was called with an implied global timeout:
//
// waitForElement('body', function() {});
// waitForElement('body', function() {}, 'custom message');
////////////////////////////////////////////////
this.cb = arguments[1];
} else if (typeof arguments[2] === 'boolean') {
////////////////////////////////////////////////
// The command was called with a custom abortOnFailure:
//
// waitForElement('body', 500, false);
////////////////////////////////////////////////
this.abortOnFailure = arguments[2];
// The optional callback is the 4th argument now
this.cb = arguments[3] || function() {};
} else if (typeof arguments[2] === 'number') {
////////////////////////////////////////////////
// The command was called with a custom rescheduleInterval:
//
// waitForElement('body', 500, 100);
////////////////////////////////////////////////
this.rescheduleInterval = arguments[2];
if (typeof arguments[3] === 'boolean') {
////////////////////////////////////////////////
// The command was called with a custom rescheduleInterval and custom abortOnFailure:
//
// waitForElement('body', 500, 100, false);
////////////////////////////////////////////////
this.abortOnFailure = arguments[3];
// The optional callback is the 5th argument now
this.cb = arguments[4] || function() {};
} else {
// The optional callback is the 4th argument now
this.cb = arguments[3] || function() {};
}
} else {
// The optional callback is the 3th argument now
this.cb = (typeof callbackOrAbort === 'function' && callbackOrAbort) || function() {};
}
// support for a custom message
this.message = null;
if (arguments.length > 1) {
var lastArgument = arguments[arguments.length - 1];
if (typeof lastArgument === 'string') {
this.message = lastArgument;
}
}
this.selector = selector;
this.checkElement();
return this;
};
/*!
* @override
*/
WaitForElement.prototype.elementFound = function(result, now) {};
/*!
* @override
*/
WaitForElement.prototype.elementNotFound = function(result, now) {};
/*!
* @override
*/
WaitForElement.prototype.elementVisible = function(result, now) {};
/*!
* @override
*/
WaitForElement.prototype.elementNotVisible = function(result, now) {};
/*!
* Reschedule the checkElement
*/
WaitForElement.prototype.reschedule = function(method) {
var self = this;
method = method || 'checkElement';
setTimeout(function() {
self[method]();
}, this.rescheduleInterval);
};
WaitForElement.prototype.complete = function() {
var args = Array.prototype.slice.call(arguments, 0);
args.push(this);
this.cb.apply(this.client.api, args);
this.emit('complete');
return this;
};
WaitForElement.prototype.pass = function(result, defaultMsg, timeMs) {
this.message = this.formatMessage(defaultMsg, timeMs);
this.client.assertion(true, null, null, this.message, this.abortOnFailure);
return this.complete(result);
};
WaitForElement.prototype.fail = function(result, actual, expected, defaultMsg) {
this.message = this.formatMessage(defaultMsg);
this.client.assertion(false, actual, expected, this.message, this.abortOnFailure, this._stackTrace);
return this.complete(result);
};
/*!
* Will start checking if the element exists and if not re-schedule the check
* until the timeout expires or the condition has been met
*/
WaitForElement.prototype.checkElement = function() {
var self = this;
this.getProtocolCommand(function(result) {
var now = new Date().getTime();
if (result.value && result.value.length > 0) {
if (result.value.length > 1) {
var message = 'WaitForElement found ' + result.value.length + ' elements for selector "' + self.selector + '".';
if (self.throwOnMultipleElementsReturned) {
throw new Error(message);
} else if (self.client.options.output) {
console.log(Logger.colors.green(' Warn: ' + message + ' Only the first one will be checked.'));
}
}
self.element = result.value[0].ELEMENT;
return self.elementFound(result, now);
}
return self.elementNotFound(result, now);
});
};
WaitForElement.prototype.getProtocolCommand = function(callback) {
return this.protocol.elements(this.locateStrategy, this.selector, callback);
};
/*!
* Will start checking if the element is visible and if not re-schedule the check
* until the timeout expires or the condition has been met
*/
WaitForElement.prototype.isVisible = function() {
var self = this;
this.protocol.elementIdDisplayed(this.element, function(result) {
var now = new Date().getTime();
if (result.status === 0 && result.value === true) {
// element was visible
return self.elementVisible(result, now);
}
if (result.status === -1 && result.errorStatus === 10) {
return self.checkElement();
}
return self.elementNotVisible(result, now);
});
};
/**
* @param {string} defaultMsg
* @param {number} [timeMs]
* @returns {string}
*/
WaitForElement.prototype.formatMessage = function (defaultMsg, timeMs) {
return Utils.format(this.message || defaultMsg, this.selector, timeMs || this.ms);
};
/**
* Set the time in milliseconds to wait for the condition, accepting a given value or a globally defined default
*
* @param {number} [timeoutMs]
* @throws Will throw an error if the global default is undefined or a non-number
* @returns {number}
*/
WaitForElement.prototype.setMilliseconds = function (timeoutMs) {
if (timeoutMs && typeof timeoutMs === 'number') {
return timeoutMs;
}
var globalTimeout = this.client.api.globals.waitForConditionTimeout;
if (typeof globalTimeout !== 'number') {
throw new Error('waitForElement expects second parameter to have a global default ' +
'(waitForConditionTimeout) to be specified if not passed as the second parameter ');
}
return globalTimeout;
};
module.exports = WaitForElement;

View File

@@ -0,0 +1,53 @@
var util = require('util');
var WaitForElement = require('./_waitForElement.js');
/**
* Opposite of `waitForElementPresent`. Waits a given time in milliseconds for an element to be not present (i.e. removed) in the page before performing any other commands or assertions.
*
* If the element is still present after the specified amount of time, the test fails.
*
* You can change the polling interval by defining a `waitForConditionPollInterval` property (in milliseconds) in as a global property in your `nightwatch.json` or in your external globals file.
*
* Similarly, a default timeout can be specified as a global `waitForConditionTimeout` property (in milliseconds).
*
* ```
* this.demoTest = function (browser) {
* browser.waitForElementNotPresent('#dialog', 1000);
* };
* ```
*
* @method waitForElementNotPresent
* @param {string} selector The selector (CSS / Xpath) used to locate the element.
* @param {number} time The number of milliseconds to wait. The runner performs repeated checks every 500 ms.
* @param {boolean} [abortOnFailure] By the default if the element is not found the test will fail. Set this to false if you wish for the test to continue even if the assertion fails. To set this globally you can define a property `abortOnAssertionFailure` in your globals.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @param {string} [message] Optional message to be shown in the output; the message supports two placeholders: %s for current selector and %d for the time (e.g. Element %s was not in the page for %d ms).
* @see waitForElementPresent
* @since v0.4.0
* @api commands
*/
function WaitForElementNotPresent() {
WaitForElement.call(this);
this.expectedValue = 'not found';
}
util.inherits(WaitForElementNotPresent, WaitForElement);
WaitForElementNotPresent.prototype.elementFound = function(result, now) {
if (now - this.startTimer < this.ms) {
// element is still there, schedule another check
this.reschedule();
return this;
}
var defaultMsg = 'Timed out while waiting for element <%s> to be removed for %d milliseconds.';
return this.fail(result, 'found', this.expectedValue, defaultMsg);
};
WaitForElementNotPresent.prototype.elementNotFound = function(result, now) {
var defaultMsg = 'Element <%s> was not present after %d milliseconds.';
return this.pass(result, defaultMsg, now - this.startTimer);
};
module.exports = WaitForElementNotPresent;

View File

@@ -0,0 +1,56 @@
var util = require('util');
var WaitForElementPresent = require('./waitForElementPresent.js');
/**
* Opposite of `waitForElementVisible`. Waits a given time in milliseconds for an element to be not visible (i.e. hidden but existing) in the page before performing any other commands or assertions.
*
* If the element fails to be hidden in the specified amount of time, the test fails.
*
* You can change the polling interval by defining a `waitForConditionPollInterval` property (in milliseconds) in as a global property in your `nightwatch.json` or in your external globals file.
*
* Similarly, a default timeout can be specified as a global `waitForConditionTimeout` property (in milliseconds).
*
* ```
* this.demoTest = function (browser) {
* browser.waitForElementNotVisible('#dialog', 1000);
* };
* ```
*
* @method waitForElementNotVisible
* @param {string} selector The selector (CSS / Xpath) used to locate the element.
* @param {number} time The number of milliseconds to wait. The runner performs repeated checks every 500 ms.
* @param {boolean} [abortOnFailure] By the default if the element is not found the test will fail. Set this to false if you wish for the test to continue even if the assertion fails. To set this globally you can define a property `abortOnAssertionFailure` in your globals.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @param {string} [message] Optional message to be shown in the output; the message supports two placeholders: %s for current selector and %d for the time (e.g. Element %s was not in the page for %d ms).
* @since v0.4.0
* @see waitForElementVisible
* @api commands
*/
function WaitForElementNotVisible() {
WaitForElementPresent.call(this);
this.expectedValue = 'not visible';
}
util.inherits(WaitForElementNotVisible, WaitForElementPresent);
WaitForElementNotVisible.prototype.elementFound = function() {
return this.isVisible();
};
WaitForElementNotVisible.prototype.elementVisible = function(result, now) {
if (now - this.startTimer < this.ms) {
// element wasn't visible, schedule another check
this.reschedule('isVisible');
return this;
}
var defaultMsg = 'Timed out while waiting for element <%s> to not be visible for %d milliseconds.';
return this.fail(result, 'visible', this.expectedValue, defaultMsg);
};
WaitForElementNotVisible.prototype.elementNotVisible = function(result, now) {
var defaultMsg = 'Element <%s> was not visible after %d milliseconds.';
return this.pass(result, defaultMsg, now - this.startTimer);
};
module.exports = WaitForElementNotVisible;

View File

@@ -0,0 +1,60 @@
var util = require('util');
var WaitForElement = require('./_waitForElement.js');
/**
* Waits a given time in milliseconds for an element to be present in the page before performing any other commands or assertions.
*
* If the element fails to be present in the specified amount of time, the test fails. You can change this by setting `abortOnFailure` to `false`.
*
* You can change the polling interval by defining a `waitForConditionPollInterval` property (in milliseconds) in as a global property in your `nightwatch.json` or in your external globals file.
*
* Similarly, a default timeout can be specified as a global `waitForConditionTimeout` property (in milliseconds).
*
* ```
* this.demoTest = function (browser) {
* browser.waitForElementPresent('body', 1000);
* // continue if failed
* browser.waitForElementPresent('body', 1000, false);
* // with callback
* browser.waitForElementPresent('body', 1000, function() {
* // do something while we're here
* });
* // custom Spanish message
* browser.waitForElementPresent('body', 1000, 'elemento %s no era presente en %d ms');
* // many combinations possible - the message is always the last argument
* browser.waitForElementPresent('body', 1000, false, function() {}, 'elemento %s no era presente en %d ms');
* };
* ```
*
* @method waitForElementPresent
* @param {string} selector The selector (CSS / Xpath) used to locate the element.
* @param {number} time The number of milliseconds to wait. The runner performs repeated checks every 500 ms.
* @param {boolean} [abortOnFailure] By the default if the element is not found the test will fail. Set this to false if you wish for the test to continue even if the assertion fails. To set this globally you can define a property `abortOnAssertionFailure` in your globals.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @param {string} [message] Optional message to be shown in the output; the message supports two placeholders: %s for current selector and %d for the time (e.g. Element %s was not in the page for %d ms).
* @api commands
*/
function WaitForElementPresent() {
WaitForElement.call(this);
this.expectedValue = 'found';
}
util.inherits(WaitForElementPresent, WaitForElement);
WaitForElementPresent.prototype.elementFound = function(result, now) {
var defaultMsg = 'Element <%s> was present after %d milliseconds.';
return this.pass(result, defaultMsg, now - this.startTimer);
};
WaitForElementPresent.prototype.elementNotFound = function(result, now) {
if (now - this.startTimer < this.ms) {
// element wasn't found, schedule another check
this.reschedule();
return this;
}
var defaultMsg = 'Timed out while waiting for element <%s> to be present for %d milliseconds.';
return this.fail({value:false}, 'not found', this.expectedValue, defaultMsg);
};
module.exports = WaitForElementPresent;

View File

@@ -0,0 +1,64 @@
var util = require('util');
var WaitForElementPresent = require('./waitForElementPresent.js');
/**
* Waits a given time in milliseconds for an element to be visible in the page before performing any other commands or assertions.
*
* If the element fails to be present and visible in the specified amount of time, the test fails. You can change this by setting `abortOnFailure` to `false`.
*
* You can change the polling interval by defining a `waitForConditionPollInterval` property (in milliseconds) in as a global property in your `nightwatch.json` or in your external globals file.
*
* Similarly, a default timeout can be specified as a global `waitForConditionTimeout` property (in milliseconds).
*
* ```
* this.demoTest = function (browser) {
* browser.waitForElementVisible('body', 1000);
* // continue if failed
* browser.waitForElementVisible('body', 1000, false);
* // with callback
* browser.waitForElementVisible('body', 1000, function() {
* // do something while we're here
* });
* // custom Spanish message
* browser.waitForElementVisible('body', 1000, 'elemento %s no era visible en %d ms');
* // many combinations possible - the message is always the last argument
* browser.waitForElementVisible('body', 1000, false, function() {}, 'elemento %s no era visible en %d ms');
* };
* ```
*
* @method waitForElementVisible
* @param {string} selector The selector (CSS / Xpath) used to locate the element.
* @param {number} time The number of milliseconds to wait. The runner performs repeated checks every 500 ms.
* @param {boolean} [abortOnFailure] By the default if the element is not found the test will fail. Set this to false if you wish for the test to continue even if the assertion fails. To set this globally you can define a property `abortOnAssertionFailure` in your globals.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @param {string} [message] Optional message to be shown in the output; the message supports two placeholders: %s for current selector and %d for the time (e.g. Element %s was not in the page for %d ms).
* @api commands
*/
function WaitForElementVisible() {
WaitForElementPresent.call(this);
this.expectedValue = 'visible';
}
util.inherits(WaitForElementVisible, WaitForElementPresent);
WaitForElementVisible.prototype.elementFound = function(result, now) {
return this.isVisible();
};
WaitForElementVisible.prototype.elementVisible = function(result, now) {
var defaultMsg = 'Element <%s> was visible after %d milliseconds.';
return this.pass(result, defaultMsg, now - this.startTimer);
};
WaitForElementVisible.prototype.elementNotVisible = function(result, now) {
if (now - this.startTimer < this.ms) {
// element wasn't visible, schedule another check
this.reschedule('isVisible');
return this;
}
var defaultMsg = 'Timed out while waiting for element <%s> to be visible for %d milliseconds.';
return this.fail(result, 'not visible', this.expectedValue, defaultMsg);
};
module.exports = WaitForElementVisible;

25
tests/node_modules/nightwatch/lib/api/errors.json generated vendored Normal file
View File

@@ -0,0 +1,25 @@
{
"0": {"id": "Success", "message": "The command executed successfully."},
"7": {"id": "NoSuchElement", "message": "An element could not be located on the page using the given search parameters."},
"8": {"id": "NoSuchFrame", "message": "A request to switch to a frame could not be satisfied because the frame could not be found."},
"9": {"id": "UnknownCommand", "message": "The requested resource could not be found, or a request was received using an HTTP method that is not supported by the mapped resource."},
"10": {"id": "StaleElementReference", "message": "An element command failed because the referenced element is no longer attached to the DOM."},
"11": {"id": "ElementNotVisible", "message": "An element command could not be completed because the element is not visible on the page."},
"12": {"id": "InvalidElementState", "message": "An element command could not be completed because the element is in an invalid state (e.g. attempting to click a disabled element)."},
"13": {"id": "UnknownError", "message": "An unknown server-side error occurred while processing the command."},
"15": {"id": "ElementIsNotSelectable", "message": "An attempt was made to select an element that cannot be selected."},
"17": {"id": "JavaScriptError", "message": "An error occurred while executing user supplied JavaScript."},
"19": {"id": "XPathLookupError", "message": "An error occurred while searching for an element by XPath."},
"23": {"id": "NoSuchWindow", "message": "A request to switch to a different window could not be satisfied because the window could not be found."},
"24": {"id": "InvalidCookieDomain", "message": "An illegal attempt was made to set a cookie under a different domain than the current page."},
"25": {"id": "UnableToSetCookie", "message": "A request to set a cookie's value could not be satisfied."},
"26": {"id": "UnexpectedAlertOpen", "message": "A modal dialog was open, blocking this operation."},
"27": {"id": "NoAlertOpenError", "message": "An attempt was made to operate on a modal dialog when one was not open."},
"28": {"id": "Timeout", "message": ""},
"29": {"id": "InvalidElementCoordinates", "message": "The coordinates provided to an interactions operation are invalid."},
"30": {"id": "IMENotAvailable", "message": "IME was not available."},
"31": {"id": "IMEEngineActivationFailed", "message": "An IME engine could not be started."},
"32": {"id": "InvalidSelector", "message": "Argument was an invalid selector (e.g. XPath/CSS)."},
"33": {"id": "SessionNotCreatedException", "message": "A new session could not be created."},
"34": {"id": "MoveTargetOutOfBounds", "message": "Target provided for a move action is out of bounds."}
}

138
tests/node_modules/nightwatch/lib/api/expect.js generated vendored Executable file
View File

@@ -0,0 +1,138 @@
var util = require('util');
var events = require('events');
var chai = require('chai-nightwatch');
var expect = chai.expect;
var ChaiAssertion = chai.Assertion;
var Q = require('q');
var flag = chai.flag;
module.exports = function(client) {
var Protocol = require('./protocol.js')(client);
var PresentAssertion = require('./expect/present.js');
var AttributeAssertion = require('./expect/attribute.js');
var CssAssertion = require('./expect/css.js');
var TextAssertion = require('./expect/text.js');
var EnabledAssertion = require('./expect/enabled.js');
var VisibleAssertion = require('./expect/visible.js');
var SelectedAssertion = require('./expect/selected.js');
var TypeAssertion = require('./expect/type.js');
var ValueAssertion = require('./expect/value.js');
var Expect = {};
ChaiAssertion.addMethod('before', function(ms) {
flag(this, 'waitFor', ms);
flag(this, 'before', true);
});
ChaiAssertion.addMethod('after', function(ms) {
flag(this, 'after', true);
flag(this, 'waitFor', ms);
});
ChaiAssertion.addProperty('present', function() {
createAssertion(PresentAssertion, this);
});
ChaiAssertion.addProperty('enabled', function() {
createAssertion(EnabledAssertion, this);
});
ChaiAssertion.addProperty('text', function() {
createAssertion(TextAssertion, this);
});
ChaiAssertion.addProperty('value', function() {
createAssertion(ValueAssertion, this);
});
ChaiAssertion.addProperty('visible', function() {
createAssertion(VisibleAssertion, this);
});
ChaiAssertion.addProperty('selected', function() {
createAssertion(SelectedAssertion, this);
});
ChaiAssertion.addMethod('attribute', function(attribute, msg) {
createAssertion(AttributeAssertion, this, [attribute, msg]);
});
ChaiAssertion.addMethod('css', function(property, msg) {
createAssertion(CssAssertion, this, [property, msg]);
});
function typeAssertion(type, msg) {
createAssertion(TypeAssertion, this, [type, msg]);
}
ChaiAssertion.addMethod('a', typeAssertion);
ChaiAssertion.addMethod('an', typeAssertion);
function createAssertion(AssertionClass, chaiAssert, args) {
function F() {
this.setAssertion(chaiAssert)
.setClient(client)
.setProtocol(Protocol)
.init();
return AssertionClass.apply(this, args);
}
F.prototype = AssertionClass.prototype;
chaiAssert.assertion = new F();
}
function Element(selector, using) {
this.selector = selector;
this.using = using;
this.startTime = null;
this.emitter = null;
this.createPromise();
}
util.inherits(Element, events.EventEmitter);
Element.prototype.getElementsCommand = function(callback) {
this.locator = this.using || client.locateStrategy || 'css selector';
return Protocol.elements(this.locator, this.selector, callback);
};
Element.prototype.promise = function() {
return this.deferred.promise;
};
Element.prototype.createPromise = function() {
this.deferred = Q.defer();
return this.deferred.promise;
};
Element.prototype.locate = function(emitter) {
if (emitter) {
this.emitter = emitter;
this.startTime = new Date().getTime();
}
this.getElementsCommand(function(result) {
if (result.status !== 0 || !result.value || result.value.length === 0) {
this.deferred.reject(result);
} else {
this.deferred.resolve(result.value[0]);
}
}.bind(this));
};
Expect.element = function(selector, using) {
var element = new Element(selector, using);
var promise = element.promise();
var expect = chai.expect(promise);
flag(expect, 'selector', selector);
flag(expect, 'promise', promise);
flag(expect, 'element', element);
return {
element : element,
expect : expect
};
};
return Expect;
};

View File

@@ -0,0 +1,341 @@
/**
* Abstract assertion class that will subclass all defined Chai assertions
*
* All assertions must implement the following api:
*
* - @type {function}
* executeCommand
* - @type {string}
* elementFound
* - @type {function}
* elementNotFound
* - @type {function}
* retryCommand
* - @type {string}
* expected
* - @type {string}
* actual
* - @type {string}
* message
* - @type {boolean}
* passed
*
* @constructor
*/
var util = require('util');
var events = require('events');
var Assertion = require('../../core/assertion.js');
var chai = require('chai-nightwatch');
var flag = chai.flag;
var Utils = require('../../util/utils.js');
function BaseAssertion() {
}
BaseAssertion.ASSERT_FLAGS = [
'be',
'that',
'have',
'which',
'equal',
'contains',
'matches',
'before',
'after',
'waitFor'
];
/**
* @override
*/
BaseAssertion.prototype.executeCommand = function(callback) {};
BaseAssertion.prototype.setAssertion = function(assertion) {
this.assertion = assertion;
return this;
};
BaseAssertion.prototype.flag = function(key, value) {
if (typeof value == 'undefined') {
return flag(this.assertion, key);
}
flag(this.assertion, key, value);
return this;
};
BaseAssertion.prototype.setClient = function(client) {
this.client = client;
return this;
};
BaseAssertion.prototype.setProtocol = function(protocol) {
this.protocol = protocol;
return this;
};
BaseAssertion.prototype.init = function() {
this.promise = this.flag('promise');
this.element = this.flag('element');
this.selector = this.flag('selector');
this.setNegate();
this.waitForMs = this.client.api.globals.waitForConditionTimeout || null;
if (this.waitForMs) {
this.flag('waitFor', this.waitForMs);
}
this.retryInterval = this.client.api.globals.waitForConditionPollInterval || 500;
this.retries = 0;
this.messageParts = [];
this.abortOnFailure = typeof this.client.api.globals.abortOnAssertionFailure == 'undefined' || this.client.api.globals.abortOnAssertionFailure;
this.passed = false;
this.expected = null;
this.elementResult = null;
this.flags = [];
};
BaseAssertion.prototype.start = function() {
this.promise.then(this.onPromiseResolved.bind(this), this.onPromiseRejected.bind(this));
};
BaseAssertion.prototype.onPromiseResolved = function(elementResult) {
if (elementResult) {
this.elementResult = elementResult;
}
this.executeCommand(function(result) {
this.resultValue = result.value;
this.resultStatus = result.status;
this.resultErrorStatus = result.errorStatus;
this.processFlags();
this.elementFound();
if (!this.passed && this.shouldRetry()) {
this.scheduleRetry();
} else {
this.done();
}
}.bind(this));
};
BaseAssertion.prototype.onPromiseRejected = function(response) {
this.processFlags();
if (this.shouldRetry() && !this.negate) {
this.scheduleRetry();
return;
}
this.messageParts.push(' - element was not found');
this.actual = 'not present';
this.expected = 'present';
this.elementNotFound();
this.done();
};
BaseAssertion.prototype.processFlags = function() {
BaseAssertion.ASSERT_FLAGS.forEach(function(entry) {
var value = this.flag(entry);
if ((typeof value != 'undefined') && (typeof this['@' + entry + 'Flag'] == 'function')) {
this.flags.push([entry, value]);
this['@' + entry + 'Flag'](value);
}
}.bind(this));
};
BaseAssertion.prototype.hasFlag = function(type) {
return this.flags.some(function(flag) {
return flag[0] === type;
});
};
/**
* @override
*/
BaseAssertion.prototype.elementFound = function() {};
/**
* @override
*/
BaseAssertion.prototype.elementNotFound = function() {};
BaseAssertion.prototype.done = function() {
this.formatMessage();
var stackTrace = this.flag('element')._stackTrace;
Assertion.assert(
this.passed,
this.actual,
this.expected,
this.message,
this.abortOnFailure,
stackTrace
);
this.element.emitter.emit('complete');
};
BaseAssertion.prototype.getResult = function(value, fn) {
var result = fn.call(this);
this.setNegate();
return this.negate ? !result : result;
};
BaseAssertion.prototype.shouldRetryLocateElement = function() {
return (!this.elementResult || this.resultStatus === 10 || this.resultErrorStatus === 10);
};
BaseAssertion.prototype.shouldRetry = function() {
if (!this.waitForMs) {
return false;
}
this.elapsedTime = this.getElapsedTime();
return (this.elapsedTime < this.waitForMs);
};
BaseAssertion.prototype.getElapsedTime = function() {
var timeNow = new Date().getTime();
return timeNow - this.element.startTime;
};
BaseAssertion.prototype.scheduleRetry = function() {
this.retries++;
setTimeout(this.retryCommand.bind(this), this.retryInterval);
};
BaseAssertion.prototype.formatMessage = function() {
this.message = Utils.format(this.message || this.message, this.selector);
this.message += this.messageParts.join('');
};
BaseAssertion.prototype['@containsFlag'] = function(value) {
var verb = (this.hasFlag('that') || this.hasFlag('which')) ? 'contains' : 'contain';
this.conditionFlag(value, function() {
return this.resultValue ? this.resultValue.indexOf(value) > -1 : false;
}, [
'not ' + verb,
verb
]);
return this;
};
BaseAssertion.prototype['@equalFlag'] = function(value) {
var verb;
if (this.hasFlag('have')) {
verb = (this.hasFlag('that') || this.hasFlag('which')) ? 'equals' : 'equal to';
} else {
verb = 'equal';
}
this.conditionFlag(value, function() {
return this.resultValue == value;
}, [
'not ' + verb,
verb
]);
return this;
};
BaseAssertion.prototype['@matchesFlag'] = function(re) {
var adverb = this.hasFlag('that') || this.hasFlag('which');
var verb = adverb ? 'matches' : 'match';
this.conditionFlag(re, function() {
return re.test(this.resultValue);
}, [
(adverb ? 'does ' : '') + 'not match',
verb
]);
return this;
};
BaseAssertion.prototype.conditionFlag = function(value, conditionFn, arrverb) {
this.passed = this.getResult(value, conditionFn);
var verb = this.negate ? arrverb[0]: arrverb[1];
this.expected = verb + ' \'' + value + '\'';
this.actual = this.resultValue;
if (this.retries > 0) {
return;
}
var needsSpace = this.messageParts.length === 0 ? true : this.messageParts[this.messageParts.length-1].slice(-1) != ' ';
if (needsSpace) {
verb = ' ' + verb;
}
if (!this.customMessage) {
this.messageParts.push(
verb,
': "', value, '"'
);
}
};
BaseAssertion.prototype.setNegate = function() {
this.negate = this.flag('negate') || false;
return this;
};
BaseAssertion.prototype['@beforeFlag'] = function(value) {};
BaseAssertion.prototype['@afterFlag'] = function(value) {};
BaseAssertion.prototype['@haveFlag'] = function(value) {};
BaseAssertion.prototype['@waitForFlag'] = function(value) {
if (this.waitForMs !== value) {
this.waitForMs = value;
if (!this.customMessage) {
this.messageParts.push(this.checkWaitForMsg(this.waitForMs));
}
}
};
BaseAssertion.prototype['@thatFlag'] = function() {
if (this.retries > 0) {
return;
}
if (!this.customMessage) {
this.messageParts.push(' that ');
}
return this;
};
BaseAssertion.prototype['@whichFlag'] = function() {
if (this.retries > 0) {
return;
}
if (!this.customMessage) {
this.messageParts.push(' which ');
}
return this;
};
BaseAssertion.prototype['@beFlag'] = function() {};
BaseAssertion.prototype.hasCondition = function() {
return (this.hasFlag('contains') || this.hasFlag('equal') || this.hasFlag('matches'));
};
BaseAssertion.prototype.checkWaitForMsg = function(waitFor) {
var preposition = this.flag('before') && 'in' ||
this.flag('after') && 'after' ||
'in';
return ' ' + preposition +' ' + waitFor + 'ms';
};
BaseAssertion.prototype.retryCommand = function() {
if (this.shouldRetryLocateElement()) {
this.promise = this.element.createPromise();
this.promise.then(this.onPromiseResolved.bind(this), this.onPromiseRejected.bind(this));
this.element.locate();
} else {
this.onPromiseResolved();
}
};
module.exports = BaseAssertion;

View File

@@ -0,0 +1,98 @@
/**
* Checks if a given attribute of an element exists and optionally if it has the expected value.
*
* ```
* this.demoTest = function (browser) {
* browser.expect.element('body').to.have.attribute('data-attr');
* browser.expect.element('body').to.not.have.attribute('data-attr');
* browser.expect.element('body').to.not.have.attribute('data-attr', 'Testing if body does not have data-attr');
* browser.expect.element('body').to.have.attribute('data-attr').before(100);
* browser.expect.element('body').to.have.attribute('data-attr')
* .equals('some attribute');
* browser.expect.element('body').to.have.attribute('data-attr')
* .not.equals('other attribute');
* browser.expect.element('body').to.have.attribute('data-attr')
* .which.contains('something');
* browser.expect.element('body').to.have.attribute('data-attr')
* .which.matches(/^something\ else/);
* };
* ```
*
* @method attribute
* @param {string} attribute The attribute name
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
* @display .attribute(name)
* @since v0.7
* @api expect
*/
var util = require('util');
var events = require('events');
var BaseAssertion = require('./_baseAssertion.js');
function AttributeAssertion(attribute, msg) {
this.flag('attributeFlag', true);
this.attribute = attribute;
this.customMessage = msg;
this.message = msg || 'Expected element <%s> to ' + (this.negate ? 'not have' : 'have') + ' attribute "' + attribute + '"';
BaseAssertion.call(this);
this.start();
}
util.inherits(AttributeAssertion, BaseAssertion);
AttributeAssertion.prototype.executeCommand = function(callback) {
this.protocol.elementIdAttribute(this.elementResult.ELEMENT, this.attribute, function(result) {
if (result.value !== null && result.status === 0) {
callback(result);
} else {
this.attributeNotFound();
}
}.bind(this));
};
AttributeAssertion.prototype.elementFound = function() {
if (this.retries > 0 && this.negate) {
return;
}
if (!this.hasCondition()) {
this.passed = this.negate ? false : true;
this.expected = this.negate ? 'not found' : 'found';
this.actual = 'found';
}
if (this.waitForMs && this.passed) {
var message = 'attribute was present';
if (this.hasCondition()) {
message = 'condition was met';
}
this.elapsedTime = this.getElapsedTime();
this.messageParts.push(' - ' + message + ' in ' + this.elapsedTime + 'ms');
}
};
AttributeAssertion.prototype.attributeNotFound = function() {
this.processFlags();
this.passed = this.hasCondition() ? false : this.negate;
if (!this.passed && this.shouldRetry()) {
this.scheduleRetry();
} else {
if (!this.hasCondition()) {
this.expected = this.negate ? 'not found' : 'found';
this.actual = 'not found';
}
if (!this.negate) {
this.messageParts.push(' - attribute was not found');
}
this.done();
}
};
AttributeAssertion.prototype.elementNotFound = function() {
this.passed = false;
};
module.exports = AttributeAssertion;

69
tests/node_modules/nightwatch/lib/api/expect/css.js generated vendored Normal file
View File

@@ -0,0 +1,69 @@
/**
* Checks a given css property of an element exists and optionally if it has the expected value.
*
* ```
* this.demoTest = function (browser) {
* browser.expect.element('#main').to.have.css('display');
* browser.expect.element('#main').to.have.css('display', 'Testing for display');
* browser.expect.element('#main').to.not.have.css('display');
* browser.expect.element('#main').to.have.css('display').before(100);
* browser.expect.element('#main').to.have.css('display').which.equals('block');
* browser.expect.element('#main').to.have.css('display').which.contains('some value');
* browser.expect.element('#main').to.have.css('display').which.matches(/some\ value/);
* };
* ```
*
* @method css
* @param {string} property The css property name
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.*
* @display .css(property)
* @since v0.7
* @api expect
*/
var util = require('util');
var events = require('events');
var BaseAssertion = require('./_baseAssertion.js');
function CssAssertion(property, msg) {
this.cssProperty = property;
this.flag('cssFlag', true);
BaseAssertion.call(this);
this.customMessage = typeof msg != 'undefined';
this.message = msg || 'Expected element <%s> to ' + (this.negate ? 'not have' : 'have') + ' css property "' + property + '"';
this.start();
}
util.inherits(CssAssertion, BaseAssertion);
CssAssertion.prototype.executeCommand = function(callback) {
this.protocol.elementIdCssProperty(this.elementResult.ELEMENT, this.cssProperty, callback);
};
CssAssertion.prototype['@haveFlag'] = function() {
this.passed = this.negate ? (this.resultValue === '') : (this.resultValue !== '');
this.expected = this.negate ? 'not present' : 'present';
this.actual = this.resultValue === '' ? 'not present' : 'present';
};
CssAssertion.prototype.elementFound = function() {
if (this.retries > 0 && this.negate) {
return;
}
if (this.passed && this.waitForMs) {
var message = 'property was present';
if (this.hasCondition()) {
message = 'condition was met';
}
this.elapsedTime = this.getElapsedTime();
this.messageParts.push(' - ' + message + ' in ' + this.elapsedTime + 'ms');
}
};
CssAssertion.prototype.elementNotFound = function() {
this.passed = false;
};
module.exports = CssAssertion;

View File

@@ -0,0 +1,55 @@
/**
* Property that checks if an element is currently enabled.
*
* ```
* this.demoTest = function (browser) {
* browser.expect.element('#weblogin').to.be.enabled;
* browser.expect.element('#main').to.not.be.enabled;
* browser.expect.element('#main').to.be.enabled.before(100);
* };
* ```
*
* @method enabled
* @display .enabled
* @since v0.7
* @api expect
*/
var util = require('util');
var events = require('events');
var BaseAssertion = require('./_baseAssertion.js');
function EnabledAssertion() {
BaseAssertion.call(this);
this.message = 'Expected element <%s> to ' + (this.negate ? 'not be enabled' : 'be enabled');
this.start();
}
util.inherits(EnabledAssertion, BaseAssertion);
EnabledAssertion.prototype.executeCommand = function(callback) {
this.protocol.elementIdEnabled(this.elementResult.ELEMENT, callback);
};
EnabledAssertion.prototype.elementFound = function() {
if (this.retries > 0 && this.negate) {
return;
}
this.passed = this.negate ? !this.resultValue : this.resultValue;
this.expected = this.negate ? 'not enabled' : 'enabled';
this.actual = this.resultValue ? 'enabled' : 'not enabled';
if (this.passed && this.waitForMs) {
this.elapsedTime = this.getElapsedTime();
this.messageParts.push(' - condition was met in ' + this.elapsedTime + 'ms');
}
};
EnabledAssertion.prototype.elementNotFound = function() {
this.passed = false;
this.expected = this.negate ? 'not enabled' : 'enabled';
this.actual = 'not found';
};
module.exports = EnabledAssertion;

View File

@@ -0,0 +1,71 @@
/**
* Property that checks if an element is present in the DOM.
*
* ```
* this.demoTest = function (browser) {
* browser.expect.element('#main').to.be.present;
* browser.expect.element('#main').to.not.be.present;
* browser.expect.element('#main').to.be.present.before(100);
* };
* ```
*
* @method present
* @display .present
* @since v0.7
* @api expect
*/
var util = require('util');
var events = require('events');
var BaseAssertion = require('./_baseAssertion.js');
function PresentAssertion() {
this.flag('present', true);
BaseAssertion.call(this);
this.message = 'Expected element <%s> to ' + (this.negate ? 'not be present' : 'be present');
this.start();
}
util.inherits(PresentAssertion, BaseAssertion);
PresentAssertion.prototype.executeCommand = function(callback) {
return callback(this.elementResult);
};
PresentAssertion.prototype.elementFound = function() {
this.passed = !this.negate;
if (!this.passed && this.shouldRetry()) {
return;
}
if (this.waitForMs) {
this.elapsedTime = this.getElapsedTime();
this.messageParts.push(' - element was present in ' + this.elapsedTime + 'ms');
}
if (this.negate) {
this.actual = 'present';
this.expected = 'not present';
}
};
PresentAssertion.prototype.elementNotFound = function() {
this.passed = this.negate;
if (!this.passed && this.shouldRetry()) {
return;
}
if (this.waitForMs && this.negate) {
this.messageParts.push(this.checkWaitForMsg(this.elapsedTime) + '.');
}
};
PresentAssertion.prototype.retryCommand = function() {
this.promise = this.element.createPromise();
this.element.deferred.promise.then(this.onPromiseResolved.bind(this), this.onPromiseRejected.bind(this));
this.element.locate();
};
module.exports = PresentAssertion;

View File

@@ -0,0 +1,55 @@
/**
* Property that checks if an OPTION element, or an INPUT element of type checkbox or radio button is currently selected.
*
* ```
* this.demoTest = function (browser) {
* browser.expect.element('#main').to.be.selected;
* browser.expect.element('#main').to.not.be.selected;
* browser.expect.element('#main').to.be.selected.before(100);
* };
* ```
*
* @method selected
* @display .selected
* @since v0.7
* @api expect
*/
var util = require('util');
var events = require('events');
var BaseAssertion = require('./_baseAssertion.js');
function SelectedAssertion() {
BaseAssertion.call(this);
this.message = 'Expected element <%s> to ' + (this.negate ? 'not be selected' : 'be selected');
this.start();
}
util.inherits(SelectedAssertion, BaseAssertion);
SelectedAssertion.prototype.executeCommand = function(callback) {
this.protocol.elementIdSelected(this.elementResult.ELEMENT, callback);
};
SelectedAssertion.prototype.elementFound = function() {
if (this.retries > 0 && this.negate) {
return;
}
this.passed = this.negate ? !this.resultValue : this.resultValue;
this.expected = this.negate ? 'not selected' : 'selected';
this.actual = this.resultValue ? 'selected' : 'not selected';
if (this.passed && this.waitForMs) {
this.elapsedTime = this.getElapsedTime();
this.messageParts.push(' - condition was met in ' + this.elapsedTime + 'ms');
}
};
SelectedAssertion.prototype.elementNotFound = function() {
this.passed = false;
this.expected = this.negate ? 'not selected' : 'selected';
this.actual = 'not found';
};
module.exports = SelectedAssertion;

58
tests/node_modules/nightwatch/lib/api/expect/text.js generated vendored Normal file
View File

@@ -0,0 +1,58 @@
/**
* Property that retrieves the text contained by an element. Can be chained to check if contains/equals/matches the specified text or regex.
*
* ```
* this.demoTest = function (browser) {
* browser.expect.element('#main').text.to.equal('The Night Watch');
* browser.expect.element('#main').text.to.not.equal('The Night Watch');
* browser.expect.element('#main').text.to.equal('The Night Watch').before(100);
* browser.expect.element('#main').text.to.contain('The Night Watch');
* browser.expect.element('#main').text.to.match(/The\ Night\ Watch/);
* };
* ```
*
* @method text
* @since v0.7
* @display .text
* @api expect
*/
var util = require('util');
var events = require('events');
var BaseAssertion = require('./_baseAssertion.js');
function TextAssertion() {
this.flag('textFlag', true);
BaseAssertion.call(this);
this.message = 'Expected element <%s> text to' + (this.negate ? ' not' : '');
this.start();
}
util.inherits(TextAssertion, BaseAssertion);
TextAssertion.prototype.executeCommand = function(callback) {
this.protocol.elementIdText(this.elementResult.ELEMENT, callback);
};
TextAssertion.prototype.elementFound = function() {
if (this.retries > 0 && this.negate) {
return;
}
if (this.passed && this.waitForMs) {
var message = '';
if (this.hasCondition()) {
message = 'condition was met';
}
this.elapsedTime = this.getElapsedTime();
this.messageParts.push(' - ' + message + ' in ' + this.elapsedTime + 'ms');
}
};
TextAssertion.prototype.elementNotFound = function() {
this.passed = false;
};
module.exports = TextAssertion;

60
tests/node_modules/nightwatch/lib/api/expect/type.js generated vendored Normal file
View File

@@ -0,0 +1,60 @@
/**
* Checks if the type (i.e. tag name) of a specified element is of an expected value.
*
* ```
* this.demoTest = function (browser) {
* browser.expect.element('#q').to.be.an('input');
* browser.expect.element('#q').to.be.an('input', 'Testing if #q is an input');
* browser.expect.element('#w').to.be.a('span');
* };
* ```
*
* @method a
* @display .a(type)
* @alias an
* @since v0.7
* @param {string} type The expected type
* @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
* @api expect
*/
var util = require('util');
var events = require('events');
var BaseAssertion = require('./_baseAssertion.js');
function TypeAssertion(type, msg) {
this.type = type;
BaseAssertion.call(this);
this.article = ['a', 'e', 'i', 'o'].indexOf(type.substring(0, 1)) > -1 ? 'an' : 'a';
this.customMessage = msg;
this.message = msg || 'Expected element <%s> to ' + (this.negate ? 'not be' : 'be') + ' ' + this.article +' ' + type;
this.start();
}
util.inherits(TypeAssertion, BaseAssertion);
TypeAssertion.prototype.executeCommand = function(callback) {
this.protocol.elementIdName(this.elementResult.ELEMENT, callback);
};
TypeAssertion.prototype.elementFound = function() {
if (this.retries > 0 && this.negate) {
return;
}
this.passed = this.negate ? (this.resultValue != this.type) : (this.resultValue == this.type);
this.expected = this.negate ? 'not be ' + this.article + ' ' + this.type : 'be ' + this.article + ' ' + this.type;
this.actual = this.resultValue;
if (this.passed && this.waitForMs) {
this.elapsedTime = this.getElapsedTime();
this.messageParts.push(' - condition was met in ' + this.elapsedTime + 'ms');
}
};
TypeAssertion.prototype.elementNotFound = function() {
this.passed = false;
};
module.exports = TypeAssertion;

55
tests/node_modules/nightwatch/lib/api/expect/value.js generated vendored Normal file
View File

@@ -0,0 +1,55 @@
/**
* Property that retrieves the value (i.e. the value attributed) of an element. Can be chained to check if contains/equals/matches the specified text or regex.
*
* ```
* this.demoTest = function (browser) {
* browser.expect.element('#q').to.have.value.that.equals('search');
* browser.expect.element('#q').to.have.value.not.equals('search');
* browser.expect.element('#q').to.have.value.which.contains('search');
* browser.expect.element('#q').to.have.value.which.matches(/search/);
* };
* ```
*
* @display .value
* @method value
* @api expect
*/
var util = require('util');
var events = require('events');
var BaseAssertion = require('./_baseAssertion.js');
function ValueAssertion() {
this.flag('valueFlag', true);
BaseAssertion.call(this);
this.message = 'Expected element <%s> to have value' + (this.negate ? ' not' : '');
this.start();
}
util.inherits(ValueAssertion, BaseAssertion);
ValueAssertion.prototype.executeCommand = function(callback) {
this.protocol.elementIdValue(this.elementResult.ELEMENT, callback);
};
ValueAssertion.prototype.elementFound = function() {
if (this.retries > 0 && this.negate) {
return;
}
if (this.passed && this.waitForMs) {
var message = '';
if (this.hasCondition()) {
message = 'condition was met';
}
this.elapsedTime = this.getElapsedTime();
this.messageParts.push(' - ' + message + ' in ' + this.elapsedTime + 'ms');
}
};
ValueAssertion.prototype.elementNotFound = function() {
this.passed = false;
};
module.exports = ValueAssertion;

View File

@@ -0,0 +1,49 @@
/**
* Property that asserts the visibility of a specified element.
*
* ```
* this.demoTest = function (browser) {
* browser.expect.element('#main').to.be.visible;
* browser.expect.element('#main').to.not.be.visible;
* browser.expect.element('#main').to.be.visible.before(100);
* };
* ```
*
* @display .visible
* @method visible
* @api expect
*/
var util = require('util');
var BaseAssertion = require('./_baseAssertion.js');
function VisibleAssertion() {
BaseAssertion.call(this);
this.message = 'Expected element <%s> to ' + (this.negate ? 'not be visible' : 'be visible');
this.start();
}
util.inherits(VisibleAssertion, BaseAssertion);
VisibleAssertion.prototype.executeCommand = function(callback) {
this.protocol.elementIdDisplayed(this.elementResult.ELEMENT, callback);
};
VisibleAssertion.prototype.elementFound = function() {
this.passed = this.negate ? this.resultValue === false : this.resultValue;
this.expected = this.negate ? 'not visible' : 'visible';
this.actual = this.resultValue ? 'visible' : 'not visible';
if (this.passed && this.waitForMs) {
this.elapsedTime = this.getElapsedTime();
this.messageParts.push(' - condition was met in ' + this.elapsedTime + 'ms');
}
};
VisibleAssertion.prototype.elementNotFound = function() {
this.passed = false;
this.expected = this.negate ? 'not visible' : 'visible';
this.actual = 'not found';
};
module.exports = VisibleAssertion;

1289
tests/node_modules/nightwatch/lib/api/protocol.js generated vendored Normal file

File diff suppressed because it is too large Load Diff