API Docs for: 0.0.9
Show:

File: lib/dalek/assertions.js

/*!
 *
 * Copyright (c) 2013 Sebastian Golasch
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

'use strict';

// ext. libs
var Q = require('q');
var uuid = require('./uuid');
var chai = require('chai');

// Module variable
var Assertions;

/**
 * @module Assertions
 * @namespace Dalek.Internal
 */

module.exports = function () {
  return Assertions;
};

/**
 * Assertions check if the assumptions you made about a website are correct.
 * For example they might check if the title of a page or the content text of
 * an element is as expected, or if your mobile website version only displays
 * a certain amount of elements.
 *
 * @class Assertions
 * @constructor
 * @part Assertions
 * @api
 */

Assertions = function (opts) {
  this.test = opts.test;
  this.proceeded = [];
  this.chaining = false;
};

/**
 * It can be really cumbersome to always write assert, assert & assert
 * all over the place when you're doing multiple assertions.
 * To avoid this, open an assertion context in your test which allows
 * you to write (n) assertions without having to write 'assert' before each.
 *
 * So, instead of writing this:
 *
 * ```javascript
 * test.open('http://doctorwhotv.co.uk/')
 *     .assert.text('#nav').is('Navigation')
 *     .assert.visible('#nav')
 *     .assert.attr('#nav', 'data-nav', 'true')
 *     .done();
 * ```
 *
 * you can write this:
 *
 * ```javascript
 * test.open('http://doctorwhotv.co.uk/')
 *     .assert.chain()
 *       .text('#nav').is('Navigation')
 *       .visible('#nav')
 *       .attr('#nav', 'data-nav', 'true')
 *     .end()
 *     .done();
 * ```
 *
 * to make it even more concise, you can combine this with the [query](actions.html#meth-query) method:
 *
 * ```javascript
 * test.open('http://doctorwhotv.co.uk/')
 *     .assert.chain()
 *       .query('#nav')
 *           .text().is('Navigation')
 *           .visible()
 *           .attr('data-nav', 'true')
 *         .end()
 *     .end()
 *     .done();
 * ```
 *
 * Always make sure to terminate it with the [end](#meth-end) method!
 *
 * @api
 * @method chain
 * @chainable
 */

Assertions.prototype.chain = function () {
  this.test.lastChain.push('chaining');
  this.chaining = true;
  return this;
};

/**
 * Terminates an assertion chain or a query
 *
 * ```javascript
 * test.open('http://doctorwhotv.co.uk/')
 *     .assert.chain()
 *       .query('#nav')
 *           .text().is('Navigation')
 *           .visible()
 *           .attr('data-nav', 'true')
 *         .end()
 *     .end()
 *     .done();
 * ```
 *
 * @api
 * @method end
 * @chainable
 */

Assertions.prototype.end = function () {
  var lastAction = this.test.lastChain.pop();
  if (lastAction === 'chaining') {
    this.chaining = false;
  }

  if (lastAction  === 'querying') {
    this.test.querying = false;
  }
  return this.test;
};

