diff --git a/.hound.yml b/.hound.yml new file mode 100644 index 000000000..6728a4cba --- /dev/null +++ b/.hound.yml @@ -0,0 +1,3 @@ +eslint: + enabled: true + config_file: .eslintrc.json \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 2df8f4f57..ee0d84913 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,19 +6,40 @@ ```js // retry action once on failure I.retry().see('Hello'); + // retry action 3 times on failure I.retry(3).see('Hello'); + // retry action 3 times waiting for 0.1 second before next try I.retry({ retries: 3, minTimeout: 100 }).see('Hello'); + // retry action 3 times waiting no more than 3 seconds for last retry I.retry({ retries: 3, maxTimeout: 3000 }).see('Hello'); -// + +// retry 2 times if error with message 'Node not visible' happens I.retry({ retries: 2, when: err => err.message === 'Node not visible' }).seeElement('#user'); ``` +* `Scenario().injectDependencies` added to dynamically add objects into DI container by @Apshenkin. See [Dependency Injection section in PageObjects](https://codecept.io/pageobjects/#dependency-injection). +* Fixed using async/await functions inside `within` +* [WebDriverIO][Protractor][Puppeteer][Nightmare] **`waitUntilExists` deprecated** in favor of `waitForElement` +* [WebDriverIO][Protractor] **`waitForStalenessOf` deprecated** in favor of `waitForDetached` +* [WebDriverIO][Protractor][Puppeteer][Nightmare] `waitForDetached` added +* [Nightmare] Added `I.seeNumberOfElements()` by @pmoncadaisla +* [Nightmare] Load blank page when starting nightmare so that the .evaluate function will work if _failed/saveScreenshot is triggered by @reubenmiller +* Fixed using plain arrays for data driven tests by @reubenmiller +* [Puppeteer] Use default tab instead of opening a new tab when starting the browser by @reubenmiller +* [Puppeteer] Added `grabNumberOfTabs` function by @reubenmiller +* [Puppeteer] Add ability to set user-agent by @abidhahmed +* [Puppeteer] Add keepCookies and keepBrowserState @abidhahmed +* [Puppeteer] Clear value attribute instead of innerhtml for TEXTAREA by @reubenmiller +* [REST] fixed sending string payload by @Spartans2017 +* Fixed unhandled rejection in async/await tests by @APshenkin + + ## 1.1.4 * Removed `yarn` call in package.json diff --git a/docs/helpers/Nightmare.md b/docs/helpers/Nightmare.md index b10223379..f5b859a7c 100644 --- a/docs/helpers/Nightmare.md +++ b/docs/helpers/Nightmare.md @@ -66,7 +66,7 @@ I.amOnPage('/login'); // opens a login page **Parameters** - `url` url path or global urlIn a second argument a list of request headers can be passed:```js - I.amOnPage('/auth', [{'x-my-custom-header': 'some value'}]) + I.amOnPage('/auth', { 'x-my-custom-header': 'some value' }) ``` - `headers` (optional, default `null`) @@ -659,6 +659,20 @@ Checks that title contains text. - `text` +## seeNumberOfElements + +asserts that an element appears a given number of times in the DOM +Element is located by label or name or CSS or XPath. + +```js +I.seeNumberOfElements('#submitBtn', 1); +``` + +**Parameters** + +- `selector` +- `num` + ## selectOption Selects an option in a drop-down select. @@ -725,6 +739,18 @@ I.wait(2); // wait 2 secs - `sec` +## waitForDetached + +Waits for an element to become not attached to the DOM on a page (by default waits for 1sec). +Element can be located by CSS or XPath. + + I.waitForDetached('#popup'); + +**Parameters** + +- `locator` element located by CSS|XPath|strict locator +- `sec` time seconds to wait, 1 by default + ## waitForElement Waits for element to be present on page (by default waits for 1sec). @@ -780,18 +806,3 @@ Element can be located by CSS or XPath. - `locator` element located by CSS|XPath|strict locator - `sec` time seconds to wait, 1 by default - -## waitUntilExists - -Waits for element not to be present on page (by default waits for 1sec). -Element can be located by CSS or XPath. - -```js -I.waitUntilExists('.btn.continue'); -I.waitUntilExists('.btn.continue', 5); // wait for 5 secs -``` - -**Parameters** - -- `locator` element located by CSS|XPath|strict locator -- `sec` time seconds to wait, 1 by default diff --git a/docs/helpers/Protractor.md b/docs/helpers/Protractor.md index 7335af361..f5a61b3e7 100644 --- a/docs/helpers/Protractor.md +++ b/docs/helpers/Protractor.md @@ -474,17 +474,22 @@ assert(cookie.value, '123456'); - `name` Returns cookie in JSON [format](https://code.google.com/p/selenium/wiki/JsonWireProtocol#Cookie_JSON_Object). -## grabSource +## grabNumberOfOpenTabs -Checks that the current page contains the given string in its raw source code. +Grab number of open tabs ```js -I.seeInSource('

Green eggs & ham

'); +I.grabNumberOfOpenTabs(); ``` -**Parameters** +## grabSource -- `text` +Retrieves page source and returns it to test. +Resumes test execution, so should be used inside an async function. + +```js +let pageSource = await I.grabSource(); +``` ## grabTextFrom @@ -571,7 +576,7 @@ I.openNewTab(); ## pressKey Presses a key on a focused element. -Speical keys like 'Enter', 'Control', [etc](https://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/value) +Special keys like 'Enter', 'Control', [etc](https://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/value) will be replaced with corresponding unicode. If modifier key is used (Control, Command, Alt, Shift) in array, it will be released afterwards. @@ -874,44 +879,48 @@ I.wait(2); // wait 2 secs Waits for element to become clickable for number of seconds. +```js +I.waitForClickable('#link'); +``` + **Parameters** - `locator` - `sec` (optional, default `null`) -## waitForElement +## waitForDetached -Waits for element to be present on page (by default waits for 1sec). +Waits for an element to become not attached to the DOM on a page (by default waits for 1sec). Element can be located by CSS or XPath. -```js -I.waitForElement('.btn.continue'); -I.waitForElement('.btn.continue', 5); // wait for 5 secs -``` + I.waitForDetached('#popup'); **Parameters** - `locator` element located by CSS|XPath|strict locator - `sec` time seconds to wait, 1 by default -## waitForInvisible +## waitForElement -Waits for an element to become invisible on a page (by default waits for 1sec). +Waits for element to be present on page (by default waits for 1sec). Element can be located by CSS or XPath. - I.waitForInvisible('#popup'); +```js +I.waitForElement('.btn.continue'); +I.waitForElement('.btn.continue', 5); // wait for 5 secs +``` **Parameters** - `locator` element located by CSS|XPath|strict locator - `sec` time seconds to wait, 1 by default -## waitForStalenessOf +## waitForInvisible -Waits for an element to become not attached to the DOM on a page (by default waits for 1sec). +Waits for an element to become invisible on a page (by default waits for 1sec). Element can be located by CSS or XPath. - I.waitForStalenessOf('#popup'); + I.waitForInvisible('#popup'); **Parameters** @@ -946,18 +955,3 @@ Element can be located by CSS or XPath. - `locator` element located by CSS|XPath|strict locator - `sec` time seconds to wait, 1 by default - -## waitUntilExists - -Waits for element not to be present on page (by default waits for 1sec). -Element can be located by CSS or XPath. - -```js -I.waitUntilExists('.btn.continue'); -I.waitUntilExists('.btn.continue', 5); // wait for 5 secs -``` - -**Parameters** - -- `locator` element located by CSS|XPath|strict locator -- `sec` time seconds to wait, 1 by default diff --git a/docs/helpers/Puppeteer.md b/docs/helpers/Puppeteer.md index 9bfc09e6b..54d43bcc1 100644 --- a/docs/helpers/Puppeteer.md +++ b/docs/helpers/Puppeteer.md @@ -10,13 +10,18 @@ Requires `puppeteer` package to be installed. This helper should be configured in codecept.json -- `url` - base url of website to be tested -- `show` (optional, default: false) - show Google Chrome window for debug. -- `disableScreenshots` (optional, default: false) - don't save screenshot on failure. -- `uniqueScreenshotNames` (optional, default: false) - option to prevent screenshot override if you have scenarios with the same name in different suites. +- `url`: base url of website to be tested +- `show`: (optional, default: false) - show Google Chrome window for debug. +- `restart`: (optional, default: true) - restart browser between tests. +- `disableScreenshots`: (optional, default: false) - don't save screenshot on failure. +- `uniqueScreenshotNames`: (optional, default: false) - option to prevent screenshot override if you have scenarios with the same name in different suites. +- `keepBrowserState`: (optional, default: false) - keep browser state between tests when `restart` is set to false. +- `keepCookies`: (optional, default: false) - keep cookies between tests when `restart` is set to false. - `waitForAction`: (optional) how long to wait after click, doubleClick or PressKey actions in ms. Default: 100. - `waitForTimeout`: (optional) default wait* timeout in ms. Default: 1000. - `windowSize`: (optional) default window size. Set a dimension like `640x480`. +- `userAgent`: (optional) user-agent string. +- `manualStart`: (optional, default: false) - do not start browser before a test, start it manually inside a helper with `this.helpers["Puppeteer"]._startBrowser()`. - `chrome`: (optional) pass additional [Puppeteer run options](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions). Example ```js @@ -479,7 +484,7 @@ let hint = yield I.grabAttributeFrom('#tooltip', 'title'); Get JS log from browser. ```js -let logs = yield I.grabBrowserLogs(); +let logs = await I.grabBrowserLogs(); console.log(JSON.stringify(logs)) ``` @@ -524,6 +529,14 @@ let postHTML = yield I.grabHTMLFrom('#post'); - `locator` +## grabNumberOfOpenTabs + +Grab number of open tabs + +```js +I.grabNumberOfOpenTabs(); +``` + ## grabNumberOfVisibleElements Grab number of visible elements by locator @@ -546,16 +559,13 @@ await I.grabPopupText(); ## grabSource -Checks that the current page contains the given string in its raw source code. +Retrieves page source and returns it to test. +Resumes test execution, so should be used inside an async function. ```js -I.seeInSource('

Green eggs & ham

'); +let pageSource = await I.grabSource(); ``` -**Parameters** - -- `text` - ## grabTextFrom Retrieves a text from an element located by CSS or XPath and returns it to test. @@ -632,7 +642,7 @@ I.openNewTab(); ## pressKey Presses a key on a focused element. -Speical keys like 'Enter', 'Control', [etc](https://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/value) +Special keys like 'Enter', 'Control', [etc](https://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/value) will be replaced with corresponding unicode. If modifier key is used (Control, Command, Alt, Shift) in array, it will be released afterwards. @@ -1026,6 +1036,18 @@ I.wait(2); // wait 2 secs - `sec` +## waitForDetached + +Waits for an element to become not attached to the DOM on a page (by default waits for 1sec). +Element can be located by CSS or XPath. + + I.waitForDetached('#popup'); + +**Parameters** + +- `locator` element located by CSS|XPath|strict locator +- `sec` time seconds to wait, 1 by default + ## waitForElement Waits for element to be present on page (by default waits for 1sec). @@ -1122,21 +1144,6 @@ I.waitUntil(() => window.requests == 0, 5); - `fn` - `sec` time seconds to wait, 1 by default -## waitUntilExists - -Waits for element not to be present on page (by default waits for 1sec). -Element can be located by CSS or XPath. - -```js -I.waitUntilExists('.btn.continue'); -I.waitUntilExists('.btn.continue', 5); // wait for 5 secs -``` - -**Parameters** - -- `locator` element located by CSS|XPath|strict locator -- `sec` time seconds to wait, 1 by default - ## waitUrlEquals Waits for the entire URL to match the expected diff --git a/docs/helpers/WebDriverIO.md b/docs/helpers/WebDriverIO.md index 8f1c8d7b6..c38cc1c46 100644 --- a/docs/helpers/WebDriverIO.md +++ b/docs/helpers/WebDriverIO.md @@ -9,20 +9,20 @@ WebDriverIO requires [Selenium Server and ChromeDriver/GeckoDriver to be install This helper should be configured in codecept.json -- `url` - base url of website to be tested -- `browser` - browser in which perform testing -- `restart` (optional, default: true) - restart browser between tests. -- `smartWait`: (optional) **enables [SmartWait](http://codecept.io/acceptance/#smartwait)**; wait for additional milliseconds for element to appear. Enable for 5 secs: "smartWait": 5000 -- `disableScreenshots` (optional, default: false) - don't save screenshot on failure -- `uniqueScreenshotNames` (optional, default: false) - option to prevent screenshot override if you have scenarios with the same name in different suites -- `keepBrowserState` (optional, default: false) - keep browser state between tests when `restart` set to false. -- `keepCookies` (optional, default: false) - keep cookies between tests when `restart` set to false. +- `url`: base url of website to be tested. +- `browser`: browser in which to perform testing. +- `restart`: (optional, default: true) - restart browser between tests. +- `smartWait`: (optional) **enables [SmartWait](http://codecept.io/acceptance/#smartwait)**; wait for additional milliseconds for element to appear. Enable for 5 secs: "smartWait": 5000. +- `disableScreenshots`: (optional, default: false) - don't save screenshots on failure. +- `uniqueScreenshotNames`: (optional, default: false) - option to prevent screenshot override if you have scenarios with the same name in different suites. +- `keepBrowserState`: (optional, default: false) - keep browser state between tests when `restart` is set to false. +- `keepCookies`: (optional, default: false) - keep cookies between tests when `restart` set to false. - `windowSize`: (optional) default window size. Set to `maximize` or a dimension in the format `640x480`. -- `waitForTimeout`: (option) sets default wait time in _ms_ for all `wait*` functions. 1000 by default; +- `waitForTimeout`: (option) sets default wait time in _ms_ for all `wait*` functions. 1000 by default. - `desiredCapabilities`: Selenium's [desired - capabilities](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities) -- `manualStart` (optional, default: false) - do not start browser before a test, start it manually inside a helper - with `this.helpers["WebDriverIO"]._startBrowser()` + capabilities](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities). +- `manualStart`: (optional, default: false) - do not start browser before a test, start it manually inside a helper + with `this.helpers["WebDriverIO"]._startBrowser()`. - `timeouts`: [WebDriverIO timeouts](http://webdriver.io/guide/testrunner/timeouts.html) defined as hash. Example: @@ -679,6 +679,14 @@ let postHTML = yield I.grabHTMLFrom('#post'); - `locator` +## grabNumberOfOpenTabs + +Grab number of open tabs + +```js +I.grabNumberOfOpenTabs(); +``` + ## grabNumberOfVisibleElements Grab number of visible elements by locator @@ -701,15 +709,14 @@ await I.grabPopupText(); ## grabSource -Checks that the current page contains the given string in its raw source code. +Retrieves page source and returns it to test. +Resumes test execution, so should be used inside an async function. ```js -I.seeInSource('

Green eggs & ham

'); +let pageSource = await I.grabSource(); ``` -**Parameters** - -- `text` Appium: support +Appium: support ## grabTextFrom @@ -779,7 +786,7 @@ I.openNewTab(); ## pressKey Presses a key on a focused element. -Speical keys like 'Enter', 'Control', [etc](https://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/value) +Special keys like 'Enter', 'Control', [etc](https://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/value) will be replaced with corresponding unicode. If modifier key is used (Control, Command, Alt, Shift) in array, it will be released afterwards. @@ -1231,6 +1238,18 @@ I.wait(2); // wait 2 secs - `sec` Appium: support +## waitForDetached + +Waits for an element to become not attached to the DOM on a page (by default waits for 1sec). +Element can be located by CSS or XPath. + + I.waitForDetached('#popup'); + +**Parameters** + +- `locator` element located by CSS|XPath|strict locator +- `sec` time seconds to wait, 1 by defaultAppium: support + ## waitForElement Waits for element to be present on page (by default waits for 1sec). @@ -1270,18 +1289,6 @@ Element can be located by CSS or XPath. - `locator` element located by CSS|XPath|strict locator - `sec` time seconds to wait, 1 by defaultAppium: support -## waitForStalenessOf - -Waits for an element to become not attached to the DOM on a page (by default waits for 1sec). -Element can be located by CSS or XPath. - - I.waitForStalenessOf('#popup'); - -**Parameters** - -- `locator` element located by CSS|XPath|strict locator -- `sec` time seconds to wait, 1 by defaultAppium: support - ## waitForText Waits for a text to appear (by default waits for 1sec). @@ -1383,21 +1390,6 @@ I.waitUntil(() => window.requests == 0, 5); - `sec` time seconds to wait, 1 by defaultAppium: support - `timeoutMsg` (optional, default `null`) -## waitUntilExists - -Waits for element not to be present on page (by default waits for 1sec). -Element can be located by CSS or XPath. - -```js -I.waitUntilExists('.btn.continue'); -I.waitUntilExists('.btn.continue', 5); // wait for 5 secs -``` - -**Parameters** - -- `locator` element located by CSS|XPath|strict locator -- `sec` time seconds to wait, 1 by defaultAppium: support - ## waitUrlEquals Waits for the entire URL to match the expected diff --git a/docs/hooks.md b/docs/hooks.md index f4d5ce804..b79e05c43 100644 --- a/docs/hooks.md +++ b/docs/hooks.md @@ -252,37 +252,6 @@ module.exports = function() { Whenever you execute tests with `--verbose` option you will see registered events and promises executed by a recorder. -### Conditional Retries with Recorder - -It is possible to execute global conditional retries to handle unforseen errors. -Lost connections and network issues are good candidates to be retried whenever they appear. - -This can be done inside a [helper](https://codecept.io/helpers/) using `recorder`: - -Example: Retrying rendering errors in Puppeteer. - -```js -_before() { - const recorder = require('codeceptjs').recorder; - recorder.retry({ - retries: 2, - when: err => err.message.indexOf('Cannot find context with specified id') > -1, - }); -} -``` - -`recorder.retry` acts similarly to `I.retry()` and accepts the same parameters. It expects the `when` parameter to be set so it would handle only specific errors and not to retry for every failed step. - -Retry rules are available in array `recorder.retries`. The last retry rule can be disabled by running `recorder.retries.pop()`; - -```js -// inside a helper -disableLastRetryRule() { - const recorder = require('codeceptjs').recorder; - recorder.retries.pop(); -} -``` - ### Output Output module provides 4 verbosity levels. Depending on the mode you can have different information printed using corresponding functions. diff --git a/docs/webapi/waitUntilExists.mustache b/docs/webapi/waitUntilExists.mustache deleted file mode 100644 index 4f36c7e92..000000000 --- a/docs/webapi/waitUntilExists.mustache +++ /dev/null @@ -1,10 +0,0 @@ -Waits for element to be present on page (by default waits for 1sec). -Element can be located by CSS or XPath. - -```js -I.waitUntilExists('.btn.continue'); -I.waitUntilExists('.btn.continue', 5); // wait for 5 secs -``` - -@param locator element located by CSS|XPath|strict locator -@param sec time seconds to wait, 1 by default diff --git a/lib/helper/Nightmare.js b/lib/helper/Nightmare.js index f81e3d4ee..d69d8921a 100644 --- a/lib/helper/Nightmare.js +++ b/lib/helper/Nightmare.js @@ -883,10 +883,17 @@ class Nightmare extends Helper { }); } + async waitUntilExists(locator, sec) { + console.log(`waitUntilExists deprecated: + * use 'waitForElement' to wait for element to be attached + * use 'waitForDetached to wait for element to be removed'`); + return this.waitForDetached(locator, sec); + } + /** - * {{> ../webapi/waitUntilExists }} + * {{> ../webapi/waitForDetached }} */ - async waitUntilExists(locator, sec) { + async waitForDetached(locator, sec) { this.browser.options.waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; sec = this.browser.options.waitForTimeout / 1000; locator = new Locator(locator, 'css'); diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index fe3bbb86b..f53e93037 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -1466,10 +1466,17 @@ class Puppeteer extends Helper { return context.waitForFunction(fn, { timeout: waitTimeout }); } + async waitUntilExists(locator, sec) { + console.log(`waitUntilExists deprecated: + * use 'waitForElement' to wait for element to be attached + * use 'waitForDetached to wait for element to be removed'`); + return this.waitForDetached(locator, sec); + } + /** - * {{> ../webapi/waitUntilExists }} + * {{> ../webapi/waitForDetached }} */ - async waitUntilExists(locator, sec) { + async waitForDetached(locator, sec) { const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; locator = new Locator(locator, 'css'); diff --git a/lib/helper/WebDriverIO.js b/lib/helper/WebDriverIO.js index 10d496246..e1a8b6c4c 100644 --- a/lib/helper/WebDriverIO.js +++ b/lib/helper/WebDriverIO.js @@ -1420,15 +1420,10 @@ class WebDriverIO extends Helper { } async waitUntilExists(locator, sec = null) { -<<<<<<< HEAD - const aSec = sec || this.options.waitForTimeout; - return this.browser.waitForExist(withStrictLocator.call(this, locator), aSec * 1000); -======= console.log(`waitUntilExists deprecated: * use 'waitForElement' to wait for element to be attached * use 'waitForDetached to wait for element to be removed'`); return this.waitForStalenessOf(locator, sec); ->>>>>>> ab24a51a7bb977452cdff9f26cf772fa6de7ed77 } @@ -1606,19 +1601,7 @@ class WebDriverIO extends Helper { * {{> ../webapi/waitForDetached }} * Appium: support */ -<<<<<<< HEAD - async waitForStalenessOf(locator, sec = null) { - return this.waitUntilNotExists(locator, sec); - } - - /** - * {{> ../webapi/waitForStalenessOf }} - * Appium: support - */ - async waitUntilNotExists(locator, sec = null) { -======= async waitForDetached(locator, sec = null) { ->>>>>>> ab24a51a7bb977452cdff9f26cf772fa6de7ed77 const aSec = sec || this.options.waitForTimeout; return this.browser.waitUntil(async () => { const res = await this.browser.elements(withStrictLocator.call(this, locator)); diff --git a/package.json b/package.json index 68a258333..87d5d725d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codeceptjs", - "version": "1.1.4", + "version": "1.1.5", "description": "Modern Era Acceptance Testing Framework for NodeJS", "keywords": [ "acceptance", @@ -52,7 +52,7 @@ "@types/node": "^8.9.3", "chai": "^3.4.1", "chai-as-promised": "^5.2.0", - "co-mocha": "^1.2.1", + "co-mocha": "^1.2. left-pad --save1", "documentation": "^4.0.0-beta1", "eslint": "^4.17.0", "eslint-config-airbnb-base": "^12.1.0",