Repository: nightwatchjs/nightwatch
Pull request #2958 (2021-11-25 07:57:11)

feat: new assertions
fixes: https://github.com/nightwatchjs/nightwatch/issues/3002

List of New assertions;

- [x] attributeMatches.js
- [x] domPropertyMatches.js
- [x] elementsCount.js
- [x] hasAttribute.js
- [x] hasClass.js
- [ ] ~~textEquals.js (Harshit already picked up)~~
- [x] textMatches.js
- [x] titleEquals.js
- [x] titleMatches.js
- [x] urlMatches.js
- [x] valueEquals.js




Patch:
diff --git a/.gitignore b/.gitignore
index 6d6e88ee..1da2f2f7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,8 @@
 .DS_Store
 *.idea
 *.vscode
-/*.log
+*.log
+*.env
 /nightwatch.json
 /nightwatch.conf.js
 node_modules
@@ -23,5 +24,4 @@ output
 screenshot.png
 /sample
 /screens
-/logs
-
+/logs
\ No newline at end of file
diff --git a/lib/api/assertions/_attributeMatches.js b/lib/api/assertions/_attributeMatches.js
deleted file mode 100644
index e938105d..00000000
--- a/lib/api/assertions/_attributeMatches.js
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * Check if an elements attribute value matches a regex
- *
- * See also: assert.containsText
- *
- */
-exports.assertion = function() {
-
-};
diff --git a/lib/api/assertions/_domPropertyMatches.js b/lib/api/assertions/_domPropertyMatches.js
deleted file mode 100644
index e69de29b..00000000
diff --git a/lib/api/assertions/_elementsCount.js b/lib/api/assertions/_elementsCount.js
deleted file mode 100644
index a54cb5ec..00000000
--- a/lib/api/assertions/_elementsCount.js
+++ /dev/null
@@ -1,1 +0,0 @@
-// same as expect.elements().count.toEqual(1)
\ No newline at end of file
diff --git a/lib/api/assertions/_hasAttribute.js b/lib/api/assertions/_hasAttribute.js
deleted file mode 100644
index f02a4748..00000000
--- a/lib/api/assertions/_hasAttribute.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * Checks if the given element contains the specified DOM attribute.
- *
- * Equivalent of: https://developer.mozilla.org/en-US/docs/Web/API/Element/hasAttribute
- */
-exports.assertion = function() {
-
-};
\ No newline at end of file
diff --git a/lib/api/assertions/_hasClass.js b/lib/api/assertions/_hasClass.js
deleted file mode 100644
index 0f98ee07..00000000
--- a/lib/api/assertions/_hasClass.js
+++ /dev/null
@@ -1,3 +0,0 @@
-/**
- * Checks if the given element has the specified CSS class. This will become cssClassPresent, which will become an alias and be deprecated.
- */
\ No newline at end of file
diff --git a/lib/api/assertions/_textMatches.js b/lib/api/assertions/_textMatches.js
deleted file mode 100644
index d0c577aa..00000000
--- a/lib/api/assertions/_textMatches.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * Check if an elements inner text matches a regex
- *
- * Implementation details: use regexp.test(), not .match()
- */
-exports.assertion = function() {
-
-};
diff --git a/lib/api/assertions/_titleEquals.js b/lib/api/assertions/_titleEquals.js
deleted file mode 100644
index 3e7436f5..00000000
--- a/lib/api/assertions/_titleEquals.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/**
- * The .assert.title() command, which will become an alias of this and will be deprecated
- *
- */
-exports.assertion = function(expected, msg) {
-
-};
diff --git a/lib/api/assertions/_titleMatches.js b/lib/api/assertions/_titleMatches.js
deleted file mode 100644
index 71801b5c..00000000
--- a/lib/api/assertions/_titleMatches.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * Checks if the current title matches a regular expression.
- *
- * Implementation details: use regexp.test(), not .match()
- */
-exports.assertion = function() {
-
-};
diff --git a/lib/api/assertions/_urlMatches.js b/lib/api/assertions/_urlMatches.js
deleted file mode 100644
index 271dc0e4..00000000
--- a/lib/api/assertions/_urlMatches.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * Checks if the current url matches a regular expression.
- *
- * Implementation details: use regexp.test(), not .match()
- */
-exports.assertion = function() {
-
-};
\ No newline at end of file
diff --git a/lib/api/assertions/_valueEquals.js b/lib/api/assertions/_valueEquals.js
deleted file mode 100644
index 2f87cfb4..00000000
--- a/lib/api/assertions/_valueEquals.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/**
- * The .assert.value() command, which will become an alias of this and will be deprecated
- *
- */
-exports.assertion = function() {
-
-};
diff --git a/lib/api/assertions/attributeMatches.js b/lib/api/assertions/attributeMatches.js
new file mode 100644
index 00000000..93815ad8
--- /dev/null
+++ b/lib/api/assertions/attributeMatches.js
@@ -0,0 +1,54 @@
+/**
+ * Check if an elements attribute value matches a regex
+ *
+ * @example
+ * 
+ * ```
+ *    this.demoTest = function (browser) {
+ *      browser.assert.attributeMatches('body', 'data-attr', '(value)');
+ *    };
+ * ```
+ *
+ * @method attributeMatches
+ * @param {string|object} definition The selector (CSS/Xpath) used to locate the element. Can either be a string or an object which specifies [element properties](https://nightwatchjs.org/guide#element-properties).
+ * @param {string} attribute The attribute name
+ * @param {string} regexExpression Regex expression to match attribute value.
+ * @param {string} [msg] Optional log message to display in the output. If missing, one is displayed by default.
+ * @api assertions
+ */
+const {setElementSelectorProps} = require('../../utils');
+
+exports.assertion = function(definition, attribute, regexExpression, msg) {
+  this.options = {
+    elementSelector: true
+  };
+
+  this.expected = function() {
+    return this.negate ? `does not matches '${regexExpression}'` : `matches '${regexExpression}'`;
+  };
+
+  this.formatMessage = function() {
+    const message = msg || `Testing if attribute %s of element %s ${this.negate ? 'doesn\'t matches %s' : 'matches %s'}`;
+
+    return {
+      message,
+      args: [`'${attribute}'`, this.elementSelector, `'${regexExpression}'`]
+    };
+  };
+
+  this.evaluate = function(value) {
+    const regex = new RegExp(regexExpression);
+
+    return regex.test(value);
+  };
+
+  this.value = function(result = {}) {
+    return result.value || '';
+  };
+
+  this.command = function(callback) {
+    this.api.getAttribute(setElementSelectorProps(definition, {
+      suppressNotFoundErrors: true
+    }), attribute, callback);
+  };
+};
diff --git a/lib/api/assertions/domPropertyContains.js b/lib/api/assertions/domPropertyContains.js
index 213c0384..915fbf38 100644
--- a/lib/api/assertions/domPropertyContains.js
+++ b/lib/api/assertions/domPropertyContains.js
@@ -48,9 +48,7 @@ exports.assertion = function(definition, domProperty, expected, msg) {
 
   this.evaluate = function(value) {
     if (Array.isArray(value) && expected) {
-      if (Array.isArray(value) && expected) {
-        return containsMultiple(value, expected);
-      }
+      return containsMultiple(value, expected);
     }
 
     value = value || '';
diff --git a/lib/api/assertions/domPropertyMatches.js b/lib/api/assertions/domPropertyMatches.js
new file mode 100644
index 00000000..b150f970
--- /dev/null
+++ b/lib/api/assertions/domPropertyMatches.js
@@ -0,0 +1,61 @@
+/**
+ * Check if specified DOM property value of a given element matches a regex. For all the available DOM element properties, consult the [Element doc at MDN](https://developer.mozilla.org/en-US/docs/Web/API/element).
+ * 
+ * 
+ * @example
+ * 
+ * ```
+ *    this.demoTest = function (browser) {
+ *      browser.assert.domPropertyMatches('#main', 'tagName', '(frame)');
+ *
+ * ```
+ * 
+ * @method domPropertyMatches
+ * @param {string|object} definition The selector (CSS/Xpath) used to locate the element. Can either be a string or an object which specifies [element properties](https://nightwatchjs.org/guide#element-properties).
+ * @param {string} domProperty The DOM property name.
+ * @param {string} regexExpression TRegex expression to match text.
+ * @param {string} [msg] Optional log message to display in the output. If missing, one is displayed by default.
+ * @api assertions
+ */
+
+const {setElementSelectorProps} = require('../../utils');
+
+exports.assertion = function (definition, domProperty, regexExpression, msg) {
+  this.options = {
+    elementSelector: true
+  };
+
+  this.expected = function() {
+    return this.negate ? `does not matches '${regexExpression}'` : `matches '${regexExpression}'`;
+  };
+
+
+  this.formatMessage = function() {
+    const message = msg || `Testing if dom property %s of element %s ${this.negate ? 'doesn\'t matches %s' : 'matches %s'}`;
+
+    return {
+      message,
+      args: [`'${domProperty}'`, this.elementSelector, `'${regexExpression}'`]
+    };
+  };
+
+  this.evaluate = function (value) { 
+    const regex = new RegExp(regexExpression);
+
+    if (!Array.isArray(value)) {
+      return regex.test(value);
+    } 
+
+    return false;
+  }; 
+
+  this.value = function(result = {}) {
+    return result.value || '';
+  };
+
+  this.command = function(callback) {
+    this.api.getElementProperty(setElementSelectorProps(definition, {
+      suppressNotFoundErrors: true
+    }), domProperty, callback);
+  };
+};
diff --git a/lib/api/assertions/elementsCount.js b/lib/api/assertions/elementsCount.js
new file mode 100644
index 00000000..153cb9e4
--- /dev/null
+++ b/lib/api/assertions/elementsCount.js
@@ -0,0 +1,64 @@
+/**
+ * Checks if the number of elements specified by a selector is equal to a given value.
+ * 
+ * @example
+ * 
+ * this.demoTest = function (browser) {
+ *   browser.assert.elementsCount('div', 10);
+ *   browser.assert.not.elementsCount('div', 10);
+ * }
+ * 
+ * @method elementsCount
+ * @param {string|object} definition The selector (CSS/Xpath) used to locate the element. Can either be a string or an object which specifies [element properties](https://nightwatchjs.org/guide#element-properties).
+ * @param {string} count expected number of elements to be present.
+ * @param {string} [msg] Optional log message to display in the output. If missing, one is displayed by default.
+ * @api assertions
+ */
+
+const Element = require('../../element');
+
+exports.assertion = function (definition, count, msg){  
+  this.options = {
+    elementSelector: true
+  };
+
+  this.expected = function() {
+    return this.negate ? `does not counts '${count}'` : `counts '${count}'`;
+  };
+
+  this.formatMessage = function() {
+    const message = msg || `Testing if the Element ${this.negate ? 'doesn\'t counts %s' : 'counts %s'}`;
+
+    return {
+      message,
+      args: [this.elementSelector, `'${count}'`]
+    };
+  };
+
+  this.evaluate = function(value) {
+    return value === count;
+  };
+
+  this.value = function(result = {}) {
+    if (!result || !result.value) {
+      return '';
+    }
+
+    return result.value.length;
+    
+  };
+
+  this.createElement = function(selector, using = this.client.locateStrategy) {
+    this.element = Element.createFromSelector(selector, using);
+
+    return this;
+  };
+
+  this.command = async function(callback) {
+    this.createElement(definition);
+
+    const {element} = this;
+
+    await this.api.findElements(element, callback);
+  };
+};
diff --git a/lib/api/assertions/hasAttribute.js b/lib/api/assertions/hasAttribute.js
new file mode 100644
index 00000000..802c9e34
--- /dev/null
+++ b/lib/api/assertions/hasAttribute.js
@@ -0,0 +1,66 @@
+
+/**
+ * Checks if the given element contains the specified DOM attribute.
+ *
+ * Equivalent of: https://developer.mozilla.org/en-US/docs/Web/API/Element/hasAttribute
+ * 
+ * @example
+ * 
+ * ```
+ *    this.demoTest = function (browser) {
+ *      browser.assert.hasAttribute('#main', 'data-track');
+ *    };
+ * ```
+ * 
+ * @method hasAttribute
+ * @param {string|object} definition The selector (CSS/Xpath) used to locate the element. Can either be a string or an object which specifies [element properties](https://nightwatchjs.org/guide#element-properties).
+ * @param {string} expectedAttribute The DOM attribute to look for.
+ * @param {string} [msg] Optional log message to display in the output. If missing, one is displayed by default.
+ * @api assertions
+ */
+
+const {setElementSelectorProps, containsMultiple} = require('../../utils');
+
+exports.assertion = function(definition, expectedAttribute, msg) {
+  this.options = {
+    elementSelector: true
+  };
+
+  this.expected = function() {
+    return this.negate ? `has not ${expectedAttribute}` : `has ${expectedAttribute}`;
+  };
+ 
+
+  this.formatMessage = function() {
+    let message = msg || `Testing if element %s ${this.negate ? 'doesn\'t have attribute %s' : 'has attribute %s'}`;
+ 
+    return {
+      message,
+      args: [this.elementSelector, `'${Array.isArray(expectedAttribute) ? expectedAttribute.join(' ') : expectedAttribute}'`]
+    };
+  };
+
+  this.evaluate = function() {
+    if (!this.attributeList) {
+      return false;
+    }
+ 
+    return containsMultiple(this.attributeList, expectedAttribute, ' ');
+  };
+
+  this.value = function(result) {
+    if (!result || !result.value) {
+      return '';
+    }
+
+    this.attributeList = result.value.map(attribute =>  attribute.name);
+
+    return this.attributeList;
+  };
+
+  this.command = function(callback) {
+    this.api.getAttribute(setElementSelectorProps(definition, {
+      suppressNotFoundErrors: true
+    }), 'attributes', callback);
+  };
+};
diff --git a/lib/api/assertions/hasClass.js b/lib/api/assertions/hasClass.js
new file mode 100644
index 00000000..e6a5e9d3
--- /dev/null
+++ b/lib/api/assertions/hasClass.js
@@ -0,0 +1,71 @@
+/**
+ * Checks if the given element has the specified CSS class. This will become cssClassPresent, which will become an alias and be deprecated.
+ * 
+ * @example
+ * 
+ *
+ * ```
+ *    this.demoTest = function (browser) {
+ *      browser.assert.hasClass('#main', 'container');
+ *      browser.assert.hasClass('#main', ['visible', 'container']);
+ *      browser.assert.hasClass('#main', 'visible container');
+ *    };
+ * ```
+ *
+ * @method hasClass
+ * @param {string|object} definition The selector (CSS/Xpath) used to locate the element. Can either be a string or an object which specifies [element properties](https://nightwatchjs.org/guide#element-properties).
+ * @param {string} className The CSS class to look for.
+ * @param {string} [msg] Optional log message to display in the output. If missing, one is displayed by default.
+ * @api assertions
+ */
+
+const classListRegexp = /\s/;
+const classNameRegexp = /\w/;
+const {containsMultiple, setElementSelectorProps} = require('../../utils');
+ 
+exports.assertion = function(definition, expected, msg) {
+  this.options = {
+    elementSelector: true
+  };
+
+  this.expected = function() {
+    return this.negate ? `has not ${expected}` : `has ${expected}`;
+  };
+ 
+  this.formatMessage = function() {
+    let message = msg || `Testing if element %s ${this.negate ? 'doesn\'t have css class %s' : 'has css class %s'}`;
+ 
+    return {
+      message,
+      args: [this.elementSelector, `'${Array.isArray(expected) ? expected.join(' ') : expected}'`]
+    };
+  };
+ 
+ 
+  this.evaluate = function() {
+    if (!this.classList) {
+      return false;
+    }
+ 
+    return containsMultiple(this.classList, expected, ' ');
+  };
+ 
+  this.value = function(result) {
+    if (!result || !result.value) {
+      return '';
+    }
+ 
+    this.classList = result.value
+      .split(classListRegexp)
+      .filter(item => classNameRegexp.test(item));
+ 
+    return result.value;
+  };
+ 
+  this.command = function(callback) {
+    this.api.getAttribute(setElementSelectorProps(definition, {
+      suppressNotFoundErrors: true
+    }), 'class', callback);
+  };
+};
+ 
\ No newline at end of file
diff --git a/lib/api/assertions/textMatches.js b/lib/api/assertions/textMatches.js
new file mode 100644
index 00000000..35944563
--- /dev/null
+++ b/lib/api/assertions/textMatches.js
@@ -0,0 +1,54 @@
+/**
+ * Check if an elements inner text matches a regex
+ *
+ * @example
+ * 
+ * ```
+ *   this.demoTest = function (browser) {
+ *     browser.assert.textMatches('#main', '^Nightwatch');
+ *   };
+ * ```
+ * 
+ * @method textMatches
+ * @param {string|object} definition The selector (CSS/Xpath) used to locate the element. Can either be a string or an object which specifies [element properties](https://nightwatchjs.org/guide#element-properties).
+ * @param {string} regexExpression Regex expression to match text.
+ * @param {string} [msg] Optional log message to display in the output. If missing, one is displayed by default.
+ * @api assertions
+ */
+
+const {setElementSelectorProps} = require('../../utils');
+
+exports.assertion = function(definition, regexExpression, msg) {
+  this.options = {
+    elementSelector: true
+  };
+
+  this.expected = function() {
+    return this.negate ? `does not matches '${regexExpression}'` : `matches '${regexExpression}'`;
+  };
+
+  this.formatMessage = function() {
+    const message = msg || `Testing if the text ${this.negate ? 'doesn\'t matches %s' : 'matches %s'}`;
+
+    return {
+      message,
+      args: [this.elementSelector, `'${regexExpression}'`]
+    };
+  };
+
+  this.evaluate = function(value) {
+    const regex = new RegExp(regexExpression);
+
+    return regex.test(value);
+  };
+
+  this.value = function(result = {}) {
+    return result.value || '';
+  };
+
+  this.command = function(callback) {
+    this.api.getText(setElementSelectorProps(definition, {
+      suppressNotFoundErrors: true
+    }), callback);
+  };
+};
diff --git a/lib/api/assertions/titleEquals.js b/lib/api/assertions/titleEquals.js
new file mode 100644
index 00000000..bdadf83d
--- /dev/null
+++ b/lib/api/assertions/titleEquals.js
@@ -0,0 +1,42 @@
+/**
+ * The .assert.title() command, which will become an alias of this and will be deprecated
+ * 
+ * @example
+ * 
+ * ```
+ *    this.demoTest = function (client) {
+ *      browser.assert.titleEquals('https://www.google.com');
+ *    };
+ * ```
+ *
+ * @method titleEquals
+ * @param {string} expected The expect page title
+ * @param {string} [msg] Optional log message to display in the output. If missing, one is displayed by default.
+ * @api assertions
+ */
+exports.assertion = function(expected, msg) {
+  this.expected = function() {
+    return this.negate ? `is not '${expected}'` : `is '${expected}'`;
+  };
+
+  this.formatMessage = function() {
+    const message = msg || `Testing if the page title ${this.negate ? 'doesn\'t equal %s' : 'equals %s'}`;
+
+    return {
+      message,
+      args: [`'${expected}'`]
+    };
+  };
+
+  this.evaluate = function(value) {
+    return value === expected;
+  };
+
+  this.value = function(result = {}) {
+    return result.value || '';
+  };
+
+  this.command = function(callback) {
+    this.api.title(callback);
+  };
+};
diff --git a/lib/api/assertions/titleMatches.js b/lib/api/assertions/titleMatches.js
new file mode 100644
index 00000000..638be66e
--- /dev/null
+++ b/lib/api/assertions/titleMatches.js
@@ -0,0 +1,44 @@
+/**
+ * Checks if the current title matches a regular expression.
+ *
+ * @example
+ * 
+ * ```
+ *    this.demoTest = function (client) {
+ *      browser.assert.titleMatches('^Nightwatch');
+ *    };
+ * ```
+ * 
+ * @method titleMatches
+ * @param {string} regexExpression Regex expression to match current title of a page
+ * @param {string} [msg] Optional log message to display in the output. If missing, one is displayed by default.
+ * @api assertions
+ */
+exports.assertion = function(regexExpression, msg) {
+  this.expected = function() {
+    return this.negate ? `does not matches '${regexExpression}'` : `matches '${regexExpression}'`;
+  };
+
+  this.formatMessage = function() {
+    const message = msg || `Testing if the page title ${this.negate ? 'doesn\'t matches %s' : 'matches %s'}`;
+
+    return {
+      message,
+      args: [`'${regexExpression}'`]
+    };
+  };
+
+  this.evaluate = function(value) {
+    const regex = new RegExp(regexExpression);
+
+    return regex.test(value);
+  };
+
+  this.value = function(result = {}) {
+    return result.value || '';
+  };
+
+  this.command = function(callback) {
+    this.api.title(callback);
+  };
+};
diff --git a/lib/api/assertions/urlMatches.js b/lib/api/assertions/urlMatches.js
new file mode 100644
index 00000000..198d1598
--- /dev/null
+++ b/lib/api/assertions/urlMatches.js
@@ -0,0 +1,46 @@
+/**
+ * Checks if the current url matches a regular expression.
+ *
+ * @example
+ * 
+ * 
+ * ```
+ *    this.demoTest = function (client) {
+ *      browser.assert.urlMatches('^https');
+ *    };
+ * ```
+ * 
+ * @method urlMatches
+ * @param {string} regexExpression Regex expression to match URL
+ * @param {string} [msg] Optional log message to display in the output. If missing, one is displayed by default.
+ * @api assertions
+ */
+exports.assertion = function(regexExpression, msg) {
+  this.expected = function() {
+    return this.negate ? `does not matches '${regexExpression}'` : `matches '${regexExpression}'`;
+  };
+
+  this.formatMessage = function() {
+    const message = msg || `Testing if the URL ${this.negate ? 'doesn\'t matches %s' : 'matches %s'}`;
+
+    return {
+      message,
+      args: [`'${regexExpression}'`]
+    };
+  };
+
+  this.evaluate = function (value) {  
+    const regex = new RegExp(regexExpression);
+
+    return regex.test(value);
+  };
+
+
+  this.value = function(result = {}) {
+    return result.value || '';
+  };
+
+  this.command = function(callback) {
+    this.api.url(callback);
+  };
+};
diff --git a/lib/api/assertions/valueEquals.js b/lib/api/assertions/valueEquals.js
new file mode 100644
index 00000000..18fa3e22
--- /dev/null
+++ b/lib/api/assertions/valueEquals.js
@@ -0,0 +1,55 @@
+
+/**
+ * Checks if the given form element's value equals the expected value.
+ * 
+ * The .assert.value() command, which will become an alias of this and will be deprecated
+ *
+ * 
+ * ```
+ *    this.demoTest = function (browser) {
+ *      browser.assert.valueEquals("form.login input[type=text]", "username");
+ *    };
+ * ```
+ *
+ * @method valueEquals
+ * @param {string|object} definition The selector (CSS/Xpath) used to locate the element. Can either be a string or an object which specifies [element properties](https://nightwatchjs.org/guide#element-properties).
+ * @param {string} expected The expected text.
+ * @param {string} [msg] Optional log message to display in the output. If missing, one is displayed by default.
+ * @api assertions
+ */
+
+const {setElementSelectorProps} = require('../../utils');
+
+
+exports.assertion = function(definition, expected, msg) {
+  this.options = {
+    elementSelector: true
+  };
+
+  this.expected = function() {
+    return this.negate ? `not equals '${expected}'` : `equals '${expected}'`;
+  };
+
+  this.formatMessage = function() {
+    const message = msg || `Testing if value of element %s ${this.negate ? 'doesn\'t equal %s' : 'equals %s'}`;
+
+    return {
+      message,
+      args: [this.elementSelector, `'${expected}'`]
+    };
+  };
+
+  this.evaluate = function(value) {
+    return value === expected;
+  };
+
+  this.value = function(result = {}) {
+    return result.value || '';
+  };
+
+  this.command = function(callback) {
+    this.api.getValue(setElementSelectorProps(definition, {
+      suppressNotFoundErrors: true
+    }), callback);
+  };
+};


Test patch:
diff --git a/test/src/api/assertions/testAttributeMatches.js b/test/src/api/assertions/testAttributeMatches.js
new file mode 100644
index 00000000..617c92c5
--- /dev/null
+++ b/test/src/api/assertions/testAttributeMatches.js
@@ -0,0 +1,91 @@
+const assert = require('assert');
+const Globals = require('../../../lib/globals.js');
+
+describe('assert.attributeMatches', function () {
+  const assertionName = 'attributeMatches';
+  const api = 'getAttribute';
+
+  function assertionTest(opts) {
+    return Globals.assertion(assertionName, api, opts);
+  }
+
+  it('attributeMatches assertion passed', function () {
+    return assertionTest({
+      args: ['.test_element', 'data-test', '(button)', 'Test message'],
+      assertMessage: true,
+      assertArgs: true,
+      assertResult: true,
+      commandResult: {
+        value: 'cta-button'
+      },
+      assertApiCommandArgs(args) {
+        assert.strictEqual(args.length, 1);
+        assert.strictEqual(typeof args[0], 'function');
+      },
+      assertion({instance, failure}) {
+        assert.deepStrictEqual(instance.options, {elementSelector: true});
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.getActual(), 'cta-button');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+
+  it('attributeMatches assertion failed', function () {
+    return assertionTest({
+      args: ['.test_element', 'data-test', '(button)'],
+      commandResult: {
+        value: 'random value'
+      },
+      assertError: true,
+      assertion({instance, failure, err}) {
+        assert.strictEqual(instance.getActual(), 'random value');
+        assert.strictEqual(instance.expected(), 'matches \'(button)\'');
+        assert.strictEqual(instance.getValue(), 'random value');
+        assert.strictEqual(failure, 'Expected "matches \'(button)\'" but got: "random value"');
+        assert.strictEqual(err.message, `Testing if attribute 'data-test' of element <.test_element> matches '(button)' in 5ms - expected "matches '(button)'" but got: "random value" (${instance.elapsedTime}ms)`);
+      }
+    });
+  });
+
+  it('.not.attributeMatches assertion passed', function () {
+    return assertionTest({
+      args: ['.test_element', 'data-test', '(button)', 'Test message'],
+      commandResult: {
+        value: 'random value'
+      },
+      assertResult: true,
+      assertMessage: true,
+      assertArgs: true,
+      negate: true,
+      assertApiCommandArgs(args) {
+        assert.strictEqual(args.length, 1);
+        assert.strictEqual(typeof args[0], 'function');
+      },
+      assertion({instance, failure}) {
+        assert.strictEqual(typeof err, 'undefined');
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.getActual(), 'random value');
+        assert.strictEqual(instance.message, 'Test message');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+
+  it('.not.attributeMatches assertion failed', function () {
+    return assertionTest({
+      args: ['.test_element', 'data-test', '(button)'],
+      commandResult: {
+        value: 'test-button'
+      },
+      assertResult: true,
+      negate: true,
+      assertError: true,
+      assertion({instance, failure}) {
+        assert.strictEqual(failure, 'Expected "does not matches \'(button)\'" but got: "test-button"');
+        assert.strictEqual(instance.getActual(), 'test-button');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+});
diff --git a/test/src/api/assertions/testDomPropertyMatches.js b/test/src/api/assertions/testDomPropertyMatches.js
new file mode 100644
index 00000000..8b0f2b39
--- /dev/null
+++ b/test/src/api/assertions/testDomPropertyMatches.js
@@ -0,0 +1,90 @@
+const assert = require('assert');
+const Globals = require('../../../lib/globals.js');
+
+describe('assert.domPropertyMatches', function () {
+  const assertionName = 'domPropertyMatches';
+  const api = 'getElementProperty';
+
+  function assertionTest(opts) {
+    return Globals.assertion(assertionName, api, opts);
+  }
+
+  it('domPropertyMatches assertion passed', function () {
+    return assertionTest({
+      args: ['.test_element', 'tagName', 'test', 'Test message'],
+      assertMessage: true,
+      assertArgs: true,
+      assertResult: true,
+      commandResult: {
+        value: 'test'
+      },
+      assertApiCommandArgs(args) {
+        assert.strictEqual(args.length, 1);
+        assert.strictEqual(typeof args[0], 'function');
+      },
+      assertion({instance, failure}) {
+        assert.deepStrictEqual(instance.options, {elementSelector: true});
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.getActual(), 'test');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+
+  it('domPropertyMatches assertion failed', function () {
+    return assertionTest({
+      args: ['.test_element', 'tagName', 'test'],
+      commandResult: {
+        value: 'random_tag'
+      },
+      assertError: true,
+      assertion({instance, failure, err}) {
+        assert.strictEqual(instance.getActual(), 'random_tag');
+        assert.strictEqual(instance.expected(), 'matches \'test\'');
+        assert.strictEqual(instance.getValue(), 'random_tag');
+        assert.strictEqual(failure, 'Expected "matches \'test\'" but got: "random_tag"');
+        assert.strictEqual(err.message, `Testing if dom property 'tagName' of element <.test_element> matches 'test' in 5ms - expected "matches 'test'" but got: "random_tag" (${instance.elapsedTime}ms)`);
+      }
+    });
+  });
+
+  it('.not.domPropertyMatches assertion passed', function () {
+    return assertionTest({
+      args: ['.test_element', 'tagName', 'test', 'Test message'],
+      commandResult: {
+        value: 'random_tag'
+      },
+      assertResult: true,
+      assertMessage: true,
+      assertArgs: true,
+      negate: true,
+      assertApiCommandArgs(args) {
+        assert.strictEqual(args.length, 1);
+        assert.strictEqual(typeof args[0], 'function');
+      },
+      assertion({instance, failure}) {
+        assert.strictEqual(typeof err, 'undefined');
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.getActual(), 'random_tag');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+
+  it('.not.domPropertyMatches assertion failed', function () {
+    return assertionTest({
+      args: ['.test_element', 'tagName', 'test'],
+      commandResult: {
+        value: 'test'
+      },
+      assertResult: true,
+      negate: true,
+      assertError: true,
+      assertion({instance, failure}) {
+        assert.strictEqual(failure, 'Expected "does not matches \'test\'" but got: "test"');
+        assert.strictEqual(instance.getActual(), 'test');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+});
diff --git a/test/src/api/assertions/testHasAttribute.js b/test/src/api/assertions/testHasAttribute.js
new file mode 100644
index 00000000..55598657
--- /dev/null
+++ b/test/src/api/assertions/testHasAttribute.js
@@ -0,0 +1,135 @@
+const assert = require('assert');
+const Globals = require('../../../lib/globals.js');
+
+describe('assert.hasAttribute', function () {
+  const assertionName = 'hasAttribute';
+  const api = 'getElementProperty';
+
+  function assertionTest(opts) {
+    return Globals.assertion(assertionName, api, opts);
+  }
+
+  it('hasAttribute assertion passed', function () {
+    return assertionTest({
+      args: ['.test_element', 'data-test', 'Test message'],
+      commandResult: {
+        value: [{name: 'data-track'}, {name: 'data-test'}]
+      },
+      assertMessage: true,
+      assertion({instance, failure}) {
+        assert.deepStrictEqual(instance.options, {elementSelector: true});
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+
+  it('not.hasAttribute assertion passed', function () {
+    return assertionTest({
+      args: ['.test_element', 'data-test'],
+      commandResult: {
+        value: [{name: 'data-track'}]
+      },
+      negate: true,
+      assertion({instance, queueOpts, message}) {
+        assert.strictEqual(typeof err, 'undefined');
+        assert.strictEqual(queueOpts.negate, true);
+
+        assert.strictEqual(instance.hasFailure(), false);
+        assert.deepStrictEqual(instance.getValue(), ['data-track']);
+        assert.deepStrictEqual(instance.getActual(), ['data-track']);
+        assert.strictEqual(instance.message, 'Testing if element <.test_element> doesn\'t have attribute \'data-test\'');
+        assert.ok(message.startsWith('Testing if element <.test_element> doesn\'t have attribute \'data-test\''), message);
+      }
+    });
+  });
+
+  it('not.hasAttribute assertion failed', function () {
+    return assertionTest({
+      args: ['.test_element', 'data-test'],
+      commandResult: {
+        value: [{name: 'data-test'}]
+      },
+      negate: true,
+      assertError: true,
+      assertion({instance, queueOpts, err}) {
+        assert.strictEqual(queueOpts.negate, true);
+        assert.strictEqual(instance.hasFailure(), false);
+        assert.deepStrictEqual(instance.getValue(), ['data-test']);
+        assert.deepStrictEqual(instance.getActual(), ['data-test']);
+        assert.strictEqual(err.message, `Testing if element <.test_element> doesn't have attribute 'data-test' in 5ms - expected "has not data-test" but got: "data-test" (${instance.elapsedTime}ms)`);
+      }
+    });
+  });
+
+  it('hasAttribute assertion passed with selector object', function() {
+    return assertionTest({
+      args: [{selector: '.test_element'}, 'data-test'],
+      commandResult: {
+        value: [{name: 'data-test'}]
+      },
+      assertResult: true,
+      assertion({instance, failure, message, err}) {
+        assert.strictEqual(err, undefined);
+        assert.deepStrictEqual(instance.options, {elementSelector: true});
+        assert.deepStrictEqual(instance.getActual(), ['data-test']);
+        assert.strictEqual(instance.hasFailure(), false);
+        assert.ok(message.startsWith('Testing if element <.test_element> has attribute \'data-test\''), message);
+        assert.strictEqual(failure, false);
+      }
+    });
+  });
+
+  it('hasAttribute assertion failed', function() {
+    return assertionTest({
+      args: ['.test_element', 'data-test', 'Test message'],
+      commandResult: {
+        value: [{name: 'not_expected'}]
+      },
+      assertError: true,
+      assertResult: true,
+      assertion({instance, failure}) {
+        assert.deepStrictEqual(instance.getActual(), ['not_expected']);
+        assert.strictEqual(failure, 'Expected "has data-test" but got: "not_expected"');
+      }
+    });
+  });
+
+  it('hasAttribute assertion - element not found', function() {
+    return assertionTest({
+      args: ['.test_element', 'data-test', 'Test attribute %s from element "%s" == %s'],
+      commandResult: {
+        status: -1,
+        value: []
+      },
+      assertError: true,
+      assertFailure: true,
+      assertResult: true,
+      assertion({instance, failure, err}) {
+        assert.strictEqual(instance.getActual(), 'element could not be located');
+        assert.strictEqual(instance.expected(), 'has data-test');
+        assert.strictEqual(instance.getValue(), null);
+        assert.strictEqual(failure, 'Expected "has data-test" but got: "element could not be located"');
+        assert.strictEqual(err.message, `Test attribute <.test_element> from element "'data-test'" == %s in 5ms - expected "has data-test" but got: "element could not be located" (${instance.elapsedTime}ms)`);
+      }
+    });
+  });
+
+  it('hasAttribute assertion - attribute not found', function() {
+    return assertionTest({
+      args: ['.test_element', 'data-test'],
+      commandResult: {
+        status: 0,
+        value: ''
+      },
+      assertError: true,
+      assertResult: true,
+      assertion({instance, message, failure}) {
+        assert.strictEqual(message, `Testing if element <.test_element> has attribute 'data-test' in 5ms - expected "has data-test" but got: "" (${instance.elapsedTime}ms)`);
+        assert.strictEqual(instance.hasFailure(), false);
+        assert.strictEqual(instance.getValue(), '');
+        assert.strictEqual(instance.getActual(), '');
+      }
+    });
+  });
+});
diff --git a/test/src/api/assertions/testHasClass.js b/test/src/api/assertions/testHasClass.js
new file mode 100644
index 00000000..bec5bf9d
--- /dev/null
+++ b/test/src/api/assertions/testHasClass.js
@@ -0,0 +1,224 @@
+const assert = require('assert');
+const Globals = require('../../../lib/globals.js');
+
+describe('assert.hasClass', function () {
+  const assertionName = 'hasClass';
+  const api = 'getAttribute';
+
+  function assertionTest(opts) {
+    return Globals.assertion(assertionName, api, opts);
+  }
+
+  it('hasClass assertion passed', function () {
+    return assertionTest({
+      args: ['.test_element', 'test-css-class'],
+      commandResult: {
+        value: 'other-css-class test-css-class'
+      },
+      assertResult: true,
+      assertApiCommandArgs(args) {
+        assert.deepStrictEqual(args[0], {
+          selector: '.test_element',
+          suppressNotFoundErrors: true
+        });
+        assert.strictEqual(args[1], 'class');
+        assert.strictEqual(typeof args[2], 'function');
+      },
+      assertion({reporter, instance, queueOpts, failure, message}) {
+        assert.deepStrictEqual(instance.args, ['.test_element', 'test-css-class']);
+        assert.deepStrictEqual(instance.options, {elementSelector: true});
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.hasFailure(), false);
+        assert.strictEqual(instance.getValue(), 'other-css-class test-css-class');
+        assert.ok(message.startsWith('Testing if element <.test_element> has css class \'test-css-class\''), message);
+      }
+    });
+  });
+
+  it('hasClass assertion passed - multiple values array', function () {
+    return assertionTest({
+      args: ['.test_element', ['test-css-class', 'other-css-class']],
+      commandResult: {
+        value: 'other-css-class test-css-class'
+      },
+      assertResult: true,
+      assertApiCommandArgs(args) {
+        assert.deepStrictEqual(args[0], {
+          selector: '.test_element',
+          suppressNotFoundErrors: true
+        });
+        assert.strictEqual(args[1], 'class');
+        assert.strictEqual(typeof args[2], 'function');
+      },
+      assertion({reporter, instance, queueOpts, failure, message}) {
+        assert.deepStrictEqual(instance.args, ['.test_element', ['test-css-class', 'other-css-class']]);
+        assert.deepStrictEqual(instance.options, {elementSelector: true});
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.hasFailure(), false);
+        assert.strictEqual(instance.getValue(), 'other-css-class test-css-class');
+        assert.ok(message.startsWith('Testing if element <.test_element> has css class \'test-css-class other-css-class\''), message);
+      }
+    });
+  });
+
+  it('hasClass assertion passed - multiple values string', function () {
+    return assertionTest({
+      args: ['.test_element', 'test-css-class other-css-class'],
+      commandResult: {
+        value: 'other-css-class test-css-class'
+      },
+      assertResult: true,
+      assertApiCommandArgs(args) {
+        assert.deepStrictEqual(args[0], {
+          selector: '.test_element',
+          suppressNotFoundErrors: true
+        });
+        assert.strictEqual(args[1], 'class');
+        assert.strictEqual(typeof args[2], 'function');
+      },
+      assertion({reporter, instance, queueOpts, failure, message}) {
+        assert.deepStrictEqual(instance.args, ['.test_element', 'test-css-class other-css-class']);
+        assert.deepStrictEqual(instance.options, {elementSelector: true});
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.hasFailure(), false);
+        assert.strictEqual(instance.getValue(), 'other-css-class test-css-class');
+        assert.ok(message.startsWith('Testing if element <.test_element> has css class \'test-css-class other-css-class\''), message);
+      }
+    });
+  });
+
+  it('not.hasClass assertion passed', function () {
+    return assertionTest({
+      args: ['.test_element', 'test-css-class'],
+      commandResult: {
+        value: 'other-css-class'
+      },
+      negate: true,
+      assertion({reporter, instance, queueOpts, message}) {
+        assert.strictEqual(typeof err, 'undefined');
+        assert.strictEqual(queueOpts.negate, true);
+
+        assert.strictEqual(instance.hasFailure(), false);
+        assert.strictEqual(instance.getValue(), 'other-css-class');
+        assert.strictEqual(instance.getActual(), 'other-css-class');
+        assert.strictEqual(instance.message, 'Testing if element <.test_element> doesn\'t have css class \'test-css-class\'');
+        assert.ok(message.startsWith('Testing if element <.test_element> doesn\'t have css class \'test-css-class\''), message);
+      }
+    });
+  });
+
+  it('.not.hasClass assertion passed - multiple values string', function () {
+    return assertionTest({
+      args: ['.test_element', 'test-css-class other-css-class'],
+      commandResult: {
+        value: 'other-css-class'
+      },
+      negate: true,
+      assertion({reporter, instance, queueOpts, failure, message}) {
+        assert.deepStrictEqual(instance.args, ['.test_element', 'test-css-class other-css-class']);
+        assert.deepStrictEqual(instance.options, {elementSelector: true});
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.hasFailure(), false);
+        assert.strictEqual(instance.getValue(), 'other-css-class');
+        assert.ok(message.startsWith('Testing if element <.test_element> doesn\'t have css class \'test-css-class other-css-class\''), message);
+      }
+    });
+  });
+
+  it('not.hasClass assertion failed', function () {
+    return assertionTest({
+      args: ['.test_element', 'test-css-class'],
+      commandResult: {
+        value: 'test-css-class other'
+      },
+      negate: true,
+      assertion({reporter, instance, queueOpts, message}) {
+        assert.strictEqual(typeof err, 'undefined');
+        assert.strictEqual(queueOpts.negate, true);
+
+        assert.strictEqual(instance.hasFailure(), false);
+        assert.strictEqual(instance.getValue(), 'test-css-class other');
+        assert.strictEqual(instance.getActual(), 'test-css-class other');
+        assert.strictEqual(instance.message, 'Testing if element <.test_element> doesn\'t have css class \'test-css-class\'');
+        assert.ok(message.startsWith('Testing if element <.test_element> doesn\'t have css class \'test-css-class\''), message);
+      }
+    });
+  });
+
+  it('not.hasClass assertion failed - multiple classes', function () {
+    return assertionTest({
+      args: ['.test_element', 'test-css-class other'],
+      commandResult: {
+        value: 'other test-css-class'
+      },
+      negate: true,
+      assertion({reporter, instance, queueOpts, message}) {
+        assert.strictEqual(typeof err, 'undefined');
+        assert.strictEqual(queueOpts.negate, true);
+
+        assert.strictEqual(instance.hasFailure(), false);
+        assert.strictEqual(instance.getValue(), 'other test-css-class');
+        assert.strictEqual(instance.getActual(), 'other test-css-class');
+        assert.strictEqual(instance.message, 'Testing if element <.test_element> doesn\'t have css class \'test-css-class other\'');
+        assert.ok(message.startsWith('Testing if element <.test_element> doesn\'t have css class \'test-css-class other\' in 5ms - expected "has not test-css-class other" but got: "other test-css-class"'), message);
+      }
+    });
+  });
+
+  it('hasClass assertion passed with selector object', function () {
+    return assertionTest({
+      args: [{selector: '.test_element'}, 'test-css-class'],
+      commandResult: {
+        value: 'other-css-class test-css-class'
+      },
+      assertResult: true,
+      assertApiCommandArgs(args) {
+        assert.deepStrictEqual(args[0], {selector: '.test_element', suppressNotFoundErrors: true});
+        assert.strictEqual(args[1], 'class');
+        assert.strictEqual(typeof args[2], 'function');
+      },
+      assertion({instance, failure, message, err}) {
+        assert.strictEqual(err, undefined);
+        assert.deepStrictEqual(instance.options, {elementSelector: true});
+        assert.strictEqual(instance.getActual(), 'other-css-class test-css-class');
+        assert.strictEqual(instance.hasFailure(), false);
+        assert.ok(message.startsWith('Testing if element <.test_element> has css class \'test-css-class\''), message);
+        assert.strictEqual(failure, false);
+      }
+    });
+  });
+
+  it('hasClass assertion failed', function () {
+    return assertionTest({
+      args: ['.test_element', 'test-css-class'],
+      commandResult: {
+        value: 'other-css-class'
+      },
+      assertError: true,
+      assertResult: true,
+      assertion({instance, failure}) {
+        assert.strictEqual(instance.getActual(), 'other-css-class');
+        assert.strictEqual(failure, 'Expected "has test-css-class" but got: "other-css-class"');
+      }
+    });
+  });
+
+  it('hasClass assertion - element not found', function () {
+    return assertionTest({
+      args: ['.test_element', 'test-css-class', 'Element %s doesnt have css class "%s"'],
+      commandResult: {
+        status: -1
+      },
+      assertError: true,
+      assertFailure: true,
+      assertResult: true,
+      assertion({instance, failure, err}) {
+        assert.strictEqual(instance.getActual(), 'element could not be located');
+        assert.strictEqual(instance.expected(), 'has test-css-class');
+        assert.strictEqual(instance.getValue(), null);
+        assert.strictEqual(failure, 'Expected "has test-css-class" but got: "element could not be located"');
+        assert.strictEqual(err.message, `Element <.test_element> doesnt have css class "'test-css-class'" in 5ms - expected "has test-css-class" but got: "element could not be located" (${instance.elapsedTime}ms)`);
+      }
+    });
+  });
+});
diff --git a/test/src/api/assertions/testTextMatches.js b/test/src/api/assertions/testTextMatches.js
new file mode 100644
index 00000000..201f258e
--- /dev/null
+++ b/test/src/api/assertions/testTextMatches.js
@@ -0,0 +1,109 @@
+const assert = require('assert');
+const Globals = require('../../../lib/globals.js');
+
+describe('assert.textMatches', function () {
+  const assertionName = 'textMatches';
+  const api = 'getText';
+
+  function assertionTest(opts) {
+    return Globals.assertion(assertionName, api, opts);
+  }
+
+  it('textMatches assertion passed', function () {
+    return assertionTest({
+      args: ['.test_element', 'text', 'Test message'],
+      assertMessage: true,
+      assertArgs: true,
+      assertResult: true,
+      commandResult: {
+        value: 'expected text result'
+      },
+      assertApiCommandArgs(args) {
+        assert.strictEqual(args.length, 1);
+        assert.strictEqual(typeof args[0], 'function');
+      },
+      assertion({instance, failure}) {
+        assert.deepStrictEqual(instance.options, {elementSelector: true});
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.getActual(), 'expected text result');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+
+  it('textMatches assertion failed', function () {
+    return assertionTest({
+      args: ['.test_element', 'text'],
+      commandResult: {
+        value: 'random value'
+      },
+      assertError: true,
+      assertion({instance, failure, err}) {
+        assert.strictEqual(instance.getActual(), 'random value');
+        assert.strictEqual(instance.expected(), 'matches \'text\'');
+        assert.strictEqual(instance.getValue(), 'random value');
+        assert.strictEqual(failure, 'Expected "matches \'text\'" but got: "random value"');
+        assert.strictEqual(err.message, `Testing if the text matches <.test_element> 'text' in 5ms - expected "matches 'text'" but got: "random value" (${instance.elapsedTime}ms)`);
+      }
+    });
+  });
+
+  it('.not.textMatches assertion passed', function () {
+    return assertionTest({
+      args: ['.test_element', 'text', 'Test message'],
+      commandResult: {
+        value: 'random value'
+      },
+      assertResult: true,
+      assertMessage: true,
+      assertArgs: true,
+      negate: true,
+      assertApiCommandArgs(args) {
+        assert.strictEqual(args.length, 1);
+        assert.strictEqual(typeof args[0], 'function');
+      },
+      assertion({instance, failure}) {
+        assert.strictEqual(typeof err, 'undefined');
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.getActual(), 'random value');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+
+  it('textMatches assertion - element not found', function() {
+    return assertionTest({
+      args: ['.test_element', 'text'],
+      commandResult: {
+        value: [],
+        status: -1
+      },
+      assertError: true,
+      assertFailure: true,
+      assertResult: true,
+      assertion({instance, failure, err}) {
+        assert.strictEqual(instance.getActual(), 'element could not be located');
+        assert.strictEqual(instance.expected(), 'matches \'text\'');
+        assert.strictEqual(failure, 'Expected "matches \'text\'" but got: "element could not be located"');
+        assert.strictEqual(err.message, `Testing if the text matches <.test_element> 'text' in 5ms - expected "matches 'text'" but got: "element could not be located" (${instance.elapsedTime}ms)`);
+      }
+    });
+  });
+
+  it('.not.textMatches assertion failed', function () {
+    return assertionTest({
+      args: ['.test_element', 'text'],
+      commandResult: {
+        value: 'expected text result'
+      },
+      assertResult: true,
+      negate: true,
+      assertError: true,
+      assertion({instance, failure}) {
+        assert.strictEqual(failure, 'Expected "does not matches \'text\'" but got: "expected text result"');
+        assert.strictEqual(instance.getActual(), 'expected text result');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+});
diff --git a/test/src/api/assertions/testTitleEquals.js b/test/src/api/assertions/testTitleEquals.js
new file mode 100644
index 00000000..aed5ab20
--- /dev/null
+++ b/test/src/api/assertions/testTitleEquals.js
@@ -0,0 +1,85 @@
+const assert = require('assert');
+const Globals = require('../../../lib/globals.js');
+
+describe('assert.titleEquals', function () {
+  const assertionName = 'titleEquals';
+  const api = 'title';
+
+  function assertionTest(opts) {
+    return Globals.assertion(assertionName, api, opts);
+  }
+
+  it('titleEquals assertion passed', function () {
+    return assertionTest({
+      args: ['Nightwatch.js', 'Test message'],
+      assertMessage: true,
+      assertResult: true,
+      commandResult: {
+        value: 'Nightwatch.js'
+      },
+      assertApiCommandArgs(args) {
+        assert.strictEqual(args.length, 1);
+        assert.strictEqual(typeof args[0], 'function');
+      },
+      assertion({instance, failure}) {
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.getActual(), 'Nightwatch.js');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+
+  it('titleEquals assertion failed', function () {
+    return assertionTest({
+      args: ['Nightwatch.js'],
+      commandResult: {
+        value: 'John Doe'
+      },
+      assertError: true,
+      assertion({instance, failure, err}) {
+        assert.strictEqual(instance.getActual(), 'John Doe');
+        assert.strictEqual(instance.expected(), 'is \'Nightwatch.js\'');
+        assert.strictEqual(instance.getValue(), 'John Doe');
+        assert.strictEqual(failure, 'Expected "is \'Nightwatch.js\'" but got: "John Doe"');
+        assert.strictEqual(err.message, `Testing if the page title equals 'Nightwatch.js' in 5ms - expected "is 'Nightwatch.js'" but got: "John Doe" (${instance.elapsedTime}ms)`);
+      }
+    });
+  });
+
+  it('.not.titleEquals assertion passed', function () {
+    return assertionTest({
+      args: ['Nightwatch.js'],
+      commandResult: {
+        value: 'John Doe'
+      },
+      assertResult: true,
+      negate: true,
+      assertApiCommandArgs(args) {
+        assert.strictEqual(args.length, 1);
+        assert.strictEqual(typeof args[0], 'function');
+      },
+      assertion({instance, failure}) {
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.getActual(), 'John Doe');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+
+  it('.not.titleEquals assertion failed', function () {
+    return assertionTest({
+      args: ['Nightwatch.js'],
+      commandResult: {
+        value: 'Nightwatch.js'
+      },
+      assertResult: true,
+      negate: true,
+      assertError: true,
+      assertion({instance, failure}) {
+        assert.strictEqual(failure, 'Expected "is not \'Nightwatch.js\'" but got: "Nightwatch.js"');
+        assert.strictEqual(instance.getActual(), 'Nightwatch.js');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+});
diff --git a/test/src/api/assertions/testTitleMatches.js b/test/src/api/assertions/testTitleMatches.js
new file mode 100644
index 00000000..38fd6660
--- /dev/null
+++ b/test/src/api/assertions/testTitleMatches.js
@@ -0,0 +1,85 @@
+const assert = require('assert');
+const Globals = require('../../../lib/globals.js');
+
+describe('assert.titleMatches', function () {
+  const assertionName = 'titleMatches';
+  const api = 'title';
+
+  function assertionTest(opts) {
+    return Globals.assertion(assertionName, api, opts);
+  }
+
+  it('titleMatches assertion passed', function () {
+    return assertionTest({
+      args: ['^Night', 'Test message'],
+      assertMessage: true,
+      assertResult: true,
+      commandResult: {
+        value: 'Nightwatch.js'
+      },
+      assertApiCommandArgs(args) {
+        assert.strictEqual(args.length, 1);
+        assert.strictEqual(typeof args[0], 'function');
+      },
+      assertion({instance, failure}) {
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.getActual(), 'Nightwatch.js');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+
+  it('titleMatches assertion failed', function () {
+    return assertionTest({
+      args: ['^Night'],
+      commandResult: {
+        value: 'John Doe'
+      },
+      assertError: true,
+      assertion({instance, failure, err}) {
+        assert.strictEqual(instance.getActual(), 'John Doe');
+        assert.strictEqual(instance.expected(), 'matches \'^Night\'');
+        assert.strictEqual(instance.getValue(), 'John Doe');
+        assert.strictEqual(failure, 'Expected "matches \'^Night\'" but got: "John Doe"');
+        assert.strictEqual(err.message, `Testing if the page title matches '^Night' in 5ms - expected "matches '^Night'" but got: "John Doe" (${instance.elapsedTime}ms)`);
+      }
+    });
+  });
+
+  it('.not.titleMatches assertion passed', function () {
+    return assertionTest({
+      args: ['^Night'],
+      commandResult: {
+        value: 'John Doe'
+      },
+      assertResult: true,
+      negate: true,
+      assertApiCommandArgs(args) {
+        assert.strictEqual(args.length, 1);
+        assert.strictEqual(typeof args[0], 'function');
+      },
+      assertion({instance, failure}) {
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.getActual(), 'John Doe');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+
+  it('.not.titleMatches assertion failed', function () {
+    return assertionTest({
+      args: ['^Night'],
+      commandResult: {
+        value: 'Nightwatch.js'
+      },
+      assertResult: true,
+      negate: true,
+      assertError: true,
+      assertion({instance, failure}) {
+        assert.strictEqual(failure, 'Expected "does not matches \'^Night\'" but got: "Nightwatch.js"');
+        assert.strictEqual(instance.getActual(), 'Nightwatch.js');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+});
diff --git a/test/src/api/assertions/testUrlMatches.js b/test/src/api/assertions/testUrlMatches.js
new file mode 100644
index 00000000..053470ad
--- /dev/null
+++ b/test/src/api/assertions/testUrlMatches.js
@@ -0,0 +1,85 @@
+const assert = require('assert');
+const Globals = require('../../../lib/globals.js');
+
+describe('assert.urlMatches', function () {
+  const assertionName = 'urlMatches';
+  const api = 'url';
+
+  function assertionTest(opts) {
+    return Globals.assertion(assertionName, api, opts);
+  }
+
+  it('urlMatches assertion passed', function () {
+    return assertionTest({
+      args: ['nightwatch', 'Test message'],
+      assertMessage: true,
+      assertResult: true,
+      commandResult: {
+        value: 'https://nightwatchjs.org/'
+      },
+      assertApiCommandArgs(args) {
+        assert.strictEqual(args.length, 1);
+        assert.strictEqual(typeof args[0], 'function');
+      },
+      assertion({instance, failure}) {
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.getActual(), 'https://nightwatchjs.org/');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+
+  it('urlMatches assertion failed', function () {
+    return assertionTest({
+      args: ['nightwatch'],
+      commandResult: {
+        value: 'John Doe'
+      },
+      assertError: true,
+      assertion({instance, failure, err}) {
+        assert.strictEqual(instance.getActual(), 'John Doe');
+        assert.strictEqual(instance.expected(), 'matches \'nightwatch\'');
+        assert.strictEqual(instance.getValue(), 'John Doe');
+        assert.strictEqual(failure, 'Expected "matches \'nightwatch\'" but got: "John Doe"');
+        assert.strictEqual(err.message, `Testing if the URL matches 'nightwatch' in 5ms - expected "matches 'nightwatch'" but got: "John Doe" (${instance.elapsedTime}ms)`);
+      }
+    });
+  });
+
+  it('.not.urlMatches assertion passed', function () {
+    return assertionTest({
+      args: ['nightwatch'],
+      commandResult: {
+        value: 'John Doe'
+      },
+      assertResult: true,
+      negate: true,
+      assertApiCommandArgs(args) {
+        assert.strictEqual(args.length, 1);
+        assert.strictEqual(typeof args[0], 'function');
+      },
+      assertion({instance, failure}) {
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.getActual(), 'John Doe');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+
+  it('.not.urlMatches assertion failed', function () {
+    return assertionTest({
+      args: ['nightwatch'],
+      commandResult: {
+        value: 'https://nightwatchjs.org/'
+      },
+      assertResult: true,
+      negate: true,
+      assertError: true,
+      assertion({instance, failure}) {
+        assert.strictEqual(failure, 'Expected "does not matches \'nightwatch\'" but got: "https://nightwatchjs.org/"');
+        assert.strictEqual(instance.getActual(), 'https://nightwatchjs.org/');
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+});
diff --git a/test/src/api/assertions/testValueEquals.js b/test/src/api/assertions/testValueEquals.js
new file mode 100644
index 00000000..17f52a7b
--- /dev/null
+++ b/test/src/api/assertions/testValueEquals.js
@@ -0,0 +1,137 @@
+const assert = require('assert');
+const Globals = require('../../../lib/globals.js');
+
+describe('assert.valueEquals', function () {
+  const assertionName = 'valueEquals';
+  const api = 'getValue';
+
+  function assertionTest(opts) {
+    return Globals.assertion(assertionName, api, opts);
+  }
+
+  it('value assertion passed', function() {
+    return assertionTest({
+      args: ['.test_element', 'some-value', 'Test message'],
+      commandResult: {
+        status: 0,
+        value: 'some-value'
+      },
+      assertMessage: true,
+      assertArgs: true,
+      assertion({reporter, instance, failure}) {
+        assert.deepStrictEqual(instance.options, {elementSelector: true});
+        assert.strictEqual(failure, false);
+        assert.strictEqual(instance.hasFailure(), false);
+      }
+    });
+  });
+
+  it('not.valueEquals assertion passed', function () {
+    return assertionTest({
+      args: ['.test_element', 'some-value'],
+      commandResult: {
+        value: 'second'
+      },
+      negate: true,
+      assertion({reporter, instance, queueOpts, message}) {
+        assert.strictEqual(typeof err, 'undefined');
+        assert.strictEqual(queueOpts.negate, true);
+
+        assert.strictEqual(instance.hasFailure(), false);
+        assert.strictEqual(instance.getValue(), 'second');
+        assert.strictEqual(instance.getActual(), 'second');
+        assert.strictEqual(instance.message, 'Testing if value of element <.test_element> doesn\'t equal \'some-value\'');
+        assert.ok(message.startsWith('Testing if value of element <.test_element> doesn\'t equal \'some-value\''), message);
+      }
+    });
+  });
+
+  it('not.valueEquals assertion failed', function () {
+    return assertionTest({
+      args: ['.test_element', 'some-value'],
+      commandResult: {
+        value: 'some-value'
+      },
+      negate: true,
+      assertError: true,
+      assertion({instance, queueOpts, err}) {
+        assert.strictEqual(queueOpts.negate, true);
+        assert.strictEqual(instance.hasFailure(), false);
+        assert.strictEqual(instance.getValue(), 'some-value');
+        assert.strictEqual(instance.getActual(), 'some-value');
+        assert.strictEqual(err.message, `Testing if value of element <.test_element> doesn't equal 'some-value' in 5ms - expected "not equals 'some-value'" but got: "some-value" (${instance.elapsedTime}ms)`);
+      }
+    });
+  });
+
+  it('value assertion passed with selector object', function() {
+    return assertionTest({
+      args: [{selector: '.test_element'}, 'some-value'],
+      commandResult: {
+        status: 0,
+        value: 'some-value'
+      },
+      assertArgs: true,
+      assertion({reporter, instance, failure, err, message}) {
+        assert.strictEqual(err, undefined);
+        assert.deepStrictEqual(instance.options, {elementSelector: true});
+        assert.strictEqual(instance.getActual(), 'some-value');
+        assert.strictEqual(instance.hasFailure(), false);
+        assert.ok(message.startsWith('Testing if value of element <.test_element> equals \'some-value\''), message);
+        assert.strictEqual(failure, false);
+      }
+    });
+  });
+
+  it('value assertion failed', function() {
+    return assertionTest({
+      args: ['.test_element', 'some-value'],
+      commandResult: {
+        status: 0,
+        value: 'wrong-value'
+      },
+      assertError: true,
+      assertResult: true,
+      assertion({instance, failure}) {
+        assert.strictEqual(instance.getActual(), 'wrong-value');
+        assert.strictEqual(failure, 'Expected "equals \'some-value\'" but got: "wrong-value"');
+      }
+    });
+  });
+
+  it('value assertion - element not found', function() {
+    return assertionTest({
+      args: ['.test_element', 'some-value', 'Test value of element %s == %s'],
+      commandResult: {
+        status: -1
+      },
+      assertError: true,
+      assertFailure: true,
+      assertResult: true,
+      assertion({instance, failure, err}) {
+        assert.strictEqual(instance.getActual(), 'element could not be located');
+        assert.strictEqual(instance.expected(), 'equals \'some-value\'');
+        assert.strictEqual(instance.getValue(), null);
+        assert.strictEqual(failure, 'Expected "equals \'some-value\'" but got: "element could not be located"');
+        assert.strictEqual(err.message, `Test value of element <.test_element> == 'some-value' in 5ms - expected "equals 'some-value'" but got: "element could not be located" (${instance.elapsedTime}ms)`);
+      }
+    });
+  });
+
+  it('attributeEquals assertion - value attribute not found', function() {
+    return assertionTest({
+      args: ['.test_element', 'some-value'],
+      commandResult: {
+        status: 0,
+        value: null
+      },
+      assertError: true,
+      assertResult: true,
+      assertion({instance, message, failure}) {
+        assert.strictEqual(message, `Testing if value of element <.test_element> equals 'some-value' in 5ms - expected "equals 'some-value'" but got: "" (${instance.elapsedTime}ms)`);
+        assert.strictEqual(instance.hasFailure(), false);
+        assert.strictEqual(instance.getValue(), '');
+      }
+    });
+  });
+});