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