Skip to content

Commit

Permalink
Merge pull request #4 from testiumjs/jk-the-rest
Browse files Browse the repository at this point in the history
Parity with testium-driver-sync
  • Loading branch information
jkrems committed Oct 29, 2015
2 parents 196df23 + 7721cfa commit 2769c15
Show file tree
Hide file tree
Showing 28 changed files with 793 additions and 409 deletions.
88 changes: 88 additions & 0 deletions lib/browser/_asserters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
'use strict';

var util = require('util');

var assert = require('assertive');
var Bluebird = require('bluebird');
var _ = require('lodash');
var wd = require('wd');

var matchers = require('./_matchers');

var Asserter = wd.Asserter;

function AssertionError() {
Error.call(this);
this.message = util.format.apply(util, arguments);
this.retriable = true;

Error.captureStackTrace(this, AssertionError);
}
util.inherits(AssertionError, Error);

exports.isDisplayed = function assertIsDisplayed(expected, selector) {
return new Asserter(function testTarget(target) {
if (!target) {
throw new AssertionError('Element not found for selector: ' + selector);
}

return target.isDisplayed().then(function compareTo(actual) {
if (actual !== expected) {
throw new AssertionError('Element %j should%s be displayed',
selector, (expected ? '' : 'n\'t'));
}
});
});
};

exports.exists = function assertExists(expected, selector) {
return new Asserter(function testTarget(target) {
if (!!target !== expected) {
throw new AssertionError('Element %j should%s exist',
selector, (expected ? '' : 'n\'t'));
}
});
};

function stringify(value) {
if (_.isRegExp(value)) {
return '' + value;
}
return JSON.stringify(value);
}

function secondToLowerCase(first, second) {
return second.toLowerCase();
}

function getterToPropName(propName) {
return propName.replace(/^get([A-Z])/, secondToLowerCase);
}

exports.fuzzyString = function assertFuzzyString(extract, expected, shouldMatch, selector) {
var propName;
if (typeof extract === 'string') {
propName = getterToPropName(extract);
extract = _.method(extract);
} else if (typeof extract === 'function') {
propName = getterToPropName(extract.name);
} else {
throw new Error('Invalid extract: ' + extract);
}
var doc = selector + ' should ' + (shouldMatch ? '' : 'not ') + 'have ' + propName;

return new Asserter(function testTarget(target) {
return Bluebird.resolve(target).then(extract).then(function compareTo(actual) {
assert.hasType(String, actual);
var match = matchers.fuzzyString(expected, actual);
if (match !== shouldMatch) {
var message = [
doc,
'- needle: ' + stringify(expected),
'- ' + propName + ': ' + stringify(actual),
].join('\n');
throw new AssertionError(message);
}
});
});
};
13 changes: 13 additions & 0 deletions lib/browser/_matchers.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,19 @@ function string(expected, actual) {
}
exports.string = string;

function fuzzyString(expected, actual) {
debug('fuzzyString: %s === %s', expected, actual);
if (expected === '') {
return actual === '';
} else if (typeof expected === 'string') {
return actual.indexOf(expected) !== -1;
} else if (_.isRegExp(expected)) {
return expected.test(actual);
}
throw new Error('Invalid assertion: ' + expected);
}
exports.fuzzyString = fuzzyString;

