browser-monkey
Advanced tools
Comparing version 1.29.2 to 2.0.0
var debug = require('debug')('browser-monkey'); | ||
var dispatchEvent = require('./dispatchEvent'); | ||
var sendkeys = require('./sendkeys'); | ||
var sendclick = require('./sendclick'); | ||
var Options = require('./options'); | ||
var $ = require('jquery'); | ||
var errorHandler = require('./errorHandler'); | ||
function notSillyBlankIEObject(element){ | ||
return Object.keys(element).length > 0; | ||
} | ||
module.exports = { | ||
focus: function(element, options) { | ||
var focus = typeof options == 'object' && options.hasOwnProperty('focus')? options.focus: true; | ||
function blurActiveElement() { | ||
var activeElement; | ||
try { | ||
activeElement = document.activeElement; | ||
} catch ( err ) { } | ||
if (focus) { | ||
var $ = this.get('$'); | ||
var document = this.get('document'); | ||
if (element && element.length > 0) { | ||
element = element[0]; | ||
} | ||
if (activeElement) { | ||
dispatchEvent(activeElement, 'blur'); | ||
} | ||
} | ||
var activeElement = document.activeElement; | ||
if (activeElement && !$(activeElement).is(':focus') && notSillyBlankIEObject(activeElement)) { | ||
$(activeElement).trigger('blur'); | ||
} | ||
document.activeElement = element; | ||
$(element).focus(); | ||
} | ||
}, | ||
module.exports = { | ||
click: function(options) { | ||
var self = this; | ||
return this.enabled().element(options).then(function(element) { | ||
if (typeof options === 'string') { | ||
self = this.linkOrButton(options); | ||
} | ||
return self.enabled().element(options).then(function(element) { | ||
debug('click', element); | ||
self.handleEvent({type: 'click', element: element}); | ||
blurActiveElement(); | ||
return sendclick(element); | ||
}); | ||
self.focus(element, options); | ||
element.trigger('mousedown'); | ||
element.trigger('mouseup'); | ||
element.trigger('click'); | ||
}).catch(errorHandler(new Error())); | ||
}, | ||
select: function(options) { | ||
var selectOptions = Options.remove(options, ['text', 'exactText']); | ||
var $ = this.get('$'); | ||
var self = this; | ||
return self.is('select').find('option', selectOptions).elements(options).then(function(optionElements) { | ||
var optionElement = optionElements[0]; | ||
optionElement.selected = true; | ||
var selectElement = optionElement.parentNode; | ||
return this.is('select').find('option', options).elements(options).then(function(optionElements) { | ||
var optionElement = $(optionElements[0]); | ||
var selectElement = optionElement.parent(); | ||
self.focus(selectElement, options); | ||
optionElement.prop('selected', true); | ||
optionElement.attr('selected', 'selected'); | ||
selectElement.val(optionElement.val()); | ||
@@ -43,3 +59,3 @@ debug('select', selectElement); | ||
type: 'select option', | ||
value: optionElement.value, | ||
value: selectElement.val(), | ||
element: selectElement, | ||
@@ -49,5 +65,4 @@ optionElement: optionElement | ||
blurActiveElement(); | ||
dispatchEvent(selectElement, 'change'); | ||
}); | ||
selectElement.trigger('change'); | ||
}).catch(errorHandler(new Error())); | ||
}, | ||
@@ -64,6 +79,6 @@ | ||
assertCanTypeIntoElement(element); | ||
self.focus(element, options); | ||
self.handleEvent({type: 'typing', text: text, element: element}); | ||
blurActiveElement(); | ||
return sendkeys(element, text); | ||
}); | ||
}).catch(errorHandler(new Error())); | ||
}, | ||
@@ -76,6 +91,6 @@ | ||
debug('submit', element); | ||
self.focus(element, options); | ||
self.handleEvent({type: 'submit', element: element}); | ||
blurActiveElement(); | ||
return $(element).submit(); | ||
}); | ||
return element.trigger('submit'); | ||
}).catch(errorHandler(new Error())); | ||
}, | ||
@@ -87,6 +102,7 @@ | ||
return this.element(options).then(function(element) { | ||
self.focus(element, options); | ||
debug('typeInHtml', element, html); | ||
self.handleEvent({type: 'typing html', html: html, element: element}); | ||
return sendkeys.html(element, html); | ||
}); | ||
}).catch(errorHandler(new Error())); | ||
}, | ||
@@ -160,3 +176,3 @@ | ||
function canTypeIntoElement(element) { | ||
return $(element).is('input:not([type]), ' + | ||
return element.is('input:not([type]), ' + | ||
'input[type=text], ' + | ||
@@ -168,2 +184,3 @@ 'input[type=email], ' + | ||
'input[type=url], ' + | ||
'input[type=number],' + | ||
'textarea'); | ||
@@ -174,4 +191,4 @@ } | ||
if (!canTypeIntoElement(element)) { | ||
throw new Error('Cannot type into ' + element.tagName); | ||
throw new Error('Cannot type into ' + element.prop('tagName')); | ||
} | ||
} |
var Options = require('./options'); | ||
var elementTester = require('./elementTester'); | ||
var expectOneElement = require('./expectOneElement'); | ||
var errorHandler = require('./errorHandler'); | ||
module.exports = { | ||
is: function (css) { | ||
return this.addFinder(elementTester({css: css})); | ||
var $ = this.get('$'); | ||
return this.addFinder(this.createElementTester({css: css})); | ||
}, | ||
@@ -15,7 +16,10 @@ | ||
shouldExist: function (options) { | ||
return this.resolve(options).then(function () {}); | ||
var error = new Error(); | ||
return this.resolve(options) | ||
.catch(errorHandler(new Error())); | ||
}, | ||
shouldNotExist: function (options) { | ||
return this.notResolve(options); | ||
return this.notResolve(options) | ||
.catch(errorHandler(new Error())); | ||
}, | ||
@@ -28,2 +32,3 @@ | ||
shouldHave: function(options) { | ||
var $ = this.get('$'); | ||
var self = this; | ||
@@ -41,10 +46,14 @@ | ||
var assertions = additionalAssertions.map(function(finderMethodName){ | ||
return self[finderMethodName]().shouldHave(additionalOptions[finderMethodName]); | ||
if (typeof self[finderMethodName] === 'function') { | ||
return self[finderMethodName]().shouldHave(additionalOptions[finderMethodName]); | ||
} | ||
}); | ||
assertions.push(this.addFinder(elementTester(options)).shouldExist(resolveOptions)); | ||
return Promise.all(assertions); | ||
assertions.push(this.addFinder(this.createElementTester(options)).shouldExist(resolveOptions)); | ||
return Promise.all(assertions) | ||
.catch(errorHandler(new Error())); | ||
}, | ||
shouldHaveElement: function(fn, options) { | ||
var $ = this.get('$'); | ||
var self = this; | ||
@@ -55,3 +64,5 @@ | ||
expectOneElement(self, elements); | ||
elements.toArray().forEach(fn); | ||
elements.toArray().forEach(function(element){ | ||
fn($(element)); | ||
}); | ||
return elements; | ||
@@ -74,7 +85,8 @@ } | ||
shouldNotHave: function(options) { | ||
var $ = this.get('$'); | ||
var resolveOptions = Options.remove(options, ['timeout', 'interval']); | ||
resolveOptions.allowMultiple = true; | ||
return this.addFinder(elementTester(options)).shouldNotExist(resolveOptions); | ||
return this.addFinder(this.createElementTester(options)).shouldNotExist(resolveOptions); | ||
} | ||
}; |
module.exports = function elementsToString(els) { | ||
return els.toArray().map(function (el) { | ||
if (el && el.outerHTML) | ||
return el.outerHTML.replace(el.innerHTML, ''); | ||
}).join(', '); | ||
} |
var chai = require('chai'); | ||
var expect = chai.expect; | ||
var $ = require('jquery'); | ||
var Options = require('./options'); | ||
var elementsToString = require('./elementsToString'); | ||
function assertElementProperties(elements, expected, getProperty, exact) { | ||
function assertElementProperties($, elements, expected, getProperty, exact) { | ||
function assertion(actual, expected) { | ||
@@ -24,8 +21,31 @@ if (exact) { | ||
var comparer = exact == true ? | ||
function(a, b) { return a == b; } : | ||
function(a, b) { return a.indexOf(b) != -1} | ||
var found = []; | ||
var actuals = actualTexts.slice(); | ||
expected.forEach(function (expected, index) { | ||
var actualText = actualTexts[index]; | ||
assertion(actualText, expected); | ||
var actualFound; | ||
for (var actualIndex=0; actualIndex<actualTexts.length; actualIndex++) { | ||
var actual = actualTexts[actualIndex]; | ||
if (comparer(actual, expected)) { | ||
actualFound = actual; | ||
found[actualIndex] = expected; | ||
break; | ||
} | ||
} | ||
}); | ||
try { | ||
expect(found).to.eql(expected) | ||
} catch(e) { | ||
if (found.slice().sort().toString() == expected.slice().sort().toString()) { | ||
e.message += '\nThe text was found but in a different order than specified - maybe you need some sorting?'; | ||
} | ||
throw e; | ||
} | ||
} else { | ||
var elementText = getProperty(elements); | ||
var elementText = getProperty($(elements)); | ||
assertion(elementText, expected); | ||
@@ -35,105 +55,101 @@ } | ||
function getNormalisedText(el) { | ||
return el.innerText().replace(/ +/g,' ').replace(/ *\r?\n */g,"\n"); | ||
} | ||
module.exports = function elementTester(options) { | ||
var options = new Options(options); | ||
function getValue(e, property) { | ||
var val = e.val(); | ||
// Fails with missing value attribute in VDOM without 'string' test (returns SoftSetHook{value: ''}) | ||
return (typeof val === "string" && val) || ''; | ||
} | ||
var css = options.option('css'); | ||
var text = options.option('text'); | ||
var exactText = options.option('exactText'); | ||
var message = options.option('message'); | ||
var predicate = options.option('elements'); | ||
var length = options.option('length'); | ||
var value = options.option('value'); | ||
var exactValue = options.option('exactValue'); | ||
var html = options.option('html'); | ||
var checked = options.option('checked'); | ||
var attributes = options.option('attributes'); | ||
module.exports = { | ||
css: function($el, message, css) { | ||
if (!$el.is(css)) { | ||
throw new Error(message || ('expected elements ' + elementsToString($el) + ' to have css ' + css)); | ||
} | ||
}, | ||
elements: function($el, message, predicate){ | ||
if (!predicate($el.toArray())) { | ||
throw new Error(message || 'expected elements to pass predicate'); | ||
} | ||
}, | ||
text: function($el, message, text) { | ||
assertElementProperties(this.get('$'), $el, text, function (e) { return getNormalisedText(e)}, text === ''); | ||
}, | ||
length: function($el, message, length) { | ||
if ($el.length !== length) { | ||
throw new Error(message || ('expected ' + elementsToString($el) + ' to have ' + length + ' elements')); | ||
} | ||
}, | ||
html: function($el, message, html) { | ||
assertElementProperties(this.get('$'), $el, html, function (e) { return e.html(); }); | ||
}, | ||
checked: function($el, message, checked) { | ||
var $ = this.get('$'); | ||
var elements = $el.toArray(); | ||
options.validate(); | ||
if (checked instanceof Array) { | ||
var elementsChecked = elements.map(function (element) { | ||
return !!$(element).prop('checked'); | ||
}); | ||
expect(elementsChecked, 'expected ' + elementsToString($el) + ' to have checked states ' + JSON.stringify(checked)).to.eql(checked); | ||
} else { | ||
var elementsNotMatching = elements.filter(function (element) { | ||
return $(element).prop('checked') !== checked; | ||
}); | ||
expect(elementsNotMatching.length, 'expected ' + elementsToString($el) + ' to be ' + (checked? 'checked': 'unchecked')).to.equal(0); | ||
} | ||
}, | ||
exactText: function($el, message, exactText) { | ||
assertElementProperties(this.get('$'), $el, exactText, function (e) { return getNormalisedText(e); }, true); | ||
}, | ||
value: function($el, message, value) { | ||
assertElementProperties(this.get('$'), $el, value, getValue, value === ''); | ||
}, | ||
exactValue: function($el, message, exactValue) { | ||
assertElementProperties(this.get('$'), $el, exactValue, getValue, true); | ||
}, | ||
attributes: function($el, message, attributes) { | ||
var $ = this.get('$'); | ||
var elements = $el.toArray(); | ||
if (typeof options === 'string') { | ||
css = options; | ||
} | ||
elements.forEach(function(el){ | ||
Object.keys(attributes).forEach(function(attributeKey){ | ||
expect($(el).attr(attributeKey)).to.equal(attributes[attributeKey]); | ||
}); | ||
}); | ||
}, | ||
if (typeof options === 'function') { | ||
predicate = options; | ||
} | ||
function getNormalisedText(el) { | ||
return el[0].innerText.replace(/ +/g,' ').replace(/ *\n */g,"\n"); | ||
} | ||
return { | ||
find: function(element) { | ||
var els = $(element); | ||
if (css && !els.is(css)) { | ||
if (!els.is(css)) { | ||
throw new Error(message || ('expected elements ' + elementsToString(els) + ' to have css ' + css)); | ||
} | ||
label: function($el, message, label) { | ||
var $ = this.get('$'); | ||
var links = $el.toArray().filter(function(el) { | ||
if ($(el).is('a')) { | ||
var anchor = $(el); | ||
var href = anchor.attr('href'); | ||
return typeof href !== typeof undefined && | ||
href !== false && | ||
( | ||
anchor.text() == label || | ||
anchor.attr('id') == label || | ||
anchor.attr('title') == label || | ||
anchor.find("img").toArray().filter(function(img) { | ||
return $(img).attr('alt') == label; | ||
}).length > 0 | ||
); | ||
} | ||
if (text !== undefined) { | ||
assertElementProperties(els, text, function (e) { return getNormalisedText(e); }); | ||
if ($(el).is('button, input[type=submit], input[type=button], input[type=reset]')) { | ||
var button = $(el); | ||
return button.attr('id') == label || | ||
button.text() == label || | ||
(typeof button.attr('value') == 'string' && button.attr('value').indexOf(label) > -1) || | ||
(typeof button.attr('title') == 'string' && button.attr('title').indexOf(label) > -1) || | ||
button.find("img").toArray().filter(function(img) { | ||
return typeof $(img).attr('alt') == 'string' && $(img).attr('alt').indexOf(label) > -1; | ||
}).length > 0 | ||
} | ||
}); | ||
if (exactText !== undefined) { | ||
assertElementProperties(els, exactText, function (e) { return getNormalisedText(e); }, true); | ||
} | ||
if (value !== undefined) { | ||
assertElementProperties(els, value, function (e) { return e.val() || ''; }); | ||
} | ||
if (exactValue !== undefined) { | ||
assertElementProperties(els, exactValue, function (e) { return e.val() || ''; }, true); | ||
} | ||
if (checked) { | ||
var elements = els.toArray(); | ||
if (checked instanceof Array) { | ||
var elementsChecked = elements.map(function (element) { | ||
return !!element.checked; | ||
}); | ||
expect(elementsChecked, 'expected ' + elementsToString(els) + ' to have checked states ' + JSON.stringify(checked)).to.eql(checked); | ||
} else { | ||
var elementsNotMatching = elements.filter(function (element) { return element.checked != checked; }); | ||
expect(elementsNotMatching.length, 'expected ' + elementsToString(els) + ' to be ' + (checked? 'checked': 'unchecked')).to.equal(0); | ||
} | ||
} | ||
if (attributes) { | ||
var elements = els.toArray(); | ||
elements.forEach(function(el){ | ||
Object.keys(attributes).forEach(function(attributeKey){ | ||
expect($(el).attr(attributeKey)).to.equal(attributes[attributeKey]); | ||
}); | ||
}); | ||
} | ||
if (html) { | ||
assertElementProperties(els, html, function (e) { return e.html(); }); | ||
} | ||
if (length !== undefined) { | ||
if (els.length !== length) { | ||
throw new Error(message || ('expected ' + elementsToString(els) + ' to have ' + length + ' elements')); | ||
} | ||
} | ||
if (predicate) { | ||
if (!predicate(els.toArray())) { | ||
throw new Error(message || 'expected elements to pass predicate'); | ||
} | ||
} | ||
return els; | ||
}, | ||
toString: function() { | ||
return message || css || text; | ||
} | ||
}; | ||
} | ||
expect(links.length).to.equal(1, message); | ||
} | ||
}; |
@@ -7,3 +7,3 @@ var chai = require('chai'); | ||
var msg = "expected to find exactly one element: " + scope.printFinders(scope._finders) + ', but found :' + elementsToString(elements); | ||
expect(elements.length, msg).to.equal(1); | ||
expect(elements.size(), msg).to.equal(1); | ||
} |
135
finders.js
var retry = require('trytryagain'); | ||
var trace = require('./trace'); | ||
var Options = require('./options'); | ||
var elementTester = require('./elementTester'); | ||
var expectOneElement = require('./expectOneElement'); | ||
var $ = require('jquery'); | ||
function filterInvisible(index){ | ||
var el = this[index] || this; | ||
var ignoreVisibilityOfTags = ['OPTION']; | ||
if (el && ignoreVisibilityOfTags.indexOf(el.tagName) !== -1) { | ||
el = el.parentNode; | ||
} | ||
return $(el).is(':visible'); | ||
} | ||
module.exports = { | ||
elementFinder: function(css) { | ||
var $ = this.get('$'); | ||
var self = this; | ||
@@ -25,3 +13,10 @@ return { | ||
if (self.get('visibleOnly')) { | ||
els = els.filter(filterInvisible); | ||
els = els.filter(function(index){ | ||
var el = this[index] || this; | ||
var ignoreVisibilityOfTags = ['OPTION']; | ||
if (el && ignoreVisibilityOfTags.indexOf(el.tagName) !== -1) { | ||
el = el.parentNode; | ||
} | ||
return $(el).is(':visible'); | ||
}); | ||
} | ||
@@ -45,3 +40,35 @@ if (els.length > 0) { | ||
createElementTester: function(criteria) { | ||
var self = this; | ||
if (typeof criteria === 'string') { | ||
criteria = { css: criteria }; | ||
} | ||
if (typeof criteria === 'function') { | ||
criteria = { predicate: criteria }; | ||
} | ||
return { | ||
find: function($el) { | ||
var message = criteria.message; | ||
Object.keys(criteria).forEach(function(key){ | ||
var value = criteria[key]; | ||
var tester = self._elementTesters[key]; | ||
if (value !== undefined && tester !== undefined) { | ||
tester.call(self, $el, message, value); | ||
} | ||
}); | ||
return $el; | ||
}, | ||
toString: function(){ | ||
return criteria.message || criteria.css || criteria.text; | ||
} | ||
}; | ||
}, | ||
find: function (selector, options) { | ||
var $ = this.get('$'); | ||
var message = JSON.stringify(options); | ||
@@ -51,3 +78,3 @@ var scope = this.addFinder(this.elementFinder(selector)); | ||
if (options) { | ||
var tester = elementTester(options); | ||
var tester = this.createElementTester(options); | ||
@@ -67,2 +94,3 @@ return scope.filter(function (element) { | ||
containing: function (selector, options) { | ||
var $ = this.get('$'); | ||
var message = options && JSON.stringify(options); | ||
@@ -73,3 +101,4 @@ var findElements = this.elementFinder(selector); | ||
if (options) { | ||
var testElements = elementTester(options); | ||
var tester = this.createElementTester(options); | ||
finder = { | ||
@@ -80,3 +109,3 @@ find: function (elements) { | ||
try { | ||
testElements.find(element); | ||
tester.find(element); | ||
return true; | ||
@@ -103,5 +132,5 @@ } catch (error) { | ||
find: function(elements) { | ||
var els = elements.filter(function() { | ||
var els = Array.prototype.filter.call(elements, function(el) { | ||
try { | ||
return finder.find(this); | ||
return finder.find(el); | ||
} catch (e) { | ||
@@ -113,3 +142,3 @@ return false; | ||
if (els.length > 0) { | ||
return els; | ||
return $(els); | ||
} | ||
@@ -124,2 +153,22 @@ }, | ||
linkOrButton: function(label) { | ||
return this.find( | ||
'a, button, input[type=submit], input[type=button], input[type=reset]', | ||
{label: label}, | ||
"[linkOrButton: " + label + "]" | ||
); | ||
}, | ||
button: function(label) { | ||
return this.find( | ||
'button, input[type=submit], input[type=button], input[type=reset]', | ||
{label: label}, | ||
"[button: " + label + "]" | ||
); | ||
}, | ||
link: function(label) { | ||
return this.find('a', {label: label}, "[link: " + label + "]"); | ||
}, | ||
elements: function (options) { | ||
@@ -131,4 +180,5 @@ options = Options.default(options, {allowMultiple: true}); | ||
element: function (options) { | ||
var $ = this.get('$'); | ||
return this.resolve(options).then(function (elements) { | ||
return elements[0]; | ||
return $(elements[0]); | ||
}); | ||
@@ -142,4 +192,5 @@ }, | ||
findElements: function (options) { | ||
var $ = this.get('$'); | ||
var self = this; | ||
var allowMultiple = options && options.hasOwnProperty('allowMultiple')? options.allowMultiple: false; | ||
var allowMultiple = Options.get(options, 'allowMultiple'); | ||
@@ -153,3 +204,3 @@ function findWithFinder(el, finderIndex) { | ||
if (!found) { | ||
throw new Error("expected to find: " + self.printFinders(self._finders.slice(0, finderIndex + 1))); | ||
throw new Error("expected to find: " + self.printFinders(self._finders)); | ||
} | ||
@@ -164,6 +215,18 @@ | ||
function selector() { | ||
if(self._selector instanceof Element && self._selector.tagName == 'IFRAME') { | ||
return self._selector.contentDocument.body; | ||
var selector = self._selector; | ||
if ( | ||
selector && | ||
typeof Element !== 'undefined' && | ||
selector instanceof Element && | ||
selector.tagName == 'IFRAME' | ||
) { | ||
return selector.contentDocument.body; | ||
} else if ( | ||
selector && | ||
typeof selector.prop === 'function' && | ||
selector.prop('tagName') === 'IFRAME' | ||
) { | ||
return selector[0].contentDocument.body; | ||
} else { | ||
return self._selector || 'body'; | ||
return selector || 'body'; | ||
} | ||
@@ -176,2 +239,3 @@ } | ||
} | ||
return elements.toArray(); | ||
@@ -182,4 +246,5 @@ }, | ||
var self = this; | ||
var retryOptions = Options.remove(options, ['timeout', 'interval', 'trace']); | ||
var traceOption = retryOptions.hasOwnProperty('trace')? retryOptions.trace: true; | ||
var defaultTimeout = this.get('timeout') || 1000; | ||
var retryOptions = Options.remove(options, ['timeout', 'interval']); | ||
retryOptions.timeout = retryOptions.timeout || defaultTimeout; | ||
@@ -190,7 +255,3 @@ var result = retry(retryOptions, function() { | ||
if (traceOption) { | ||
return trace(result); | ||
} else { | ||
return result; | ||
} | ||
return result; | ||
}, | ||
@@ -214,5 +275,8 @@ | ||
filter: function (filter, message) { | ||
var $ = this.get('$'); | ||
return this.addFinder({ | ||
find: function (elements) { | ||
var filteredElements = elements.toArray().filter(filter); | ||
var filteredElements = elements.toArray().filter(function(element){ | ||
return filter($(element)) | ||
}); | ||
@@ -232,3 +296,4 @@ if (filteredElements && filteredElements.length > 0) { | ||
return this.filter(function (element) { | ||
return !((element.tagName == 'BUTTON' || element.tagName == 'INPUT') && element.disabled == true); | ||
var tagName = element.prop('tagName'); | ||
return !((tagName == 'BUTTON' || tagName == 'INPUT') && element.prop('disabled')); | ||
}, '[disabled=false]'); | ||
@@ -235,0 +300,0 @@ } |
84
index.js
@@ -1,83 +0,1 @@ | ||
var finders = require('./finders'); | ||
var actions = require('./actions'); | ||
var assertions = require('./assertions'); | ||
function Selector(selector, finders, options) { | ||
this._selector = selector; | ||
this._finders = finders || []; | ||
this._options = options || { visibleOnly: true }; | ||
this._handlers = []; | ||
} | ||
Selector.prototype.set = function(options){ | ||
var self = this; | ||
Object.keys(options).forEach(function(key){ | ||
self._options[key] = options[key]; | ||
}); | ||
return this; | ||
} | ||
Selector.prototype.get = function(key){ | ||
return this._options[key]; | ||
} | ||
Selector.prototype.clone = function (extension) { | ||
var clone = new this.constructor(); | ||
var self = this; | ||
Object.keys(self).forEach(function (key) { | ||
clone[key] = self[key]; | ||
}); | ||
Object.keys(extension).forEach(function (key) { | ||
clone[key] = extension[key]; | ||
}); | ||
return clone; | ||
}; | ||
Selector.prototype.on = function (handler) { | ||
this._handlers.push(handler); | ||
return this; | ||
}; | ||
Selector.prototype.handleEvent = function () { | ||
var args = arguments; | ||
this._handlers.forEach(function (handler) { | ||
handler.apply(undefined, args); | ||
}); | ||
}; | ||
Selector.prototype.scope = function (scope) { | ||
if (scope instanceof Selector) { | ||
return this.clone(scope); | ||
} else { | ||
return this.clone({_selector: scope}); | ||
} | ||
}; | ||
Selector.prototype.extend = function (methods) { | ||
return this.component(methods); | ||
}; | ||
Selector.prototype.component = function (methods) { | ||
function Component() { | ||
Selector.apply(this, arguments); | ||
} | ||
Component.prototype = new this.constructor(); | ||
Object.keys(methods).forEach(function (method) { | ||
Component.prototype[method] = methods[method]; | ||
}); | ||
Component.prototype.constructor = Component; | ||
return new Component().scope(this); | ||
}; | ||
module.exports = new Selector() | ||
.component(finders) | ||
.component(actions) | ||
.component(assertions); | ||
module.exports = require('./create')(); |
@@ -34,6 +34,10 @@ // Karma configuration | ||
preprocessors: { | ||
'test/global.js': ['browserify'], | ||
'test/global.js': ['browserify', 'env'], | ||
'test/**/*Spec.js': ['browserify'] | ||
}, | ||
envPreprocessor: [ | ||
'BM_TIMEOUT', | ||
], | ||
browserify: { | ||
@@ -43,6 +47,12 @@ debug: true | ||
client: { | ||
mocha: { | ||
timeout: 0 | ||
} | ||
}, | ||
// test results reporter to use | ||
// possible values: 'dots', 'progress' | ||
// available reporters: https://npmjs.org/browse/keyword/karma-reporter | ||
reporters: ['mocha'], | ||
reporters: process.env.BROWSERS? ['dots']: ['mocha'], | ||
@@ -69,9 +79,81 @@ | ||
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher | ||
browsers: ['Chrome'], | ||
browsers: process.env.BROWSERS == 'all'? Object.keys(browsers): ['Chrome'], | ||
browserStack: { | ||
username: process.env.BROWSERSTACK_USER, | ||
accessKey: process.env.BROWSERSTACK_PASSWORD | ||
}, | ||
// Continuous Integration mode | ||
// if true, Karma captures browsers, runs the tests and exits | ||
singleRun: false | ||
singleRun: false, | ||
customLaunchers: browsers, | ||
browserNoActivityTimeout: 60000 | ||
}); | ||
}; | ||
var browsers = { | ||
'browserstack-firefox': { | ||
base: 'BrowserStack', | ||
browser : 'Firefox', | ||
browser_version : '47.0', | ||
os : 'OS X', | ||
os_version : 'El Capitan', | ||
resolution : '1024x768' | ||
}, | ||
'browserstack-safari': { | ||
base: 'BrowserStack', | ||
browser : 'Safari', | ||
browser_version : '9.1', | ||
os : 'OS X', | ||
os_version : 'El Capitan', | ||
resolution : '1024x768' | ||
}, | ||
'browserstack-safari-ios': { | ||
base: 'BrowserStack', | ||
device : 'iPhone 6S', | ||
os : 'ios', | ||
os_version : '9.1', | ||
}, | ||
'browserstack-chrome': { | ||
base: 'BrowserStack', | ||
browser : 'Chrome', | ||
browser_version : '52.0', | ||
os : 'OS X', | ||
os_version : 'El Capitan', | ||
resolution : '1024x768' | ||
}, | ||
'browserstack-ie9': { | ||
base: 'BrowserStack', | ||
browser : 'IE', | ||
browser_version : '9.0', | ||
os : 'Windows', | ||
os_version : '7', | ||
resolution : '1024x768' | ||
}, | ||
'browserstack-ie10': { | ||
base: 'BrowserStack', | ||
browser : 'IE', | ||
browser_version : '10.0', | ||
os : 'Windows', | ||
os_version : '8', | ||
resolution : '1024x768' | ||
}, | ||
'browserstack-ie11': { | ||
base: 'BrowserStack', | ||
browser : 'IE', | ||
browser_version : '11.0', | ||
os : 'Windows', | ||
os_version : '10', | ||
resolution : '1024x768' | ||
},'browserstack-edge': { | ||
base: 'BrowserStack', | ||
browser : 'Edge', | ||
browser_version : '13.0', | ||
os : 'Windows', | ||
os_version : '10', | ||
resolution : '1024x768' | ||
}, | ||
}; |
@@ -7,2 +7,10 @@ function Options(options){ | ||
Options.get = function(options, propertyName){ | ||
if (typeof options === 'object') { | ||
var value = options[propertyName]; | ||
return value; | ||
} | ||
} | ||
Options.remove = function(options, propertyNames){ | ||
@@ -9,0 +17,0 @@ var newOptions = {}; |
{ | ||
"name": "browser-monkey", | ||
"version": "1.29.2", | ||
"version": "2.0.0", | ||
"description": "reliable dom testing", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "./node_modules/.bin/karma start --browsers Firefox --single-run" | ||
"test": "mocha && karma start --single-run" | ||
}, | ||
@@ -12,17 +12,29 @@ "author": "Tim Macfarlane <timmacfarlane@gmail.com>", | ||
"devDependencies": { | ||
"chai-as-promised": "5.1.0", | ||
"karma": "0.12.31", | ||
"karma-browserify": "4.0.0", | ||
"karma-chrome-launcher": "0.1.7", | ||
"karma-cli": "0.0.4", | ||
"karma-firefox-launcher": "^0.1.7", | ||
"karma-mocha": "0.1.10", | ||
"karma-mocha-reporter": "1.0.2", | ||
"2vdom": "^0.2.0", | ||
"browserify": "^13.1.1", | ||
"chai-as-promised": "6.0.0", | ||
"detect-node": "^2.0.3", | ||
"hyperdom": "^0.2.0", | ||
"karma": "1.3.0", | ||
"karma-browserify": "5.1.0", | ||
"karma-browserstack-launcher": "1.1.1", | ||
"karma-chrome-launcher": "2.0.0", | ||
"karma-cli": "1.0.1", | ||
"karma-env-preprocessor": "0.1.1", | ||
"karma-firefox-launcher": "^1.0.0", | ||
"karma-ievms": "0.1.0", | ||
"karma-mocha": "1.2.0", | ||
"karma-mocha-reporter": "2.2.0", | ||
"lie": "^3.0.1", | ||
"mocha": "2.2.1" | ||
"mocha": "3.1.2", | ||
"vdom-query": "https://github.com/featurist/vdom-query", | ||
"virtual-dom": "^2.1.1", | ||
"watchify": "^3.7.0" | ||
}, | ||
"dependencies": { | ||
"chai": "3.3.0", | ||
"chai": "3.5.0", | ||
"debug": "2.2.0", | ||
"jquery": "2.1.3", | ||
"detect-browser": "1.5.0", | ||
"global": "^4.3.0", | ||
"jquery": "2.2.4", | ||
"trytryagain": "1.2.0" | ||
@@ -29,0 +41,0 @@ }, |
@@ -24,18 +24,22 @@ # browser monkey [![npm version](https://img.shields.io/npm/v/browser-monkey.svg)](https://www.npmjs.com/package/browser-monkey) [![npm](https://img.shields.io/npm/dm/browser-monkey.svg)](https://www.npmjs.com/package/browser-monkey) [![Build Status](https://travis-ci.org/featurist/browser-monkey.svg?branch=master)](https://travis-ci.org/featurist/browser-monkey) | ||
```js | ||
import createBrowser from 'browser-monkey/create'; | ||
describe('admin', function () { | ||
let browser = createBrowser(document.body); | ||
// describes the admin panel, with a search box, results and a user editor | ||
var adminPanel = browser.component({ | ||
searchUsers: function () { | ||
let adminPanel = browser.component({ | ||
searchUsers() { | ||
return this.find('.search'); | ||
}, | ||
userResult: function (name) { | ||
userResult(name) { | ||
// find a user in the results by their name | ||
return this.find('.results .user', {text: name}); | ||
} | ||
userEditor: function () { | ||
}, | ||
userEditor() { | ||
// return the user editor, scoped to the .user-editor div. | ||
return this.find('.user-editor').component({ | ||
name: function () { this.find('.name'); }, | ||
email: function () { this.find('.email'); }, | ||
save: function () { this.find('.save'); } | ||
name() { return this.find('.name'); }, | ||
email() { return this.find('.email'); }, | ||
save() { return this.find('.save'); } | ||
}); | ||
@@ -45,17 +49,13 @@ } | ||
it('can search for, edit and save a user', function () { | ||
return adminPanel.searchUsers().typeIn('bar').then(function () { | ||
return adminPanel.userResult('Barry').click(); | ||
}).then(function () { | ||
var userEditor = adminPanel.userEditor(); | ||
return Promise.all([ | ||
userEditor.name().typeIn('Barry Jones'), | ||
userEditor.email().typeIn('barryjones@example.com') | ||
]).then(function () { | ||
return userEditor.save().click(); | ||
}); | ||
}).then(function () { | ||
// verify that the user was saved | ||
// use mock-xhr-router! | ||
}); | ||
it('can search for, edit and save a user', async () => { | ||
await adminPanel.searchUsers().typeIn('bar'); | ||
await adminPanel.userResult('Barry').click(); | ||
let userEditor = adminPanel.userEditor(); | ||
await userEditor.name().typeIn('Barry Jones'); | ||
await userEditor.email().typeIn('barryjones@example.com'); | ||
await userEditor.save().click(); | ||
// verify that the user was saved | ||
}); | ||
@@ -109,6 +109,7 @@ }); | ||
innerScope.get(); // {visibleOnly: false}; | ||
innerScope.get('visibleOnly'); // returns false | ||
``` | ||
* `visibleOnly` if true, then only visible elements will be found, if false, then all elements are considered. Visible is determined by the element's computed CSS, see [jQuery's :visible selector](https://api.jquery.com/visible-selector/). Default is true. | ||
* `timeout` an integer specifying the milliseconds to wait for an element to appear. This can be overriden by specifying the timeout when calling an action. | ||
@@ -517,1 +518,27 @@ ## find | ||
* `event.html` is the html entered, in the case of type `'typing html'`. | ||
# Semantic Finders | ||
Semantic finders use a text fragment to find matching elements. | ||
## link | ||
`browser.link('gorilla')` matches: | ||
- `<a>gorilla</a>` | ||
- `<a id="gorilla">link</a>` | ||
- `<a title="gorilla">link</a>` | ||
- `<a><img alt="gorilla"></a>` | ||
## button | ||
A button is considered any of the following types - `input[type=submit]`, `input[type=button]`, `input[type=reset]` | ||
`browser.button('tamarin')` matches: | ||
- `<button>tamarin</button>` | ||
- `<button id="tamarin">button</button>` | ||
- `<button value="tamarin">button</button>` | ||
- `<button id="tamarin">button</button>` | ||
- `<button><img alt="tamarin"></button>` | ||
## linkOrButton | ||
would match either a link or button according to their respective rules | ||
## click | ||
Normally the click action is performed on a scope but you can also provide it with a string `browser.click('monkey')` and it will search for a link or button that matches and perform the click on it. |
function dispatchEvent(el, type, char) { | ||
var event = document.createEvent("Events"); | ||
event.initEvent(type, true, false); | ||
event.charCode = char; | ||
el.dispatchEvent(event); | ||
el.trigger(type, {charCode: char}); | ||
} | ||
@@ -10,17 +7,12 @@ | ||
dispatchEvent(el, "keydown", char); | ||
dispatchEvent(el, "keyup", char); | ||
dispatchEvent(el, "keypress", char); | ||
dispatchEvent(el, "input"); | ||
dispatchEvent(el, "keyup", char); | ||
} | ||
function sendkeys(el, text) { | ||
el.focus(); | ||
if (el.setActive) { | ||
el.setActive(); | ||
} | ||
var originalValue = el.val(); | ||
var originalValue = el.value; | ||
if (text.length === 0) { | ||
el.value = ''; | ||
el.val(''); | ||
sendkey(el, ''); | ||
@@ -30,3 +22,4 @@ } else { | ||
var char = text[n]; | ||
el.value = text.substring(0, n + 1); | ||
var value = text.substring(0, n + 1); | ||
el.val(value); | ||
sendkey(el, char); | ||
@@ -33,0 +26,0 @@ } |
@@ -1,14 +0,15 @@ | ||
var browser = require('..'); | ||
var createTestDom = require('./createTestDom'); | ||
var $ = require('jquery'); | ||
var domTest = require('./domTest'); | ||
var retry = require('trytryagain'); | ||
describe('actions', function(){ | ||
var dom; | ||
describe('clicking', function () { | ||
domTest('stack trace', function(browser, dom){ | ||
return browser.find('div') | ||
.click() | ||
.assertStackTrace(__filename); | ||
}, { | ||
mochaOnly: true | ||
}); | ||
beforeEach(function(){ | ||
dom = createTestDom(); | ||
}); | ||
describe('clicking', function () { | ||
it('should eventually click an element', function () { | ||
domTest('should eventually click an element', function (browser, dom, $) { | ||
var promise = browser.find('.element').click(); | ||
@@ -18,3 +19,3 @@ var clicked = false; | ||
dom.eventuallyInsert( | ||
$('<div class="element"></div>').click(function () { | ||
$('<div class="element"></div>').on('click', function () { | ||
clicked = true; | ||
@@ -29,10 +30,10 @@ }) | ||
it('sends mousedown mouseup and click events', function () { | ||
domTest('sends mousedown mouseup and click events', function (browser, dom) { | ||
var events = []; | ||
dom.insert('<div class="element"></div>').mousedown(function () { | ||
dom.insert('<div class="element"></div>').on('mousedown', function () { | ||
events.push('mousedown'); | ||
}).mouseup(function () { | ||
}).on('mouseup', function () { | ||
events.push('mouseup'); | ||
}).click(function () { | ||
}).on('click', function () { | ||
events.push('click'); | ||
@@ -46,3 +47,19 @@ }); | ||
it('waits until checkbox is enabled before clicking', function () { | ||
domTest('mousedown mouseup and click events bubble up to parent', function (browser, dom) { | ||
var events = []; | ||
dom.insert('<div class="element"><div class="inner-element">inner</div></div>').on('mousedown', function () { | ||
events.push('mousedown'); | ||
}).on('mouseup', function () { | ||
events.push('mouseup'); | ||
}).on('click', function () { | ||
events.push('click'); | ||
}); | ||
return browser.find('.inner-element').click().then(function () { | ||
expect(events).to.eql(['mousedown', 'mouseup', 'click']); | ||
}); | ||
}, {vdom: false}); | ||
domTest('waits until checkbox is enabled before clicking', function (browser, dom) { | ||
var promise = browser.find('input[type=checkbox]').click(); | ||
@@ -53,3 +70,3 @@ var clicked; | ||
var button = dom.insert('<input type=checkbox disabled></input>'); | ||
button[0].addEventListener('click', function () { | ||
button.on('click', function () { | ||
clicked = buttonState; | ||
@@ -61,3 +78,3 @@ }); | ||
buttonState = 'enabled' | ||
}, 100); | ||
}, 10); | ||
@@ -69,3 +86,3 @@ return promise.then(function () { | ||
it('waits until button is enabled before clicking', function () { | ||
domTest('waits until button is enabled before clicking', function (browser, dom) { | ||
var promise = browser.find('button', {text: 'a button'}).click(); | ||
@@ -75,4 +92,4 @@ var clicked; | ||
var button = dom.insert('<button disabled>a button</button>'); | ||
button[0].addEventListener('click', function () { | ||
button = dom.insert('<button disabled>a button</button>'); | ||
button.on('click', function () { | ||
clicked = buttonState; | ||
@@ -84,3 +101,3 @@ }); | ||
buttonState = 'enabled' | ||
}, 100); | ||
}, 10); | ||
@@ -94,17 +111,22 @@ return promise.then(function () { | ||
describe('select', function(){ | ||
domTest('stack trace', function(browser, dom){ | ||
return browser.find('div') | ||
.select({text: 'Text'}) | ||
.assertStackTrace(__filename); | ||
}, { | ||
mochaOnly: true | ||
}); | ||
describe('text', function(){ | ||
it('respects timeout option', function(){ | ||
var promise = browser.find('.element').select({text: 'Second', timeout: 100}); | ||
domTest('respects timeout option', function(browser, dom, $){ | ||
var promise = browser.find('.element').select({text: 'Second', timeout: 3 }); | ||
dom.eventuallyInsert( | ||
$('<select class="element"><option>First</option><option>Second</option></select>').change(function (e) { | ||
var el = e.target; | ||
selectedItem = el.options[el.selectedIndex].text; | ||
}) | ||
); | ||
$('<select class="element"><option>First</option><option>Second</option></select>') | ||
, 6); | ||
return expect(promise).to.be.rejected | ||
return expect(promise).to.be.rejected; | ||
}); | ||
it('eventually selects an option element using the text', function(){ | ||
domTest('should eventually select an option element using the text', function(browser, dom, $){ | ||
var promise = browser.find('.element').select({text: 'Second'}); | ||
@@ -114,5 +136,4 @@ var selectedItem = undefined; | ||
dom.eventuallyInsert( | ||
$('<select class="element"><option>First</option><option>Second</option></select>').change(function (e) { | ||
var el = e.target; | ||
selectedItem = el.options[el.selectedIndex].text; | ||
$('<select class="element"><option>First</option><option>Second</option></select>').on('change', function () { | ||
selectedItem = $(this).find('option[selected]').text(); | ||
}) | ||
@@ -126,3 +147,3 @@ ); | ||
it('eventually selects an option element using a partial match', function(){ | ||
domTest('should eventually select an option element using a partial match', function(browser, dom, $){ | ||
var promise = browser.find('.element').select({text: 'Seco'}); | ||
@@ -132,5 +153,4 @@ var selectedItem = undefined; | ||
dom.eventuallyInsert( | ||
$('<select class="element"><option>First</option><option>Second</option></select>').change(function (e) { | ||
var el = e.target; | ||
selectedItem = el.options[el.selectedIndex].text; | ||
$('<select class="element"><option>First</option><option>Second</option></select>').on('change', function (e) { | ||
selectedItem = $(this).find('option[selected]').text(); | ||
}) | ||
@@ -144,6 +164,6 @@ ); | ||
it('selects the first match if multiple available', function(){ | ||
domTest('selects the first match if multiple available', function(browser, dom, $){ | ||
var selectedItem = undefined; | ||
var select = dom.insert('<select><option value="1">Item</option><option value="2">Item</option></select>').change(function (e) { | ||
var select = dom.insert('<select><option value="1">Item</option><option value="2">Item</option></select>').on('change', function (e) { | ||
selectedItem = select.val(); | ||
@@ -157,13 +177,12 @@ }); | ||
it('selects an option that eventually appears', function(){ | ||
domTest('selects an option that eventually appears', function(browser, dom, $){ | ||
var promise = browser.find('.element').select({text: 'Second'}); | ||
var selectedItem = undefined; | ||
var select = dom.insert('<select class="element"></select>').change(function (e) { | ||
var el = e.target; | ||
selectedItem = el.options[el.selectedIndex].text; | ||
var select = dom.insert('<select class="element"></select>').on('change', function (e) { | ||
selectedItem = $(this).find('option[selected]').text(); | ||
}); | ||
setTimeout(function () { | ||
$('<option>First</option><option>Second</option>').appendTo(select); | ||
select.append('<option>First</option><option>Second</option>'); | ||
}, 20); | ||
@@ -176,3 +195,3 @@ | ||
it('errors when the specified option does not exist', function(){ | ||
domTest('errors when the specified option does not exist', function(browser, dom){ | ||
var promise = browser.find('.element').select({text: 'Does not exist'}); | ||
@@ -182,8 +201,6 @@ | ||
return Promise.all([ | ||
expect(promise).to.be.rejected | ||
]); | ||
return expect(promise).to.be.rejected; | ||
}); | ||
it('errors when the input is not a select', function(){ | ||
domTest('errors when the input is not a select', function(browser, dom){ | ||
var promise = browser.find('.element').select({text: 'Whatevs'}); | ||
@@ -194,9 +211,8 @@ dom.eventuallyInsert('<div class="element"></div>'); | ||
it('selects an option using text that is falsy', function(){ | ||
domTest('selects an option using text that is falsy', function(browser, dom, $){ | ||
var promise = browser.find('.element').select({text: 0}); | ||
var selectedItem = undefined; | ||
var select = dom.insert('<select class="element"><option>0</option><option>1</option></select>').change(function (e) { | ||
var el = e.currentTarget; | ||
selectedItem = el.options[el.selectedIndex].text; | ||
var select = dom.insert('<select class="element"><option>0</option><option>1</option></select>').on('change', function (e) { | ||
selectedItem = $(this).find('option[selected]').text(); | ||
}); | ||
@@ -212,9 +228,8 @@ | ||
describe('exactText', function(){ | ||
it('should select an option using exact text that would otherwise match multiple options', function(){ | ||
domTest('should select an option using exact text that would otherwise match multiple options', function(browser, dom, $){ | ||
var promise = browser.find('.element').select({exactText: 'Mr'}); | ||
var selectedItem = undefined; | ||
var select = dom.insert('<select class="element"><option>Mr</option><option>Mrs</option></select>').change(function (e) { | ||
var el = e.currentTarget; | ||
selectedItem = el.options[el.selectedIndex].text; | ||
var select = dom.insert('<select class="element"><option>Mr</option><option>Mrs</option></select>').on('change', function (e) { | ||
selectedItem = $(this).find('option[selected]').text(); | ||
}); | ||
@@ -228,9 +243,8 @@ | ||
it('should select an option using exact text that is falsy', function(){ | ||
domTest('should select an option using exact text that is falsy', function(browser, dom, $){ | ||
var promise = browser.find('.element').select({exactText: 0}); | ||
var selectedItem = undefined; | ||
var select = dom.insert('<select class="element"><option>0</option><option>1</option></select>').change(function (e) { | ||
var el = e.currentTarget; | ||
selectedItem = el.options[el.selectedIndex].text; | ||
var select = dom.insert('<select class="element"><option>0</option><option>1</option></select>').on('change', function (e) { | ||
selectedItem = $(this).find('option[selected]').text(); | ||
}); | ||
@@ -247,9 +261,30 @@ | ||
describe('submit', function () { | ||
it('should submit the form', function () { | ||
var submitted; | ||
domTest('stack trace', function(browser, dom){ | ||
return browser.find('div') | ||
.submit() | ||
.assertStackTrace(__filename); | ||
}, { | ||
mochaOnly: true | ||
}); | ||
domTest('should submit the form', function (browser, dom) { | ||
var submitted = false; | ||
var promise = browser.find('input').submit(); | ||
dom.insert('<form><input type=text></form>').submit(function (ev) { | ||
dom.insert('<form action="#"><input type=text></form>').on('submit', function (ev) { | ||
submitted = true; | ||
}); | ||
return promise.then(function () { | ||
expect(submitted).to.be.true; | ||
}); | ||
}); | ||
domTest('should submit the form when submit button is clicked', function (browser, dom) { | ||
var submitted = false; | ||
var promise = browser.find('input').click(); | ||
dom.insert('<form action="#"><input type="submit">submit</input></form>').on('submit', function (ev) { | ||
ev.preventDefault(); | ||
submitted = true; | ||
}); | ||
@@ -260,6 +295,14 @@ | ||
}); | ||
}); | ||
}, {vdom: false}); | ||
}); | ||
describe('typeIn', function(){ | ||
domTest('stack trace', function(browser, dom){ | ||
return browser.find('input') | ||
.typeIn('hello') | ||
.assertStackTrace(__filename); | ||
}, { | ||
mochaOnly: true | ||
}); | ||
[ | ||
@@ -273,15 +316,15 @@ '<input class="element"></input>', | ||
'<input class="element" type="url"></input>', | ||
'<input class="element" type="number"></input>', | ||
'<textarea class="element"></textara>' | ||
].forEach(function(html) { | ||
it('eventually enters text into: ' + html, function () { | ||
var promise = browser.find('.element').typeIn('haha'); | ||
domTest('eventually enters text into: ' + html, function (browser, dom) { | ||
var promise = browser.find('.element').typeIn('1234'); | ||
dom.eventuallyInsert(html); | ||
return promise.then(function () { | ||
expect(dom.el.find('.element').val()).to.equal('haha'); | ||
expect(dom.el.find('.element').val()).to.equal('1234'); | ||
}); | ||
}); | ||
}); | ||
return | ||
[ | ||
@@ -292,12 +335,11 @@ '<div class="element"></div>', | ||
].forEach(function(html) { | ||
it('rejects attempt to type into element: ' + html, function () { | ||
domTest('rejects attempt to type into element: ' + html, function (browser, dom, $) { | ||
var promise = browser.find('.element').typeIn('whatevs'); | ||
dom.eventuallyInsert(html); | ||
return expect(promise).to.be.rejectedWith('Cannot type into ' + $(html)[0].tagName); | ||
return expect(promise).to.be.rejectedWith('Cannot type into ' + $(html).prop('tagName')); | ||
}); | ||
}); | ||
it('blanks out existing text when typing empty text', function () { | ||
domTest('blanks out existing text when typing empty text', function (browser, dom) { | ||
var firedEvents = []; | ||
@@ -308,12 +350,28 @@ dom.insert('<input type="text" class="element" value="good bye">') | ||
return browser.find('.element').typeIn('').then(function () { | ||
expect(dom.el.find('input.element').val()).to.equal(''); | ||
expect(firedEvents).to.eql(['input: ""']) | ||
return retry(function(){ | ||
expect(dom.el.find('input.element').val()).to.equal(''); | ||
expect(firedEvents).to.eql(['input']); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('typeInHtml', function(){ | ||
domTest('stack trace', function(browser, dom){ | ||
return browser.find('input') | ||
.typeInHtml('<p>hello</p>') | ||
.assertStackTrace(__filename); | ||
}, { | ||
mochaOnly: true | ||
}); | ||
}); | ||
describe('checkboxes', function(){ | ||
it('can check a checkbox by clicking it', function () { | ||
domTest('can check a checkbox by clicking on it', function (browser, dom, $) { | ||
var checkbox = dom.insert('<input class="checkbox" type=checkbox>'); | ||
var checked; | ||
checkbox.on('click', function (ev) { | ||
checked = $(this).prop('checked'); | ||
}); | ||
expect(checkbox.prop('checked')).to.be.false; | ||
@@ -324,2 +382,3 @@ | ||
expect(checkbox.prop('checked')).to.be.true; | ||
expect(checked).to.be.true; | ||
}).then(function () { | ||
@@ -329,8 +388,32 @@ return browser.find('.checkbox').click(); | ||
expect(checkbox.prop('checked')).to.be.false; | ||
expect(checked).to.be.false; | ||
}); | ||
}); | ||
domTest('can check a checkbox by clicking its label', function (browser, dom, $) { | ||
var label = dom.insert('<label>Check: <input class="checkbox" type=checkbox></label>'); | ||
var checkbox = dom.el.find('input'); | ||
var checked; | ||
checkbox.on('click', function (ev) { | ||
checked = $(this).prop('checked'); | ||
}); | ||
expect(checkbox.prop('checked')).to.be.false; | ||
var clicked = browser.find('label').click(); | ||
return clicked.then(function () { | ||
expect(checkbox.prop('checked')).to.be.true; | ||
expect(checked).to.be.true; | ||
}).then(function () { | ||
return browser.find('.checkbox').click(); | ||
}).then(function () { | ||
expect(checkbox.prop('checked')).to.be.false; | ||
expect(checked).to.be.false; | ||
}); | ||
}); | ||
}); | ||
describe('fill', function(){ | ||
it('fills a component with the supplied values', function(){ | ||
domTest('fills a component with the supplied values', function(browser, dom){ | ||
var component = browser.component({ | ||
@@ -344,3 +427,4 @@ title: function(){ | ||
}); | ||
dom.eventuallyInsert('<select class="title"><option>Mrs</option><option>Mr</option></select><input type="text" class="name"></input>'); | ||
dom.eventuallyInsert('<select class="title"><option>Mrs</option><option>Mr</option></select>'); | ||
dom.eventuallyInsert('<input type="text" class="name"></input>'); | ||
@@ -356,3 +440,3 @@ return component.fill([ | ||
it('can fill using shortcut syntax', function(){ | ||
domTest('can fill using shortcut syntax', function(browser, dom){ | ||
var component = browser.component({ | ||
@@ -369,3 +453,5 @@ title: function(){ | ||
}); | ||
dom.eventuallyInsert('<select class="title"><option>Mrs</option><option>Mr</option></select><input type="text" class="name"></input><label class="agree"><input type="checkbox"></label>'); | ||
dom.eventuallyInsert('<select class="title"><option>Mrs</option><option>Mr</option></select>'); | ||
dom.eventuallyInsert('<input type="text" class="name"></input>'); | ||
dom.eventuallyInsert('<label class="agree">Check: <input type="checkbox"></label>'); | ||
@@ -383,3 +469,3 @@ return component.fill([ | ||
it('can execute actions on a component', function(){ | ||
domTest('can execute actions on a component', function(browser, dom){ | ||
var myActionRan = false; | ||
@@ -408,3 +494,3 @@ var component = browser.component({ | ||
it('throws an error if the action cannot be found', function(){ | ||
domTest('throws an error if the action cannot be found', function(browser, dom){ | ||
var component = browser.component({}); | ||
@@ -420,3 +506,3 @@ var error; | ||
it('throws an error when trying to call an action on a field which does not exist', function(){ | ||
domTest('throws an error when trying to call an action on a field which does not exist', function(browser, dom){ | ||
var component = browser.component({}); | ||
@@ -431,3 +517,3 @@ | ||
it('throws an error if the field does not exist', function(){ | ||
domTest('throws an error if the field does not exist', function(browser, dom){ | ||
var component = browser.component({}); | ||
@@ -442,2 +528,2 @@ | ||
}); | ||
}); | ||
}) |
@@ -1,15 +0,9 @@ | ||
var browser = require('..'); | ||
var createTestDom = require('./createTestDom'); | ||
var domTest = require('./domTest'); | ||
describe('assertions', function(){ | ||
var dom; | ||
beforeEach(function(){ | ||
dom = createTestDom(); | ||
}); | ||
describe('shouldNotExist', function () { | ||
it("should ensure that element eventually doesn't exists", function () { | ||
var elementToRemove = dom.insert('<div class="removing"></div>'); | ||
var elementToStay = dom.insert('<div class="staying"></div>'); | ||
domTest("should ensure that element eventually doesn't exists", function (browser, dom) { | ||
dom.insert('<div class="removing"></div>'); | ||
dom.insert('<div class="staying"></div>'); | ||
@@ -20,3 +14,3 @@ var good = browser.find('.removing').shouldNotExist(); | ||
setTimeout(function () { | ||
elementToRemove.remove(); | ||
dom.el.find('.removing').remove(); | ||
}, 50); | ||
@@ -30,4 +24,4 @@ | ||
it('allows trytryagain parameters to be used', function () { | ||
var elementToRemove = dom.insert('<div class="removing"></div>'); | ||
domTest('allows trytryagain parameters to be used', function (browser, dom) { | ||
dom.insert('<div class="removing"></div>'); | ||
@@ -37,3 +31,3 @@ var promise = browser.find('.removing').shouldNotExist({timeout: 500, interval: 100}); | ||
setTimeout(function () { | ||
elementToRemove.remove(); | ||
dom.el.find('.removing').remove(); | ||
}, 50); | ||
@@ -43,6 +37,26 @@ | ||
}); | ||
domTest('stack trace', function(browser, dom){ | ||
dom.insert('<div></div>'); | ||
return browser.find('div') | ||
.shouldNotExist() | ||
.assertStackTrace(__filename); | ||
}, { | ||
mochaOnly: true | ||
}); | ||
}); | ||
describe('shouldExist', function(){ | ||
domTest('stack trace', function(browser, dom){ | ||
return browser.find('div') | ||
.shouldExist() | ||
.assertStackTrace(__filename); | ||
}, { | ||
mochaOnly: true | ||
}); | ||
}); | ||
describe('is', function () { | ||
it('should eventually find an element if it has a class', function () { | ||
domTest('should eventually find an element if it has a class', function (browser, dom) { | ||
var good = browser.find('.element').is('.good').shouldExist(); | ||
@@ -56,4 +70,4 @@ var bad = browser.find('.element').is('.bad').shouldExist(); | ||
element.addClass('good'); | ||
}, 100); | ||
}, 200); | ||
}, 10); | ||
}, 10); | ||
@@ -63,3 +77,4 @@ return Promise.all([good, expect(bad).to.be.rejected]); | ||
}); | ||
it('eventually finds an element containing text', function () { | ||
domTest('eventually finds an element containing text', function (browser, dom) { | ||
var promise = browser.find('.element', {text: 'some t'}).shouldExist(); | ||
@@ -70,4 +85,4 @@ dom.eventuallyInsert('<div class="element"><div>some text</div></div>'); | ||
it('eventually finds an element containing text as it appears on the page', function () { | ||
var promise = browser.find('.element', {text: 'This is some text that is all on one line.\nAnd some more on another line'}).shouldExist(); | ||
domTest('eventually finds an element containing text as it appears on the page', function (browser, dom) { | ||
var promise = browser.find('.element').shouldHave({text: 'This is some text that is all on one line.\nAnd some more on another line'}); | ||
dom.eventuallyInsert('<div class="element"><div>\ | ||
@@ -85,3 +100,3 @@ This\ | ||
it('eventually finds an element containing exactText', function () { | ||
domTest('eventually finds an element containing exactText', function (browser, dom) { | ||
var good = browser.find('.a', {exactText: '8'}).shouldExist(); | ||
@@ -98,4 +113,25 @@ var bad = browser.find('.b', {exactText: '8'}).shouldExist(); | ||
domTest("treats assertion of text: '' as exact text", function (browser, dom) { | ||
dom.eventuallyInsert('<div><div class="a">something</div><div class="b"></div></div>'); | ||
return browser.find('.a', {text: 'something'}).shouldExist().then(function () { | ||
return Promise.all([ | ||
browser.find('.a', {text: ''}).shouldNotExist(), | ||
browser.find('.b', {text: ''}).shouldExist() | ||
]) | ||
}) | ||
}); | ||
describe('shouldHave', function () { | ||
it('eventually finds an element and asserts that it has text', function () { | ||
domTest('stack trace', function(browser, dom){ | ||
dom.insert('<div>hello</div>'); | ||
return browser.find('div') | ||
.shouldHave({text: 'something'}) | ||
.assertStackTrace(__filename); | ||
}, { | ||
mochaOnly: true | ||
}); | ||
domTest('eventually finds an element and asserts that it has text', function (browser, dom) { | ||
var good = browser.find('.element').shouldHave({text: 'some t'}); | ||
@@ -112,3 +148,3 @@ var bad = browser.find('.element').shouldHave({text: 'sme t'}); | ||
it('allows trytryagain parameters to be used', function () { | ||
domTest('allows trytryagain parameters to be used', function (browser, dom) { | ||
var good = browser.find('.element').shouldHave({text: 'some t', timeout: 400, interval: 100}); | ||
@@ -125,3 +161,3 @@ var bad = browser.find('.element').shouldHave({text: 'sme t'}); | ||
it('eventually finds an element and asserts that it has value', function () { | ||
domTest('eventually finds an element and asserts that it has value', function (browser, dom) { | ||
var good1 = browser.find('.element1 input').shouldHave({value: 'some t'}); | ||
@@ -141,3 +177,19 @@ var good2 = browser.find('.element2 input').shouldHave({value: 0}); | ||
it('finds an element with exact value', function () { | ||
domTest('error has a tip with suggestions for how to fix it', function(browser, dom){ | ||
dom.insert('<span>abc</span>'); | ||
dom.insert('<span>bac</span>'); | ||
dom.insert('<span>cba</span>'); | ||
return browser.find('span').shouldHave({ | ||
text: [ | ||
'cba', | ||
'abc', | ||
'bac', | ||
] | ||
}).catch(function(error) { | ||
expect(error.message).to.include('\nThe text was found but in a different order than specified - maybe you need some sorting?'); | ||
}); | ||
}); | ||
domTest('finds an element with exact value', function (browser, dom) { | ||
var bad = browser.find('.element1 input').shouldHave({exactValue: 'some t'}); | ||
@@ -154,3 +206,18 @@ var good = browser.find('.element1 input').shouldHave({exactValue: 'some text'}); | ||
it("treats selects with no value as empty string", function(){ | ||
domTest("treats assertion of value: '' as exact value", function (browser, dom) { | ||
var bad = browser.find('.element1 input').shouldHave({value: ''}); | ||
var good = browser.find('.element2 input').shouldHave({value: ''}); | ||
dom.eventuallyInsert('<div>\n' + | ||
'<div class="element1"><input type=text value="some text" /></div>\n' + | ||
'<div class="element2"><input type=text value="" /></div>\n' + | ||
'</div>'); | ||
return Promise.all([ | ||
good, | ||
expect(bad).to.be.rejected | ||
]); | ||
}); | ||
domTest("treats selects with no value as empty string", function(browser, dom){ | ||
dom.insert('<select></select>'); | ||
@@ -166,3 +233,3 @@ | ||
it('recurses through a tree of assertions', function(){ | ||
domTest('recurses through a tree of assertions', function(browser, dom){ | ||
dom.insert('<div class="airport"><span class="date">Aug 2055</span><span class="text">LHR</span><span class="blank"></span></div>'); | ||
@@ -186,3 +253,3 @@ return browser.component({ | ||
it('verifies attributes are present', function(){ | ||
domTest('verifies attributes are present', function(browser, dom){ | ||
dom.insert('<a id="abc" href="/home">hello</a>'); | ||
@@ -201,3 +268,3 @@ var good = browser.find('a').shouldHave({ | ||
return Promise.all([ | ||
good, | ||
good, | ||
expect(bad).to.be.rejected | ||
@@ -208,3 +275,3 @@ ]); | ||
describe('exactText', function(){ | ||
it('eventually finds elements that have the exact array of text', function(){ | ||
domTest('eventually finds elements that have the exact array of text', function(browser, dom){ | ||
var promise = browser.find('.element option').shouldHave({exactText: ['', 'Mr', 'Mrs']}); | ||
@@ -216,6 +283,14 @@ | ||
}); | ||
domTest('fails to find exact text', function(browser, dom){ | ||
var promise = browser.find('option').shouldHave({exactText: ['', 'Mr', 'Mrs']}); | ||
dom.eventuallyInsert('<select><option>Optional</option><option>Mr</option><option>Mrs</option></select>'); | ||
return expect(promise).to.be.rejected; | ||
}); | ||
}); | ||
describe('checkboxes', function () { | ||
it('eventually finds a checked checkbox', function () { | ||
domTest('eventually finds a checked checkbox', function (browser, dom) { | ||
var good = browser.find('.checkbox').shouldHave({checked: true}); | ||
@@ -233,9 +308,9 @@ | ||
it('fails if only one of many checkboxes is checked', function () { | ||
domTest('fails if only one of many checkboxes is checked', function (browser, dom) { | ||
var good = browser.find('.checkbox').shouldHave({checked: true}); | ||
var checkbox = dom.insert('<input class="checkbox" type=checkbox /><input class="checkbox" type=checkbox />'); | ||
var checkbox = dom.insert('<input class="checkbox" type=checkbox />'); | ||
dom.insert('<input class="checkbox" type=checkbox />'); | ||
setTimeout(function () { | ||
checkbox[0].checked = true; | ||
checkbox.prop('checked', true); | ||
}, 20); | ||
@@ -248,9 +323,10 @@ | ||
it('ensures that each checkbox in the scope is either checked or unchecked', function () { | ||
domTest('ensures that each checkbox in the scope is either checked or unchecked', function (browser, dom) { | ||
var good = browser.find('.checkbox').shouldHave({checked: [true, false]}); | ||
var bad = browser.find('.checkbox').shouldHave({checked: [false, true]}); | ||
var checkbox = dom.insert('<input class="checkbox" type=checkbox /><input class="checkbox" type=checkbox />'); | ||
var checkbox = dom.insert('<input class="checkbox" type=checkbox />'); | ||
dom.insert('<input class="checkbox" type=checkbox />'); | ||
setTimeout(function () { | ||
checkbox[0].checked = true; | ||
checkbox.prop('checked', true); | ||
}, 20); | ||
@@ -264,3 +340,3 @@ | ||
it('fails to find a checked checkbox', function () { | ||
domTest('fails to find a checked checkbox', function (browser, dom) { | ||
var good = browser.find('.checkbox').shouldHave({checked: false}); | ||
@@ -278,3 +354,3 @@ var bad = browser.find('.checkbox').shouldHave({checked: true}); | ||
it('eventually finds elements and asserts that they each have text', function () { | ||
domTest('eventually finds elements and asserts that they each have text', function (browser, dom) { | ||
var good = browser.find('.element div').shouldHave({text: ['one', 2]}); | ||
@@ -293,3 +369,3 @@ var bad1 = browser.find('.element div').shouldHave({text: ['one']}); | ||
it('eventually finds elements and asserts that they each have value', function () { | ||
domTest('eventually finds elements and asserts that they each have value', function (browser, dom) { | ||
var good = browser.find('.element input').shouldHave({value: ['one', 2, 0]}); | ||
@@ -308,3 +384,3 @@ var bad1 = browser.find('.element input').shouldHave({value: ['one']}); | ||
it('eventually finds an element and asserts that it has css', function () { | ||
domTest('eventually finds an element and asserts that it has css', function (browser, dom) { | ||
var good = browser.find('.element').shouldHave({css: '.the-class'}); | ||
@@ -323,7 +399,8 @@ var bad1 = browser.find('.element').shouldHave({css: '.not-the-class'}); | ||
it('eventually finds an element and asserts that it has n elements', function () { | ||
domTest('eventually finds an element and asserts that it has n elements', function (browser, dom) { | ||
var good = browser.find('.element').shouldHave({length: 2}); | ||
var bad1 = browser.find('.element').shouldHave({length: 1}); | ||
dom.eventuallyInsert('<div class="element"></div><div class="element"></div>'); | ||
dom.eventuallyInsert('<div class="element"></div>'); | ||
dom.eventuallyInsert('<div class="element"></div>'); | ||
@@ -336,17 +413,18 @@ return Promise.all([ | ||
it('eventually finds an element and asserts that it passes an assertion', function () { | ||
domTest('eventually finds an element and asserts that it passes an assertion', function (browser, dom, $) { | ||
var good1 = browser.find('.element').shouldHaveElement(function (element) { | ||
expect(element.innerText).to.equal('a'); | ||
expect(element.text()).to.equal('a'); | ||
}); | ||
var bad1 = browser.find('.multi').shouldHaveElement(function (element) { | ||
expect(element.innerText).to.equal('b'); | ||
expect(element.text()).to.equal('b'); | ||
}); | ||
var bad2 = browser.find('.element').shouldHaveElement(function (element) { | ||
expect(element.innerText).to.equal('b'); | ||
expect(element.text()).to.equal('b'); | ||
}); | ||
var element = dom.insert('<div class="element"></div>'); | ||
dom.eventuallyInsert('<div class="multi"></div><div class="multi">b</div>'); | ||
dom.eventuallyInsert('<div class="multi"></div>'); | ||
dom.eventuallyInsert('<div class="multi">b</div>'); | ||
@@ -364,6 +442,6 @@ setTimeout(function () { | ||
it('eventually finds elements and asserts that they pass an assertion', function () { | ||
domTest('eventually finds elements and asserts that they pass an assertion', function (browser, dom, $) { | ||
var good1 = browser.find('.element').shouldHaveElements(function (elements) { | ||
var xs = elements.map(function (element) { | ||
return element.dataset.x; | ||
return $(element).attr('data-x'); | ||
}); | ||
@@ -376,3 +454,3 @@ | ||
var xs = elements.map(function (element) { | ||
return element.dataset.x; | ||
return $(element).attr('data-x'); | ||
}); | ||
@@ -383,3 +461,5 @@ | ||
dom.eventuallyInsert('<div class="element" data-x="one"></div><div class="element" data-x="two"></div><div class="element" data-x="three"></div>'); | ||
dom.eventuallyInsert('<div class="element" data-x="one"></div>'); | ||
dom.eventuallyInsert('<div class="element" data-x="two"></div>'); | ||
dom.eventuallyInsert('<div class="element" data-x="three"></div>'); | ||
@@ -394,3 +474,3 @@ return Promise.all([ | ||
describe('shouldNotHave', function () { | ||
it('eventually finds an element and asserts that it does not have text', function () { | ||
domTest('eventually finds an element and asserts that it does not have text', function (browser, dom) { | ||
var promise = browser.find('.element').shouldNotHave({text: 'sme t'}); | ||
@@ -403,3 +483,3 @@ | ||
it('allows trytryagain parameters to be used', function () { | ||
domTest('allows trytryagain parameters to be used', function (browser, dom) { | ||
var promise = browser.find('.element').shouldNotHave({text: 'sme t', timeout: 400, interval: 100}); | ||
@@ -406,0 +486,0 @@ |
@@ -1,12 +0,5 @@ | ||
var browser = require('..'); | ||
var createTestDom = require('./createTestDom'); | ||
var domTest = require('./domTest'); | ||
describe('component', function () { | ||
var dom; | ||
beforeEach(function(){ | ||
dom = createTestDom(); | ||
}); | ||
it('can return new selectors by extending', function () { | ||
domTest('can return new selectors by extending', function (browser, dom) { | ||
var user = browser.component({ | ||
@@ -29,3 +22,3 @@ name: function () { | ||
it('components are independent', function () { | ||
domTest('components are independent', function (browser, dom) { | ||
var user = browser.component({ | ||
@@ -50,3 +43,3 @@ name: function () { | ||
it('can extend another component', function () { | ||
domTest('can extend another component', function (browser, dom) { | ||
var user = browser.component({ | ||
@@ -76,3 +69,3 @@ name: function () { | ||
it('can return new scoped selectors', function () { | ||
domTest('can return new scoped selectors', function (browser, dom) { | ||
var admin = browser.component({ | ||
@@ -101,3 +94,3 @@ user: function () { | ||
it('components inherit scope', function () { | ||
domTest('components inherit scope', function (browser, dom) { | ||
var adminArea = browser.find('.admin'); | ||
@@ -104,0 +97,0 @@ |
@@ -24,9 +24,9 @@ var $ = require('jquery'); | ||
}, | ||
eventuallyInsert: function(html) { | ||
eventuallyInsert: function(html, after) { | ||
var self = this; | ||
setTimeout(function () { | ||
self.insert(html); | ||
}, 200); | ||
}, after || 10); | ||
} | ||
}; | ||
}; |
@@ -1,12 +0,6 @@ | ||
var browser = require('..'); | ||
var createTestDom = require('./createTestDom'); | ||
var retry = require('trytryagain'); | ||
var domTest = require('./domTest'); | ||
describe('events', function(){ | ||
var dom; | ||
beforeEach(function(){ | ||
dom = createTestDom(); | ||
}); | ||
it('typeIn element should fire change', function(){ | ||
domTest('typeIn element should fire change', function(browser, dom){ | ||
var firedEvents = []; | ||
@@ -28,3 +22,3 @@ | ||
it('typeIn element should fire input on each character', function(){ | ||
domTest('typeIn element should fire input on each character', function(browser, dom){ | ||
var firedEvents = []; | ||
@@ -46,10 +40,11 @@ | ||
it('typeIn element should fire change and then blur event on input', function(){ | ||
domTest('typeIn element should fire change and then blur event on input', function(browser, dom){ | ||
var firedEvents = []; | ||
dom.insert('<input type="text" class="input"><input type="text" class="change">'); | ||
dom.insert('<input type="text" class="input" />'); | ||
dom.insert('<input type="text" class="change" />'); | ||
dom.el.find('.input').one('blur', function(e){ | ||
dom.el.find('.input').on('blur', function(e){ | ||
firedEvents.push('blur'); | ||
}).one('change', function(){ | ||
}).on('change', function(){ | ||
firedEvents.push('change'); | ||
@@ -61,19 +56,19 @@ }); | ||
}).then(function () { | ||
expect(firedEvents).to.eql([ | ||
'change', | ||
'blur' | ||
]) | ||
return retry(function(){ | ||
expect(firedEvents).to.eql([ | ||
'change', | ||
'blur' | ||
]); | ||
}); | ||
}); | ||
}); | ||
it('click element should fire blur event on input', function(){ | ||
domTest('click element should fire blur event on input', function(browser, dom){ | ||
var blurred = false; | ||
dom.insert('<input type="text" class="input"><button>button</button>'); | ||
dom.insert('<input type="text" class="input" />'); | ||
dom.insert('<button>button</button>'); | ||
dom.el.find('.input').on('blur', function(e){ | ||
if (e.target.className === 'input') { | ||
blurred = true; | ||
} | ||
blurred = true; | ||
}) | ||
@@ -84,22 +79,24 @@ | ||
}).then(function(){ | ||
expect(blurred).to.be.true | ||
return retry(function(){ | ||
expect(blurred).to.be.true; | ||
}); | ||
}); | ||
}); | ||
it('select element should fire blur event on input', function(){ | ||
domTest('select element should fire blur event on input', function(browser, dom, $){ | ||
var blurred = false; | ||
dom.insert('<input type="text" class="input"><select><option>one</option></select>'); | ||
dom.insert('<select><option>one</option></select>'); | ||
dom.insert('<input type="text" class="input"></input>'); | ||
dom.el.find('input').on('blur', function(e){ | ||
blurred = true; | ||
}); | ||
dom.el.find('.input').on('blur', function(e){ | ||
if (e.target.className === 'input') { | ||
blurred = true; | ||
} | ||
}) | ||
return browser.find('.input').typeIn('first').then(function(){ | ||
return browser.find('select').select({text: 'one'}); | ||
}).then(function(){ | ||
expect(blurred).to.be.true | ||
return retry(function(){ | ||
expect(blurred).to.be.true; | ||
}); | ||
}); | ||
@@ -109,4 +106,4 @@ }); | ||
describe('callbacks on interaction', function () { | ||
it('fires events on clicks', function () { | ||
var button = dom.insert('<button>a button</button>')[0]; | ||
domTest('fires events on clicks', function (browser, dom) { | ||
var button = dom.insert('<button>a button</button>'); | ||
@@ -120,8 +117,8 @@ var event; | ||
expect(event.type).to.equal('click'); | ||
expect(event.element).to.equal(button); | ||
expect(event.element[0]).to.equal(button[0]); | ||
}); | ||
}); | ||
it('fires events on typeIn', function () { | ||
var input = dom.insert('<input></input>')[0]; | ||
domTest('fires events on typeIn', function (browser, dom) { | ||
var input = dom.insert('<input></input>'); | ||
@@ -136,8 +133,8 @@ var event; | ||
expect(event.text).to.equal('some text'); | ||
expect(event.element).to.equal(input); | ||
expect(event.element[0]).to.equal(input[0]); | ||
}); | ||
}); | ||
it('fires events on typeIn', function () { | ||
var editorDiv = dom.insert('<div class="editor"></div>')[0]; | ||
domTest('fires events on typeIn', function (browser, dom) { | ||
var editorDiv = dom.insert('<div class="editor"></div>'); | ||
@@ -152,8 +149,8 @@ var event; | ||
expect(event.html).to.equal('some <b>html</b>'); | ||
expect(event.element).to.equal(editorDiv); | ||
expect(event.element[0]).to.equal(editorDiv[0]); | ||
}); | ||
}); | ||
it('fires events on select', function () { | ||
var select = dom.insert('<select><option>one</option></select>')[0]; | ||
domTest('fires events on select', function (browser, dom) { | ||
var select = dom.insert('<select><option>one</option></select>'); | ||
@@ -164,8 +161,8 @@ var event; | ||
event = e; | ||
}).find('select').select('one').then(function () { | ||
}).find('select').select({text: 'one'}).then(function () { | ||
expect(event, 'expected event to fire').to.not.be.undefined; | ||
expect(event.type).to.equal('select option'); | ||
expect(event.value).to.equal('one'); | ||
expect(event.optionElement).to.equal(select.firstChild); | ||
expect(event.element).to.equal(select); | ||
expect(event.optionElement[0]).to.equal(select.find('option')[0]); | ||
expect(event.element[0]).to.equal(select[0]); | ||
}); | ||
@@ -172,0 +169,0 @@ }); |
@@ -1,13 +0,5 @@ | ||
var browser = require('..'); | ||
var createTestDom = require('./createTestDom'); | ||
var $ = require('jquery'); | ||
var domTest = require('./domTest'); | ||
describe('find', function () { | ||
var dom; | ||
beforeEach(function(){ | ||
dom = createTestDom(); | ||
}); | ||
it('should eventually find an element', function () { | ||
domTest('should eventually find an element', function (browser, dom) { | ||
var promise = browser.find('.element').shouldExist(); | ||
@@ -20,5 +12,5 @@ | ||
it('should eventually find an element using a filter', function () { | ||
domTest('should eventually find an element using a filter', function (browser, dom) { | ||
var promise = browser.find('.element').filter(function (element) { | ||
return element.classList.contains('correct'); | ||
return element.hasClass('correct'); | ||
}, 'has class "correct"').element(); | ||
@@ -30,7 +22,7 @@ | ||
return promise.then(function (element) { | ||
expect(element.className).to.equal('element correct'); | ||
expect(element.attr('class')).to.equal('element correct'); | ||
}); | ||
}); | ||
it('should eventually find an element with the right text', function () { | ||
domTest('should eventually find an element with the right text', function (browser, dom) { | ||
var promise = browser.find('.element', {text: 'green'}).element(); | ||
@@ -42,9 +34,9 @@ | ||
return promise.then(function (element) { | ||
expect(element.innerText).to.equal('green'); | ||
expect(element.text()).to.equal('green'); | ||
}); | ||
}); | ||
it('filter fails with the right message', function () { | ||
domTest('filter fails with the right message', function (browser, dom) { | ||
var promise = browser.find('.element').filter(function (element) { | ||
return element.classList.contains('correct'); | ||
return element.hasClass('correct'); | ||
}, 'has class "correct"').element(); | ||
@@ -58,3 +50,3 @@ | ||
it('should eventually find an element in an iframe', function(){ | ||
domTest('should eventually find an element in an iframe', function(browser, dom){ | ||
var iframe = document.createElement('iframe'); | ||
@@ -72,6 +64,10 @@ iframe.src = '/base/test/page1.html'; | ||
}); | ||
}); | ||
}, {vdom: false}); | ||
it('can find things in an iframe', function(){ | ||
dom.eventuallyInsert('<iframe src="/base/test/page2.html"></iframe>'); | ||
domTest('can find things in an iframe', function(browser, dom){ | ||
var iframe = document.createElement('iframe'); | ||
iframe.src = '/base/test/page2.html'; | ||
iframe.width = 700; | ||
iframe.height = 1000; | ||
dom.el.append(iframe); | ||
@@ -81,8 +77,8 @@ return browser.find('iframe').element().then(function(iframe){ | ||
}); | ||
}); | ||
}, {vdom: false}); | ||
it('calls a function for each element found', function(){ | ||
domTest('calls a function for each element found', function(browser, dom){ | ||
var promise = browser.find('span').elements(); | ||
dom.eventuallyInsert('<div><span>a</span><span>b</span></div>'); | ||
dom.insert('<div><span>a</span><span>b</span></div>'); | ||
@@ -94,10 +90,11 @@ return promise.then(function(elements){ | ||
describe('visibility', function(){ | ||
it('should not find an element that is visually hidden', function(){ | ||
domTest('should not find an element that is visually hidden', function(browser, dom){ | ||
dom.insert('<div class="element">hello <span style="display:none;">world</span></div>'); | ||
return browser.find('.element > span').shouldNotExist(); | ||
}); | ||
}, {vdom: false}); | ||
it('should find an element that is visually hidden when visibleOnly = false', function(){ | ||
domTest('should find an element that is visually hidden when visibleOnly = false', function(browser, dom){ | ||
dom.insert('<div class="element">hello <span style="display:none;">world</span></div>'); | ||
@@ -108,3 +105,3 @@ | ||
it('should find elements that are visually hidden because of how html renders them', function(){ | ||
domTest('should find elements that are visually hidden because of how html renders them', function(browser, dom){ | ||
dom.insert('<select><option>First</option><option>Second</option></select>'); | ||
@@ -114,4 +111,5 @@ return browser.find('select option').shouldHave({text: ['First', 'Second']}); | ||
}); | ||
describe('containing', function () { | ||
it('eventually finds an element containing another element', function () { | ||
domTest('eventually finds an element containing another element', function (browser, dom) { | ||
var promise = browser.find('.outer').containing('.inner').shouldExist(); | ||
@@ -122,3 +120,3 @@ | ||
dom.insert('<div class="outer"><div class="inner">good</div></div>'); | ||
}, 200); | ||
}, 10); | ||
@@ -128,3 +126,3 @@ return promise; | ||
it('element returns the outer element', function () { | ||
domTest('element returns the outer element', function (browser, dom) { | ||
var promise = browser.find('.outer').containing('.inner').element(); | ||
@@ -135,10 +133,10 @@ | ||
dom.insert('<div class="outer"><div class="inner">good</div></div>'); | ||
}, 200); | ||
}, 10); | ||
return promise.then(function (element) { | ||
expect($(element).is('.outer')).to.be.true; | ||
expect(element.hasClass('outer')).to.be.true; | ||
}); | ||
}); | ||
it('errors with a usable css selector if it cant find something', function () { | ||
domTest('errors with a usable css selector if it cant find something', function (browser, dom) { | ||
var promise = browser.find('.outer').find('.not-there').element(); | ||
@@ -150,6 +148,6 @@ | ||
expect(promise).to.be.rejectedWith('expected to find: .outer .not-there') | ||
return expect(promise).to.be.rejectedWith('expected to find: .outer .not-there') | ||
}); | ||
it('errors with a usable css selector if it cant find an element containing another', function () { | ||
domTest('errors with a usable css selector if it cant find an element containing another', function (browser, dom) { | ||
var promise = browser.find('.outer').containing('.not-there').shouldExist(); | ||
@@ -161,6 +159,6 @@ | ||
expect(promise).to.be.rejectedWith('expected to find: .outer:has(.not-there)') | ||
return expect(promise).to.be.rejectedWith('expected to find: .outer:has(.not-there)') | ||
}); | ||
it("fails if it can't find an element containing another", function () { | ||
domTest("fails if it can't find an element containing another", function (browser, dom) { | ||
var promise = browser.find('.outer').containing('.inner').shouldExist(); | ||
@@ -172,2 +170,22 @@ | ||
return expect(promise).to.be.rejectedWith('expected to find: .outer:has(.inner)'); | ||
}); | ||
domTest('errors with a usable css selector if it cant find an element containing another', function (browser, dom) { | ||
var promise = browser.find('.outer').containing('.not-there').shouldExist(); | ||
setTimeout(function () { | ||
dom.insert('<div class="outer"><div>bad</div></div>'); | ||
}, 200); | ||
return expect(promise).to.be.rejectedWith('expected to find: .outer:has(.not-there)') | ||
}); | ||
domTest("fails if it can't find an element containing another", function (browser, dom) { | ||
var promise = browser.find('.outer').containing('.inner').shouldExist(); | ||
setTimeout(function () { | ||
dom.insert('<div class="outer"><div>bad</div></div>'); | ||
}, 10); | ||
return expect(promise).to.be.rejected; | ||
@@ -178,3 +196,3 @@ }); | ||
describe('chains', function () { | ||
it('eventually finds the inner element, even if the outer element exists', function () { | ||
domTest('eventually finds the inner element, even if the outer element exists', function (browser, dom) { | ||
var promise = browser.find('.outer').find('.inner').shouldExist(); | ||
@@ -186,4 +204,4 @@ | ||
outer.append('<div class="inner">good</div>'); | ||
}, 200); | ||
}, 200); | ||
}, 10); | ||
}, 10); | ||
@@ -193,3 +211,3 @@ return promise; | ||
it('fails to find the inner element if it never arrives', function () { | ||
domTest('fails to find the inner element if it never arrives', function (browser, dom) { | ||
var promise = browser.find('.outer').find('.inner').shouldExist(); | ||
@@ -199,3 +217,3 @@ | ||
var outer = dom.insert('<div class="outer"></div>'); | ||
}, 200); | ||
}, 10); | ||
@@ -202,0 +220,0 @@ return expect(promise).to.be.rejected; |
@@ -8,1 +8,14 @@ require('lie/polyfill'); | ||
global.expect = chai.expect; | ||
global.timeout = parseInt(typeof window == 'object' && window.__env__.BM_TIMEOUT || 100); | ||
Promise.prototype.assertStackTrace = function(file) { | ||
return this.then(function(){ | ||
throw new Error('This test should have thrown an error but did not. You need to fix this.'); | ||
}).catch(function(error){ | ||
var specLine = error.stack.split('\n').find(function(line){ | ||
return line.indexOf(file) != -1; | ||
}); | ||
expect(specLine).to.include(file); | ||
}); | ||
} |
@@ -1,6 +0,6 @@ | ||
var browser = require('..'); | ||
var createTestDom = require('./createTestDom'); | ||
var create = require('../create'); | ||
describe('options', function () { | ||
it('can set an option that is inerhited by components', function(){ | ||
var browser = create(); | ||
var parentComponent = browser.find('div').component({}); | ||
@@ -11,2 +11,14 @@ parentComponent.set({myOption: 'abc'}); | ||
}); | ||
it('can overide default timeout', function(){ | ||
var browser = create(); | ||
browser.set({timeout: 10}); | ||
var start = new Date(); | ||
return browser.find('.doesnt-exist').shouldExist().catch(function(){ | ||
var end = new Date(); | ||
var duration = end - start; | ||
expect(duration).to.be.below(50); | ||
}); | ||
}); | ||
}); |
@@ -1,13 +0,5 @@ | ||
var browser = require('..'); | ||
var createTestDom = require('./createTestDom'); | ||
var $ = require('jquery'); | ||
var domTest = require('./domTest'); | ||
describe('scope', function () { | ||
var dom; | ||
beforeEach(function(){ | ||
dom = createTestDom(); | ||
}); | ||
it('can scope with an element', function () { | ||
domTest('can scope with an element', function (browser, dom, $) { | ||
var red = dom.insert('<div><div class="element">red</div></div>'); | ||
@@ -25,3 +17,3 @@ var blue = dom.insert('<div><div class="element">blue</div></div>'); | ||
it('can scope with another finder', function () { | ||
domTest('can scope with another finder', function (browser, dom, $) { | ||
var red = dom.insert('<div class="red"><div class="element">red</div></div>'); | ||
@@ -28,0 +20,0 @@ var blue = dom.insert('<div class="blue"><div class="element">blue</div></div>'); |
Sorry, the diff of this file is not supported yet
111662
34
2471
541
6
20
+ Addeddetect-browser@1.5.0
+ Addedglobal@^4.3.0
+ Addedchai@3.5.0(transitive)
+ Addeddetect-browser@1.5.0(transitive)
+ Addeddom-walk@0.1.2(transitive)
+ Addedglobal@4.4.0(transitive)
+ Addedjquery@2.2.4(transitive)
+ Addedmin-document@2.19.0(transitive)
+ Addedprocess@0.11.10(transitive)
- Removedchai@3.3.0(transitive)
- Removedjquery@2.1.3(transitive)
Updatedchai@3.5.0
Updatedjquery@2.2.4