From 9fdf4881bbc8ff7e3f2359094ec3b0965e272d32 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9s?= <angrykoala@outlook.es>
Date: Fri, 1 Jun 2018 14:52:11 +0200
Subject: [PATCH 01/13] small fix in readme

---
 README.md | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/README.md b/README.md
index 1fd0e26b..0d496329 100644
--- a/README.md
+++ b/README.md
@@ -270,7 +270,7 @@ Waits until the given selector is no longer visible or doesn't exists, with the
 await browser.waitUntilNotVisible(".toast");
 ```
 
-**waitForUrl(url, timeout=500)**
+**waitForUrl(url, timeout=500)**    
 Waits for page url to be the given url.
 
 ```js
@@ -563,12 +563,12 @@ Asserts that the first element matching the given selector has a checked value s
 
 > Css, Xpath and Dom selectors supported
 
-**disabled(selector, msg?)**
+**disabled(selector, msg?)**    
 Asserts that the first element matching the given selector is disabled (has attribute disabled).
 
 > Css, Xpath and Dom selectors supported
 
-**enabled(selector, msg?)**
+**enabled(selector, msg?)**    
 Asserts that the first element matching the given selector is enabled (doesn't have attribute disabled).
 
 > Css, Xpath and Dom selectors supported
@@ -675,12 +675,12 @@ Note that if the element doesn't have a checked value (i.e. is not a checkbox) t
 
 > Css, Xpath and Dom selectors supported
 
-**not.disabled(selector, msg?)**
+**not.disabled(selector, msg?)**    
 Asserts that the first element matching the given selector is not disabled (same as assert.enabled).
 
 > Css, Xpath and Dom selectors supported
 
-**not.enabled(selector, msg?)**
+**not.enabled(selector, msg?)**    
 Asserts that the first element matching the given selector is not enabled (same as assert.disabled).
 
 > Css, Xpath and Dom selectors supported

From d783dd9cab4dafeb0aa8a8e8af47d25bafa15052 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9s?= <angrykoala@outlook.es>
Date: Fri, 1 Jun 2018 14:52:49 +0200
Subject: [PATCH 02/13] version update

---
 CHANGELOG.md      | 4 ++++
 package-lock.json | 2 +-
 package.json      | 2 +-
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7cf1e729..6f6df83d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+0.7.4 / ####-##-##
+==================
+
+
 0.7.3 / 2018-06-01
 ==================
 
diff --git a/package-lock.json b/package-lock.json
index 562e7d02..4e9e5802 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "wendigo",
-  "version": "0.7.3",
+  "version": "0.7.4",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/package.json b/package.json
index fa9e7902..ccf2f911 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "wendigo",
-  "version": "0.7.3",
+  "version": "0.7.4",
   "description": "A proper monster for front-end automated testing",
   "engines": {
     "node": ">=8.0.0"

From 0f26dfbafa183f1ace7eae368e630b7a0ec336b4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9s?= <angrykoala@outlook.es>
Date: Fri, 1 Jun 2018 15:30:26 +0200
Subject: [PATCH 03/13] fixed redirect scripts bug, close #96

---
 CHANGELOG.md                          |   1 +
 config.js                             |   5 +-
 injection_scripts/selector_query.js   | 151 +++++++++++++-------------
 injection_scripts/wendigo_utils.js    |  56 +++++-----
 lib/browser_core.js                   |  21 +++-
 tests/browser/navigation_load.test.js |  33 ++++++
 6 files changed, 160 insertions(+), 107 deletions(-)
 create mode 100644 tests/browser/navigation_load.test.js

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6f6df83d..9dbb3d1e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
 0.7.4 / ####-##-##
 ==================
 
+  * Fixed bug where navigation to a different page breaks some methods
 
 0.7.3 / 2018-06-01
 ==================
diff --git a/config.js b/config.js
index a76f88d4..13ca12d3 100644
--- a/config.js
+++ b/config.js
@@ -4,6 +4,9 @@ const path = require('path');
 module.exports = {
     injectionScripts: {
         path: path.join(__dirname, "injection_scripts"),
-        files: ["selector_query.js", "wendigo_utils.js"]
+        files: {
+            WendigoQuery: "selector_query.js",
+            WendigoUtils: "wendigo_utils.js"
+        }
     }
 };
diff --git a/injection_scripts/selector_query.js b/injection_scripts/selector_query.js
index 7000889d..a1ac370f 100644
--- a/injection_scripts/selector_query.js
+++ b/injection_scripts/selector_query.js
@@ -1,79 +1,80 @@
 "use strict";
+if(!window.WendigoQuery) {
+    window.WendigoQuery = {
+        selectorTypes: { // Warning: Same as selector type
+            css: "css",
+            xpath: "xpath",
+            domElement: "domElement"
+        },
+        query(selector) {
+            const type = this._parseSelectorType(selector);
+            switch(type) {
+                case this.selectorTypes.css:
+                    return this.queryCss(selector);
+                case this.selectorTypes.xpath:
+                    return this.queryXPath(selector);
+                case this.selectorTypes.domElement:
+                    return this.queryDomElement(selector);
+                default:
+                    throw new Error(`Query Error: ${selector} with type ${type}`);
+            }
+        },
+        queryAll(selector) {
+            const type = this._parseSelectorType(selector);
 
-window.WendigoQuery = {
-    selectorTypes: { // Warning: Same as selector type
-        css: "css",
-        xpath: "xpath",
-        domElement: "domElement"
-    },
-    query(selector) {
-        const type = this._parseSelectorType(selector);
-        switch(type) {
-            case this.selectorTypes.css:
-                return this.queryCss(selector);
-            case this.selectorTypes.xpath:
-                return this.queryXPath(selector);
-            case this.selectorTypes.domElement:
-                return this.queryDomElement(selector);
-            default:
-                throw new Error(`Query Error: ${selector} with type ${type}`);
-        }
-    },
-    queryAll(selector) {
-        const type = this._parseSelectorType(selector);
+            switch(type) {
+                case this.selectorTypes.css:
+                    return this.queryCssAll(selector);
+                case this.selectorTypes.xpath:
+                    return this.queryXPathAll(selector);
+                case this.selectorTypes.domElement:
+                    return this.queryDomElementAll(selector);
+                default:
+                    throw new Error(`QueryAll Error: ${selector} with type ${type}`);
+            }
+        },
+        queryCss(cssSelector) {
+            return document.querySelector(cssSelector);
+        },
+        queryCssAll(cssSelector) {
+            return Array.from(document.querySelectorAll(cssSelector));
+        },
+        queryDomElement(element) {
+            if(Array.isArray(element)) return element[0];
+            else return element;
+        },
+        queryDomElementAll(elements) {
+            if(Array.isArray(elements)) return elements;
+            else return [elements];
+        },
+        queryXPath(xPath) {
+            const xPathResult = document.evaluate(xPath, document, null, XPathResult.ANY_TYPE, null);
+            const result = xPathResult.iterateNext();
+            return result;
+        },
+        queryXPathAll(xPath) {
+            const xPathResult = document.evaluate(xPath, document, null, XPathResult.ANY_TYPE, null);
+            const result = [];
+            let r = xPathResult.iterateNext();
+            while(r !== null) {
+                result.push(r);
+                r = xPathResult.iterateNext();
+            }
+            return result;
+        },
 
-        switch(type) {
-            case this.selectorTypes.css:
-                return this.queryCssAll(selector);
-            case this.selectorTypes.xpath:
-                return this.queryXPathAll(selector);
-            case this.selectorTypes.domElement:
-                return this.queryDomElementAll(selector);
-            default:
-                throw new Error(`QueryAll Error: ${selector} with type ${type}`);
-        }
-    },
-    queryCss(cssSelector) {
-        return document.querySelector(cssSelector);
-    },
-    queryCssAll(cssSelector) {
-        return Array.from(document.querySelectorAll(cssSelector));
-    },
-    queryDomElement(element) {
-        if(Array.isArray(element)) return element[0];
-        else return element;
-    },
-    queryDomElementAll(elements) {
-        if(Array.isArray(elements)) return elements;
-        else return [elements];
-    },
-    queryXPath(xPath) {
-        const xPathResult = document.evaluate(xPath, document, null, XPathResult.ANY_TYPE, null);
-        const result = xPathResult.iterateNext();
-        return result;
-    },
-    queryXPathAll(xPath) {
-        const xPathResult = document.evaluate(xPath, document, null, XPathResult.ANY_TYPE, null);
-        const result = [];
-        let r = xPathResult.iterateNext();
-        while(r !== null) {
-            result.push(r);
-            r = xPathResult.iterateNext();
-        }
-        return result;
-    },
+        _parseSelectorType(selector) {
+            if(typeof(selector) === "string") {
+                return this._parseStringSelector(selector);
+            } else if(typeof(selector) === "object") {
+                return this.selectorTypes.domElement;
+            } else return null;
+        },
 
-    _parseSelectorType(selector) {
-        if(typeof(selector) === "string") {
-            return this._parseStringSelector(selector);
-        } else if(typeof(selector) === "object") {
-            return this.selectorTypes.domElement;
-        } else return null;
-    },
-
-    _parseStringSelector(selector) {
-        if(selector.length === 0) return null;
-        if(selector[0] === "/") return this.selectorTypes.xpath;
-        else return this.selectorTypes.css;
-    }
-};
+        _parseStringSelector(selector) {
+            if(selector.length === 0) return null;
+            if(selector[0] === "/") return this.selectorTypes.xpath;
+            else return this.selectorTypes.css;
+        }
+    };
+}
diff --git a/injection_scripts/wendigo_utils.js b/injection_scripts/wendigo_utils.js
index 83774abb..1e991e68 100644
--- a/injection_scripts/wendigo_utils.js
+++ b/injection_scripts/wendigo_utils.js
@@ -1,31 +1,33 @@
 /* global WendigoQuery */
 "use strict";
 
-window.WendigoUtils = {
-    isVisible(element) {
-        if(!element) return false;
-        if (element === document) return true; // Top element, always visible
-        const style = window.getComputedStyle(element);
-        if (style.display === 'none') return false;
-        if (style.visibility === 'hidden') return false;
-        return this.isVisible(element.parentNode);
-    },
-    queryElement(selector) {
-        return WendigoQuery.query(selector);
-    },
-    queryAll(selector) {
-        return WendigoQuery.queryAll(selector);
-    },
-    xPathQuery(xPath) {
-        return WendigoQuery.queryXPathAll(xPath);
-    },
-    getStyles(element) {
-        const rawStyles = getComputedStyle(element);
-        const result = {};
-        for(let i = 0;i < rawStyles.length;i++) {
-            const name = rawStyles[i];
-            result[name] = rawStyles.getPropertyValue(name);
+if(!window.WendigoUtils) {
+    window.WendigoUtils = {
+        isVisible(element) {
+            if(!element) return false;
+            if (element === document) return true; // Top element, always visible
+            const style = window.getComputedStyle(element);
+            if (style.display === 'none') return false;
+            if (style.visibility === 'hidden') return false;
+            return this.isVisible(element.parentNode);
+        },
+        queryElement(selector) {
+            return WendigoQuery.query(selector);
+        },
+        queryAll(selector) {
+            return WendigoQuery.queryAll(selector);
+        },
+        xPathQuery(xPath) {
+            return WendigoQuery.queryXPathAll(xPath);
+        },
+        getStyles(element) {
+            const rawStyles = getComputedStyle(element);
+            const result = {};
+            for(let i = 0;i < rawStyles.length;i++) {
+                const name = rawStyles[i];
+                result[name] = rawStyles.getPropertyValue(name);
+            }
+            return result;
         }
-        return result;
-    }
-};
+    };
+}
diff --git a/lib/browser_core.js b/lib/browser_core.js
index aa98c70c..d893c803 100644
--- a/lib/browser_core.js
+++ b/lib/browser_core.js
@@ -20,13 +20,16 @@ module.exports = class BrowserCore {
         if(this._settings.log) {
             this.page.on("console", pageLog);
         }
+
+        this.page.on('load', () => {
+            if(this._loaded) this._afterPageLoad();
+        });
     }
 
     open(url) {
         return this._beforeOpen().then(() => {
             return this.page.goto(url).then(() => {
-                return this._afterPageLoad().then(() => {
-                });
+                return this._afterPageLoad();
             });
         }).catch(() => {
             return Promise.reject(ErrorFactory.generateFatalError(`Failed to open ${url}.`));
@@ -68,9 +71,19 @@ module.exports = class BrowserCore {
         });
     }
 
+    _addScript(key, scriptPath) {
+        return this.page.evaluate((key) => {
+            return Boolean(window[key]);
+        }, key).then((exists) => {
+            if(exists) return Promise.resolve();
+            return this.page.addScriptTag({path: path.join(injectionScriptsPath, scriptPath)});
+        });
+    }
+
     _addJsScripts() {
-        const promises = injectionScripts.map((s) => {
-            return this.page.addScriptTag({path: path.join(injectionScriptsPath, s)});
+        const scripts = Object.keys(injectionScripts);
+        const promises = scripts.map((s) => {
+            return this._addScript(s, injectionScripts[s]);
         });
         return Promise.all(promises);
     }
diff --git a/tests/browser/navigation_load.test.js b/tests/browser/navigation_load.test.js
new file mode 100644
index 00000000..0c1d8375
--- /dev/null
+++ b/tests/browser/navigation_load.test.js
@@ -0,0 +1,33 @@
+"use strict";
+
+const Wendigo = require('../../lib/wendigo');
+const configUrls = require('../config.json').urls;
+
+describe("Wait For", function() {
+    this.timeout(5000);
+    let browser;
+
+    before(async () => {
+        browser = await Wendigo.createBrowser();
+    });
+
+    after(async () => {
+        await browser.close();
+    });
+
+
+    it("Wendigo Utils Exists", async () => {
+        await browser.open(configUrls.index);
+        await browser.assert.global("WendigoUtils");
+    });
+
+    it("Using Wendigo Utils After Redirect", async () => {
+        await browser.open(configUrls.index);
+        await browser.click("a");
+        await browser.waitForUrl(configUrls.simple);
+        await browser.wait();
+        await browser.assert.global("WendigoUtils");
+        await browser.assert.text("p", "html_test"); // Requires WendigoUtils
+    });
+
+});

From 20c52aac8a1d1158f40baa16f978d8d3a585363a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9s?= <angrykoala@outlook.es>
Date: Fri, 1 Jun 2018 16:53:11 +0200
Subject: [PATCH 04/13] small fix on addScript

---
 lib/browser_core.js                  | 2 +-
 lib/mixins/browser_wait.js           | 2 --
 tests/browser/value.test.js          | 2 +-
 tests/browser/wait_for.test.js       | 2 +-
 tests/dummy_server/static/forms.html | 8 +++++++-
 5 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/lib/browser_core.js b/lib/browser_core.js
index d893c803..0e13bda7 100644
--- a/lib/browser_core.js
+++ b/lib/browser_core.js
@@ -22,7 +22,7 @@ module.exports = class BrowserCore {
         }
 
         this.page.on('load', () => {
-            if(this._loaded) this._afterPageLoad();
+            if(this._loaded) return this._afterPageLoad().catch(() => {}); // Will fail if browser is closed
         });
     }
 
diff --git a/lib/mixins/browser_wait.js b/lib/mixins/browser_wait.js
index 6cbc4601..4a74d75b 100644
--- a/lib/mixins/browser_wait.js
+++ b/lib/mixins/browser_wait.js
@@ -25,7 +25,6 @@ module.exports = function BrowserWaitMixin(s) {
         }
 
         waitUntilNotVisible(selector, timeout = 500) {
-            this._failIfNotLoaded();
             return this.waitFor((selector) => {
                 const element = WendigoUtils.queryElement(selector);
                 return !WendigoUtils.isVisible(element);
@@ -35,7 +34,6 @@ module.exports = function BrowserWaitMixin(s) {
         }
 
         waitForUrl(url, timeout = 500) {
-            this._failIfNotLoaded();
             return this.waitFor((expectedUrl) => {
                 let currentUrl = window.location.href;
                 if(currentUrl === "about:blank") currentUrl = null;
diff --git a/tests/browser/value.test.js b/tests/browser/value.test.js
index 7aaf5e7c..face6014 100644
--- a/tests/browser/value.test.js
+++ b/tests/browser/value.test.js
@@ -60,7 +60,7 @@ describe("Value", function() {
     });
 
     it("Set Value Multiple Elements", async () => {
-        const changed = await browser.setValue("form input", "my-val");
+        const changed = await browser.setValue("form.basic-input input", "my-val");
         const value1 = await browser.value(".input1");
         const value2 = await browser.value(".input2");
         assert.strictEqual(value1, "my-val");
diff --git a/tests/browser/wait_for.test.js b/tests/browser/wait_for.test.js
index 033c3772..1897a5a2 100644
--- a/tests/browser/wait_for.test.js
+++ b/tests/browser/wait_for.test.js
@@ -107,7 +107,7 @@ describe("Wait For", function() {
         await browser.assert.url(configUrls.simple);
     });
 
-    it("Wait For Url", async () => {
+    it("Wait For Url Throws", async () => {
         await browser.open(configUrls.index);
         await browser.click("a");
         await utils.assertThrowsAsync (async () => {
diff --git a/tests/dummy_server/static/forms.html b/tests/dummy_server/static/forms.html
index edd8aa98..06175758 100644
--- a/tests/dummy_server/static/forms.html
+++ b/tests/dummy_server/static/forms.html
@@ -3,7 +3,7 @@
 
 <body>
     <h1>Main Title</h1>
-    <form>
+    <form class="basic-input">
         First Input: <input class="input1" name="firstname"> Last Input: <input class="input2" name="lastname" value="default value">
     </form>
     <p id="value-input"></p>
@@ -28,6 +28,12 @@ <h1>Main Title</h1>
         <input type="checkbox" value="car">Car<br>
     </div>
 
+    <form id="radio">
+        <input type="radio" name="test-select" value="bike" checked>Bike<br>
+        <input type="radio" name="test-select" value="car">Car<br>
+        <input type="radio" name="test-select" value="other"> Other
+    </form>
+
     <script>
         document.querySelector(".input1").onkeypress = function(ev) {
             document.getElementById("value-input").textContent = String.fromCharCode(ev.charCode)

From 4303cb23f3847e0cbd86d51eff8a42fc1d636a61 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9s?= <angrykoala@outlook.es>
Date: Fri, 1 Jun 2018 17:20:19 +0200
Subject: [PATCH 05/13] assert focus

---
 CHANGELOG.md                                  |  1 +
 README.md                                     | 18 ++++-
 lib/modules/assertions/browser_assertions.js  | 19 +++++
 .../assertions/browser_not_assertions.js      |  7 ++
 tests/assertions/assert_disabled.test.js      |  2 +-
 tests/assertions/assert_focus.test.js         | 77 +++++++++++++++++++
 tests/dummy_server/static/forms.html          |  6 --
 7 files changed, 122 insertions(+), 8 deletions(-)
 create mode 100644 tests/assertions/assert_focus.test.js

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9dbb3d1e..6c855b80 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
 0.7.4 / ####-##-##
 ==================
 
+  * Assert.focus
   * Fixed bug where navigation to a different page breaks some methods
 
 0.7.3 / 2018-06-01
diff --git a/README.md b/README.md
index 0d496329..a1ae8b91 100644
--- a/README.md
+++ b/README.md
@@ -573,6 +573,17 @@ Asserts that the first element matching the given selector is enabled (doesn't h
 
 > Css, Xpath and Dom selectors supported
 
+**focus(selector, msg?)**    
+Asserts that an element matching the given selector is focused.
+
+```js
+browser.click(".btn");
+browser.assert.focus(".btn");
+```
+
+> Css, Xpath and Dom selectors supported
+
+
 ### Negative assertions
 Most of the browser assertions have a negative version that can be used with `browser.assert.not`. Most of the "not" assertions are simply the inverse of the positive version.
 
@@ -594,7 +605,7 @@ If expected is an array, no element in it should match any element with given se
 await browser.assert.not.text("p", "This text doesn't exists");
 ```
 
-**textContains(selector, expected, msg?)**   
+**not.textContains(selector, expected, msg?)**   
 Asserts that no elements matching the given selector contain the expected text.
 
 ```js
@@ -685,6 +696,11 @@ Asserts that the first element matching the given selector is not enabled (same
 
 > Css, Xpath and Dom selectors supported
 
+**not.focus(selector, msg?)**    
+Asserts that none of the elements matching the given selector is focused.
+
+> Css, Xpath and Dom selectors supported
+
 ## Cookies
 The module `browser.cookies` provides a way to easily handle cookies through Puppeteer's api. All methods return Promises.
 
diff --git a/lib/modules/assertions/browser_assertions.js b/lib/modules/assertions/browser_assertions.js
index 5da4b9fc..1b11e077 100644
--- a/lib/modules/assertions/browser_assertions.js
+++ b/lib/modules/assertions/browser_assertions.js
@@ -304,6 +304,25 @@ module.exports = class BrowserAssertions extends BrowserModule {
             }
         });
     }
+
+    focus(selector, msg) {
+        return this._browser.evaluate((q) => {
+            const elements = WendigoUtils.queryAll(q);
+            if(elements.length === 0) return Promise.reject();
+            for(const el of elements) {
+                if(document.activeElement === el) return true;
+            }
+            return false;
+        }, selector).catch(() => {
+            const error = ErrorFactory.generateQueryError(`Element "${selector}" not found when trying to assert focus.`);
+            return Promise.reject(error);
+        }).then((focused) => {
+            if(!focused) {
+                if(!msg) msg = `Expected element "${selector}" to be focused.`;
+                return assertUtils.rejectAssertion(msg);
+            }
+        });
+    }
 };
 
 /* eslint-enable max-lines */
diff --git a/lib/modules/assertions/browser_not_assertions.js b/lib/modules/assertions/browser_not_assertions.js
index a80fc3a5..ffe72508 100644
--- a/lib/modules/assertions/browser_not_assertions.js
+++ b/lib/modules/assertions/browser_not_assertions.js
@@ -167,4 +167,11 @@ module.exports = class BrowserNotAssertions {
             return this._assertions.enabled(selector, "x");
         }, msg);
     }
+
+    focus(selector, msg) {
+        if(!msg) msg = `Expected element "${selector}" to be unfocused.`;
+        return assertUtils.invertify(() => {
+            return this._assertions.focus(selector, "x");
+        }, msg);
+    }
 };
diff --git a/tests/assertions/assert_disabled.test.js b/tests/assertions/assert_disabled.test.js
index b4409e8e..c9abd004 100644
--- a/tests/assertions/assert_disabled.test.js
+++ b/tests/assertions/assert_disabled.test.js
@@ -4,7 +4,7 @@ const Wendigo = require('../../lib/wendigo');
 const utils = require('../test_utils');
 const configUrls = require('../config.json').urls;
 
-describe("Assert Element", function() {
+describe("Assert Disabled", function() {
     this.timeout(5000);
     let browser;
 
diff --git a/tests/assertions/assert_focus.test.js b/tests/assertions/assert_focus.test.js
new file mode 100644
index 00000000..f9df7954
--- /dev/null
+++ b/tests/assertions/assert_focus.test.js
@@ -0,0 +1,77 @@
+"use strict";
+
+const Wendigo = require('../../lib/wendigo');
+const configUrls = require('../config.json').urls;
+const utils = require('../test_utils');
+
+describe("Assert Focus", function() {
+    this.timeout(5000);
+    let browser;
+
+    before(async () => {
+        browser = await Wendigo.createBrowser();
+    });
+    beforeEach(async () => {
+        await browser.open(configUrls.click);
+    });
+
+    it("Assert Focus", async () => {
+        await browser.click(".btn");
+        await browser.assert.focus(".btn");
+    });
+
+    it("Assert Focus Multiple Elements", async () => {
+        await browser.click(".btn");
+        await browser.assert.focus("button");
+    });
+
+    it("Assert Focus Throws", async () => {
+        await browser.click(".btn2");
+        await utils.assertThrowsAssertionAsync (async () => {
+            await browser.assert.focus(".btn");
+        }, `Expected element ".btn" to be focused.`);
+    });
+
+    it("Assert Focus Throws Custom Message", async () => {
+        await utils.assertThrowsAssertionAsync (async () => {
+            await browser.assert.focus(".btn", "focus fails");
+        }, `focus fails`);
+    });
+
+    it("Assert Focus Element Not Exist", async () => {
+        await utils.assertThrowsAsync (async () => {
+            await browser.assert.focus(".btn10");
+        }, `QueryError: Element ".btn10" not found when trying to assert focus.`);
+    });
+
+    it("Assert Not Focus", async () => {
+        await browser.assert.not.focus(".btn");
+    });
+
+    it("Assert Not Focus Throws", async () => {
+        await browser.click(".btn");
+        await utils.assertThrowsAssertionAsync (async () => {
+            await browser.assert.not.focus(".btn");
+        }, `Expected element ".btn" to be unfocused.`);
+    });
+
+    it("Assert Not Focus Throws Multiple Elements", async () => {
+        await browser.click(".btn");
+        await utils.assertThrowsAssertionAsync (async () => {
+            await browser.assert.not.focus("button");
+        }, `Expected element "button" to be unfocused.`);
+    });
+
+    it("Assert Not Focus Throws Custom Message", async () => {
+        await browser.click(".btn");
+        await utils.assertThrowsAssertionAsync (async () => {
+            await browser.assert.not.focus(".btn", "focus fails");
+        }, `focus fails`);
+    });
+
+    it("Assert Not Focus Element Not Exist", async () => {
+        await utils.assertThrowsAsync (async () => {
+            await browser.assert.not.focus(".btn10");
+        }, `QueryError: Element ".btn10" not found when trying to assert focus.`);
+    });
+});
diff --git a/tests/dummy_server/static/forms.html b/tests/dummy_server/static/forms.html
index 06175758..39a93300 100644
--- a/tests/dummy_server/static/forms.html
+++ b/tests/dummy_server/static/forms.html
@@ -28,12 +28,6 @@ <h1>Main Title</h1>
         <input type="checkbox" value="car">Car<br>
     </div>
 
-    <form id="radio">
-        <input type="radio" name="test-select" value="bike" checked>Bike<br>
-        <input type="radio" name="test-select" value="car">Car<br>
-        <input type="radio" name="test-select" value="other"> Other
-    </form>
-
     <script>
         document.querySelector(".input1").onkeypress = function(ev) {
             document.getElementById("value-input").textContent = String.fromCharCode(ev.charCode)

From 1115de17a7c4b8652b82db9e20546515489eb7d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9s?= <angrykoala@outlook.es>
Date: Fri, 1 Jun 2018 17:37:19 +0200
Subject: [PATCH 06/13] browser.focus, close #15

---
 CHANGELOG.md                  |  1 +
 README.md                     |  3 +++
 lib/mixins/browser_actions.js |  7 +++++++
 tests/browser/focus.test.js   | 36 +++++++++++++++++++++++++++++++++++
 4 files changed, 47 insertions(+)
 create mode 100644 tests/browser/focus.test.js

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6c855b80..1cee3278 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
 0.7.4 / ####-##-##
 ==================
 
+  * Browser.focus
   * Assert.focus
   * Fixed bug where navigation to a different page breaks some methods
 
diff --git a/README.md b/README.md
index a1ae8b91..1e001983 100644
--- a/README.md
+++ b/README.md
@@ -400,6 +400,9 @@ await browser.setViewport({width: 300});
 
 > Unlike Puppeteer setViewport, no parameter is required, as the current values will be used for the new viewport.
 
+**focus(selector)**
+Focus the first element matching the given selector
+
 ## Assert
 The submodule `browser.assert` provide some out-of-the-box assertions that can be used to easily write tests that are readable without having to specifically query for elements o perform evaluations. All the assertions have a last optional parameter (msg?) to define a custom assertion message.
 
diff --git a/lib/mixins/browser_actions.js b/lib/mixins/browser_actions.js
index 81442e93..5af3f400 100644
--- a/lib/mixins/browser_actions.js
+++ b/lib/mixins/browser_actions.js
@@ -125,7 +125,14 @@ module.exports = function BrowserActionsMixin(s) {
                 const error = ErrorFactory.generateQueryError(`Element "${selector}" not found when trying to uncheck.`);
                 return Promise.reject(error);
             });
+        }
 
+        focus(selector) {
+            this._failIfNotLoaded();
+            return this.page.focus(selector).catch(() => {
+                const error = ErrorFactory.generateQueryError(`Element "${selector}" not found when trying to focus.`);
+                return Promise.reject(error);
+            });
         }
     };
 };
diff --git a/tests/browser/focus.test.js b/tests/browser/focus.test.js
new file mode 100644
index 00000000..cce1070e
--- /dev/null
+++ b/tests/browser/focus.test.js
@@ -0,0 +1,36 @@
+"use strict";
+
+const Wendigo = require('../../lib/wendigo');
+const configUrls = require('../config.json').urls;
+const utils = require('../test_utils');
+
+
+describe("Focus", function() {
+    this.timeout(5000);
+    let browser;
+
+    before(async () => {
+        browser = await Wendigo.createBrowser();
+    });
+
+    beforeEach(async () => {
+        await browser.open(configUrls.click);
+    });
+
+    after(async () => {
+        await browser.close();
+    });
+
+    it("Focus", async () => {
+        await browser.click(".btn");
+        await browser.assert.not.focus(".btn2");
+        await browser.focus(".btn2");
+        await browser.assert.focus(".btn2");
+    });
+
+    it("Focus Not Existing Element", async () => {
+        await utils.assertThrowsAsync (async () => {
+            await browser.focus(".btn10");
+        }, `QueryError: Element ".btn10" not found when trying to focus.`);
+    });
+});

From 2acf2612d3c2cd1ad67dbe2578096d2b4c904940 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9s?= <angrykoala@outlook.es>
Date: Wed, 6 Jun 2018 19:39:12 +0200
Subject: [PATCH 07/13] changes in readme

---
 README.md | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 1e001983..d5a59a60 100644
--- a/README.md
+++ b/README.md
@@ -401,7 +401,9 @@ await browser.setViewport({width: 300});
 > Unlike Puppeteer setViewport, no parameter is required, as the current values will be used for the new viewport.
 
 **focus(selector)**
-Focus the first element matching the given selector
+Focus the first element matching the given selector.
+
+> Css, Xpath and Dom selectors supported
 
 ## Assert
 The submodule `browser.assert` provide some out-of-the-box assertions that can be used to easily write tests that are readable without having to specifically query for elements o perform evaluations. All the assertions have a last optional parameter (msg?) to define a custom assertion message.

From 9fdebc75623349a1093510d6f99aa30691ac1c84 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9s?= <angrykoala@outlook.es>
Date: Wed, 6 Jun 2018 19:52:46 +0200
Subject: [PATCH 08/13] objects accepted as mock response body, close #134

---
 CHANGELOG.md                                    |  1 +
 README.md                                       |  2 +-
 lib/request_mocker.js                           | 11 ++++++++++-
 tests/browser_components/request_mocker.test.js | 11 ++++++++++-
 4 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1cee3278..d04a6e97 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
 
   * Browser.focus
   * Assert.focus
+  * Request mock supports objects as response method
   * Fixed bug where navigation to a different page breaks some methods
 
 0.7.3 / 2018-06-01
diff --git a/README.md b/README.md
index d5a59a60..9039ff6c 100644
--- a/README.md
+++ b/README.md
@@ -830,7 +830,7 @@ Response is an object with the following attributes:
 * `status` Response status code, defaults to 200.
 * `headers` Optional response headers.
 * `contentType` If set, equals to setting Content-Type response header.
-* `body` Optional response body. This must be a string
+* `body` Optional response body. It can be a string or a json-serializable object
 
 > This object matches the interface with Puppeteer's [respond method](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#requestrespondresponse)
 
diff --git a/lib/request_mocker.js b/lib/request_mocker.js
index 265f4206..3b1b54c8 100644
--- a/lib/request_mocker.js
+++ b/lib/request_mocker.js
@@ -17,7 +17,7 @@ module.exports = class RequestMocker {
 
     mockRequest(url, response, method = RequestMethods.ALL) {
         const mockData = this._mockedRequests.get(url) || {};
-        mockData[method] = response;
+        mockData[method] = this._processMockedResponse(response);
         this._mockedRequests.set(url, mockData);
     }
 
@@ -35,4 +35,13 @@ module.exports = class RequestMocker {
         return mockData[method] || mockData[RequestMethods.ALL];
     }
 
+    _processMockedResponse(response) {
+        if(response.body) {
+            if(typeof response.body === "object") {
+                response.body = JSON.stringify(response.body);
+            }
+        }
+        return response;
+    }
+
 };
diff --git a/tests/browser_components/request_mocker.test.js b/tests/browser_components/request_mocker.test.js
index 6553fb90..af81c838 100644
--- a/tests/browser_components/request_mocker.test.js
+++ b/tests/browser_components/request_mocker.test.js
@@ -7,7 +7,7 @@ describe("Requests Mocker", function() {
     this.timeout(5000);
     let browser;
     const mockResponse = {
-        body: JSON.stringify({result: "MOCK"})
+        body: {result: "MOCK"}
     };
 
 
@@ -33,6 +33,15 @@ describe("Requests Mocker", function() {
         await browser.assert.text("#result", "MOCK");
     });
 
+    it("Mocked Request With String", async () => {
+        await browser.requests.mock(configUrls.api, {
+            body: JSON.stringify({result: "MOCK"})
+        });
+        await browser.clickText("click me");
+        await browser.wait(100);
+        await browser.assert.text("#result", "MOCK");
+    });
+
     it("Mocked Request With Method", async () => {
         await browser.requests.mock(configUrls.api, mockResponse, "GET");
         await browser.clickText("click me");

From 519d34714021d67da748c30f8e55807075b3eefe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9s?= <angrykoala@outlook.es>
Date: Thu, 7 Jun 2018 00:19:52 +0200
Subject: [PATCH 09/13] fixed type tests, close #135

---
 CHANGELOG.md                  |   9 +-
 README.md                     |   3 +
 lib/mixins/browser_actions.js |   4 +-
 package-lock.json             | 659 +++++++++++++++++-----------------
 tests/browser/type.test.js    |   4 +-
 5 files changed, 329 insertions(+), 350 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d04a6e97..5fb4ba1f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,17 +1,10 @@
-0.7.4 / ####-##-##
-==================
-
-  * Browser.focus
-  * Assert.focus
-  * Request mock supports objects as response method
-  * Fixed bug where navigation to a different page breaks some methods
-
 0.7.3 / 2018-06-01
 ==================
 
   * Assert.enabled and assert.disabled
   * WaitForUrl
   * Fixed assert.attribute with null expected
+  * Minor bugs in tests fixed
   * Dependencies update
 
 0.7.2 / 2017-05-03
diff --git a/README.md b/README.md
index 9039ff6c..78a885c9 100644
--- a/README.md
+++ b/README.md
@@ -1074,6 +1074,9 @@ test:
 ```
 _Example of .gitlab-ci.yml_
 
+### Assertion failed messages without error
+If you are using node@10 and puppeteer 1.4.0 or less, you may experience messages such as `Assertion failed: No node found for selector`, this is due to a change in how `console.assertion` works in node 10 and how puppeteer uses it, these messages won't affect the tests, if the messages are a big problem for you, consider downgrading your node.js version, upgrading puppeteer if possible or overriding console.assert: `console.assert=()=>{}`.
+
 > Remember to check [Puppeteer Troubleshooting](https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md)
 
 ## Acknowledgements
diff --git a/lib/mixins/browser_actions.js b/lib/mixins/browser_actions.js
index 5af3f400..92992686 100644
--- a/lib/mixins/browser_actions.js
+++ b/lib/mixins/browser_actions.js
@@ -19,8 +19,8 @@ module.exports = function BrowserActionsMixin(s) {
             this._failIfNotLoaded();
             if(!Array.isArray(key)) key = [key];
             const funcs = key.map(k => () => this.page.keyboard.press(k));
-            return utils.promiseSerial(funcs).catch((err) => {
-                return Promise.reject(new Error(err.message));
+            return utils.promiseSerial(funcs).catch(() => {
+                return Promise.reject(new Error(`Could not press keys "${key.join(", ")}"`));
             });
         }
 
diff --git a/package-lock.json b/package-lock.json
index 4e9e5802..aafc90b6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,14 +10,14 @@
       "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=",
       "dev": true,
       "requires": {
-        "mime-types": "~2.1.18",
+        "mime-types": "2.1.18",
         "negotiator": "0.6.1"
       }
     },
     "acorn": {
-      "version": "5.5.3",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz",
-      "integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==",
+      "version": "5.6.2",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.6.2.tgz",
+      "integrity": "sha512-zUzo1E5dI2Ey8+82egfnttyMlMZ2y0D8xOCO3PNPPlYXpl8NZvF6Qk9L9BEtJs+43FqEmfBViDqc5d1ckRDguw==",
       "dev": true
     },
     "acorn-jsx": {
@@ -26,7 +26,7 @@
       "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
       "dev": true,
       "requires": {
-        "acorn": "^3.0.4"
+        "acorn": "3.3.0"
       },
       "dependencies": {
         "acorn": {
@@ -42,7 +42,7 @@
       "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.0.tgz",
       "integrity": "sha512-c+R/U5X+2zz2+UCrCFv6odQzJdoqI+YecuhnAJLa1zYaMc13zPfwMwZrr91Pd1DYNo/yPRbiM4WVf9whgwFsIg==",
       "requires": {
-        "es6-promisify": "^5.0.0"
+        "es6-promisify": "5.0.0"
       }
     },
     "ajv": {
@@ -51,10 +51,10 @@
       "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
       "dev": true,
       "requires": {
-        "co": "^4.6.0",
-        "fast-deep-equal": "^1.0.0",
-        "fast-json-stable-stringify": "^2.0.0",
-        "json-schema-traverse": "^0.3.0"
+        "co": "4.6.0",
+        "fast-deep-equal": "1.1.0",
+        "fast-json-stable-stringify": "2.0.0",
+        "json-schema-traverse": "0.3.1"
       }
     },
     "ajv-keywords": {
@@ -87,7 +87,7 @@
       "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
       "dev": true,
       "requires": {
-        "sprintf-js": "~1.0.2"
+        "sprintf-js": "1.0.3"
       }
     },
     "array-flatten": {
@@ -102,7 +102,7 @@
       "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
       "dev": true,
       "requires": {
-        "array-uniq": "^1.0.1"
+        "array-uniq": "1.0.3"
       }
     },
     "array-uniq": {
@@ -128,9 +128,9 @@
       "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
       "dev": true,
       "requires": {
-        "chalk": "^1.1.3",
-        "esutils": "^2.0.2",
-        "js-tokens": "^3.0.2"
+        "chalk": "1.1.3",
+        "esutils": "2.0.2",
+        "js-tokens": "3.0.2"
       },
       "dependencies": {
         "chalk": {
@@ -139,11 +139,11 @@
           "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
           "dev": true,
           "requires": {
-            "ansi-styles": "^2.2.1",
-            "escape-string-regexp": "^1.0.2",
-            "has-ansi": "^2.0.0",
-            "strip-ansi": "^3.0.0",
-            "supports-color": "^2.0.0"
+            "ansi-styles": "2.2.1",
+            "escape-string-regexp": "1.0.5",
+            "has-ansi": "2.0.0",
+            "strip-ansi": "3.0.1",
+            "supports-color": "2.0.0"
           }
         },
         "strip-ansi": {
@@ -152,7 +152,7 @@
           "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
           "dev": true,
           "requires": {
-            "ansi-regex": "^2.0.0"
+            "ansi-regex": "2.1.1"
           }
         }
       }
@@ -169,17 +169,26 @@
       "dev": true,
       "requires": {
         "bytes": "3.0.0",
-        "content-type": "~1.0.4",
+        "content-type": "1.0.4",
         "debug": "2.6.9",
-        "depd": "~1.1.1",
-        "http-errors": "~1.6.2",
+        "depd": "1.1.2",
+        "http-errors": "1.6.3",
         "iconv-lite": "0.4.19",
-        "on-finished": "~2.3.0",
+        "on-finished": "2.3.0",
         "qs": "6.5.1",
         "raw-body": "2.3.2",
-        "type-is": "~1.6.15"
+        "type-is": "1.6.16"
       },
       "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
         "iconv-lite": {
           "version": "0.4.19",
           "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
@@ -193,7 +202,7 @@
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
       "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
       "requires": {
-        "balanced-match": "^1.0.0",
+        "balanced-match": "1.0.0",
         "concat-map": "0.0.1"
       }
     },
@@ -204,9 +213,9 @@
       "dev": true
     },
     "buffer-from": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz",
-      "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA=="
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz",
+      "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ=="
     },
     "bytes": {
       "version": "3.0.0",
@@ -220,7 +229,7 @@
       "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
       "dev": true,
       "requires": {
-        "callsites": "^0.2.0"
+        "callsites": "0.2.0"
       }
     },
     "callsites": {
@@ -230,14 +239,14 @@
       "dev": true
     },
     "chalk": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.0.tgz",
-      "integrity": "sha512-Wr/w0f4o9LuE7K53cD0qmbAMM+2XNLzR29vFn5hqko4sxGlUsyy363NvmyGIyk5tpe9cjTr9SJYbysEyPkRnFw==",
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+      "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
       "dev": true,
       "requires": {
-        "ansi-styles": "^3.2.1",
-        "escape-string-regexp": "^1.0.5",
-        "supports-color": "^5.3.0"
+        "ansi-styles": "3.2.1",
+        "escape-string-regexp": "1.0.5",
+        "supports-color": "5.4.0"
       },
       "dependencies": {
         "ansi-styles": {
@@ -246,7 +255,7 @@
           "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
           "dev": true,
           "requires": {
-            "color-convert": "^1.9.0"
+            "color-convert": "1.9.1"
           }
         },
         "supports-color": {
@@ -255,7 +264,7 @@
           "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
           "dev": true,
           "requires": {
-            "has-flag": "^3.0.0"
+            "has-flag": "3.0.0"
           }
         }
       }
@@ -278,7 +287,7 @@
       "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
       "dev": true,
       "requires": {
-        "restore-cursor": "^2.0.0"
+        "restore-cursor": "2.0.0"
       }
     },
     "cli-width": {
@@ -299,7 +308,7 @@
       "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
       "dev": true,
       "requires": {
-        "color-name": "^1.1.1"
+        "color-name": "1.1.3"
       }
     },
     "color-name": {
@@ -325,14 +334,14 @@
       "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
     },
     "concat-stream": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz",
-      "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=",
-      "dev": true,
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
       "requires": {
-        "inherits": "^2.0.3",
-        "readable-stream": "^2.2.2",
-        "typedarray": "^0.0.6"
+        "buffer-from": "1.1.0",
+        "inherits": "2.0.3",
+        "readable-stream": "2.3.6",
+        "typedarray": "0.0.6"
       }
     },
     "content-disposition": {
@@ -370,15 +379,15 @@
       "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
       "dev": true,
       "requires": {
-        "lru-cache": "^4.0.1",
-        "shebang-command": "^1.2.0",
-        "which": "^1.2.9"
+        "lru-cache": "4.1.3",
+        "shebang-command": "1.2.0",
+        "which": "1.3.1"
       }
     },
     "debug": {
-      "version": "2.6.9",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+      "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
       "requires": {
         "ms": "2.0.0"
       }
@@ -400,13 +409,13 @@
       "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
       "dev": true,
       "requires": {
-        "globby": "^5.0.0",
-        "is-path-cwd": "^1.0.0",
-        "is-path-in-cwd": "^1.0.0",
-        "object-assign": "^4.0.1",
-        "pify": "^2.0.0",
-        "pinkie-promise": "^2.0.0",
-        "rimraf": "^2.2.8"
+        "globby": "5.0.0",
+        "is-path-cwd": "1.0.0",
+        "is-path-in-cwd": "1.0.1",
+        "object-assign": "4.1.1",
+        "pify": "2.3.0",
+        "pinkie-promise": "2.0.1",
+        "rimraf": "2.6.2"
       }
     },
     "depd": {
@@ -433,7 +442,7 @@
       "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
       "dev": true,
       "requires": {
-        "esutils": "^2.0.2"
+        "esutils": "2.0.2"
       }
     },
     "ee-first": {
@@ -458,7 +467,7 @@
       "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
       "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
       "requires": {
-        "es6-promise": "^4.0.3"
+        "es6-promise": "4.2.4"
       }
     },
     "escape-html": {
@@ -479,64 +488,44 @@
       "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==",
       "dev": true,
       "requires": {
-        "ajv": "^5.3.0",
-        "babel-code-frame": "^6.22.0",
-        "chalk": "^2.1.0",
-        "concat-stream": "^1.6.0",
-        "cross-spawn": "^5.1.0",
-        "debug": "^3.1.0",
-        "doctrine": "^2.1.0",
-        "eslint-scope": "^3.7.1",
-        "eslint-visitor-keys": "^1.0.0",
-        "espree": "^3.5.4",
-        "esquery": "^1.0.0",
-        "esutils": "^2.0.2",
-        "file-entry-cache": "^2.0.0",
-        "functional-red-black-tree": "^1.0.1",
-        "glob": "^7.1.2",
-        "globals": "^11.0.1",
-        "ignore": "^3.3.3",
-        "imurmurhash": "^0.1.4",
-        "inquirer": "^3.0.6",
-        "is-resolvable": "^1.0.0",
-        "js-yaml": "^3.9.1",
-        "json-stable-stringify-without-jsonify": "^1.0.1",
-        "levn": "^0.3.0",
-        "lodash": "^4.17.4",
-        "minimatch": "^3.0.2",
-        "mkdirp": "^0.5.1",
-        "natural-compare": "^1.4.0",
-        "optionator": "^0.8.2",
-        "path-is-inside": "^1.0.2",
-        "pluralize": "^7.0.0",
-        "progress": "^2.0.0",
-        "regexpp": "^1.0.1",
-        "require-uncached": "^1.0.3",
-        "semver": "^5.3.0",
-        "strip-ansi": "^4.0.0",
-        "strip-json-comments": "~2.0.1",
+        "ajv": "5.5.2",
+        "babel-code-frame": "6.26.0",
+        "chalk": "2.4.1",
+        "concat-stream": "1.6.2",
+        "cross-spawn": "5.1.0",
+        "debug": "3.1.0",
+        "doctrine": "2.1.0",
+        "eslint-scope": "3.7.1",
+        "eslint-visitor-keys": "1.0.0",
+        "espree": "3.5.4",
+        "esquery": "1.0.1",
+        "esutils": "2.0.2",
+        "file-entry-cache": "2.0.0",
+        "functional-red-black-tree": "1.0.1",
+        "glob": "7.1.2",
+        "globals": "11.5.0",
+        "ignore": "3.3.8",
+        "imurmurhash": "0.1.4",
+        "inquirer": "3.3.0",
+        "is-resolvable": "1.1.0",
+        "js-yaml": "3.12.0",
+        "json-stable-stringify-without-jsonify": "1.0.1",
+        "levn": "0.3.0",
+        "lodash": "4.17.10",
+        "minimatch": "3.0.4",
+        "mkdirp": "0.5.1",
+        "natural-compare": "1.4.0",
+        "optionator": "0.8.2",
+        "path-is-inside": "1.0.2",
+        "pluralize": "7.0.0",
+        "progress": "2.0.0",
+        "regexpp": "1.1.0",
+        "require-uncached": "1.0.3",
+        "semver": "5.5.0",
+        "strip-ansi": "4.0.0",
+        "strip-json-comments": "2.0.1",
         "table": "4.0.2",
-        "text-table": "~0.2.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
-          "dev": true,
-          "requires": {
-            "ms": "2.0.0"
-          }
-        },
-        "mkdirp": {
-          "version": "0.5.1",
-          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
-          "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
-          "dev": true,
-          "requires": {
-            "minimist": "0.0.8"
-          }
-        }
+        "text-table": "0.2.0"
       }
     },
     "eslint-scope": {
@@ -545,8 +534,8 @@
       "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=",
       "dev": true,
       "requires": {
-        "esrecurse": "^4.1.0",
-        "estraverse": "^4.1.1"
+        "esrecurse": "4.2.1",
+        "estraverse": "4.2.0"
       }
     },
     "eslint-visitor-keys": {
@@ -561,8 +550,8 @@
       "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==",
       "dev": true,
       "requires": {
-        "acorn": "^5.5.0",
-        "acorn-jsx": "^3.0.0"
+        "acorn": "5.6.2",
+        "acorn-jsx": "3.0.1"
       }
     },
     "esprima": {
@@ -577,7 +566,7 @@
       "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==",
       "dev": true,
       "requires": {
-        "estraverse": "^4.0.0"
+        "estraverse": "4.2.0"
       }
     },
     "esrecurse": {
@@ -586,7 +575,7 @@
       "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
       "dev": true,
       "requires": {
-        "estraverse": "^4.1.0"
+        "estraverse": "4.2.0"
       }
     },
     "estraverse": {
@@ -613,36 +602,53 @@
       "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=",
       "dev": true,
       "requires": {
-        "accepts": "~1.3.5",
+        "accepts": "1.3.5",
         "array-flatten": "1.1.1",
         "body-parser": "1.18.2",
         "content-disposition": "0.5.2",
-        "content-type": "~1.0.4",
+        "content-type": "1.0.4",
         "cookie": "0.3.1",
         "cookie-signature": "1.0.6",
         "debug": "2.6.9",
-        "depd": "~1.1.2",
-        "encodeurl": "~1.0.2",
-        "escape-html": "~1.0.3",
-        "etag": "~1.8.1",
+        "depd": "1.1.2",
+        "encodeurl": "1.0.2",
+        "escape-html": "1.0.3",
+        "etag": "1.8.1",
         "finalhandler": "1.1.1",
         "fresh": "0.5.2",
         "merge-descriptors": "1.0.1",
-        "methods": "~1.1.2",
-        "on-finished": "~2.3.0",
-        "parseurl": "~1.3.2",
+        "methods": "1.1.2",
+        "on-finished": "2.3.0",
+        "parseurl": "1.3.2",
         "path-to-regexp": "0.1.7",
-        "proxy-addr": "~2.0.3",
+        "proxy-addr": "2.0.3",
         "qs": "6.5.1",
-        "range-parser": "~1.2.0",
+        "range-parser": "1.2.0",
         "safe-buffer": "5.1.1",
         "send": "0.16.2",
         "serve-static": "1.13.2",
         "setprototypeof": "1.1.0",
-        "statuses": "~1.4.0",
-        "type-is": "~1.6.16",
+        "statuses": "1.4.0",
+        "type-is": "1.6.16",
         "utils-merge": "1.0.1",
-        "vary": "~1.1.2"
+        "vary": "1.1.2"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "safe-buffer": {
+          "version": "5.1.1",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+          "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
+          "dev": true
+        }
       }
     },
     "external-editor": {
@@ -651,9 +657,9 @@
       "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
       "dev": true,
       "requires": {
-        "chardet": "^0.4.0",
-        "iconv-lite": "^0.4.17",
-        "tmp": "^0.0.33"
+        "chardet": "0.4.2",
+        "iconv-lite": "0.4.23",
+        "tmp": "0.0.33"
       }
     },
     "extract-zip": {
@@ -667,15 +673,12 @@
         "yauzl": "2.4.1"
       },
       "dependencies": {
-        "concat-stream": {
-          "version": "1.6.2",
-          "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
-          "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
           "requires": {
-            "buffer-from": "^1.0.0",
-            "inherits": "^2.0.3",
-            "readable-stream": "^2.2.2",
-            "typedarray": "^0.0.6"
+            "ms": "2.0.0"
           }
         }
       }
@@ -703,7 +706,7 @@
       "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
       "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
       "requires": {
-        "pend": "~1.2.0"
+        "pend": "1.2.0"
       }
     },
     "figures": {
@@ -712,7 +715,7 @@
       "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
       "dev": true,
       "requires": {
-        "escape-string-regexp": "^1.0.5"
+        "escape-string-regexp": "1.0.5"
       }
     },
     "file-entry-cache": {
@@ -721,8 +724,8 @@
       "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
       "dev": true,
       "requires": {
-        "flat-cache": "^1.2.1",
-        "object-assign": "^4.0.1"
+        "flat-cache": "1.3.0",
+        "object-assign": "4.1.1"
       }
     },
     "finalhandler": {
@@ -732,12 +735,23 @@
       "dev": true,
       "requires": {
         "debug": "2.6.9",
-        "encodeurl": "~1.0.2",
-        "escape-html": "~1.0.3",
-        "on-finished": "~2.3.0",
-        "parseurl": "~1.3.2",
-        "statuses": "~1.4.0",
-        "unpipe": "~1.0.0"
+        "encodeurl": "1.0.2",
+        "escape-html": "1.0.3",
+        "on-finished": "2.3.0",
+        "parseurl": "1.3.2",
+        "statuses": "1.4.0",
+        "unpipe": "1.0.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        }
       }
     },
     "flat-cache": {
@@ -746,10 +760,10 @@
       "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=",
       "dev": true,
       "requires": {
-        "circular-json": "^0.3.1",
-        "del": "^2.0.2",
-        "graceful-fs": "^4.1.2",
-        "write": "^0.2.1"
+        "circular-json": "0.3.3",
+        "del": "2.2.2",
+        "graceful-fs": "4.1.11",
+        "write": "0.2.1"
       }
     },
     "forwarded": {
@@ -780,18 +794,18 @@
       "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
       "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
       "requires": {
-        "fs.realpath": "^1.0.0",
-        "inflight": "^1.0.4",
-        "inherits": "2",
-        "minimatch": "^3.0.4",
-        "once": "^1.3.0",
-        "path-is-absolute": "^1.0.0"
+        "fs.realpath": "1.0.0",
+        "inflight": "1.0.6",
+        "inherits": "2.0.3",
+        "minimatch": "3.0.4",
+        "once": "1.4.0",
+        "path-is-absolute": "1.0.1"
       }
     },
     "globals": {
-      "version": "11.4.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-11.4.0.tgz",
-      "integrity": "sha512-Dyzmifil8n/TmSqYDEXbm+C8yitzJQqQIlJQLNRMwa+BOUJpRC19pyVeN12JAjt61xonvXjtff+hJruTRXn5HA==",
+      "version": "11.5.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-11.5.0.tgz",
+      "integrity": "sha512-hYyf+kI8dm3nORsiiXUQigOU62hDLfJ9G01uyGMxhc6BKsircrUhC4uJPQPUSuq2GrTmiiEt7ewxlMdBewfmKQ==",
       "dev": true
     },
     "globby": {
@@ -800,12 +814,12 @@
       "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
       "dev": true,
       "requires": {
-        "array-union": "^1.0.1",
-        "arrify": "^1.0.0",
-        "glob": "^7.0.3",
-        "object-assign": "^4.0.1",
-        "pify": "^2.0.0",
-        "pinkie-promise": "^2.0.0"
+        "array-union": "1.0.2",
+        "arrify": "1.0.1",
+        "glob": "7.1.2",
+        "object-assign": "4.1.1",
+        "pify": "2.3.0",
+        "pinkie-promise": "2.0.1"
       }
     },
     "graceful-fs": {
@@ -826,7 +840,7 @@
       "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
       "dev": true,
       "requires": {
-        "ansi-regex": "^2.0.0"
+        "ansi-regex": "2.1.1"
       }
     },
     "has-flag": {
@@ -847,10 +861,10 @@
       "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
       "dev": true,
       "requires": {
-        "depd": "~1.1.2",
+        "depd": "1.1.2",
         "inherits": "2.0.3",
         "setprototypeof": "1.1.0",
-        "statuses": ">= 1.4.0 < 2"
+        "statuses": "1.4.0"
       }
     },
     "https-proxy-agent": {
@@ -858,33 +872,23 @@
       "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz",
       "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==",
       "requires": {
-        "agent-base": "^4.1.0",
-        "debug": "^3.1.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
-          "requires": {
-            "ms": "2.0.0"
-          }
-        }
+        "agent-base": "4.2.0",
+        "debug": "3.1.0"
       }
     },
     "iconv-lite": {
-      "version": "0.4.21",
-      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.21.tgz",
-      "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==",
+      "version": "0.4.23",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
+      "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
       "dev": true,
       "requires": {
-        "safer-buffer": "^2.1.0"
+        "safer-buffer": "2.1.2"
       }
     },
     "ignore": {
-      "version": "3.3.7",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz",
-      "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==",
+      "version": "3.3.8",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.8.tgz",
+      "integrity": "sha512-pUh+xUQQhQzevjRHHFqqcTy0/dP/kS9I8HSrUydhihjuD09W6ldVWFtIrwhXdUJHis3i2rZNqEHpZH/cbinFbg==",
       "dev": true
     },
     "imurmurhash": {
@@ -898,8 +902,8 @@
       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
       "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
       "requires": {
-        "once": "^1.3.0",
-        "wrappy": "1"
+        "once": "1.4.0",
+        "wrappy": "1.0.2"
       }
     },
     "inherits": {
@@ -913,20 +917,20 @@
       "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==",
       "dev": true,
       "requires": {
-        "ansi-escapes": "^3.0.0",
-        "chalk": "^2.0.0",
-        "cli-cursor": "^2.1.0",
-        "cli-width": "^2.0.0",
-        "external-editor": "^2.0.4",
-        "figures": "^2.0.0",
-        "lodash": "^4.3.0",
+        "ansi-escapes": "3.1.0",
+        "chalk": "2.4.1",
+        "cli-cursor": "2.1.0",
+        "cli-width": "2.2.0",
+        "external-editor": "2.2.0",
+        "figures": "2.0.0",
+        "lodash": "4.17.10",
         "mute-stream": "0.0.7",
-        "run-async": "^2.2.0",
-        "rx-lite": "^4.0.8",
-        "rx-lite-aggregates": "^4.0.8",
-        "string-width": "^2.1.0",
-        "strip-ansi": "^4.0.0",
-        "through": "^2.3.6"
+        "run-async": "2.3.0",
+        "rx-lite": "4.0.8",
+        "rx-lite-aggregates": "4.0.8",
+        "string-width": "2.1.1",
+        "strip-ansi": "4.0.0",
+        "through": "2.3.8"
       }
     },
     "ipaddr.js": {
@@ -953,7 +957,7 @@
       "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
       "dev": true,
       "requires": {
-        "is-path-inside": "^1.0.0"
+        "is-path-inside": "1.0.1"
       }
     },
     "is-path-inside": {
@@ -962,7 +966,7 @@
       "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
       "dev": true,
       "requires": {
-        "path-is-inside": "^1.0.1"
+        "path-is-inside": "1.0.2"
       }
     },
     "is-promise": {
@@ -995,13 +999,13 @@
       "dev": true
     },
     "js-yaml": {
-      "version": "3.11.0",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.11.0.tgz",
-      "integrity": "sha512-saJstZWv7oNeOyBh3+Dx1qWzhW0+e6/8eDzo7p5rDFqxntSztloLtuKu+Ejhtq82jsilwOIZYsCz+lIjthg1Hw==",
+      "version": "3.12.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
+      "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
       "dev": true,
       "requires": {
-        "argparse": "^1.0.7",
-        "esprima": "^4.0.0"
+        "argparse": "1.0.10",
+        "esprima": "4.0.0"
       }
     },
     "json-schema-traverse": {
@@ -1022,24 +1026,24 @@
       "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
       "dev": true,
       "requires": {
-        "prelude-ls": "~1.1.2",
-        "type-check": "~0.3.2"
+        "prelude-ls": "1.1.2",
+        "type-check": "0.3.2"
       }
     },
     "lodash": {
-      "version": "4.17.5",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz",
-      "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==",
+      "version": "4.17.10",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+      "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
       "dev": true
     },
     "lru-cache": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz",
-      "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==",
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz",
+      "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==",
       "dev": true,
       "requires": {
-        "pseudomap": "^1.0.2",
-        "yallist": "^2.1.2"
+        "pseudomap": "1.0.2",
+        "yallist": "2.1.2"
       }
     },
     "media-typer": {
@@ -1077,7 +1081,7 @@
       "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
       "dev": true,
       "requires": {
-        "mime-db": "~1.33.0"
+        "mime-db": "1.33.0"
       }
     },
     "mimic-fn": {
@@ -1091,7 +1095,7 @@
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
       "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
       "requires": {
-        "brace-expansion": "^1.1.7"
+        "brace-expansion": "1.1.11"
       }
     },
     "minimist": {
@@ -1131,22 +1135,13 @@
         "supports-color": "5.4.0"
       },
       "dependencies": {
-        "debug": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
-          "dev": true,
-          "requires": {
-            "ms": "2.0.0"
-          }
-        },
         "supports-color": {
           "version": "5.4.0",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
           "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
           "dev": true,
           "requires": {
-            "has-flag": "^3.0.0"
+            "has-flag": "3.0.0"
           }
         }
       }
@@ -1194,7 +1189,7 @@
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
       "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
       "requires": {
-        "wrappy": "1"
+        "wrappy": "1.0.2"
       }
     },
     "onetime": {
@@ -1203,7 +1198,7 @@
       "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
       "dev": true,
       "requires": {
-        "mimic-fn": "^1.0.0"
+        "mimic-fn": "1.2.0"
       }
     },
     "optionator": {
@@ -1212,12 +1207,12 @@
       "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
       "dev": true,
       "requires": {
-        "deep-is": "~0.1.3",
-        "fast-levenshtein": "~2.0.4",
-        "levn": "~0.3.0",
-        "prelude-ls": "~1.1.2",
-        "type-check": "~0.3.2",
-        "wordwrap": "~1.0.0"
+        "deep-is": "0.1.3",
+        "fast-levenshtein": "2.0.6",
+        "levn": "0.3.0",
+        "prelude-ls": "1.1.2",
+        "type-check": "0.3.2",
+        "wordwrap": "1.0.0"
       }
     },
     "os-tmpdir": {
@@ -1272,7 +1267,7 @@
       "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
       "dev": true,
       "requires": {
-        "pinkie": "^2.0.0"
+        "pinkie": "2.0.4"
       }
     },
     "pluralize": {
@@ -1303,7 +1298,7 @@
       "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==",
       "dev": true,
       "requires": {
-        "forwarded": "~0.1.2",
+        "forwarded": "0.1.2",
         "ipaddr.js": "1.6.0"
       }
     },
@@ -1323,24 +1318,14 @@
       "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.4.0.tgz",
       "integrity": "sha512-WDnC1FSHTedvRSS8BZB73tPAx2svUCWFdcxVjrybw8pbKOAB1v5S/pW0EamkqQoL1mXiBc+v8lyYjhhzMHIk1Q==",
       "requires": {
-        "debug": "^3.1.0",
-        "extract-zip": "^1.6.5",
-        "https-proxy-agent": "^2.1.0",
-        "mime": "^2.0.3",
-        "progress": "^2.0.0",
-        "proxy-from-env": "^1.0.0",
-        "rimraf": "^2.6.1",
-        "ws": "^3.0.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
-          "requires": {
-            "ms": "2.0.0"
-          }
-        }
+        "debug": "3.1.0",
+        "extract-zip": "1.6.7",
+        "https-proxy-agent": "2.2.1",
+        "mime": "2.3.1",
+        "progress": "2.0.0",
+        "proxy-from-env": "1.0.0",
+        "rimraf": "2.6.2",
+        "ws": "3.3.3"
       }
     },
     "qs": {
@@ -1382,7 +1367,7 @@
             "depd": "1.1.1",
             "inherits": "2.0.3",
             "setprototypeof": "1.0.3",
-            "statuses": ">= 1.3.1 < 2"
+            "statuses": "1.4.0"
           }
         },
         "iconv-lite": {
@@ -1404,13 +1389,13 @@
       "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
       "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
       "requires": {
-        "core-util-is": "~1.0.0",
-        "inherits": "~2.0.3",
-        "isarray": "~1.0.0",
-        "process-nextick-args": "~2.0.0",
-        "safe-buffer": "~5.1.1",
-        "string_decoder": "~1.1.1",
-        "util-deprecate": "~1.0.1"
+        "core-util-is": "1.0.2",
+        "inherits": "2.0.3",
+        "isarray": "1.0.0",
+        "process-nextick-args": "2.0.0",
+        "safe-buffer": "5.1.2",
+        "string_decoder": "1.1.1",
+        "util-deprecate": "1.0.2"
       }
     },
     "regexpp": {
@@ -1425,8 +1410,8 @@
       "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
       "dev": true,
       "requires": {
-        "caller-path": "^0.1.0",
-        "resolve-from": "^1.0.0"
+        "caller-path": "0.1.0",
+        "resolve-from": "1.0.1"
       }
     },
     "resolve-from": {
@@ -1441,8 +1426,8 @@
       "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
       "dev": true,
       "requires": {
-        "onetime": "^2.0.0",
-        "signal-exit": "^3.0.2"
+        "onetime": "2.0.1",
+        "signal-exit": "3.0.2"
       }
     },
     "rimraf": {
@@ -1450,7 +1435,7 @@
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
       "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
       "requires": {
-        "glob": "^7.0.5"
+        "glob": "7.1.2"
       }
     },
     "run-async": {
@@ -1459,7 +1444,7 @@
       "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
       "dev": true,
       "requires": {
-        "is-promise": "^2.1.0"
+        "is-promise": "2.1.0"
       }
     },
     "rx-lite": {
@@ -1474,13 +1459,13 @@
       "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=",
       "dev": true,
       "requires": {
-        "rx-lite": "*"
+        "rx-lite": "4.0.8"
       }
     },
     "safe-buffer": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
-      "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
     },
     "safer-buffer": {
       "version": "2.1.2",
@@ -1501,20 +1486,29 @@
       "dev": true,
       "requires": {
         "debug": "2.6.9",
-        "depd": "~1.1.2",
-        "destroy": "~1.0.4",
-        "encodeurl": "~1.0.2",
-        "escape-html": "~1.0.3",
-        "etag": "~1.8.1",
+        "depd": "1.1.2",
+        "destroy": "1.0.4",
+        "encodeurl": "1.0.2",
+        "escape-html": "1.0.3",
+        "etag": "1.8.1",
         "fresh": "0.5.2",
-        "http-errors": "~1.6.2",
+        "http-errors": "1.6.3",
         "mime": "1.4.1",
         "ms": "2.0.0",
-        "on-finished": "~2.3.0",
-        "range-parser": "~1.2.0",
-        "statuses": "~1.4.0"
+        "on-finished": "2.3.0",
+        "range-parser": "1.2.0",
+        "statuses": "1.4.0"
       },
       "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
         "mime": {
           "version": "1.4.1",
           "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
@@ -1529,9 +1523,9 @@
       "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==",
       "dev": true,
       "requires": {
-        "encodeurl": "~1.0.2",
-        "escape-html": "~1.0.3",
-        "parseurl": "~1.3.2",
+        "encodeurl": "1.0.2",
+        "escape-html": "1.0.3",
+        "parseurl": "1.3.2",
         "send": "0.16.2"
       }
     },
@@ -1547,7 +1541,7 @@
       "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
       "dev": true,
       "requires": {
-        "shebang-regex": "^1.0.0"
+        "shebang-regex": "1.0.0"
       }
     },
     "shebang-regex": {
@@ -1568,7 +1562,7 @@
       "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==",
       "dev": true,
       "requires": {
-        "is-fullwidth-code-point": "^2.0.0"
+        "is-fullwidth-code-point": "2.0.0"
       }
     },
     "sprintf-js": {
@@ -1589,8 +1583,8 @@
       "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
       "dev": true,
       "requires": {
-        "is-fullwidth-code-point": "^2.0.0",
-        "strip-ansi": "^4.0.0"
+        "is-fullwidth-code-point": "2.0.0",
+        "strip-ansi": "4.0.0"
       }
     },
     "string_decoder": {
@@ -1598,7 +1592,7 @@
       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
       "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
       "requires": {
-        "safe-buffer": "~5.1.0"
+        "safe-buffer": "5.1.2"
       }
     },
     "strip-ansi": {
@@ -1607,7 +1601,7 @@
       "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
       "dev": true,
       "requires": {
-        "ansi-regex": "^3.0.0"
+        "ansi-regex": "3.0.0"
       },
       "dependencies": {
         "ansi-regex": {
@@ -1636,12 +1630,12 @@
       "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==",
       "dev": true,
       "requires": {
-        "ajv": "^5.2.3",
-        "ajv-keywords": "^2.1.0",
-        "chalk": "^2.1.0",
-        "lodash": "^4.17.4",
+        "ajv": "5.5.2",
+        "ajv-keywords": "2.1.1",
+        "chalk": "2.4.1",
+        "lodash": "4.17.10",
         "slice-ansi": "1.0.0",
-        "string-width": "^2.1.1"
+        "string-width": "2.1.1"
       }
     },
     "text-table": {
@@ -1662,7 +1656,7 @@
       "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
       "dev": true,
       "requires": {
-        "os-tmpdir": "~1.0.2"
+        "os-tmpdir": "1.0.2"
       }
     },
     "type-check": {
@@ -1671,7 +1665,7 @@
       "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
       "dev": true,
       "requires": {
-        "prelude-ls": "~1.1.2"
+        "prelude-ls": "1.1.2"
       }
     },
     "type-is": {
@@ -1681,7 +1675,7 @@
       "dev": true,
       "requires": {
         "media-typer": "0.3.0",
-        "mime-types": "~2.1.18"
+        "mime-types": "2.1.18"
       }
     },
     "typedarray": {
@@ -1718,12 +1712,12 @@
       "dev": true
     },
     "which": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
-      "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==",
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
       "dev": true,
       "requires": {
-        "isexe": "^2.0.0"
+        "isexe": "2.0.0"
       }
     },
     "wordwrap": {
@@ -1743,18 +1737,7 @@
       "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
       "dev": true,
       "requires": {
-        "mkdirp": "^0.5.1"
-      },
-      "dependencies": {
-        "mkdirp": {
-          "version": "0.5.1",
-          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
-          "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
-          "dev": true,
-          "requires": {
-            "minimist": "0.0.8"
-          }
-        }
+        "mkdirp": "0.5.1"
       }
     },
     "ws": {
@@ -1762,9 +1745,9 @@
       "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
       "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
       "requires": {
-        "async-limiter": "~1.0.0",
-        "safe-buffer": "~5.1.0",
-        "ultron": "~1.1.0"
+        "async-limiter": "1.0.0",
+        "safe-buffer": "5.1.2",
+        "ultron": "1.1.1"
       }
     },
     "yallist": {
@@ -1778,7 +1761,7 @@
       "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
       "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=",
       "requires": {
-        "fd-slicer": "~1.0.1"
+        "fd-slicer": "1.0.1"
       }
     }
   }
diff --git a/tests/browser/type.test.js b/tests/browser/type.test.js
index e9aa7066..587c941a 100644
--- a/tests/browser/type.test.js
+++ b/tests/browser/type.test.js
@@ -63,8 +63,8 @@ describe("Type", function() {
 
     it("KeyPress Invalud Input", async () => {
         await browser.click(".input1");
-        utils.assertThrowsAsync(async () => {
+        await utils.assertThrowsAsync(async () => {
             await browser.keyPress("NotAKey");
-        }, `Error: Unknown key: "NotAKey"`);
+        }, `Error: Could not press keys "NotAKey"`);
     });
 });

From 5a6a3fa701e13d6fb34543f6af970d3de93f9d9e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9s?= <angrykoala@outlook.es>
Date: Thu, 7 Jun 2018 00:37:51 +0200
Subject: [PATCH 10/13] browser.hover #16

---
 .travis.yml                          |  2 +-
 CHANGELOG.md                         | 11 ++++++++-
 README.md                            |  7 +++++-
 lib/mixins/browser_actions.js        |  8 +++++++
 tests/browser/hover.test.js          | 35 ++++++++++++++++++++++++++++
 tests/config.json                    |  1 +
 tests/dummy_server/static/hover.html | 25 ++++++++++++++++++++
 7 files changed, 86 insertions(+), 3 deletions(-)
 create mode 100644 tests/browser/hover.test.js
 create mode 100644 tests/dummy_server/static/hover.html

diff --git a/.travis.yml b/.travis.yml
index 4a5350a1..2f1e439b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,7 +8,7 @@ sudo: false
 env:
   - NO_SANDBOX=true
 
-script:
+script: travis_retry
     - npm test
 
 cache:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5fb4ba1f..f9ec659b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,10 +1,19 @@
+0.7.4 / ####-##-##
+==================
+
+  * Browser.focus
+  * Browser.hover	
+  * Assert.focus
+  * Minor bugs in tests fixed
+  * Request mock supports objects as response method
+  * Fixed bug where navigation to a different page breaks some methods
+
 0.7.3 / 2018-06-01
 ==================
 
   * Assert.enabled and assert.disabled
   * WaitForUrl
   * Fixed assert.attribute with null expected
-  * Minor bugs in tests fixed
   * Dependencies update
 
 0.7.2 / 2017-05-03
diff --git a/README.md b/README.md
index 78a885c9..2085ba35 100644
--- a/README.md
+++ b/README.md
@@ -403,7 +403,12 @@ await browser.setViewport({width: 300});
 **focus(selector)**
 Focus the first element matching the given selector.
 
-> Css, Xpath and Dom selectors supported
+> Only CSS selectors supported
+
+**hover(selector)**
+Hovers over the first element matching the given selector.
+
+> Only CSS selectors supported
 
 ## Assert
 The submodule `browser.assert` provide some out-of-the-box assertions that can be used to easily write tests that are readable without having to specifically query for elements o perform evaluations. All the assertions have a last optional parameter (msg?) to define a custom assertion message.
diff --git a/lib/mixins/browser_actions.js b/lib/mixins/browser_actions.js
index 92992686..9e6ab2dd 100644
--- a/lib/mixins/browser_actions.js
+++ b/lib/mixins/browser_actions.js
@@ -134,5 +134,13 @@ module.exports = function BrowserActionsMixin(s) {
                 return Promise.reject(error);
             });
         }
+
+        hover(selector) {
+            this._failIfNotLoaded();
+            return this.page.hover(selector).catch(() => {
+                const error = ErrorFactory.generateQueryError(`Element "${selector}" not found when trying to hover.`);
+                return Promise.reject(error);
+            });
+        }
     };
 };
diff --git a/tests/browser/hover.test.js b/tests/browser/hover.test.js
new file mode 100644
index 00000000..67f6eb4f
--- /dev/null
+++ b/tests/browser/hover.test.js
@@ -0,0 +1,35 @@
+"use strict";
+
+const Wendigo = require('../../lib/wendigo');
+const configUrls = require('../config.json').urls;
+const utils = require('../test_utils');
+
+
+describe("Hover", function() {
+    this.timeout(5000);
+    let browser;
+
+    before(async () => {
+        browser = await Wendigo.createBrowser();
+    });
+
+    beforeEach(async () => {
+        await browser.open(configUrls.hover);
+    });
+
+    after(async () => {
+        await browser.close();
+    });
+
+    it("Hover", async () => {
+        await browser.assert.text("#hover", "not hover");
+        await browser.hover(".hover-me");
+        await browser.assert.text("#hover", "hover");
+    });
+
+    it("Hover Not Existing Element", async () => {
+        await utils.assertThrowsAsync (async () => {
+            await browser.hover(".btn10");
+        }, `QueryError: Element ".btn10" not found when trying to hover.`);
+    });
+});
diff --git a/tests/config.json b/tests/config.json
index ebc84582..3d98f99f 100644
--- a/tests/config.json
+++ b/tests/config.json
@@ -10,6 +10,7 @@
         "viewport": "http://localhost:3456/viewport.html",
         "hiddenChild": "http://localhost:3456/hidden_child.html",
         "disabledItems": "http://localhost:3456/disabled_items.html",
+        "hover": "http://localhost:3456/hover.html",
         "api": "http://localhost:3456/api"
     }
 }
diff --git a/tests/dummy_server/static/hover.html b/tests/dummy_server/static/hover.html
new file mode 100644
index 00000000..18d77084
--- /dev/null
+++ b/tests/dummy_server/static/hover.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <title>Hover Test</title>
+</head>
+
+<body>
+    <p class="hover-me" onmouseover="isHover()" onmouseout="isNotHover()">hover me</p>
+    <p id="hover" class="hover">not hover</p>
+
+    <script>
+        function isHover() {
+            var elem = document.querySelector("#hover");
+            elem.textContent = "hover"
+        }
+
+        function isNotHover() {
+            var elem = document.querySelector("#hover");
+            elem.textContent = "not hover"
+        }
+    </script>
+</body>
+
+</html>

From f8c2cdb0ec2b8ece6b5f0eec62903a06f6fd8ca2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9s?= <angrykoala@outlook.es>
Date: Thu, 7 Jun 2018 00:44:39 +0200
Subject: [PATCH 11/13] travis retry fix

---
 .travis.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 2f1e439b..d5bd8d0a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,8 +8,8 @@ sudo: false
 env:
   - NO_SANDBOX=true
 
-script: travis_retry
-    - npm test
+script:
+  - travis_retry npm test
 
 cache:
   directories:

From 6d388e2448fac0e16d185c94c57781494008ad77 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9s?= <angrykoala@outlook.es>
Date: Thu, 7 Jun 2018 00:47:11 +0200
Subject: [PATCH 12/13] changelog update

---
 CHANGELOG.md | 4 ++--
 README.md    | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index f9ec659b..77ea1af6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,8 @@
-0.7.4 / ####-##-##
+0.7.4 / 2018-06-07
 ==================
 
   * Browser.focus
-  * Browser.hover	
+  * Browser.hover
   * Assert.focus
   * Minor bugs in tests fixed
   * Request mock supports objects as response method
diff --git a/README.md b/README.md
index 2085ba35..96d54f35 100644
--- a/README.md
+++ b/README.md
@@ -1036,7 +1036,7 @@ This error may appear when running wendigo on certain systems and in most CI ser
 For example `NO_SANDBOX=true npm test`.
 
 ### Running Tests With Travis CI
-Running tests using Puppeteer's require disabling the sandbox running mode. This can easily be achieved by passing the environment variable `NO_SANDBOX=true`, this can be done either as part of the test execution command, as a Travis secret env variable or in the `.travis.yml` file itself:
+Running tests using Puppeteer's require disabling the sandbox running mode. This can easily be achieved by passing the environment variable `NO_SANDBOX=true`, this can be done either as part of the test execution command, as a Travis secret env variable or in the `.travis.yml` file itself. It is recommended to add `travis_retry` to allow travis to execute the tests multiple times, as browser-based setup may fail frequently on travis workers:
 
 ```yml
 language: node_js
@@ -1049,7 +1049,7 @@ env:
   - NO_SANDBOX=true
 
 script:
-    - npm test
+    - travis_retry npm test
 
 cache:
   directories:

From 5bc45011007a99b44bc0b6294b1b75ef6cce5def Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9s?= <angrykoala@outlook.es>
Date: Thu, 7 Jun 2018 00:48:30 +0200
Subject: [PATCH 13/13] readme typo

---
 README.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 96d54f35..25eb5481 100644
--- a/README.md
+++ b/README.md
@@ -391,7 +391,7 @@ Navigates to next page in history.
 **refresh()**     
 Reloads current page.
 
-**setViewport(viewportConfig)**   
+**setViewport(viewportConfig)**     
 Sets the configuration of the page viewport, using the same config as [Puppeteer method](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagesetviewportviewport).
 
 ```js
@@ -400,12 +400,12 @@ await browser.setViewport({width: 300});
 
 > Unlike Puppeteer setViewport, no parameter is required, as the current values will be used for the new viewport.
 
-**focus(selector)**
+**focus(selector)**    
 Focus the first element matching the given selector.
 
 > Only CSS selectors supported
 
-**hover(selector)**
+**hover(selector)**    
 Hovers over the first element matching the given selector.
 
 > Only CSS selectors supported