/**
 * Asserts that a given resource does exist in the environment.
 *
 * @method resourceExists
 * @param {string} url URL of the resource to check
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.resourceExists = function (url, message) {
  var hash = uuid();
  var cb = this._generateCallbackAssertion('resourceExists', 'resourceExists', this._testTruthy, hash, {url: url, message: message}).bind(this.test);
  this._addToActionQueue([url, hash], 'resourceExists', cb);
  return this.chaining ? this : this.test;
};

/**
 * Asserts that a given element appears n times on the page.
 *
 * Given this portion of HTML, you would like to assure that all of these elements
 * are ending up in your rendered markup on your page.
 *
 * ```html
 * <section id="blog-overview">
 *   <article class="teaser"></article>
 *   <article class="teaser"></article>
 *   <article class="teaser"></article>
 *   <article class="teaser"></article>
 * </section>
 * ```
 *
 * The simple solution is to check if all these elements are present
 *
 * ```javascript
 * test.assert.numberOfElements('#blog-overview .teaser', 4, '4 blog teasers are present')
 * ```
 * The alternate syntax for this is:
 *
 * ```javascript
 * test.assert.numberOfElements('#blog-overview .teaser')
 *     .is(4, '4 blog teasers are present')
 * ```
 *
 * If you are not sure how many elements will exactly end up in your markup,
 * you could use the between assertion handler
 *
 * ```javascript
 * test.assert.numberOfElements('#blog-overview .teaser')
 *     .is.between([2, 6], 'Between 2 and 6 blog teasers are present')
 * ```
 *
 * If you dealing with the situation that you have a minimum of elements,
 * you expect, you can use this helper:
 *
 * ```javascript
 * test.assert.numberOfElements('#blog-overview .teaser')
 *     .is.gt(2, 'At least 3 blog teasers are present')
 * ```
 * If you want to know if its 'greater than equal', use this one
 *
 * ```javascript
 * test.assert.numberOfElements('#blog-overview .teaser')
 *     .is.gte(2, 'At least 2 blog teasers are present')
 * ```
 * as well as their 'lower than' and 'lower than equal' equivalents.
 *
 * ```javascript
 * test.assert.numberOfElements('#blog-overview .teaser')
 *     .is.lt(5, 'Less than 5 blog teasers are present')
 * ```
 *
 * ```javascript
 * test.assert.numberOfElements('#blog-overview .teaser')
 *     .is.lte(5, 'Less than, or 5 blog teasers are present')
 * ```
 * And if you just want to know, if a certain amount of teasers isnʼt present,
 * you can still use the not() assertion helper
 *
 * ```javascript
 * test.assert.numberOfElements('#blog-overview .teaser')
 *     .is.not(5, 'There are more or less than 5 teasers present')
 * ```
 *
 * @api
 * @method numberOfElements
 * @param {string} selector Selector that matches the elements to test
 * @param {string} expected Expected test result
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.numberOfElements = function (selector, expected, message) {
  var hash = uuid();

  if (this.test.querying === true) {
    message = expected;
    expected = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('numberOfElements', 'numberOfElements', this._testShallowEquals, hash, {expected: expected, selector: selector, message: message}).bind(this.test);
  this._addToActionQueue([selector, expected, hash], 'getNumberOfElements', cb);
  return this.chaining ? this : this.test;
};

/**
 *
 * Asserts that a given element is visible n times in the current viewport.
 *
 *
 * Given this portion of HTML, you would like to assure that all of these elements
 * are ending up in your rendered markup on your page.
 *
 * ```html
 * <section id="blog-overview">
 *   <article class="teaser"></article>
 *   <article class="teaser"></article>
 *   <article class="teaser"></article>
 *   <article class="teaser"></article>
 * </section>
 * ```
 *
 * The simple solution is to check if all these elements are visible
 *
 * ```javascript
 * test.assert.numberOfVisibleElements('#blog-overview .teaser', 4, '4 blog teasers are visible')
 * ```
 * The alternate syntax for this is:
 *
 * ```javascript
 * test.assert.numberOfVisibleElements('#blog-overview .teaser')
 *     .is(4, '4 blog teasers are visible')
 * ```
 *
 * If you are not sure how many elements will exactly be shown in the current viewport,
 * you could use the between assertion handler
 *
 * ```javascript
 * test.assert.numberOfVisibleElements('#blog-overview .teaser')
 *     .is.between(2, 6, 'Between 2 and 6 blog teasers are visible')
 * ```
 *
 * If you dealing with the situation that you have a minimum of elements,
 * you expect, use this helper:
 *
 * ```javascript
 * test.assert.numberOfVisibleElements('#blog-overview .teaser')
 *     .is.gt(2, 'At least 3 blog teasers are visible')
 * ```
 * If you want to know if its 'greater than equal', you can use this one
 *
 * ```javascript
 * test.assert.numberOfVisibleElements('#blog-overview .teaser')
 *     .is.gte(2, 'At least 2 blog teasers are visible')
 * ```
 * as well as their 'lower than' and 'lower than equal' equivalents.
 *
 * ```javascript
 * test.assert.numberOfVisibleElements('#blog-overview .teaser')
 *     .is.lt(5, 'Less than 5 blog teasers are visible')
 * ```
 *
 * ```javascript
 * test.assert.numberOfVisibleElements('#blog-overview .teaser')
 *     .is.lte(5, 'Less than, or 5 blog teasers are visible')
 * ```
 * And if you just want to know, if a certain amount of teasers isnʼt visible,
 * you can still use the ':not(): assertion helper
 *
 * ```javascript
 * test.assert.numberOfVisibleElements('#blog-overview .teaser')
 *     .is.not(5, 'There are more or less than 5 teasers visible')
 * ```
 *
 * > NOTE: Buggy on all browsers
 *
 * @api
 * @method numberOfVisibleElements
 * @param {string} selector Selector that matches the elements to test
 * @param {string} expected Expected test result
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.numberOfVisibleElements = function (selector, expected, message) {
  var hash = uuid();

  if (this.test.querying === true) {
    message = expected;
    expected = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('numberOfVisibleElements', 'numberOfVisibleElements', this._testShallowEquals, hash, {expected: expected, selector: selector, message: message}).bind(this.test);
  this._addToActionQueue([selector, expected, hash], 'getNumberOfVisibleElements', cb);
  return this.chaining ? this : this.test;
};

/**
 * Asserts that a given form field has the provided value.
 *
 * Given this portion of HTML, we would like to get the information which option element
 * is currently selected.
 *
 * ```html
 * <form name="fav-doctor" id="fav-doctor">
 *   <select id="the-doctors">
 *     <option value="9">Eccleston</option>
 *     <option selected value="10">Tennant</option>
 *     <option value="11">Smith</option>
 *   </select>
 * </form>
 * ```
 *
 * ```javascript
 * test
 *   .assert.val('#the-doctors', 10, 'David is the favourite')
 *   // lets change the favourite by selection the last option
 *  .click('#the-doctors option:last')
 *  .assert.val('#the-doctors', 11, 'Matt is now my favourite, bow ties are cool')
 * ```
 *
 * This assertion is capable of getting the values from every form element
 * that holds a value attribute
 *
 * Getting texts out of normal input fields is pretty straight forward
 *
 * ```html
 * <label for="fav-enemy">Tell my your favourity Who enemy:</label>
 * <input id="fav-enemy" name="fav-enemy" type="text" value="Daleks" />
 * ```
 *
 * ```javascript
 * test
 *   .assert.val('#fav-enemy', 'Daleks', 'Daleks are so cute')
 *   // lets change the favourite by typing smth. new
 *  .type('#fav-enemy', 'Cyberman')
 *  .assert.val('#fav-enemy', 'Cyberman', 'Cyberman are so cyber')
 * ```
 *
 * @api
 * @method val
 * @param {string} selector Selector that matches the elements to test
 * @param {string} expected Expected test result
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.val = function (selector, expected, message) {
  var hash = uuid();

  if (this.test.querying === true) {
    message = expected;
    expected = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('val', 'val', this._testShallowEquals, hash, {expected: expected, selector: selector, message: message}).bind(this.test);
  this._addToActionQueue([selector, expected, hash], 'val', cb);
  return this.chaining ? this : this.test;
};

/**
 * Checks the computed style.
 * Note: When selecting values like em or percent, they will be converted to px. So it's currently not possible
 * to check em, %, ... values, only px.
 *
 * ```html
 * <div id="superColoredElement">Rose</div>
 * ```
 *
 * ```css
 * #superColoredElement {
 *   background-color: rgba(255, 0, 0, 1);
 *   color: rgba(0, 128, 0, 1);
 * }
 * ```
 *
 * ```javascript
 *  test
 *    .open('http://unicorns.rainbows.io')
 *    .assert.css('#superColoredElement', 'background-color', 'rgba(255, 0, 0, 1)')
 *    .assert.css('#superColoredElement', 'color', 'rgba(0, 128, 0, 1)')
 *    .done();
 * ```
 *
 * Can also check if a computed style is greater or lower than the expected value.
 * TODO: We might extract the part that determines the comparison operator to reuse it in other test. We might also
 *       add >= and <=.
 *
 * ```html
 * <div id="fancyPlacedElement">Tulip</div>
 * ```
 *
 * ```css
 * #fancyPlacedElement {
 *   top: 100px;
 * }
 * ```
 *
 * ```javascript
 *  test
 *    .open('http://unicorns.rainbows.io')
 *    .assert.css('#fancyPlacedElement', 'top', '>50px') // 100 is greater than 50, success
 *    .assert.css('#fancyPlacedElement', 'top', '<150px') // 100 is lower than 150, success
 *    .assert.css('#fancyPlacedElement', 'top', '>150px') // 100 is lower than 150, fail
 *    .assert.css('#fancyPlacedElement', 'top', '<50px') // 100 is greater than 50, fail
 *    .done();
 * ```
 *
 * @api
 * @method css
 * @param {string} selector Selector that matches the elements to test
 * @param {string} property CSS property to check
 * @param {string} expected Expected test result
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.css = function (selector, property, expected, message) {
  var hash = uuid();
  var assertionMethod;
  var comparisonOperator;

  if (this.test.querying === true) {
    message = expected;
    expected = property;
    property = selector;
    selector = this.test.selector;
  }

  switch (expected.substr(0, 1)) {
    case '>':
      assertionMethod = this._testLowerThan;
      expected = expected.substr(1);
      comparisonOperator = '>';
      break;
    case '<':
      assertionMethod = this._testGreaterThan;
      expected = expected.substr(1);
      comparisonOperator = '<';
      break;
    default:
      assertionMethod = this._testShallowEquals;
      comparisonOperator = '';
      break;
  }

  var cb = this._generateCallbackAssertion('css', 'css', assertionMethod, hash, {comparisonOperator: comparisonOperator, expected: expected, selector: selector, porperty: property, message: message, parseFloatOnValues: true}).bind(this.test);
  this._addToActionQueue([selector, property, expected, hash], 'css', cb);
  return this.chaining ? this : this.test;
};

/**
 * Checks the actual width of an element.
 *
 * ```html
 *   <div id="fixed-dimensions" style="width: 100px"></div>
 * ```
 *
 * ```javascript
 *  test
 *    .open('http://localhost:5000/index.html')
 *    // all true, all pixel
 *    .assert.width('#fixed-dimensions', 100)
 *    .assert.width('#fixed-dimensions').is(100)
 *    .assert.width('#fixed-dimensions').is.not(100)
 *    .assert.width('#fixed-dimensions').is.gt(90)
 *    .assert.width('#fixed-dimensions').is.gte(97)
 *    .assert.width('#fixed-dimensions').is.lt(120)
 *    .assert.width('#fixed-dimensions').is.lte(110)
 *    .assert.width('#fixed-dimensions').is.between([90, 110])
 *    .done();
 * ```
 *
 * @api
 * @method width
 * @param {string} selector Selector that matches the elements to test
 * @param {string} expected Expected test result
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.width = function (selector, expected, message) {
  var hash = uuid();

  if (this.test.querying === true) {
    message = expected;
    expected = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('width', 'width', this._testShallowEquals, hash, {expected: expected, selector: selector, message: message}).bind(this.test);
  this._addToActionQueue([selector, expected, hash], 'width', cb);
  return this.chaining ? this : this.test;
};

/**
 * Checks the actual height of an element.
 *
 * ```html
 *   <div id="fixed-dimensions" style="height: 100px"></div>
 * ```
 *
 * ```javascript
 *  test
 *    .open('http://localhost:5000/index.html')
 *    // all true, all pixel
 *    .assert.height('#fixed-dimensions', 100)
 *    .assert.height('#fixed-dimensions').is(100)
 *    .assert.height('#fixed-dimensions').is.not(100)
 *    .assert.height('#fixed-dimensions').is.gt(90)
 *    .assert.height('#fixed-dimensions').is.gte(97)
 *    .assert.height('#fixed-dimensions').is.lt(120)
 *    .assert.height('#fixed-dimensions').is.lte(110)
 *    .assert.height('#fixed-dimensions').is.between([90, 110])
 *    .done();
 * ```
 *
 * @api
 * @method height
 * @param {string} selector Selector that matches the elements to test
 * @param {string} expected Expected test result
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.height = function (selector, expected, message) {
  var hash = uuid();

  if (this.test.querying === true) {
    message = expected;
    expected = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('height', 'height', this._testShallowEquals, hash, {expected: expected, selector: selector, message: message}).bind(this.test);
  this._addToActionQueue([selector, expected, hash], 'height', cb);
  return this.chaining ? this : this.test;
};

/**
 * Determine if an <option> element, or an <input> element of type checkbox or radio is currently selected.
 *
 * ```html
 * <input type="checkbox" id="unchecked_checkbox" name="unchecked_checkbox"/>
 * <input type="checkbox" id="checked_checkbox" name="checked_checkbox" checked="checked"/>
 * <select id="select_elm" name="select_elm">
 *   <option value="9">Eccleston</option>
 *   <option selected value="10">Tennant</option>
 *   <option value="11">Smith</option>
 * </select>
 * ```
 *
 * Checking radio and checkboxes:
 *
 * ```javascript
 *  test
 *    .open('http://selectables.org')
 *    .assert.selected('#checked_checkbox')
 *    .done();
 * ```
 *
 * Checking option elements:
 *
 * ```javascript
 *  test
 *    .open('http://selectables.org')
 *    .assert.selected('#select_elm option:nth-child(2)')
 *    .done();
 * ```
 *
 * @api
 * @method selected
 * @param {string} selector Selector that matches the elements to test
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.selected = function (selector, message) {
  var hash = uuid();

  if (this.test.querying === true) {
    message = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('selected', 'selected', this._testShallowEquals, hash, {expected: true, selector: selector, message: message}).bind(this.test);
  this._addToActionQueue([selector, true, hash], 'selected', cb);
  return this.chaining ? this : this.test;
};

/**
 * Determine if an <option> element, or an <input> element of type
 * checkbox or radio is currently not selected.
 *
 * ```html
 * <input type="checkbox" id="unchecked_checkbox" name="unchecked_checkbox"/>
 * <input type="checkbox" id="checked_checkbox" name="checked_checkbox" checked="checked"/>
 * <select id="select_elm" name="select_elm">
 *   <option value="9">Eccleston</option>
 *   <option selected value="10">Tennant</option>
 *   <option value="11">Smith</option>
 * </select>
 * ```
 *
 * Checking radio and checkboxes:
 *
 * ```javascript
 *  test
 *    .open('http://selectables.org')
 *    .assert.notSelected('#unchecked_checkbox')
 *    .done();
 * ```
 *
 * Checking option elements:
 *
 * ```javascript
 *  test
 *    .open('http://selectables.org')
 *    .assert.notSelected('#select_elm option:last-child')
 *    .done();
 * ```
 *
 * @api
 * @method notSelected
 * @param {string} selector Selector that matches the elements to test
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.notSelected = function (selector, message) {
  var hash = uuid();

  if (this.test.querying === true) {
    message = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('selected', 'selected', this._testShallowEquals, hash, {expected: false, selector: selector, message: message}).bind(this.test);
  this._addToActionQueue([selector, false, hash], 'selected', cb);
  return this.chaining ? this : this.test;
};

/**
 * Determine if an element is currently enabled.
 *
 * ```html
 * <input id="onmars" type="text" size="50" name="onmars" placeholder="State your name, rank and intention!"></input>
 * ```
 *
 * ```javascript
 * test
 *   .open('http://doctor.thedoctor.com/doctor')
 *   .assert.enabled('#onmars', 'Is enabled!')
 *   .done();
 * ```
 *
 * @api
 * @method enabled
 * @param {string} selector Selector that matches the elements to test
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.enabled = function (selector, message) {
  var hash = uuid();

  if (this.test.querying === true) {
    message = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('enabled', 'enabled', this._testShallowEquals, hash, {expected: true, selector: selector, message: message}).bind(this.test);
  this._addToActionQueue([selector, true, hash], 'enabled', cb);
  return this.chaining ? this : this.test;
};

/**
 * Determine if an element is currently disabled.
 *
 * ```html
 * <input disabled id="onearth" type="text" size="50" name="onearth" placeholder="State your name, rank and intention!"></input>
 * ```
 *
 * ```javascript
 * test
 *   .open('http://doctor.thedoctor.com/doctor')
 *   .assert.disabled('#onearth', 'Is disabled!')
 *   .done();
 * ```
 *
 * @api
 * @method disabled
 * @param {string} selector Selector that matches the elements to test
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.disabled = function (selector, message) {
  var hash = uuid();

  if (this.test.querying === true) {
    message = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('enabled', 'enabled', this._testShallowEquals, hash, {expected: false, selector: selector, message: message}).bind(this.test);
  this._addToActionQueue([selector, false, hash], 'enabled', cb);
  return this.chaining ? this : this.test;
};

/**
 * Checks the contents of a cookie.
 *
 * ```javascript
 *  test
 *    .open('http://cookiejar.io/not_your_mothers_javascript.html')
 *    .setCookie('atestcookie', 'foobar=baz')
 *    .assert.cookie('atestcookie', 'foobar=baz')
 *    .done();
 * ```
 *
 * @api
 * @method cookie
 * @param {string} name Name of the cookie
 * @param {string} expect Expected testresult
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.cookie = function (name, expected, message) {
  var hash = uuid();
  var cb = this._generateCallbackAssertion('cookie', 'cookie', this._testShallowEquals, hash, {expected: expected, name: name, message: message}).bind(this.test);
  this._addToActionQueue([name, expected, hash], 'cookie', cb);
  return this.chaining ? this : this.test;
};

/**
 * Asserts that current HTTP status code is the same as the one passed as argument.
 * TODO: Needs some work to be implement (maybe JavaScript, Webdriver ha no method for this)
 *
 * @method httpStatus
 * @param {integer} status HTTP status code
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.httpStatus = function (status, message) {
  var hash = uuid();
  var cb = this._generateCallbackAssertion('httpStatus', 'httpStatus', this._testShallowEquals, hash, {expected: status, message: message}).bind(this.test);
  this._addToActionQueue([status, hash], 'httpStatus', cb);
  return this.chaining ? this : this.test;
};

/**
 * Asserts that an element matching the provided selector expression exists in remote DOM environment.
 *
 * ```html
 * <body>
 *   <p id="so-lonely">Last of the timelords</p>
 * </body>
 * ```
 *
 * ```javascript
 * test
 *   .open('http://doctor.thedoctor.com/doctor')
 *   .assert.exists('#so-lonely', 'The loneliest element in the universe exists')
 *   .done()
 * ```
 *
 * @api
 * @method exists
 * @param {string} selector Selector that matches the elements to test
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.exists = function (selector, message) {
  var hash = uuid();

  if (this.test.querying === true) {
    message = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('exists', 'exists', this._testTruthy, hash, {selector: selector, message: message}).bind(this.test);
  this._addToActionQueue([selector, hash], 'exists', cb);
  return this.chaining ? this : this.test;
};

/**
 * Asserts that an element matching the provided selector expression doesnʼt
 * exists within the remote DOM environment.
 *
 * ```html
 * <body>
 *   <p id="so-lonely">Last of the time lords</p>
 * </body>
 * ```
 *
 * ```javascript
 * test
 *   .open('http://doctor.thedoctor.com/doctor')
 *   .assert.doesntExist('#the-master', 'The master element has not been seen')
 *   .done();
 * ```
 *
 * @api
 * @method doesntExist
 * @param {string} selector Selector that matches the elements to test
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.doesntExist = function (selector, message) {
  var hash = uuid();

  if (this.test.querying === true) {
    message = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('exists', '!exists', this._testFalsy, hash, {selector: selector, message: message}).bind(this.test);
  this._addToActionQueue([selector, hash], 'exists', cb);
  return this.chaining ? this : this.test;
};

/**
 * Asserts that the element matching the provided selector expression is not visible.
 *
 * ```html
 * <body>
 *   <h1 style="display: none">Me? So hidden …</h1>
 *   <h2>Me? So in viewport...</h2>
 * </body>
 * ```
 *
 * ```javascript
 *  test
 *    .open('http://allyourviewportsbelongto.us')
 *    .assert.notVisible('h1', 'Element is not visible')
 *    .done();
 * ```
 *
 *
 * > NOTE: Buggy on all browsers
 *
 * @api
 * @method notVisible
 * @param {string} selector Selector that matches the elements to test
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.notVisible = function (selector, message) {
  var hash = uuid();

  if (this.test.querying === true) {
    message = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('visible', '!visible', this._testFalsy, hash, {selector: selector, message: message}).bind(this.test);
  this._addToActionQueue([selector, hash], 'visible', cb);
  return this.chaining ? this : this.test;
};

/**
 * Asserts that the element matching the provided selector expression is visible.
 *
 * ```html
 * <body>
 *   <h1>Me? So in viewport …</h1>
 * </body>
 * ```
 *
 * ```javascript
 *  test
 *    .open('http://allyourviewportsbelongto.us')
 *    .assert.visible('h1', 'Element is visible')
 *    .done();
 * ```
 *
 * > NOTE: Buggy on all browsers
 *
 * @api
 * @method visible
 * @param {string} selector Selector that matches the elements to test
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.visible = function (selector, message) {
  var hash = uuid();

  if (this.test.querying === true) {
    message = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('visible', 'visible', this._testTruthy, hash, {selector: selector, message: message}).bind(this.test);
  this._addToActionQueue([selector, hash], 'visible', cb);
  return this.chaining ? this : this.test;
};

/**
 * Asserts that given text does not exist in the provided selector.
 *
 * ```html
 * <body>
 *   <h1>This is a CasperJS sandbox</h1>
 * </body>
 * ```
 *
 * ```javascript
 *  test
 *    .open('http://dalekjs.com/guineapig/')
 *    .assert.doesntHaveText('h1', 'This page is a Dalek sandbox', 'It´s a sandbox!')
 *    .done();
 * ```
 *
 * > NOTE: You cant match for a substring with contain() here.
 *
 * @api
 * @method doesntHaveText
 * @param {string} selector Selector that matches the elements to test
 * @param {string} expected Expected test result
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.doesntHaveText = function (selector, expected, message) {
  var hash = uuid();
  if (this.test.querying === true) {
    message = expected;
    expected = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('text', '!text', this._testShallowUnequals, hash, {selector: selector, expected: expected, message: message}).bind(this.test);
  this._addToActionQueue([selector, expected, hash], 'text', cb);
  return this.chaining ? this : this.test;
};

/**
 * Asserts that given text does not exist in the current alert/prompt/confirm dialog.
 *
 * ```html
 * <a href="#" id="alert_confirm" onclick="confirm('Confirm me!')">I make confirm</a>
 * ```
 *
 * ```javascript
 *  test
 *    .open('http://skaaro.com/index.html')
 *    .click('#alert_confirm')
 *    .assert.dialogDoesntHaveText('I am an alert')
 *    .accept()
 *    .done();
 * ```
 *
 * > NOTE: You cant match for a substring with contain() here.
 * > NOTE: Does not work in Firefox & PhantomJS
 *
 * @api
 * @method dialogDoesntHaveText
 * @param {string} expected Expected test result
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.dialogDoesntHaveText = function (expected, message) {
  var hash = uuid();
  var cb = this._generateCallbackAssertion('alertText', '!alertText', this._testShallowUnequals, hash, {expected: expected, message: message}).bind(this.test);
  this._addToActionQueue([expected, hash], 'alertText', cb);
  return this.chaining ? this : this.test;
};

/**
 * Asserts that given text does exist in the provided selector.
 *
 * ```html
 * <body>
 *   <h1>This is a Dalek sandbox</h1>
 * </body>
 * ```
 *
 * ```javascript
 *  test
 *    .open('http://dalekjs.com/guineapig/')
 *    .assert.text('h1', 'This page is a Dalek sandbox', 'Exterminate!')
 *    .done();
 * ```
 *
 * of course, text works also with the assertion helpers is() and not()
 *
 * ```javascript
 *  test
 *    .open('http://dalekjs.com/guineapig/')
 *    .assert.text('h1').is('This page is a Dalek sandbox', 'Exterminate!')
 *    .done();
 * ```
 *
 * ```javascript
 *  test
 *    .open('http://dalekjs.com/guineapig/')
 *    .assert.text('h1').is.not('This page is a CasperJS sandbox', 'Exterminate!')
 *    .done();
 * ```
 *
 * and you can also check for the occurrence of a substring with to.contain() (but don't try to chain it with not() as this is not possible)
 *
 * ```javascript
 *  test
 *    .open('http://dalekjs.com/guineapig/')
 *    .assert.text('h1').to.contain('CasperJS')
 *    .done();
 * ```
 *
 * @api
 * @method text
 * @param {string} selector Selector that matches the elements to test
 * @param {string} expected Expected test result
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.text = function (selector, expected, message) {
  var hash = uuid();
  if (this.test.querying === true) {
    message = expected;
    expected = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('text', 'text', this._testShallowEquals, hash, {selector: selector, expected: expected, message: message}).bind(this.test);
  this._addToActionQueue([selector, expected, hash], 'text', cb);
  return (this.chaining || this.test.querying) ? this : this.test;
};

/**
 * Asserts that given alertText does exist in the provided alert/confirm or prompt dialog.
 *
 * ```html
 * <a href="#" id="alert" onclick="alert('I am an alert')">I make alerts!</a>
 * ```
 *
 * ```javascript
 *  test
 *    .open('http://skaaro.com/index.html')
 *    .click('#alert_confirm')
 *    .assert.dialogText('I am an alert')
 *    .accept()
 *    .done();
 * ```
 *
 * of course, text works also with the assertion helpers is() and not()
 *
 * ```javascript
 *  test
 *    .open('http://dalekjs.com/guineapig/')
 *    .assert.dialogText().is('I am an alert', 'Exterminate!')
 *    .done();
 * ```
 *
 * ```javascript
 *  test
 *    .open('http://dalekjs.com/guineapig/')
 *    .assert.dialogText().is.not('I am an prompt', 'Exterminate!')
 *    .done();
 * ```
 *
 *
 * > NOTE: Does not work in Firefox & PhantomJS
 *
 * @api
 * @method dialogText
 * @param {string} expected Expected testresult
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.dialogText = function (expected, message) {
  var hash = uuid();
  var cb = this._generateCallbackAssertion('alertText', 'alertText', this._testShallowEquals, hash, {expected: expected, message: message}).bind(this.test);
  this._addToActionQueue([expected, hash], 'alertText', cb);
  return (this.chaining || this.test.querying) ? this : this.test;
};

/**
 * Asserts that the page title is as expected.
 *
 * ```javascript
 *   test.open('http://doctorwhotv.co.uk/')
 *     .assert.title('Doctor Who TV', 'Not your Daleks TV')
 *     .done();
 * ```
 *
 * Yep, using assertion helpers is also possible:
 *
 * ```javascript
 *   test.open('http://doctorwhotv.co.uk/')
 *     .assert.title().is('Doctor Who TV', 'Not your Daleks TV')
 *     .done();
 * ```
 *
 * the not() helper is available too:
 *
 * ```javascript
 *   test.open('http://doctorwhotv.co.uk/')
 *     .assert.title().is.not('Dalek Emperor TV', 'Not your Daleks TV')
 *     .done();
 * ```
 *
 * and you can also match for a substring with to.contain() (but don't try to chain it with not() as this is not possible):
 *
 * ```javascript
 *   test.open('http://doctorwhotv.co.uk/')
 *     .assert.title().to.contain('Emperor')
 *     .done();
 * ```
 *
 * @api
 * @method title
 * @param {string} expected Expected test result
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.title = function (expected, message) {
  var hash = uuid();
  var cb = this._generateCallbackAssertion('title', 'title', this._testShallowEquals, hash, {expected: expected, message: message}).bind(this.test);
  this._addToActionQueue([expected, hash], 'title', cb);
  return this.chaining ? this : this.test;
};

/**
 * Asserts that given title does not match the given expectations.
 *
 * ```javascript
 *   test.open('http://doctorwhotv.co.uk/')
 *     .assert.doesntHaveTitle('Dalek Emperor TV', 'Not your Daleks TV')
 *     .done();
 * ```
 *
 * @api
 * @method doesntHaveTitle
 * @param {string} expected Expected test result
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.doesntHaveTitle = function (expected, message) {
  var hash = uuid();
  var cb = this._generateCallbackAssertion('title', '!title', this._testShallowUnequals, hash, {expected: expected, message: message}).bind(this.test);
  this._addToActionQueue([expected, hash], 'title', cb);
  return this.chaining ? this : this.test;
};

/**
* Asserts that screenshot is equal to already stored image.
* Should follow only after screenshot action
*
* ```javascript
*    test.open('http://google.com')
*      .wait(500)
*      .screenshot('test/screenshots/google.png','#lga')
*      .assert.screenshotIsEqualTo('test/screenshots/google_etalon.png', true, 'Google Doodles')
*      .done();
* ```
*
* @api
* @method doesntHaveTitle
* @param {string} expected Path to expected png image
* @param {boolean} do make diff image
* @param {string} message Message for the test reporter
* @chainable
*/
Assertions.prototype.screenshotIsEqualTo = function (expected, makediff, message) {
  if (this.test.screenshotParams) {
    var hash = uuid();

    if (typeof makediff === 'string') {
      message = makediff;
      makediff = true;
    } else if (typeof makediff === 'undefined') {
      makediff = true;
    }

    var cb = this._generateCallbackAssertion('imagecompare', 'compare with etalon', this._testImagecompare, hash, { expected: expected, message: message, comparisonOperator: 'Screenshot is equal to ' }).bind(this.test);
    this._addToActionQueue([this.test.screenshotParams, expected, makediff, hash], 'imagecompare', cb);
  } else {
    this.test.reporter.emit('error', 'Assert screenshotIsEqualTo can follow only after screenshot action!');
  }

  return this.chaining ? this : this.test;
};

