From 896a689e84327795d2c26a5fd40119dfbde21db7 Mon Sep 17 00:00:00 2001 From: Benjamin Keen Date: Thu, 4 Dec 2014 15:01:20 -0800 Subject: [PATCH] New waitForAttribute nightwatch helper This test allows us to not just wait for an element, but for an element attribute containing a certain value. This can be helpful in a number of scenarios, like when a JS event changes the content of a page but the DOM structure remains largely the same (e.g. a form). --- .../custom-commands/waitForAttribute.js | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 test/nightwatch_tests/custom-commands/waitForAttribute.js diff --git a/test/nightwatch_tests/custom-commands/waitForAttribute.js b/test/nightwatch_tests/custom-commands/waitForAttribute.js new file mode 100644 index 000000000..429a9b526 --- /dev/null +++ b/test/nightwatch_tests/custom-commands/waitForAttribute.js @@ -0,0 +1,57 @@ +var util = require('util'); +var events = require('events'); + +/* + * This custom command allows us to locate an HTML element on the page and then wait until the value of a specified + * attribute matches the provided expression (aka. the 'checker' function). It retries executing the checker function + * every 100ms until either it evaluates to true or it reaches maxTimeInMilliseconds (which fails the test). + * Nightwatch uses the Node.js EventEmitter pattern to handle asynchronous code so this command is also an EventEmitter. + */ + +function WaitForAttribute() { + events.EventEmitter.call(this); + this.startTimeInMilliseconds = null; +} + +util.inherits(WaitForAttribute, events.EventEmitter); + +WaitForAttribute.prototype.command = function (element, attribute, checker, timeoutInMilliseconds) { + this.startTimeInMilliseconds = new Date().getTime(); + var self = this; + var message; + + if (typeof timeoutInMilliseconds !== 'number') { + timeoutInMilliseconds = 8000; + } + + this.check(element, attribute, checker, function (result, loadedTimeInMilliseconds) { + if (result) { + message = 'waitForAttribute: ' + element + '@' + attribute + '. Expression was true after ' + (loadedTimeInMilliseconds - self.startTimeInMilliseconds) + ' ms.'; + } else { + message = 'waitForAttribute: ' + element + '@' + attribute + '. Expression wasn\'t true in ' + timeoutInMilliseconds + ' ms.'; + } + self.client.assertion(result, 'expression false', 'expression true', message, true); + self.emit('complete'); + }, timeoutInMilliseconds); + + return this; +}; + +WaitForAttribute.prototype.check = function (element, attribute, checker, callback, maxTimeInMilliseconds) { + var self = this; + + this.api.getAttribute(element, attribute, function (result) { + var now = new Date().getTime(); + if (result.status === 0 && checker(result.value)) { + callback(true, now); + } else if (now - self.startTimeInMilliseconds < maxTimeInMilliseconds) { + setTimeout(function () { + self.check(element, attribute, checker, callback, maxTimeInMilliseconds); + }, 100); + } else { + callback(false); + } + }); +}; + +module.exports = WaitForAttribute;