module.exports = function(chai, utils) { function matches(against, value) { return against instanceof RegExp ? against.test(value) : against === value } /* Language Chains ---------- @@@@ element A language chain that sets an `element` flag that tells other casper-chai assertions to not require all elements to match the criteria, but at least one. ```javascript expect("ul.header li").to.have.an.element.with.attr('aria-selected') ``` In this example, the assertion with pass if any `li` has the `aria-selected` attribute. Otherwise, by default `attr` will assert that all elements matched have that attribute. */ chai.Assertion.addProperty('element', function() { return utils.flag(this, 'element', true) }) /* @@@@ evaluate Change the assertion subject to the result of the expression evaluated in the page. An expression may be a function, a function string, or a simple expression. When a string is passed in it is wrapped in 'function () {}', with a 'return' statement added if one is not already included, and this wrapped function is evaluated as an ordinary function would be. When it is a function it is simply evaluated in the page as is. ```javascript "true".should.evaluate.to.true; (function() { return false }).should.evaluate.to.false; expect("function () { return true }").to.evaluate.to.true; "document.querySelectorAll('body').length".should.evaluate.to.be.at.least(1); var foo = function () { return typeof jQuery ; ) expect(foo).to.evaluate.to.be.undefined; // unless jQuery is installed. "0 === -0".should.evaluate.to.be.false.wat ``` */ chai.Assertion.addProperty('evaluate', function() { var expr = utils.flag(this, 'object') if (typeof expr === 'string' && !/^\s*function\s+/.test(expr)) { if (expr.indexOf('return ') === -1) { expr = 'function () { return ' + expr + ' }' } else { expr = 'function () { ' + expr + ' }' } } return utils.flag(this, 'object', casper.evaluate(expr)) }) /* Casper-Chai Assertions ---------- The following are the assertion tests that are added onto `Chai.Assertion`. */ /* @@@@ attr(attributeName) / attribute(attributeName) Asserts that attribute `attribute_name` are on all elements matched by `selector`. If the `element` chain was used, it asserts that any element has that selector. ```javascript expect("#my_header").to.have.attr('class') expect("ul.header li").to.have.an.element.with.attribute('aria-selected') ``` It also changes the subject of the assertion to the attributes, so you can do further assertions on those attributes ````javascript "#tabs li a".should.have.an.element.with.attribute('aria-selected')[0].that.equals('true') "section a.add".should.have.attr('data-bind')[0].and.contains('click:') ```` */ var assertAttr = function(attr) { var selector = this._obj, attrs = casper.getElementsAttribute(selector, attr) if (utils.flag(this, 'element')) { this.assert(attrs.some(function(a) { return a }), ('Expected some elements matching selector ' + selector + ' to have attribute') + ('' + attr + ' set, but none did'), ('Expected no elements matching selector ' + selector + ' to have attribute') + ('' + attr + ' set, but at least one did')) } else { this.assert(attrs.every(function(a) { return a }), ('Expected all elements matching selector ' + selector + ' to have attribute ') + ('' + attr + ' set, but some did not have it'), ('Expected no elements matching selector ' + selector + ' to have attribute ') + ('' + attr + ' set, but some had it')) } return utils.flag(this, 'object', attrs) } chai.Assertion.addMethod('attr', assertAttr) chai.Assertion.addMethod('attribute', assertAttr) /* @@@@ fieldValue True when the named input provided has the given value. Wraps Casper's `__utils__.getFieldValue(inputName)`. Examples: ```javascript expect("name_of_input").to.have.fieldValue("123"); ``` */ chai.Assertion.addMethod('fieldValue', function(givenValue) { var name = this._obj, remoteValue = casper.evaluate(function(n) { return __utils__.getFieldValue(n) }, name) return this.assert(remoteValue === givenValue, ('expected field(s) ' + name + ' to have value ' + givenValue + ', ') + ('but it was ' + remoteValue), ('expected field(s) ' + name + ' to not have value ' + givenValue + ', ') + 'but it was') }) /* @@@@ inDOM True when the given selector is in the DOM ```javascript "#target".should.be.inDOM; ``` Note: We use "inDOM" instead of "exist" so we don't conflict with the chai.js BDD. */ chai.Assertion.addProperty('inDOM', function() { var selector = this._obj return this.assert(casper.exists(selector), 'expected selector ' + selector + ' to be in the DOM, but it was not', 'expected selector ' + selector + ' to not be in the DOM, but it was') }) /* @@@@ loaded True when the given resource exists in the phantom browser. ```javascript expect("styles.css").to.not.be.loaded "jquery-1.8.3".should.be.loaded ``` */ chai.Assertion.addProperty('loaded', function() { return this.assert(casper.resourceExists(this._obj), 'expected resource ' + this._obj + ' to exist, but it does not', 'expected resource ' + this._obj + ' to not exist, but it does') }) /* @@@@ matchTitle True when the the title matches the given regular expression, or where a string is used match that string exactly. ```javascript expect("Google").to.matchTitle; ``` */ chai.Assertion.addProperty('matchTitle', function() { var matcher = this._obj, title = casper.getTitle() return this.assert(matches(matcher, title), 'expected title ' + matcher + ' to match ' + title + ', but it did not', 'expected title ' + matcher + ' to not match ' + title + ', but it did') }) /* @@@@ matchCurrentUrl True when the current URL matches the given string or regular expression ```javascript expect(/https:\/\//).to.matchCurrentUrl; ``` */ chai.Assertion.addProperty('matchCurrentUrl', function() { var matcher = this._obj, currentUrl = casper.getCurrentUrl() return this.assert(matches(matcher, currentUrl), 'expected url ' + currentUrl + ' to match ' + this + ', but it did not', 'expected url ' + currentUrl + ' to not match ' + this + ', but it did') }) /* @@@@ tagName All elements matching the given selector are one of the given tag names. In other words, given a selector, all tags must be one of the given tags. Note that those tags need not appear in the selector. ```javascript ".menuItem".should.have.tagName('li') "menu li *".should.have.tagName(['a', 'span']) ``` */ chai.Assertion.addMethod('tagName', function(ok_names) { var selector = this._obj if (typeof ok_names === 'string') { ok_names = [ok_names] } else if (!Array.isArray(ok_names)) { throw new Error('tagName must be a string or list, it was ' + typeof ok_names); } var tagnames = casper.evaluate(function(selector) { return Array.prototype.map.call(__utils__.findAll(selector), function(e) { return e.tagName.toLowerCase() }) }, selector) var diff = tagnames.filter(function(t) { return ok_names.indexOf(t) < 0 }) return this.assert(diff.length === 0, ('Expected ' + selector + ' to have only tags [' + ok_names + '], but there was ') + ('also tag(s) [' + diff + ']'), ('Expected ' + selector + ' to have tags other than [' + ok_names + '], but ') + 'those were the only tags that appeared') }) /* @@@@ textInDOM The given text can be found in the phantom browser's DOM. ```javascript "search".should.be.textInDOM ``` */ chai.Assertion.addProperty('textInDOM', function() { var needle = this._obj, haystack = casper.evaluate(function() { return document.body.textContent || document.body.innerText }) return this.assert(haystack.indexOf(needle) !== -1, 'expected text ' + needle + ' to be in the document, but it was not', 'expected text ' + needle + ' to not be in the document, but it was found') }) /* @@@@ text The text of the given selector matches the expression if it is a regular expression, or is equal to the text, if a string. It supports the `contains` and `include` language chain to do partial matching ```javascript expect("#element").to.have.text(/case InSenSitIvE/i); expect("#element").to.have.text("Welcome to My Site"); expect("#element").to.contain.text("Welcome"); ``` */ chai.Assertion.addMethod('text', function(matcher) { var selector = this._obj, text = casper.fetchText(selector) if (utils.flag(this, 'contains') && typeof matcher === 'string') { return this.assert((text != null ? text.indexOf(matcher) : void 0) >= 0, 'expected \'' + selector + '\' to contain ' + matcher + ', but it was "' + text + '"', 'expected \'' + selector + '\' to not contain ' + matcher + ', but it did') } else { var verb = matcher instanceof RegExp ? 'contain' : 'be' return this.assert(matches(matcher, text), 'expected \'' + selector + '\' to ' + verb + ' ' + matcher + ', but it was "' + text + '"', 'expected \'' + selector + '\' to not ' + verb + ' ' + matcher + ', but it did') } }) /* @@@@ visible The selector matches a visible element. ```javascript expect("#hidden").to.not.be.visible ``` */ chai.Assertion.addProperty('visible', function() { var selector = this._obj return this.assert(casper.visible(selector), 'expected selector ' + selector + ' to be visible, but it was not', 'expected selector ' + selector + ' to not be visible, but it was') }) }