/**
 * Asserts that the page’s url is as expected.
 *
 * ```javascript
 *   test.open('http://doctorwhotv.co.uk/')
 *     .assert.url('http://doctorwhotv.co.uk/', 'URL is as expected')
 *     .done();
 * ```
 *
 * You can also check if the protocol changed,
 * nice to see when you open GitHub with 'http' instead of 'https'
 *
 * ```javascript
 *   test.open('http://github.com')
 *     .assert.url('https://github.com/', 'Changed prototcols')
 *     .done();
 * ```
 *
 * Yep, using assertion helpers is also possible:
 *
 * ```javascript
 *   test.open('http://github.com')
 *     .assert.url().is('http://doctorwhotv.co.uk/', 'URL is as expected')
 *     .done();
 * ```
 *
 * the not() helper is available too:
 *
 * ```javascript
 *   test.open('http://doctorwhotv.co.uk/')
 *     .assert.url().is.not('http://doctorwhotv.co.uk/', 'URL is as expected')
 *     .done();
 * ```
 *
 * and you can also match for a substring with to.contain() (but don't try to chain it with not() as this is not possible):
 *
 * ```javascript
 *   test.open('http://doctorwhotv.co.uk/')
 *     .assert.url().to.contain('doctor')
 *     .done();
 * ```
 *
 * @api
 * @method url
 * @param {string} expected Expected test result
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.url = function (expected, message) {
  var hash = uuid();
  var cb = this._generateCallbackAssertion('url', 'url', this._testShallowEquals, hash, {expected: expected, message: message}).bind(this.test);
  this._addToActionQueue([expected, hash], 'url', cb);
  return this.chaining ? this : this.test;
};

/**
 * Asserts that the pages URL does not match the expectation.
 *
 * ```javascript
 *   test.open('http://doctorwhotv.co.uk/')
 *     .assert.doesntHaveUrl('http://doctorwhotv.co.uk/', 'URL is not expected')
 *     .done();
 * ```
 *
 * Oh, you might also match for a substring with to.contain():
 *
 *  * ```javascript
 *   test.open('http://doctorwhotv.co.uk/')
 *     .assert.doesntHaveUrl().to.contain('doctor')
 *     .done();
 * ```
 *
 * @api
 * @method doesntHaveUrl
 * @param {string} expected Expected test result
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.doesntHaveUrl = function (expected, message) {
  var hash = uuid();
  var cb = this._generateCallbackAssertion('url', '!url', this._testShallowUnequals, hash, {expected: expected, message: message}).bind(this.test);
  this._addToActionQueue([expected, hash], 'url', cb);
  return this.chaining ? this : this.test;
};

/**
 * Asserts that an elements attribute is as expected.
 *
 * ```html
 * <form>
 *   <button class="jumpButton" type="submit">Fire</button>
 * </form>
 * ```
 *
 * ```javascript
 *  test
 *    .open('http://dalekjs.com/guineapig/')
 *    .assert.attr('.jumpButton', 'type', 'submit')
 *    .done();
 * ```
 *
 * ```html
 * <div class="wellImUpperUpperClassHighSociety" id="dataDiv" data-spot="cat"></div>
 * ```
 *
 * ```javascript
 *  test
 *    .open('http://dalekjs.com/guineapig/')
 *    .assert.attr('#dataDiv').is('data-spot', 'cat', 'We found Dataʼs cat!')
 *    .done();
 * ```
 *
 * ```javascript
 *  test
 *    .open('http://dalekjs.com/guineapig/')
 *    .assert.attr('#dataDiv').is.not('data-spot', 'doc', 'Spot is not a dog!')
 *    .done();
 * ```
 *
 * You can also use attr() for checking if a class is existent
 *
 * ```javascript
 *  test
 *    .open('http://dalekjs.com/guineapig/')
 *    .assert.attr('#dataDiv', 'class', 'wellImUpperUpperClassHighSociety')
 *    .done();
 * ```
 *
 * and you can also match a substring (e. g. a single class if more classes are on that elem) with to.contain():
 *
 * ```javascript
 *  test
 *    .open('http://dalekjs.com/guineapig/')
 *    .assert.attr('#dataDiv', 'class').to.contain('upperUpperClass')
 *    .done();
 * ```
 *
 * @api
 * @method attr
 * @param {string} selector Selector that matches the elements to test
 * @param {string} attribute The attribute to test
 * @param {string} expected Expected test result
 * @param {string} message Message for the test reporter
 * @chainable
 */