function stringUnlessNull(expected, actual) {
if (expected === null || expected === undefined) {
debug('skipping: %s === %s', expected, actual);
Expand Down
9 changes: 9 additions & 0 deletions lib/browser/alert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict';

exports.getAlertText = function getAlertText() {
return this.alertText();
};

exports.typeAlert = function typeAlert(text) {
return this.alertKeys(text);
};
22 changes: 22 additions & 0 deletions lib/browser/cookie.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict';

var assert = require('assertive');
var Bluebird = require('bluebird');
var _ = require('lodash');

Expand All @@ -9,6 +10,20 @@ exports.clearCookies = function clearCookies() {
return this.deleteAllCookies();
};

exports.setCookieValue = function setCookieValue(name, value, options) {
var cookie = _.extend({
name: name,
value: value,
path: '/',
secure: false,
}, options || {});
return this.setCookie(cookie);
};

exports.getCookieValue = function getCookieValue(name) {
return this.getCookie(name).then(_.property('value'));
};

exports.setCookies = function setCookies(cookies) {
return Bluebird.all(cookies.map(this.setCookie, this));
};
Expand Down Expand Up @@ -39,6 +54,13 @@ exports.getStatusCode = function getStatusCode() {
return this._getTestiumCookieField('statusCode');
};

exports.assertStatusCode = function assertStatusCode(expectedStatus) {
return this.getStatusCode()
.then(function compareTo(actualStatus) {
assert.equal('statusCode', expectedStatus, actualStatus);
});
};

exports.getHeaders = function getHeaders() {
return this._getTestiumCookieField('headers');
};
Expand Down
140 changes: 140 additions & 0 deletions lib/browser/element.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
'use strict';

var assert = require('assertive');
var Bluebird = require('bluebird');
var _ = require('lodash');

var asserters = require('./_asserters');

exports.getElementOrNull = function getElementOrNull(selector) {
return this.elementByCssSelectorOrNull(selector);
};

exports.getElement = function getElement(selector) {
return this.elementByCssSelectorOrNull(selector)
.then(function rejectNullElement(element) {
if (element === null) {
throw new Error('Element not found for selector: ' + selector);
}
return element;
});
};

exports.getElements = function getElements(selector) {
return this.elementsByCssSelector(selector);
};

// Our own version of wd's waitForElement.
// wd's version of waitFor* has the unfortunate habit of generating really
// unhelpful error messages.
function _waitForElement(browser, selector, asserter, timeout, pollFreq) {
/* eslint no-use-before-define:0 */
timeout = timeout || 2000;
pollFreq = pollFreq || 50;

var endTime = Date.now() + timeout;

function attempt() {
var element = browser.elementByCssSelectorOrNull(selector);
return element
.then(asserter.assert)
.catch(retry)
.then(_.constant(element));
}

function retry(error) {
if (!error.retriable) {
throw error;
}
if (Date.now() >= endTime) {
error.message = 'Timeout (' + timeout + 'ms): ' + error.message;
throw error;
}
return Bluebird.delay(pollFreq).then(attempt);
}

return attempt();
}

exports.waitForElementDisplayed = function waitForElementDisplayed(selector, timeout) {
return _waitForElement(this, selector, asserters.isDisplayed(true, selector), timeout);
};

exports.waitForElementNotDisplayed = function waitForElementNotDisplayed(selector, timeout) {
return _waitForElement(this, selector, asserters.isDisplayed(false, selector), timeout);
};

exports.waitForElementExist = function waitForElementExist(selector, timeout, pollFreq) {
return _waitForElement(this, selector, asserters.exists(true, selector), timeout, pollFreq);
};

exports.waitForElementNotExist = function waitForElementNotExist(selector, timeout, pollFreq) {
return _waitForElement(this, selector, asserters.exists(false, selector), timeout, pollFreq);
};

exports.clickOn = function clickOn(selector) {
return this.getElement(selector).click();
};

exports.assert = function _assert(asserter) {
return asserter.assert(this);
};

exports.assertElement = function assertElement(selector, asserter) {
assert.hasType('selector should be a string', String, selector);
var element = this.elementsByCssSelector(selector)
.then(function ensureUnique(elements) {
switch (elements.length) {
case 0:
throw new Error('Element not found for selector: ' + selector);

case 1:
return elements[0];

default:
throw new Error(
'Selector ' + selector + ' has ' + elements.length +
' hits on the page, assertions require unique elements');
}
});
return element.then(asserter.assert).then(_.constant(element));
};

exports.assertElementIsDisplayed = function assertElementIsDisplayed(selector) {
return this.assertElement(selector, asserters.isDisplayed(true, selector));
};

exports.assertElementNotDisplayed = function assertElementNotDisplayed(selector) {
return this.elementByCssSelectorOrNull(selector)
.then(asserters.isDisplayed(false, selector).assert);
};

exports.assertElementExists = function assertElementExists(selector) {
return this.elementByCssSelectorOrNull(selector)
.then(asserters.exists(true, selector).assert);
};

exports.assertElementDoesntExist = function assertElementDoesntExist(selector) {
return this.elementByCssSelectorOrNull(selector)
.then(asserters.exists(false, selector).assert);
};

exports.assertElementHasText = function assertElementHasText(selector, textOrRegExp) {
return this.assertElement(selector,
asserters.fuzzyString('text', textOrRegExp, true, selector));
};

exports.assertElementLacksText = function assertElementLacksText(selector, textOrRegExp) {
return this.assertElement(selector,
asserters.fuzzyString('text', textOrRegExp, false, selector));
};

exports.assertElementHasValue = function assertElementHasValue(selector, textOrRegExp) {
return this.assertElement(selector,
asserters.fuzzyString('getValue', textOrRegExp, true, selector));
};

exports.assertElementLacksValue = function assertElementLacksValue(selector, textOrRegExp) {
return this.assertElement(selector,
asserters.fuzzyString('getValue', textOrRegExp, false, selector));
};
24 changes: 24 additions & 0 deletions lib/browser/evaluate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use strict';

var assert = require('assertive');
var _ = require('lodash');

exports.evaluate = function evaluate() {
var args = _.toArray(arguments);
var clientFunction = args.pop();

var invocation = 'evaluate(clientFunction) - requires (Function|String) clientFunction';
assert.truthy(invocation, clientFunction);

switch (typeof clientFunction) {
case 'function':
clientFunction =
'return (' + clientFunction + ').apply(this, ' + JSON.stringify(args) + ');';
/* falls through */
case 'string':
return this.execute(clientFunction);

default:
throw new Error(invocation);
}
};
13 changes: 13 additions & 0 deletions lib/browser/form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use strict';

exports.clear = function clear(selector) {
return this.getElement(selector).clear();
};

exports.type = function type(selector, value) {
return this.getElement(selector).type(value);
};

exports.clearAndType = function clearAndType(selector, value) {
return this.getElement(selector).clear().type(value);
};
27 changes: 27 additions & 0 deletions lib/browser/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use strict';

var _ = require('lodash');

function extractWidthHeight(dimensions) {
return _.pick(dimensions, 'width', 'height');
}

exports.setPageSize = function setPageSize(size) {
return this.setWindowSize(size.width, size.height);
};

exports.getPageSize = function getPageSize() {
return this.getWindowSize().then(extractWidthHeight);
};

exports.getPageTitle = function getPageTitle() {
return this.title();
};

exports.getPageSource = function getPageSource() {
return this.source();
};

exports.getScreenshot = function getScreenshot() {
return this.takeScreenshot();
};
17 changes: 17 additions & 0 deletions lib/browser/window.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use strict';

exports.switchToFrame = function switchToFrame(id) {
return this.frame(id);
};

exports.switchToDefaultFrame = function switchToDefaultFrame() {
return this.frame(null);
};

exports.switchToWindow = function switchToWindow(id) {
return this.window(id);
};

exports.closeWindow = function closeWindow() {
return this.close();
};
Loading

0 comments on commit 2769c15

Please sign in to comment.