Assertions.prototype.attr = function (selector, attribute, expected, message) {
  var hash = uuid();

  if (this.test.querying === true) {
    message = expected;
    expected = attribute;
    attribute = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('attribute', 'attribute', this._testShallowEquals, hash, {expected: expected, message: message, selector: selector, attribute: attribute}).bind(this.test);
  this._addToActionQueue([selector, attribute, expected, hash], 'attribute', cb);
  return this.chaining ? this : this.test;
};


/**
* Asserts that an element contains class.
*
* ```html
* <form>
*   <button class="plain-btn action submit-product" type="submit">Fire</button>
* </form>
* ```
*
* ```javascript
*  test
*    .open('http://dalekjs.com/index.html')
*    .assert.hasClass('.grid__item.one-whole.info-box', 'info-box', 'div has info-box class')
*    .done();
* ```
*
* @api
* @method attr
* @param {string} selector Selector that matches the elements to test
* @param {string} expected Expected test result
* @param {string} message Message for the test reporter
* @chainable
*/

Assertions.prototype.hasClass = function (selector, expected, message) {
  var hash = uuid();
  var attribute = 'class';

  if (this.test.querying === true) {
    message = expected;
    expected = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('attribute', 'hasClass', this._containsItem, hash, {expected: expected, message: message, selector: selector, attribute: attribute}).bind(this.test);
  this._addToActionQueue([selector, attribute, expected, hash], 'attribute', cb);
  return this.chaining ? this : this.test;
};


/**
* Asserts that element doesn't contain class.
*
* ```html
* <form>
*   <button class="plain-btn action submit-product" type="submit">Fire</button>
* </form>
* ```
*
* ```javascript
*  test
*    .open('http://dalekjs.com/index.html')
*    .assert.doesntHaveClass('.grid__item.one-whole.info-box', 'info', 'div doesn\'t have info class')
*    .done();
* ```
*
* @api
* @method attr
* @param {string} selector Selector that matches the elements to test
* @param {string} expected Expected test result
* @param {string} message Message for the test reporter
* @chainable
*/

Assertions.prototype.doesntHaveClass = function (selector, expected, message) {
  var hash = uuid();
  var attribute = 'class';

  if (this.test.querying === true) {
    message = expected;
    expected = selector;
    selector = this.test.selector;
  }

  var cb = this._generateCallbackAssertion('attribute', '!hasClass', this._doesntContainItem, hash, {expected: expected, message: message, selector: selector, attribute: attribute}).bind(this.test);
  this._addToActionQueue([selector, attribute, expected, hash], 'attribute', cb);
  return this.chaining ? this : this.test;
};

/**
Assert result of the execution of JavaScript function within the browser context.

  test
    .open('http://dalekjs.com/index.html')
    .assert.evaluate(function () {
      return document.getElementsByClassName('grid').length;
    }).is(2, 'Count of grid on page is equal 2')
    .done();

* > Note: Buggy in Firefox
*
* @api
* @method execute
* @param {function} script JavaScript function that should be executed
* @return chainable
*/

Assertions.prototype.evaluate = function (script) {
  var hash = uuid();
  var args = [this.contextVars].concat(Array.prototype.slice.call(arguments, 1) || []);

  var cb = this._generateCallbackAssertion('evaluate', 'evaluate', this._testTruthy, hash, {script: script, args: args, has:hash}).bind(this.test);
  this._addToActionQueue([script, args, hash], 'evaluate', cb);
  return this.chaining ? this : this.test;
};


// TEST HELPER
// -----------

/**
 * Is helper
 *
 * @method is
 * @param {mixed} expected Value to check
 * @param {string} message Test message
 * @chainable
 */

Assertions.prototype.is = function (expected, message) {
  return this.generateTestHelper('is', '_testShallowEquals', false)(expected, message);
};

/**
 * Not helper
 *
 * @method not
 * @param {mixed} expected Value to check
 * @param {string} message Test message
 * @chainable
 */

Assertions.prototype.not = function (expected, message) {
  return this.generateTestHelper('not', '_testShallowEquals', true)(expected, message);
};

/**
 * Between helper
 *
 * @method between
 * @param {mixed} expected Value to check
 * @param {string} message Test message
 * @chainable
 */

Assertions.prototype.between = function (expected, message) {
  return this.generateTestHelper('between', '_testBetween', false)(expected, message);
};

/**
 * Gt helper
 *
 * @method gt
 * @param {mixed} expected Value to check
 * @param {string} message Test message
 * @chainable
 */

Assertions.prototype.gt = function (expected, message) {
  return this.generateTestHelper('gt', '_testGreaterThan', false)(expected, message);
};

/**
 * Gte helper
 *
 * @method gte
 * @param {mixed} expected Value to check
 * @param {string} message Test message
 * @chainable
 */

Assertions.prototype.gte = function (expected, message) {
  return this.generateTestHelper('gte', '_testGreaterThanEqual', false)(expected, message);
};

/**
 * Lt helper
 *
 * @method lt
 * @param {mixed} expected Value to check
 * @param {string} message Test message
 * @chainable
 */

Assertions.prototype.lt = function (expected, message) {
  return this.generateTestHelper('lt', '_testLowerThan', false)(expected, message);
};

/**
 * Lte helper
 *
 * @method lte
 * @param {mixed} expected Value to check
 * @param {string} message Test message
 * @chainable
 */

Assertions.prototype.lte = function (expected, message) {
  return this.generateTestHelper('lte', '_testLowerThanEqual', false)(expected, message);
};

/**
* Assert if a given value contians a second given value
*
* @method _containsItem
* @param {mixed} a Value to test
* @param {mixed} b Value to test
* @return {bool} false if values doesn't contain, true if contains
* @private
*/

Assertions.prototype._containsItem = function (a, b) {
  a = a || '';
  var index = a.split(' ').indexOf(b);

  try {
    chai.expect(index).to.be.above(-1);
  } catch (e) {
    return false;
  }

  return true;
};

/**
* Assert if a given value doesn't contian a second given value
*
* @method _containsItem
* @param {mixed} a Value to test
* @param {mixed} b Value to test
* @return {bool} false if values contains, true if don't contain
* @private
*/
Assertions.prototype._doesntContainItem = function (a, b) {
  a = a || '';
  var index = a.split(' ').indexOf(b);
  try {
    chai.assert.equal(index, -1);
  } catch (e) {
    return false;
  }

  return true;
};

/**
 * Contain helper
 *
 * @method contain
 * @param {mixed} expected Value to check
 * @param {string} message Test message
 * @chainable
 */

Assertions.prototype.contain = function (expected, message) {
  return this.generateTestHelper('contain', '_contain', false)(expected, message);
};

/**
 * Not contain helper
 *
 * @method notContain
 * @param {mixed} expected Value to check
 * @param {string} message Test message
 * @chainable
 */

Assertions.prototype.notContain = function (expected, message) {
  return this.generateTestHelper('notContain', '_notContain', false)(expected, message);
};

/**
 * Match helper
 *
 * @method match
 * @param {string} expected Regex to match on
 * @param {string} message Test message
 * @chainable
 */

Assertions.prototype.match = function (expected, message) {
  return this.generateTestHelper('match', '_match', false)(expected, message);
};

/**
 * Equals case insensitive helper
 *
 * @method equalsCaseInsensitive
 * @param {mixed} expected Value to check
 * @param {string} message Test message
 * @chainable
 */

Assertions.prototype.equalsCaseInsensitive = function (expected, message) {
  return this.generateTestHelper('equalsCaseInsensitive', '_caseInsensitiveMatch', false)(expected, message);
};

// HELPER METHODS
// --------------

/**
 * Generates a callback that will be fired when the action has been completed.
 * The callback itself will then validate the answer and will also emit an event
 * that the action has been successfully executed.
 *
 * @method _generateCallbackAssertion
 * @param {string} key Unique key of the action
 * @param {string} type Type of the action (usually the actions name)
 * @param {string} test test method to be used
 * @param {string} hash the uuid
 * @param {object} opts the options object
 * @return {function} The generated callback function
 * @private
 */

Assertions.prototype._generateCallbackAssertion = function (key, type, test, hash, opts) {
  var cb = function (data) {
    if (data && data.key === key && data.hash === hash) {

      this._lastGeneratedAction = {key: key, type: type, test: test, hash: hash, opts: opts, data: data};

      var chainingKeys = ['title', 'width', 'height', 'url', 'text' , 'attribute', 'numberOfElements', 'numberOfVisibleElements', 'evaluate'];
      if (!opts.expected && chainingKeys.indexOf(key) > -1) {
        return false;
      }

      if (typeof opts.expected === 'function') {
        opts.expected = opts.expected();
      }

      var testResult = test(data.value, opts.expected, opts.parseFloatOnValues);
      this.reporter.emit('report:assertion', {
        success: testResult,
        expected: opts.comparisonOperator ? opts.comparisonOperator + opts.expected : opts.expected,
        value: data.value,
        message: opts.message,
        type: type,
        selector: data.selector
      });

      this.incrementExpectations();
      if (!testResult) {
        this.incrementFailedAssertions();
      }
    }
  };
  return cb;
};

/**
 * Adds a method to the queue of actions/assertions to execute
 *
 * @method _addToActionQueue
 * @param {object} opts Options of the action to invoke
 * @param {string} driverMethod Name of the method to call on the driver
 * @param {function} A callback function that will be executed when the action has been executed
 * @private
 * @chainable
 */

Assertions.prototype._addToActionQueue = function (opts, driverMethod, cb) {
  this._lastGeneratedShit = {opts: opts, driverMethod: driverMethod};
  this.test.actionPromiseQueue.push(function () {
    var deferredAction = Q.defer();
    this.test.driver[driverMethod].apply(this.test.driver, opts);
    deferredAction.resolve();
    this.test.driver.events.on('driver:message', cb);
    return deferredAction.promise;
  }.bind(this));
  return this;
};

/**
 * Generates a function that can be used
 *
 * @method generateTestHelper
 * @param name
 * @param assertionFn
 * @param negate
 * @return
 * @private
 */

Assertions.prototype.generateTestHelper = function (name, assertionFn, negate) {
  return function (expected, message) {
    var gen = this._lastGeneratedShit;

    this.test.actionPromiseQueue.push(function () {
      var deferredAction = Q.defer();
      deferredAction.resolve();
      this.test.driver.events.on('driver:message', function () {

        if (gen.opts && gen.opts[(gen.opts.length - 1)] && this.test._lastGeneratedAction && this.test._lastGeneratedAction.hash) {
          if (gen.opts[(gen.opts.length - 1)] === this.test._lastGeneratedAction.hash && !this.proceeded[this.test._lastGeneratedAction.hash + name]) {
            var testResult = this[assertionFn](expected, this.test._lastGeneratedAction.data.value);

            if (negate) {
              testResult = !testResult;
            }

            this.proceeded[this.test._lastGeneratedAction.hash + name] = true;

            this.test.reporter.emit('report:assertion', {
              success: testResult,
              expected: expected,
              value: this.test._lastGeneratedAction.data.value,
              message: message,
              type: this.test._lastGeneratedAction.type
            });

            this.test.incrementExpectations();

            if (!testResult) {
              this.test.incrementFailedAssertions();
            }
          }
        }
      }.bind(this));
      return deferredAction.promise;
    }.bind(this));

    return this.chaining ? this : this.test;
  }.bind(this);
};

// ASSERT METHODS
// --------------

/**
 * Assert if a given value shallow equals a second given value
 *
 * @method _testShallowEquals
 * @param {mixed} a Value to test
 * @param {mixed} b Value to test
 * @return {bool} false if values donʼt match, true if they match
 * @private
 */

Assertions.prototype._testShallowEquals = function (a, b) {
  try {
    chai.assert.equal(a, b);
  } catch (e) {
    return false;
  }

  return true;
};

/**
 * Assert if a given value shallow does not equal a second given value
 *
 * @method _testShallowUnequals
 * @param {mixed} a Value to test
 * @param {mixed} b Value to test
 * @return {bool} true if values donʼt match, false if they match
 * @private
 */

Assertions.prototype._testShallowUnequals = function (a, b) {
  try {
    chai.assert.notEqual(a, b);
  } catch (e) {
    return false;
  }

  return true;
};

/**
 * Assert if a given value matches a range
 *
 * @method _testBetween
 * @param {array} a Range to test
 * @param {bool} b Value to compare
 * @return {bool} test result
 * @private
 */

Assertions.prototype._testBetween = function (a, b) {
  try {
    chai.expect(b).to.be.within(a[0], a[1]);
  } catch (e) {
    return false;
  }

  return true;
};

/**
 * Assert if a given value is greater than the value to compare
 *
 * @method _testGreaterThan
 * @param {bool} a Value to test
 * @param {bool} b Value to compare
 * @param {parseFloatOnValues} b Whether to apply parseFloat to both values prior comparision
 * @return {bool} test result
 * @private
 */

Assertions.prototype._testGreaterThan = function (a, b, parseFloatOnValues) {
  if (parseFloatOnValues) {
    a = parseFloat(a);
    b = parseFloat(b);
  }

  try {
    chai.expect(b).to.be.above(a);
  } catch (e) {
    return false;
  }

  return true;
};

/**
 * Assert if a given value is greater or equal than the value to compare
 *
 * @method _testGreaterThanEqual
 * @param {bool} a Value to test
 * @param {bool} b Value to compare
 * @return {bool} test result
 * @private
 */

Assertions.prototype._testGreaterThanEqual = function (a, b) {
  return this._testGreaterThan(a - 1, b);
};

/**
 * Assert if a given value is lower than the value to compare
 *
 * @method _testLowerThan
 * @param {bool} a Value to test
 * @param {bool} b Value to compare
 * @param {parseFloatOnValues} b Whether to apply parseFloatOnValues to both values prior comparision
 * @return {bool} test result
 * @private
 */

Assertions.prototype._testLowerThan = function (a, b, parseFloatOnValues) {
  if (parseFloatOnValues) {
    a = parseFloat(a);
    b = parseFloat(b);
  }

  try {
    chai.expect(b).to.be.below(a);
  } catch (e) {
    return false;
  }

  return true;
};

/**
 * Asserts that 2 string match regardless of case
 *
 * @method _caseInsensitiveMatch
 * @param {string} a Value to test
 * @param {string} b Value to compare
 * @return {bool} testresult
 * @private
 */

Assertions.prototype._caseInsensitiveMatch = function (a, b) {
  try {
    if(a.toLowerCase && b.toLowerCase) {
      chai.expect(b.toLowerCase()).to.eql(a.toLowerCase());
    } else {
      return false;
    }
  } catch (e) {
    return false;
  }

  return true;
};

/**
 * Assert if a given value contain another value
 *
 * @method _contain
 * @param {bool} a Value to test
 * @param {bool} b Value to compare
 * @return {bool} test result
 * @private
 */

Assertions.prototype._contain = function (a, b) {
  try {
    chai.expect(b).to.include(a);
  } catch (e) {
    return false;
  }

  return true;
};

/**
 * Assert if a given value doesn't contain another value
 *
 * @method _notContain
 * @param {bool} a Value to test
 * @param {bool} b Value to compare
 * @return {bool} test result
 * @private
 */
Assertions.prototype._notContain = function (a, b) {
  try {
    chai.expect(b).to.not.include(a);
  } catch (e) {
    return false;
  }

  return true;
};

/**
 * Assert if a given value is lower or equal than the value to compare
 *
 * @method _testLowerThanEqual
 * @param {bool} a Value to test
 * @param {bool} b Value to compare
 * @return {bool} test result
 * @private
 */

Assertions.prototype._testLowerThanEqual = function (a, b) {
  return this._testLowerThan(a + 1, b);
};

/**
 * Assert if a given value is boolean 'true'
 *
 * @method _testTruthy
 * @param {bool} a Value to test
 * @return {bool} false if value is false, true if value is true
 * @private
 */

Assertions.prototype._testTruthy = function (a) {
  return a === 'true' || a === true;
};

/**
 * Assert if a given value is boolean 'false'
 *
 * @method _testFalsy
 * @param {bool} a Value to test
 * @return {bool} true if value is false, false if value is true
 * @private
 */

Assertions.prototype._testFalsy = function (a) {
  return a === 'false' || a === false;
};

/**
 * Assert a given value matches a RegEx
 *
 * @method _contain
 * @param {mixed} a Value to test
 * @param {string} b Value to compare
 * @return {bool} test result
 * @private
 */

Assertions.prototype._match = function (a, b) {
  try {
    chai.expect(b).to.match(a);
  } catch (e) {
    return false;
  }

  return true;
};


/**
 * Assert if a image compare result is equal
 *
 * @method _testImagecompare
 * @param {string} a Value to test if it equal to 'equal'
 * @return {bool} true if value is 'equal', false if value has some other values
 * @private
 */

Assertions.prototype._testImagecompare = function (a) {
  return a === 'equal';
};