From 6bf2752bb7fc08db9e3cd913e2b42db9a9569afc Mon Sep 17 00:00:00 2001 From: Michael Bodnarchuk Date: Sun, 5 Jan 2025 16:11:07 +0200 Subject: [PATCH] Refactored mocha classes (#4704) * refactored mocha, implemented hooks * refactored mocha classes, added class hooks * fixed tests * fixed formatting * updated tests * workers fix * fixed def * fixed type definitions * refactored mocha classes * fixed bdd tests * added hook config * fixed lint * refactored tests --------- Co-authored-by: DavertMik --- docs/basics.md | 426 +++--- docs/helpers/AI.md | 30 +- docs/helpers/ApiDataFactory.md | 104 +- docs/helpers/Appium.md | 594 ++++---- docs/helpers/Detox.md | 289 ++-- docs/helpers/FileSystem.md | 69 +- docs/helpers/GraphQL.md | 58 +- docs/helpers/GraphQLDataFactory.md | 92 +- docs/helpers/JSONResponse.md | 59 +- docs/helpers/MockRequest.md | 127 +- docs/helpers/Nightmare.md | 536 ++++---- docs/helpers/Playwright.md | 1196 ++++++++--------- docs/helpers/Protractor.md | 730 +++++----- docs/helpers/Puppeteer.md | 1085 +++++++-------- docs/helpers/REST.md | 105 +- docs/helpers/TestCafe.md | 514 ++++--- docs/helpers/WebDriver.md | 965 +++++++------ docs/plugins.md | 12 +- lib/cli.js | 257 ---- lib/codecept.js | 165 +-- lib/command/gherkin/snippets.js | 2 +- lib/command/gherkin/steps.js | 2 +- lib/container.js | 2 +- lib/event.js | 1 + lib/listener/{retry.js => globalRetry.js} | 0 lib/listener/{timeout.js => globalTimeout.js} | 0 lib/listener/steps.js | 15 +- lib/listener/store.js | 12 + lib/mocha/asyncWrapper.js | 204 +++ lib/{interfaces => mocha}/bdd.js | 0 lib/mocha/cli.js | 257 ++++ lib/mocha/factory.js | 107 ++ lib/{interfaces => mocha}/featureConfig.js | 23 +- lib/{interfaces => mocha}/gherkin.js | 25 +- lib/mocha/hooks.js | 84 ++ lib/mocha/index.js | 12 + lib/{interfaces => mocha}/inject.js | 0 lib/{interfaces => mocha}/scenarioConfig.js | 14 +- lib/mocha/suite.js | 55 + lib/mocha/test.js | 58 + lib/mocha/types.d.ts | 30 + lib/mocha/ui.js | 219 +++ lib/mochaFactory.js | 113 -- lib/output.js | 20 +- lib/scenario.js | 203 --- lib/store.js | 7 +- lib/ui.js | 236 ---- lib/workers.js | 476 ++++--- .../data/sandbox/configs/bootstrap/fs_test.js | 24 +- .../codecept.retry.hookconfig.conf.js | 12 + .../retryHooks/retry_async_hook_test2.js | 18 + test/runner/bootstrap_test.js | 2 + test/runner/codecept_test.js | 2 + test/runner/retry_hooks_test.js | 8 + test/runner/session_test.js | 4 +- test/runner/within_test.js | 4 +- test/support/TestHelper.js | 6 + test/unit/assert/empty_test.js | 46 +- test/unit/assert/equal_test.js | 50 +- test/unit/assert/include_test.js | 50 +- test/unit/bdd_test.js | 10 +- test/unit/data/dataTableArgument_test.js | 76 +- test/unit/data/table_test.js | 134 +- test/unit/data/ui_test.js | 134 +- test/unit/helper/FileSystem_test.js | 72 +- test/unit/helper/element_not_found_test.js | 38 +- .../asyncWrapper_test.js} | 30 +- test/unit/{ => mocha}/ui_test.js | 26 +- test/unit/plugin/customLocator_test.js | 92 +- test/unit/plugin/eachElement_test.js | 58 +- test/unit/plugin/retryFailedStep_test.js | 345 +++-- test/unit/plugin/retryto_test.js | 56 +- test/unit/plugin/screenshotOnFail_test.js | 112 +- test/unit/plugin/subtitles_test.js | 207 +-- test/unit/plugin/tryTo_test.js | 38 +- typings/index.d.ts | 5 +- typings/jsdoc.conf.js | 9 +- 77 files changed, 5667 insertions(+), 5591 deletions(-) delete mode 100644 lib/cli.js rename lib/listener/{retry.js => globalRetry.js} (100%) rename lib/listener/{timeout.js => globalTimeout.js} (100%) create mode 100644 lib/listener/store.js create mode 100644 lib/mocha/asyncWrapper.js rename lib/{interfaces => mocha}/bdd.js (100%) create mode 100644 lib/mocha/cli.js create mode 100644 lib/mocha/factory.js rename lib/{interfaces => mocha}/featureConfig.js (67%) rename lib/{interfaces => mocha}/gherkin.js (87%) create mode 100644 lib/mocha/hooks.js create mode 100644 lib/mocha/index.js rename lib/{interfaces => mocha}/inject.js (100%) rename lib/{interfaces => mocha}/scenarioConfig.js (91%) create mode 100644 lib/mocha/suite.js create mode 100644 lib/mocha/test.js create mode 100644 lib/mocha/types.d.ts create mode 100644 lib/mocha/ui.js delete mode 100644 lib/mochaFactory.js delete mode 100644 lib/scenario.js delete mode 100644 lib/ui.js create mode 100644 test/data/sandbox/configs/retryHooks/codecept.retry.hookconfig.conf.js create mode 100644 test/data/sandbox/configs/retryHooks/retry_async_hook_test2.js rename test/unit/{scenario_test.js => mocha/asyncWrapper_test.js} (79%) rename test/unit/{ => mocha}/ui_test.js (87%) diff --git a/docs/basics.md b/docs/basics.md index 6904c78d9..39134b4b7 100644 --- a/docs/basics.md +++ b/docs/basics.md @@ -8,12 +8,12 @@ title: Getting Started CodeceptJS is a modern end to end testing framework with a special BDD-style syntax. The tests are written as a linear scenario of the user's action on a site. ```js -Feature('CodeceptJS demo'); +Feature('CodeceptJS demo') Scenario('check Welcome page on site', ({ I }) => { - I.amOnPage('/'); - I.see('Welcome'); -}); + I.amOnPage('/') + I.see('Welcome') +}) ``` Tests are expected to be written in **ECMAScript 7**. @@ -38,10 +38,10 @@ However, because of the difference in backends and their limitations, they are n Refer to following guides to more information on: -* [▶ Playwright](/playwright) -* [▶ WebDriver](/webdriver) -* [▶ Puppeteer](/puppeteer) -* [▶ TestCafe](/testcafe) +- [▶ Playwright](/playwright) +- [▶ WebDriver](/webdriver) +- [▶ Puppeteer](/puppeteer) +- [▶ TestCafe](/testcafe) > ℹ Depending on a helper selected a list of available actions may change. @@ -50,15 +50,14 @@ or enable [auto-completion by generating TypeScript definitions](#intellisense). > 🤔 It is possible to access API of a backend you use inside a test or a [custom helper](/helpers/). For instance, to use Puppeteer API inside a test use [`I.usePuppeteerTo`](/helpers/Puppeteer/#usepuppeteerto) inside a test. Similar methods exist for each helper. - ## Writing Tests Tests are written from a user's perspective. There is an actor (represented as `I`) which contains actions taken from helpers. A test is written as a sequence of actions performed by an actor: ```js -I.amOnPage('/'); -I.click('Login'); -I.see('Please Login', 'h1'); +I.amOnPage('/') +I.click('Login') +I.see('Please Login', 'h1') // ... ``` @@ -70,40 +69,39 @@ Start a test by opening a page. Use the `I.amOnPage()` command for this: ```js // When "http://site.com" is url in config -I.amOnPage('/'); // -> opens http://site.com/ -I.amOnPage('/about'); // -> opens http://site.com/about -I.amOnPage('https://google.com'); // -> https://google.com +I.amOnPage('/') // -> opens http://site.com/ +I.amOnPage('/about') // -> opens http://site.com/about +I.amOnPage('https://google.com') // -> https://google.com ``` When an URL doesn't start with a protocol (http:// or https://) it is considered to be a relative URL and will be appended to the URL which was initially set-up in the config. > It is recommended to use a relative URL and keep the base URL in the config file, so you can easily switch between development, stage, and production environments. - ### Locating Element Element can be found by CSS or XPath locators. ```js -I.seeElement('.user'); // element with CSS class user -I.seeElement('//button[contains(., "press me")]'); // button +I.seeElement('.user') // element with CSS class user +I.seeElement('//button[contains(., "press me")]') // button ``` By default CodeceptJS tries to guess the locator type. In order to specify the exact locator type you can pass an object called **strict locator**. ```js -I.seeElement({css: 'div.user'}); -I.seeElement({xpath: '//div[@class=user]'}); +I.seeElement({ css: 'div.user' }) +I.seeElement({ xpath: '//div[@class=user]' }) ``` Strict locators allow to specify additional locator types: ```js // locate form element by name -I.seeElement({name: 'password'}); +I.seeElement({ name: 'password' }) // locate element by React component and props -I.seeElement({react: 'user-profile', props: {name: 'davert'}}); +I.seeElement({ react: 'user-profile', props: { name: 'davert' } }) ``` In [mobile testing](https://codecept.io/mobile/#locating-elements) you can use `~` to specify the accessibility id to locate an element. In web application you can locate elements by their `aria-label` value. @@ -111,7 +109,7 @@ In [mobile testing](https://codecept.io/mobile/#locating-elements) you can use ` ```js // locate element by [aria-label] attribute in web // or by accessibility id in mobile -I.seeElement('~username'); +I.seeElement('~username') ``` > [▶ Learn more about using locators in CodeceptJS](/locators). @@ -124,7 +122,7 @@ By default CodeceptJS tries to find the button or link with the exact text on it ```js // search for link or button -I.click('Login'); +I.click('Login') ``` If none was found, CodeceptJS tries to find a link or button containing that text. In case an image is clickable its `alt` attribute will be checked for text inclusion. Form buttons will also be searched by name. @@ -132,8 +130,8 @@ If none was found, CodeceptJS tries to find a link or button containing that tex To narrow down the results you can specify a context in the second parameter. ```js -I.click('Login', '.nav'); // search only in .nav -I.click('Login', {css: 'footer'}); // search only in footer +I.click('Login', '.nav') // search only in .nav +I.click('Login', { css: 'footer' }) // search only in footer ``` > To skip guessing the locator type, pass in a strict locator - A locator starting with '#' or '.' is considered to be CSS. Locators starting with '//' or './/' are considered to be XPath. @@ -142,9 +140,9 @@ You are not limited to buttons and links. Any element can be found by passing in ```js // click element by CSS -I.click('#signup'); +I.click('#signup') // click element located by special test-id attribute -I.click('//dev[@test-id="myid"]'); +I.click('//dev[@test-id="myid"]') ``` > ℹ If click doesn't work in a test but works for user, it is possible that frontend application is not designed for automated testing. To overcome limitation of standard click in this edgecase use `forceClick` method. It will emulate click instead of sending native event. This command will click an element no matter if this element is visible or animating. It will send JavaScript "click" event to it. @@ -159,19 +157,19 @@ Let's submit this sample form for a test: ```html
- -
- -
- -
- -
- -
+ +
+ +
+ +
+ +
+ +
``` @@ -179,14 +177,14 @@ We need to fill in all those fields and click the "Update" button. CodeceptJS ma ```js // we are using label to match user_name field -I.fillField('Name', 'Miles'); +I.fillField('Name', 'Miles') // we can use input name -I.fillField('user[email]','miles@davis.com'); +I.fillField('user[email]', 'miles@davis.com') // select element by label, choose option by text -I.selectOption('Role','Admin'); +I.selectOption('Role', 'Admin') // click 'Save' button, found by text -I.checkOption('Accept'); -I.click('Save'); +I.checkOption('Accept') +I.click('Save') ``` > ℹ `selectOption` works only with standard ` HTML elements. If your selectbox is created by React, Vue, or as a component of any other framework, this method potentially won't work with it. Use `click` to manipulate it. @@ -197,18 +195,18 @@ Alternative scenario: ```js // we are using CSS -I.fillField('#user_name', 'Miles'); -I.fillField('#user_email','miles@davis.com'); +I.fillField('#user_name', 'Miles') +I.fillField('#user_email', 'miles@davis.com') // select element by label, option by value -I.selectOption('#user_role','1'); +I.selectOption('#user_role', '1') // click 'Update' button, found by name -I.click('submitButton', '#update_form'); +I.click('submitButton', '#update_form') ``` To fill in sensitive data use the `secret` function, it won't expose actual value in logs. ```js -I.fillField('password', secret('123456')); +I.fillField('password', secret('123456')) ``` > ℹ️ Learn more about [masking secret](/secrets/) output @@ -222,11 +220,11 @@ The most general and common assertion is `see`, which checks visilibility of a t ```js // Just a visible text on a page -I.see('Hello'); +I.see('Hello') // text inside .msg element -I.see('Hello', '.msg'); +I.see('Hello', '.msg') // opposite -I.dontSee('Bye'); +I.dontSee('Bye') ``` You should provide a text as first argument and, optionally, a locator to search for a text in a context. @@ -234,16 +232,16 @@ You should provide a text as first argument and, optionally, a locator to search You can check that specific element exists (or not) on a page, as it was described in [Locating Element](#locating-element) section. ```js -I.seeElement('.notice'); -I.dontSeeElement('.error'); +I.seeElement('.notice') +I.dontSeeElement('.error') ``` Additional assertions: ```js -I.seeInCurrentUrl('/user/miles'); -I.seeInField('user[name]', 'Miles'); -I.seeInTitle('My Website'); +I.seeInCurrentUrl('/user/miles') +I.seeInField('user[name]', 'Miles') +I.seeInTitle('My Website') ``` To see all possible assertions, check the helper's reference. @@ -257,15 +255,15 @@ Imagine the application generates a password, and you want to ensure that user c ```js Scenario('login with generated password', async ({ I }) => { - I.fillField('email', 'miles@davis.com'); - I.click('Generate Password'); - const password = await I.grabTextFrom('#password'); - I.click('Login'); - I.fillField('email', 'miles@davis.com'); - I.fillField('password', password); - I.click('Log in!'); - I.see('Hello, Miles'); -}); + I.fillField('email', 'miles@davis.com') + I.click('Generate Password') + const password = await I.grabTextFrom('#password') + I.click('Login') + I.fillField('email', 'miles@davis.com') + I.fillField('password', password) + I.click('Log in!') + I.see('Hello, Miles') +}) ``` The `grabTextFrom` action is used to retrieve the text from an element. All actions starting with the `grab` prefix are expected to return data. In order to synchronize this step with a scenario you should pause the test execution with the `await` keyword of ES6. To make it work, your test should be written inside a async function (notice `async` in its definition). @@ -273,9 +271,9 @@ The `grabTextFrom` action is used to retrieve the text from an element. All acti ```js Scenario('use page title', async ({ I }) => { // ... - const password = await I.grabTextFrom('#password'); - I.fillField('password', password); -}); + const password = await I.grabTextFrom('#password') + I.fillField('password', password) +}) ``` ### Waiting @@ -285,9 +283,9 @@ Sometimes that may cause delays. A test may fail while trying to click an elemen To handle these cases, the `wait*` methods has been introduced. ```js -I.waitForElement('#agree_button', 30); // secs +I.waitForElement('#agree_button', 30) // secs // clicks a button only when it is visible -I.click('#agree_button'); +I.click('#agree_button') ``` ## How It Works @@ -304,16 +302,16 @@ If you want to get information from a running test you can use `await` inside th ```js Scenario('try grabbers', async ({ I }) => { - let title = await I.grabTitle(); -}); + let title = await I.grabTitle() +}) ``` then you can use those variables in assertions: ```js -var title = await I.grabTitle(); -var assert = require('assert'); -assert.equal(title, 'CodeceptJS'); +var title = await I.grabTitle() +var assert = require('assert') +assert.equal(title, 'CodeceptJS') ``` It is important to understand the usage of **async** functions in CodeceptJS. While non-returning actions can be called without await, if an async function uses `grab*` action it must be called with `await`: @@ -321,15 +319,15 @@ It is important to understand the usage of **async** functions in CodeceptJS. Wh ```js // a helper function async function getAllUsers(I) { - const users = await I.grabTextFrom('.users'); - return users.filter(u => u.includes('active')) + const users = await I.grabTextFrom('.users') + return users.filter(u => u.includes('active')) } // a test Scenario('try helper functions', async ({ I }) => { // we call function with await because it includes `grab` - const users = await getAllUsers(I); -}); + const users = await getAllUsers(I) +}) ``` If you miss `await` you get commands unsynchrhonized. And this will result to an error like this: @@ -388,7 +386,6 @@ npx codeceptjs run --grep "slow" It is recommended to [filter tests by tags](/advanced/#tags). - > For more options see [full reference of `run` command](/commands/#run). ### Parallel Run @@ -416,7 +413,7 @@ exports.config = { }, include: { // current actor and page objects - } + }, } ``` @@ -433,12 +430,12 @@ Tuning configuration for helpers like WebDriver, Puppeteer can be hard, as it re For instance, you can set the window size or toggle headless mode, no matter of which helpers are actually used. ```js -const { setHeadlessWhen, setWindowSize } = require('@codeceptjs/configure'); +const { setHeadlessWhen, setWindowSize } = require('@codeceptjs/configure') // run headless when CI environment variable set -setHeadlessWhen(process.env.CI); +setHeadlessWhen(process.env.CI) // set window size for any helper: Puppeteer, WebDriver, TestCafe -setWindowSize(1600, 1200); +setWindowSize(1600, 1200) exports.config = { // ... @@ -455,8 +452,8 @@ By using the interactive shell you can stop execution at any point and type in a This is especially useful while writing a new scratch. After opening a page call `pause()` to start interacting with a page: ```js -I.amOnPage('/'); -pause(); +I.amOnPage('/') +pause() ``` Try to perform your scenario step by step. Then copy succesful commands and insert them into a test. @@ -492,7 +489,7 @@ To see all available commands, press TAB two times to see list of all actions in PageObjects and other variables can also be passed to as object: ```js -pause({ loginPage, data: 'hi', func: () => console.log('hello') }); +pause({ loginPage, data: 'hi', func: () => console.log('hello') }) ``` Inside a pause mode you can use `loginPage`, `data`, `func` variables. @@ -519,7 +516,6 @@ npx codeceptjs run -p pauseOnFail > To enable pause after a test without a plugin you can use `After(pause)` inside a test file. - ### Screenshot on Failure By default CodeceptJS saves a screenshot of a failed test. @@ -536,21 +532,22 @@ To see how the test was executed, use [stepByStepReport Plugin](/plugins/#stepby Common preparation steps like opening a web page or logging in a user, can be placed in the `Before` or `Background` hooks: ```js -Feature('CodeceptJS Demonstration'); +Feature('CodeceptJS Demonstration') -Before(({ I }) => { // or Background - I.amOnPage('/documentation'); -}); +Before(({ I }) => { + // or Background + I.amOnPage('/documentation') +}) Scenario('test some forms', ({ I }) => { - I.click('Create User'); - I.see('User is valid'); - I.dontSeeInCurrentUrl('/documentation'); -}); + I.click('Create User') + I.see('User is valid') + I.dontSeeInCurrentUrl('/documentation') +}) Scenario('test title', ({ I }) => { - I.seeInTitle('Example application'); -}); + I.seeInTitle('Example application') +}) ``` Same as `Before` you can use `After` to run teardown for each scenario. @@ -563,13 +560,13 @@ You can use them to execute handlers that will setup your environment. `BeforeSu ```js BeforeSuite(({ I }) => { - I.syncDown('testfolder'); -}); + I.syncDown('testfolder') +}) AfterSuite(({ I }) => { - I.syncUp('testfolder'); - I.clearDir('testfolder'); -}); + I.syncUp('testfolder') + I.clearDir('testfolder') +}) ``` ## Retries @@ -577,7 +574,7 @@ AfterSuite(({ I }) => { ### Auto Retry Each failed step is auto-retried by default via [retryFailedStep Plugin](/plugins/#retryfailedstep). -If this is not expected, this plugin can be disabled in a config. +If this is not expected, this plugin can be disabled in a config. > **[retryFailedStep plugin](/plugins/#retryfailedstep) is enabled by default** incide global configuration @@ -589,30 +586,29 @@ If you have a step which often fails, you can retry execution for this single st Use the `retry()` function before an action to ask CodeceptJS to retry it on failure: ```js -I.retry().see('Welcome'); +I.retry().see('Welcome') ``` If you'd like to retry a step more than once, pass the amount as a parameter: ```js -I.retry(3).see('Welcome'); +I.retry(3).see('Welcome') ``` Additional options can be provided to `retry`, so you can set the additional options (defined in [promise-retry](https://www.npmjs.com/package/promise-retry) library). - ```js // retry action 3 times waiting for 0.1 second before next try -I.retry({ retries: 3, minTimeout: 100 }).see('Hello'); +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'); +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'); + when: err => err.message === 'Node not visible', +}).seeElement('#user') ``` Pass a function to the `when` option to retry only when an error matches the expected one. @@ -623,11 +619,11 @@ To retry a group of steps enable [retryTo plugin](/plugins/#retryto): ```js // retry these steps 5 times before failing -await retryTo((tryNum) => { - I.switchTo('#editor frame'); - I.click('Open'); +await retryTo(tryNum => { + I.switchTo('#editor frame') + I.click('Open') I.see('Opened') -}, 5); +}, 5) ``` ### Retry Scenario @@ -640,38 +636,57 @@ You can set the number of a retries for a feature: ```js Scenario('Really complex', ({ I }) => { // test goes here -}).retry(2); +}).retry(2) // alternative -Scenario('Really complex', { retries: 2 },({ I }) => {}); +Scenario('Really complex', { retries: 2 }, ({ I }) => {}) ``` This scenario will be restarted two times on a failure. Unlike retry step, there is no `when` condition supported for retries on a scenario level. -### Retry Before +### Retry Before + +To retry `Before`, `BeforeSuite`, `After`, `AfterSuite` hooks, call `retry()` after declaring the hook. + +- `Before().retry()` +- `BeforeSuite().retry()` +- `After().retry()` +- `AfterSuite().retry()` -To retry `Before`, `BeforeSuite`, `After`, `AfterSuite` hooks, add corresponding option to a `Feature`: +For instance, to retry Before hook 3 times before failing: -* `retryBefore` -* `retryBeforeSuite` -* `retryAfter` -* `retryAfterSuite` +```js +Before(({ I }) => { + I.amOnPage('/') +}).retry(3) +``` -For instance, to retry Before hook 3 times: +Same applied for `BeforeSuite`: ```js -Feature('this have a flaky Befure', { retryBefore: 3 }) +BeforeSuite(() => { + // do some prepreations +}).retry(3) ``` -Multiple options of different values can be set at the same time +Alternatively, retry options can be set on Feature level: + +```js +Feature('my tests', { + retryBefore: 3, + retryBeforeSuite: 2, + retryAfter: 1, + retryAfterSuite: 3, +}) +``` ### Retry Feature To set this option for all scenarios in a file, add `retry` to a feature: ```js -Feature('Complex JS Stuff').retry(3); +Feature('Complex JS Stuff').retry(3) // or Feature('Complex JS Stuff', { retries: 3 }) ``` @@ -701,7 +716,7 @@ retry: { Before: ..., BeforeSuite: ..., After: ..., - AfterSuite: ..., + AfterSuite: ..., } ``` @@ -712,32 +727,32 @@ Multiple retry configs can be added via array. To use different retry configs fo retry: [ { // enable this config only for flaky tests - grep: '@flaky', + grep: '@flaky', Before: 3 Scenario: 3 - }, + }, { // retry less when running slow tests - grep: '@slow' + grep: '@slow' Scenario: 1 Before: 1 }, { - // retry all BeforeSuite + // retry all BeforeSuite BeforeSuite: 3 } ] ``` -When using `grep` with `Before`, `After`, `BeforeSuite`, `AfterSuite`, a suite title will be checked for included value. +When using `grep` with `Before`, `After`, `BeforeSuite`, `AfterSuite`, a suite title will be checked for included value. > ℹ️ `grep` value can be string or regexp Rules are applied in the order of array element, so the last option will override a previous one. Global retries config can be overridden in a file as described previously. -### Retry Run +### Retry Run On the highest level of the "retry pyramid" there is an option to retry a complete run multiple times. -Even this is the slowest option of all, it can be helpful to detect flaky tests. +Even this is the slowest option of all, it can be helpful to detect flaky tests. [`run-rerun`](https://codecept.io/commands/#run-rerun) command will restart the run multiple times to values you provide. You can set minimal and maximal number of restarts in configuration file. @@ -745,7 +760,6 @@ Even this is the slowest option of all, it can be helpful to detect flaky tests. npx codeceptjs run-rerun ``` - [Here are some ideas](https://github.com/codeceptjs/CodeceptJS/pull/231#issuecomment-249554933) on where to use BeforeSuite hooks. ## Within @@ -756,14 +770,14 @@ Everything executed in its context will be narrowed to context specified by loca Usage: `within('section', ()=>{})` ```js -I.amOnPage('https://github.com'); +I.amOnPage('https://github.com') within('.js-signup-form', () => { - I.fillField('user[login]', 'User'); - I.fillField('user[email]', 'user@user.com'); - I.fillField('user[password]', 'user@user.com'); - I.click('button'); -}); -I.see('There were problems creating your account.'); + I.fillField('user[login]', 'User') + I.fillField('user[email]', 'user@user.com') + I.fillField('user[password]', 'user@user.com') + I.click('button') +}) +I.see('There were problems creating your account.') ``` > ⚠ `within` can cause problems when used incorrectly. If you see a weird behavior of a test try to refactor it to not use `within`. It is recommended to keep within for simplest cases when possible. @@ -771,23 +785,22 @@ I.see('There were problems creating your account.'); `within` can also work with IFrames. A special `frame` locator is required to locate the iframe and get into its context. - See example: ```js -within({frame: "#editor"}, () => { - I.see('Page'); -}); +within({ frame: '#editor' }, () => { + I.see('Page') +}) ``` > ℹ IFrames can also be accessed via `I.switchTo` command of a corresponding helper. -Nested IFrames can be set by passing an array *(WebDriver & Puppeteer only)*: +Nested IFrames can be set by passing an array _(WebDriver & Puppeteer only)_: ```js -within({frame: [".content", "#editor"]}, () => { - I.see('Page'); -}); +within({ frame: ['.content', '#editor'] }, () => { + I.see('Page') +}) ``` When running steps inside, a within block will be shown with a shift: @@ -799,26 +812,26 @@ Within can return a value, which can be used in a scenario: ```js // inside async function const val = await within('#sidebar', () => { - return I.grabTextFrom({ css: 'h1' }); -}); -I.fillField('Description', val); + return I.grabTextFrom({ css: 'h1' }) +}) +I.fillField('Description', val) ``` ## Conditional Actions -There is a way to execute unsuccessful actions to without failing a test. +There is a way to execute unsuccessful actions to without failing a test. This might be useful when you might need to click "Accept cookie" button but probably cookies were already accepted. To handle these cases `tryTo` function was introduced: ```js -tryTo(() => I.click('Accept', '.cookies')); +tryTo(() => I.click('Accept', '.cookies')) ``` You may also use `tryTo` for cases when you deal with uncertainty on page: -* A/B testing -* soft assertions -* cookies & gdpr +- A/B testing +- soft assertions +- cookies & gdpr `tryTo` function is enabled by default via [tryTo plugin](/plugins/#tryto) @@ -828,20 +841,19 @@ There is a simple way to add additional comments to your test scenario: Use the `say` command to print information to screen: ```js -I.say('I am going to publish post'); -I.say('I enter title and body'); -I.say('I expect post is visible on site'); +I.say('I am going to publish post') +I.say('I enter title and body') +I.say('I expect post is visible on site') ``` Use the second parameter to pass in a color value (ASCII). ```js -I.say('This is red', 'red'); //red is used -I.say('This is blue', 'blue'); //blue is used -I.say('This is by default'); //cyan is used +I.say('This is red', 'red') //red is used +I.say('This is blue', 'blue') //blue is used +I.say('This is by default') //cyan is used ``` - ## IntelliSense ![Edit](/img/edit.gif) @@ -867,33 +879,32 @@ Create a file called `jsconfig.json` in your project root directory, unless you Alternatively, you can include `/// ` into your test files to get method autocompletion while writing tests. - ## Multiple Sessions CodeceptJS allows to run several browser sessions inside a test. This can be useful for testing communication between users inside a chat or other systems. To open another browser use the `session()` function as shown in the example: ```js Scenario('test app', ({ I }) => { - I.amOnPage('/chat'); - I.fillField('name', 'davert'); - I.click('Sign In'); - I.see('Hello, davert'); + I.amOnPage('/chat') + I.fillField('name', 'davert') + I.click('Sign In') + I.see('Hello, davert') session('john', () => { // another session started - I.amOnPage('/chat'); - I.fillField('name', 'john'); - I.click('Sign In'); - I.see('Hello, john'); - }); + I.amOnPage('/chat') + I.fillField('name', 'john') + I.click('Sign In') + I.see('Hello, john') + }) // switching back to default session - I.fillField('message', 'Hi, john'); + I.fillField('message', 'Hi, john') // there is a message from current user - I.see('me: Hi, john', '.messages'); + I.see('me: Hi, john', '.messages') session('john', () => { // let's check if john received it - I.see('davert: Hi, john', '.messages'); - }); -}); + I.see('davert: Hi, john', '.messages') + }) +}) ``` The `session` function expects the first parameter to be the name of the session. You can switch back to this session by using the same name. @@ -901,10 +912,10 @@ The `session` function expects the first parameter to be the name of the session You can override the configuration for the session by passing a second parameter: ```js -session('john', { browser: 'firefox' } , () => { +session('john', { browser: 'firefox' }, () => { // run this steps in firefox - I.amOnPage('/'); -}); + I.amOnPage('/') +}) ``` or just start the session without switching to it. Call `session` passing only its name: @@ -924,15 +935,16 @@ Scenario('test', ({ I }) => { }); } ``` + `session` can return a value which can be used in a scenario: ```js // inside async function const val = await session('john', () => { - I.amOnPage('/info'); - return I.grabTextFrom({ css: 'h1' }); -}); -I.fillField('Description', val); + I.amOnPage('/info') + return I.grabTextFrom({ css: 'h1' }) +}) +I.fillField('Description', val) ``` Functions passed into a session can use the `I` object, page objects, and any other objects declared for the scenario. @@ -940,17 +952,15 @@ This function can also be declared as async (but doesn't work as generator). Also, you can use `within` inside a session, but you can't call session from inside `within`. - ## Skipping Like in Mocha you can use `x` and `only` to skip tests or to run a single test. -* `xScenario` - skips current test -* `Scenario.skip` - skips current test -* `Scenario.only` - executes only the current test -* `xFeature` - skips current suite -* `Feature.skip` - skips the current suite - +- `xScenario` - skips current test +- `Scenario.skip` - skips current test +- `Scenario.only` - executes only the current test +- `xFeature` - skips current suite +- `Feature.skip` - skips the current suite ## Todo Test @@ -961,19 +971,19 @@ This test will be skipped like with regular `Scenario.skip` but with additional Use it with a test body as a test plan: ```js -Scenario.todo('Test', I => { -/** - * 1. Click to field - * 2. Fill field - * - * Result: - * 3. Field contains text - */ -}); +Scenario.todo('Test', I => { + /** + * 1. Click to field + * 2. Fill field + * + * Result: + * 3. Field contains text + */ +}) ``` Or even without a test body: ```js -Scenario.todo('Test'); +Scenario.todo('Test') ``` diff --git a/docs/helpers/AI.md b/docs/helpers/AI.md index 96e0dc607..6e086ccde 100644 --- a/docs/helpers/AI.md +++ b/docs/helpers/AI.md @@ -22,11 +22,11 @@ Use it only in development mode. It is recommended to run it only inside pause() This helper should be configured in codecept.conf.{js|ts} -* `chunkSize`: - The maximum number of characters to send to the AI API at once. We split HTML fragments by 8000 chars to not exceed token limit. Increase this value if you use GPT-4. +- `chunkSize`: - The maximum number of characters to send to the AI API at once. We split HTML fragments by 8000 chars to not exceed token limit. Increase this value if you use GPT-4. ### Parameters -* `config` +- `config` ### askForPageObject @@ -37,22 +37,22 @@ Prompt can be customized in a global config file. ```js // create page object for whole page -I.askForPageObject('home'); +I.askForPageObject('home') // create page object with extra prompt -I.askForPageObject('home', 'implement signIn(username, password) method'); +I.askForPageObject('home', 'implement signIn(username, password) method') // create page object for a specific element -I.askForPageObject('home', null, '.detail'); +I.askForPageObject('home', null, '.detail') ``` Asks for a page object based on the provided page name, locator, and extra prompt. #### Parameters -* `pageName` **[string][1]** The name of the page to retrieve the object for. -* `extraPrompt` **([string][1] | null)** An optional extra prompt for additional context or information. -* `locator` **([string][1] | null)** An optional locator to find a specific element on the page. +- `pageName` **[string][1]** The name of the page to retrieve the object for. +- `extraPrompt` **([string][1] | null)** An optional extra prompt for additional context or information. +- `locator` **([string][1] | null)** An optional locator to find a specific element on the page. Returns **[Promise][2]<[Object][3]>** A promise that resolves to the requested page object. @@ -62,7 +62,7 @@ Send a general request to AI and return response. #### Parameters -* `prompt` **[string][1]** +- `prompt` **[string][1]** Returns **[Promise][2]<[string][1]>** A Promise that resolves to the generated response from the GPT model. @@ -71,12 +71,12 @@ Returns **[Promise][2]<[string][1]>** A Promise that resolves to the generated r Asks the AI GPT language model a question based on the provided prompt within the context of the current page's HTML. ```js -I.askGptOnPage('what does this page do?'); +I.askGptOnPage('what does this page do?') ``` #### Parameters -* `prompt` **[string][1]** The question or prompt to ask the GPT model. +- `prompt` **[string][1]** The question or prompt to ask the GPT model. Returns **[Promise][2]<[string][1]>** A Promise that resolves to the generated responses from the GPT model, joined by newlines. @@ -85,18 +85,16 @@ Returns **[Promise][2]<[string][1]>** A Promise that resolves to the generated r Asks the AI a question based on the provided prompt within the context of a specific HTML fragment on the current page. ```js -I.askGptOnPageFragment('describe features of this screen', '.screen'); +I.askGptOnPageFragment('describe features of this screen', '.screen') ``` #### Parameters -* `prompt` **[string][1]** The question or prompt to ask the GPT-3.5 model. -* `locator` **[string][1]** The locator or selector used to identify the HTML fragment on the page. +- `prompt` **[string][1]** The question or prompt to ask the GPT-3.5 model. +- `locator` **[string][1]** The locator or selector used to identify the HTML fragment on the page. Returns **[Promise][2]<[string][1]>** A Promise that resolves to the generated response from the GPT model. [1]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String - [2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise - [3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object diff --git a/docs/helpers/ApiDataFactory.md b/docs/helpers/ApiDataFactory.md index d76af53e0..eefc97591 100644 --- a/docs/helpers/ApiDataFactory.md +++ b/docs/helpers/ApiDataFactory.md @@ -28,9 +28,9 @@ Most of web application have API, and it can be used to create and delete test r By combining REST API with Factories you can easily create records for tests: ```js -I.have('user', { login: 'davert', email: 'davert@mail.com' }); -let id = await I.have('post', { title: 'My first post'}); -I.haveMultiple('comment', 3, {post_id: id}); +I.have('user', { login: 'davert', email: 'davert@mail.com' }) +let id = await I.have('post', { title: 'My first post' }) +I.haveMultiple('comment', 3, { post_id: id }) ``` To make this work you need @@ -53,14 +53,14 @@ See the example for Posts factories: ```js // tests/factories/posts.js -const { Factory } = require('rosie'); -const { faker } = require('@faker-js/faker'); +const { Factory } = require('rosie') +const { faker } = require('@faker-js/faker') module.exports = new Factory() - // no need to set id, it will be set by REST API - .attr('author', () => faker.person.findName()) - .attr('title', () => faker.lorem.sentence()) - .attr('body', () => faker.lorem.paragraph()); + // no need to set id, it will be set by REST API + .attr('author', () => faker.person.findName()) + .attr('title', () => faker.lorem.sentence()) + .attr('body', () => faker.lorem.paragraph()) ``` For more options see [rosie documentation][1]. @@ -71,12 +71,12 @@ Then configure ApiDataHelper to match factories and REST API: ApiDataFactory has following config options: -* `endpoint`: base URL for the API to send requests to. -* `cleanup` (default: true): should inserted records be deleted up after tests -* `factories`: list of defined factories -* `returnId` (default: false): return id instead of a complete response when creating items. -* `headers`: list of headers -* `REST`: configuration for REST requests +- `endpoint`: base URL for the API to send requests to. +- `cleanup` (default: true): should inserted records be deleted up after tests +- `factories`: list of defined factories +- `returnId` (default: false): return id instead of a complete response when creating items. +- `headers`: list of headers +- `REST`: configuration for REST requests See the example: @@ -121,19 +121,19 @@ For instance, to set timeout you should add: By default to create a record ApiDataFactory will use endpoint and plural factory name: -* create: `POST {endpoint}/{resource} data` -* delete: `DELETE {endpoint}/{resource}/id` +- create: `POST {endpoint}/{resource} data` +- delete: `DELETE {endpoint}/{resource}/id` Example (`endpoint`: `http://app.com/api`): -* create: POST request to `http://app.com/api/users` -* delete: DELETE request to `http://app.com/api/users/1` +- create: POST request to `http://app.com/api/users` +- delete: DELETE request to `http://app.com/api/users/1` This behavior can be configured with following options: -* `uri`: set different resource uri. Example: `uri: account` => `http://app.com/api/account`. -* `create`: override create options. Expected format: `{ method: uri }`. Example: `{ "post": "/users/create" }` -* `delete`: override delete options. Expected format: `{ method: uri }`. Example: `{ "post": "/users/delete/{id}" }` +- `uri`: set different resource uri. Example: `uri: account` => `http://app.com/api/account`. +- `create`: override create options. Expected format: `{ method: uri }`. Example: `{ "post": "/users/create" }` +- `delete`: override delete options. Expected format: `{ method: uri }`. Example: `{ "post": "/users/delete/{id}" }` Requests can also be overridden with a function which returns [axois request config][4]. @@ -146,11 +146,11 @@ delete: (id) => ({ method: 'delete', url: '/posts', data: { id } }) Requests can be updated on the fly by using `onRequest` function. For instance, you can pass in current session from a cookie. ```js - onRequest: async (request) => { - // using global codeceptjs instance - let cookie = await codeceptjs.container.helpers('WebDriver').grabCookie('session'); - request.headers = { Cookie: `session=${cookie.value}` }; - } +onRequest: async request => { + // using global codeceptjs instance + let cookie = await codeceptjs.container.helpers('WebDriver').grabCookie('session') + request.headers = { Cookie: `session=${cookie.value}` } +} ``` ### Responses @@ -158,7 +158,7 @@ Requests can be updated on the fly by using `onRequest` function. For instance, By default `I.have()` returns a promise with a created data: ```js -let client = await I.have('client'); +let client = await I.have('client') ``` Ids of created records are collected and used in the end of a test for the cleanup. @@ -166,11 +166,11 @@ If you need to receive `id` instead of full response enable `returnId` in a help ```js // returnId: false -let clientId = await I.have('client'); +let clientId = await I.have('client') // clientId == 1 // returnId: true -let clientId = await I.have('client'); +let clientId = await I.have('client') // client == { name: 'John', email: 'john@snow.com' } ``` @@ -190,27 +190,27 @@ By default `id` property of response is taken. This behavior can be changed by s ### Parameters -* `config` +- `config` -### _requestCreate +### \_requestCreate Executes request to create a record in API. Can be replaced from a in custom helper. #### Parameters -* `factory` **any** -* `data` **any** +- `factory` **any** +- `data` **any** -### _requestDelete +### \_requestDelete Executes request to delete a record in API Can be replaced from a custom helper. #### Parameters -* `factory` **any** -* `id` **any** +- `factory` **any** +- `id` **any** ### have @@ -218,19 +218,19 @@ Generates a new record using factory and saves API request to store it. ```js // create a user -I.have('user'); +I.have('user') // create user with defined email // and receive it when inside async function -const user = await I.have('user', { email: 'user@user.com'}); +const user = await I.have('user', { email: 'user@user.com' }) // create a user with options that will not be included in the final request -I.have('user', { }, { age: 33, height: 55 }) +I.have('user', {}, { age: 33, height: 55 }) ``` #### Parameters -* `factory` **any** factory to use -* `params` **any?** predefined parameters -* `options` **any?** options for programmatically generate the attributes +- `factory` **any** factory to use +- `params` **any?** predefined parameters +- `options` **any?** options for programmatically generate the attributes Returns **[Promise][5]** @@ -240,28 +240,24 @@ Generates bunch of records and saves multiple API requests to store them. ```js // create 3 posts -I.haveMultiple('post', 3); +I.haveMultiple('post', 3) // create 3 posts by one author -I.haveMultiple('post', 3, { author: 'davert' }); +I.haveMultiple('post', 3, { author: 'davert' }) // create 3 posts by one author with options -I.haveMultiple('post', 3, { author: 'davert' }, { publish_date: '01.01.1997' }); +I.haveMultiple('post', 3, { author: 'davert' }, { publish_date: '01.01.1997' }) ``` #### Parameters -* `factory` **any** -* `times` **any** -* `params` **any?** -* `options` **any?** +- `factory` **any** +- `times` **any** +- `params` **any?** +- `options` **any?** [1]: https://github.com/rosiejs/rosie - [2]: https://www.npmjs.com/package/faker - [3]: http://codecept.io/helpers/REST/ - [4]: https://github.com/axios/axios#request-config - [5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise diff --git a/docs/helpers/Appium.md b/docs/helpers/Appium.md index 7b9fdab62..d68b66484 100644 --- a/docs/helpers/Appium.md +++ b/docs/helpers/Appium.md @@ -32,20 +32,20 @@ Launch the daemon: `appium` This helper should be configured in codecept.conf.ts or codecept.conf.js -* `appiumV2`: set this to true if you want to run tests with AppiumV2. See more how to setup [here][3] -* `app`: Application path. Local path or remote URL to an .ipa or .apk file, or a .zip containing one of these. Alias to desiredCapabilities.appPackage -* `host`: (default: 'localhost') Appium host -* `port`: (default: '4723') Appium port -* `platform`: (Android or IOS), which mobile OS to use; alias to desiredCapabilities.platformName -* `restart`: restart browser or app between tests (default: true), if set to false cookies will be cleaned but browser window will be kept and for apps nothing will be changed. -* `desiredCapabilities`: \[], Appium capabilities, see below - * `platformName` - Which mobile OS platform to use - * `appPackage` - Java package of the Android app you want to run - * `appActivity` - Activity name for the Android activity you want to launch from your package. - * `deviceName`: The kind of mobile device or emulator to use - * `platformVersion`: Mobile OS version - * `app` - The absolute local path or remote http URL to an .ipa or .apk file, or a .zip containing one of these. Appium will attempt to install this app binary on the appropriate device first. - * `browserName`: Name of mobile web browser to automate. Should be an empty string if automating an app instead. +- `appiumV2`: set this to true if you want to run tests with AppiumV2. See more how to setup [here][3] +- `app`: Application path. Local path or remote URL to an .ipa or .apk file, or a .zip containing one of these. Alias to desiredCapabilities.appPackage +- `host`: (default: 'localhost') Appium host +- `port`: (default: '4723') Appium port +- `platform`: (Android or IOS), which mobile OS to use; alias to desiredCapabilities.platformName +- `restart`: restart browser or app between tests (default: true), if set to false cookies will be cleaned but browser window will be kept and for apps nothing will be changed. +- `desiredCapabilities`: \[], Appium capabilities, see below + - `platformName` - Which mobile OS platform to use + - `appPackage` - Java package of the Android app you want to run + - `appActivity` - Activity name for the Android activity you want to launch from your package. + - `deviceName`: The kind of mobile device or emulator to use + - `platformVersion`: Mobile OS version + - `app` - The absolute local path or remote http URL to an .ipa or .apk file, or a .zip containing one of these. Appium will attempt to install this app binary on the appropriate device first. + - `browserName`: Name of mobile web browser to automate. Should be an empty string if automating an app instead. Example Android App: @@ -157,7 +157,7 @@ let browser = this.helpers['Appium'].browser ### Parameters -* `config` +- `config` ### runOnIOS @@ -165,35 +165,38 @@ Execute code only on iOS ```js I.runOnIOS(() => { - I.click('//UIAApplication[1]/UIAWindow[1]/UIAButton[1]'); - I.see('Hi, IOS', '~welcome'); -}); + I.click('//UIAApplication[1]/UIAWindow[1]/UIAButton[1]') + I.see('Hi, IOS', '~welcome') +}) ``` Additional filter can be applied by checking for capabilities. For instance, this code will be executed only on iPhone 5s: ```js -I.runOnIOS({deviceName: 'iPhone 5s'},() => { - // ... -}); +I.runOnIOS({ deviceName: 'iPhone 5s' }, () => { + // ... +}) ``` Also capabilities can be checked by a function. ```js -I.runOnAndroid((caps) => { - // caps is current config of desiredCapabiliites - return caps.platformVersion >= 6 -},() => { - // ... -}); +I.runOnAndroid( + caps => { + // caps is current config of desiredCapabiliites + return caps.platformVersion >= 6 + }, + () => { + // ... + }, +) ``` #### Parameters -* `caps` **any** -* `fn` **any** +- `caps` **any** +- `fn` **any** ### runOnAndroid @@ -201,35 +204,38 @@ Execute code only on Android ```js I.runOnAndroid(() => { - I.click('io.selendroid.testapp:id/buttonTest'); -}); + I.click('io.selendroid.testapp:id/buttonTest') +}) ``` Additional filter can be applied by checking for capabilities. For instance, this code will be executed only on Android 6.0: ```js -I.runOnAndroid({platformVersion: '6.0'},() => { - // ... -}); +I.runOnAndroid({ platformVersion: '6.0' }, () => { + // ... +}) ``` Also capabilities can be checked by a function. In this case, code will be executed only on Android >= 6. ```js -I.runOnAndroid((caps) => { - // caps is current config of desiredCapabiliites - return caps.platformVersion >= 6 -},() => { - // ... -}); +I.runOnAndroid( + caps => { + // caps is current config of desiredCapabiliites + return caps.platformVersion >= 6 + }, + () => { + // ... + }, +) ``` #### Parameters -* `caps` **any** -* `fn` **any** +- `caps` **any** +- `fn` **any** ### runInWeb @@ -237,9 +243,9 @@ Execute code only in Web mode. ```js I.runInWeb(() => { - I.waitForElement('#data'); - I.seeInCurrentUrl('/data'); -}); + I.waitForElement('#data') + I.seeInCurrentUrl('/data') +}) ``` ### checkIfAppIsInstalled @@ -247,12 +253,12 @@ I.runInWeb(() => { Returns app installation status. ```js -I.checkIfAppIsInstalled("com.example.android.apis"); +I.checkIfAppIsInstalled('com.example.android.apis') ``` #### Parameters -* `bundleId` **[string][5]** String ID of bundled app +- `bundleId` **[string][5]** String ID of bundled app Returns **[Promise][6]<[boolean][7]>** Appium: support only Android @@ -261,12 +267,12 @@ Returns **[Promise][6]<[boolean][7]>** Appium: support only Android Check if an app is installed. ```js -I.seeAppIsInstalled("com.example.android.apis"); +I.seeAppIsInstalled('com.example.android.apis') ``` #### Parameters -* `bundleId` **[string][5]** String ID of bundled app +- `bundleId` **[string][5]** String ID of bundled app Returns **[Promise][6]\** Appium: support only Android @@ -275,12 +281,12 @@ Returns **[Promise][6]\** Appium: support only Android Check if an app is not installed. ```js -I.seeAppIsNotInstalled("com.example.android.apis"); +I.seeAppIsNotInstalled('com.example.android.apis') ``` #### Parameters -* `bundleId` **[string][5]** String ID of bundled app +- `bundleId` **[string][5]** String ID of bundled app Returns **[Promise][6]\** Appium: support only Android @@ -289,12 +295,12 @@ Returns **[Promise][6]\** Appium: support only Android Install an app on device. ```js -I.installApp('/path/to/file.apk'); +I.installApp('/path/to/file.apk') ``` #### Parameters -* `path` **[string][5]** path to apk file +- `path` **[string][5]** path to apk file Returns **[Promise][6]\** Appium: support only Android @@ -303,22 +309,22 @@ Returns **[Promise][6]\** Appium: support only Android Remove an app from the device. ```js -I.removeApp('appName', 'com.example.android.apis'); +I.removeApp('appName', 'com.example.android.apis') ``` Appium: support only Android #### Parameters -* `appId` **[string][5]** -* `bundleId` **[string][5]?** ID of bundle +- `appId` **[string][5]** +- `bundleId` **[string][5]?** ID of bundle ### resetApp Reset the currently running app for current session. ```js -I.resetApp(); +I.resetApp() ``` ### seeCurrentActivityIs @@ -326,12 +332,12 @@ I.resetApp(); Check current activity on an Android device. ```js -I.seeCurrentActivityIs(".HomeScreenActivity") +I.seeCurrentActivityIs('.HomeScreenActivity') ``` #### Parameters -* `currentActivity` **[string][5]** +- `currentActivity` **[string][5]** Returns **[Promise][6]\** Appium: support only Android @@ -340,7 +346,7 @@ Returns **[Promise][6]\** Appium: support only Android Check whether the device is locked. ```js -I.seeDeviceIsLocked(); +I.seeDeviceIsLocked() ``` Returns **[Promise][6]\** Appium: support only Android @@ -350,7 +356,7 @@ Returns **[Promise][6]\** Appium: support only Android Check whether the device is not locked. ```js -I.seeDeviceIsUnlocked(); +I.seeDeviceIsUnlocked() ``` Returns **[Promise][6]\** Appium: support only Android @@ -360,13 +366,13 @@ Returns **[Promise][6]\** Appium: support only Android Check the device orientation ```js -I.seeOrientationIs('PORTRAIT'); +I.seeOrientationIs('PORTRAIT') I.seeOrientationIs('LANDSCAPE') ``` #### Parameters -* `orientation` **(`"LANDSCAPE"` | `"PORTRAIT"`)** LANDSCAPE or PORTRAITAppium: support Android and iOS +- `orientation` **(`"LANDSCAPE"` | `"PORTRAIT"`)** LANDSCAPE or PORTRAITAppium: support Android and iOS Returns **[Promise][6]\** @@ -375,13 +381,13 @@ Returns **[Promise][6]\** Set a device orientation. Will fail, if app will not set orientation ```js -I.setOrientation('PORTRAIT'); +I.setOrientation('PORTRAIT') I.setOrientation('LANDSCAPE') ``` #### Parameters -* `orientation` **(`"LANDSCAPE"` | `"PORTRAIT"`)** LANDSCAPE or PORTRAITAppium: support Android and iOS +- `orientation` **(`"LANDSCAPE"` | `"PORTRAIT"`)** LANDSCAPE or PORTRAITAppium: support Android and iOS ### grabAllContexts @@ -396,7 +402,7 @@ Returns **[Promise][6]<[Array][8]<[string][5]>>** Appium: support Android and iO Retrieve current context ```js -let context = await I.grabContext(); +let context = await I.grabContext() ``` Returns **[Promise][6]<([string][5] | null)>** Appium: support Android and iOS @@ -406,7 +412,7 @@ Returns **[Promise][6]<([string][5] | null)>** Appium: support Android and iOS Get current device activity. ```js -let activity = await I.grabCurrentActivity(); +let activity = await I.grabCurrentActivity() ``` Returns **[Promise][6]<[string][5]>** Appium: support only Android @@ -418,7 +424,7 @@ The actual server value will be a number. However WebdriverIO additional properties to the response object to allow easier assertions. ```js -let con = await I.grabNetworkConnection(); +let con = await I.grabNetworkConnection() ``` Returns **[Promise][6]<{}>** Appium: support only Android @@ -428,7 +434,7 @@ Returns **[Promise][6]<{}>** Appium: support only Android Get current orientation. ```js -let orientation = await I.grabOrientation(); +let orientation = await I.grabOrientation() ``` Returns **[Promise][6]<[string][5]>** Appium: support Android and iOS @@ -438,7 +444,7 @@ Returns **[Promise][6]<[string][5]>** Appium: support Android and iOS Get all the currently specified settings. ```js -let settings = await I.grabSettings(); +let settings = await I.grabSettings() ``` Returns **[Promise][6]<[string][5]>** Appium: support Android and iOS @@ -449,7 +455,7 @@ Switch to the specified context. #### Parameters -* `context` **any** the context to switch to +- `context` **any** the context to switch to ### switchToWeb @@ -458,33 +464,33 @@ If no context is provided switches to the first detected web context ```js // switch to first web context -I.switchToWeb(); +I.switchToWeb() // or set the context explicitly -I.switchToWeb('WEBVIEW_io.selendroid.testapp'); +I.switchToWeb('WEBVIEW_io.selendroid.testapp') ``` #### Parameters -* `context` **[string][5]?** +- `context` **[string][5]?** Returns **[Promise][6]\** ### switchToNative Switches to native context. -By default switches to NATIVE\_APP context unless other specified. +By default switches to NATIVE_APP context unless other specified. ```js -I.switchToNative(); +I.switchToNative() // or set context explicitly -I.switchToNative('SOME_OTHER_CONTEXT'); +I.switchToNative('SOME_OTHER_CONTEXT') ``` #### Parameters -* `context` **any?** (optional, default `null`) +- `context` **any?** (optional, default `null`) Returns **[Promise][6]\** @@ -493,15 +499,15 @@ Returns **[Promise][6]\** Start an arbitrary Android activity during a session. ```js -I.startActivity('io.selendroid.testapp', '.RegisterUserActivity'); +I.startActivity('io.selendroid.testapp', '.RegisterUserActivity') ``` Appium: support only Android #### Parameters -* `appPackage` **[string][5]** -* `appActivity` **[string][5]** +- `appPackage` **[string][5]** +- `appActivity` **[string][5]** Returns **[Promise][6]\** @@ -509,9 +515,9 @@ Returns **[Promise][6]\** Set network connection mode. -* airplane mode -* wifi mode -* data data +- airplane mode +- wifi mode +- data data ```js I.setNetworkConnection(0) // airplane mode off, wifi off, data off @@ -527,7 +533,7 @@ Appium: support only Android #### Parameters -* `value` **[number][10]** The network connection mode bitmask +- `value` **[number][10]** The network connection mode bitmask Returns **[Promise][6]<[number][10]>** @@ -536,12 +542,12 @@ Returns **[Promise][6]<[number][10]>** Update the current setting on the device ```js -I.setSettings({cyberdelia: 'open'}); +I.setSettings({ cyberdelia: 'open' }) ``` #### Parameters -* `settings` **[object][11]** objectAppium: support Android and iOS +- `settings` **[object][11]** objectAppium: support Android and iOS ### hideDeviceKeyboard @@ -549,19 +555,19 @@ Hide the keyboard. ```js // taps outside to hide keyboard per default -I.hideDeviceKeyboard(); -I.hideDeviceKeyboard('tapOutside'); +I.hideDeviceKeyboard() +I.hideDeviceKeyboard('tapOutside') // or by pressing key -I.hideDeviceKeyboard('pressKey', 'Done'); +I.hideDeviceKeyboard('pressKey', 'Done') ``` Appium: support Android and iOS #### Parameters -* `strategy` **(`"tapOutside"` | `"pressKey"`)?** Desired strategy to close keyboard (‘tapOutside’ or ‘pressKey’) -* `key` **[string][5]?** Optional key +- `strategy` **(`"tapOutside"` | `"pressKey"`)?** Desired strategy to close keyboard (‘tapOutside’ or ‘pressKey’) +- `key` **[string][5]?** Optional key ### sendDeviceKeyEvent @@ -569,12 +575,12 @@ Send a key event to the device. List of keys: [https://developer.android.com/reference/android/view/KeyEvent.html][12] ```js -I.sendDeviceKeyEvent(3); +I.sendDeviceKeyEvent(3) ``` #### Parameters -* `keyValue` **[number][10]** Device specific key value +- `keyValue` **[number][10]** Device specific key value Returns **[Promise][6]\** Appium: support only Android @@ -583,7 +589,7 @@ Returns **[Promise][6]\** Appium: support only Android Open the notifications panel on the device. ```js -I.openNotifications(); +I.openNotifications() ``` Returns **[Promise][6]\** Appium: support only Android @@ -597,13 +603,13 @@ application on the device. [See complete documentation][13] ```js -I.makeTouchAction("~buttonStartWebviewCD", 'tap'); +I.makeTouchAction('~buttonStartWebviewCD', 'tap') ``` #### Parameters -* `locator` -* `action` +- `locator` +- `action` Returns **[Promise][6]\** Appium: support Android and iOS @@ -612,14 +618,14 @@ Returns **[Promise][6]\** Appium: support Android and iOS Taps on element. ```js -I.tap("~buttonStartWebviewCD"); +I.tap('~buttonStartWebviewCD') ``` Shortcut for `makeTouchAction` #### Parameters -* `locator` **any** +- `locator` **any** Returns **[Promise][6]\** @@ -628,18 +634,18 @@ Returns **[Promise][6]\** Perform a swipe on the screen or an element. ```js -let locator = "#io.selendroid.testapp:id/LinearLayout1"; -I.swipe(locator, 800, 1200, 1000); +let locator = '#io.selendroid.testapp:id/LinearLayout1' +I.swipe(locator, 800, 1200, 1000) ``` [See complete reference][14] #### Parameters -* `locator` **([string][5] | [object][11])** -* `xoffset` **[number][10]** -* `yoffset` **[number][10]** -* `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) +- `locator` **([string][5] | [object][11])** +- `xoffset` **[number][10]** +- `yoffset` **[number][10]** +- `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) Returns **[Promise][6]\** Appium: support Android and iOS @@ -648,30 +654,30 @@ Returns **[Promise][6]\** Appium: support Android and iOS Perform a swipe on the screen. ```js -I.performSwipe({ x: 300, y: 100 }, { x: 200, y: 100 }); +I.performSwipe({ x: 300, y: 100 }, { x: 200, y: 100 }) ``` #### Parameters -* `from` **[object][11]** -* `to` **[object][11]** Appium: support Android and iOS +- `from` **[object][11]** +- `to` **[object][11]** Appium: support Android and iOS ### swipeDown Perform a swipe down on an element. ```js -let locator = "#io.selendroid.testapp:id/LinearLayout1"; -I.swipeDown(locator); // simple swipe -I.swipeDown(locator, 500); // set speed -I.swipeDown(locator, 1200, 1000); // set offset and speed +let locator = '#io.selendroid.testapp:id/LinearLayout1' +I.swipeDown(locator) // simple swipe +I.swipeDown(locator, 500) // set speed +I.swipeDown(locator, 1200, 1000) // set offset and speed ``` #### Parameters -* `locator` **([string][5] | [object][11])** -* `yoffset` **[number][10]?** (optional) (optional, default `1000`) -* `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) +- `locator` **([string][5] | [object][11])** +- `yoffset` **[number][10]?** (optional) (optional, default `1000`) +- `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) Returns **[Promise][6]\** Appium: support Android and iOS @@ -680,17 +686,17 @@ Returns **[Promise][6]\** Appium: support Android and iOS Perform a swipe left on an element. ```js -let locator = "#io.selendroid.testapp:id/LinearLayout1"; -I.swipeLeft(locator); // simple swipe -I.swipeLeft(locator, 500); // set speed -I.swipeLeft(locator, 1200, 1000); // set offset and speed +let locator = '#io.selendroid.testapp:id/LinearLayout1' +I.swipeLeft(locator) // simple swipe +I.swipeLeft(locator, 500) // set speed +I.swipeLeft(locator, 1200, 1000) // set offset and speed ``` #### Parameters -* `locator` **([string][5] | [object][11])** -* `xoffset` **[number][10]?** (optional) (optional, default `1000`) -* `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) +- `locator` **([string][5] | [object][11])** +- `xoffset` **[number][10]?** (optional) (optional, default `1000`) +- `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) Returns **[Promise][6]\** Appium: support Android and iOS @@ -699,17 +705,17 @@ Returns **[Promise][6]\** Appium: support Android and iOS Perform a swipe right on an element. ```js -let locator = "#io.selendroid.testapp:id/LinearLayout1"; -I.swipeRight(locator); // simple swipe -I.swipeRight(locator, 500); // set speed -I.swipeRight(locator, 1200, 1000); // set offset and speed +let locator = '#io.selendroid.testapp:id/LinearLayout1' +I.swipeRight(locator) // simple swipe +I.swipeRight(locator, 500) // set speed +I.swipeRight(locator, 1200, 1000) // set offset and speed ``` #### Parameters -* `locator` **([string][5] | [object][11])** -* `xoffset` **[number][10]?** (optional) (optional, default `1000`) -* `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) +- `locator` **([string][5] | [object][11])** +- `xoffset` **[number][10]?** (optional) (optional, default `1000`) +- `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) Returns **[Promise][6]\** Appium: support Android and iOS @@ -718,17 +724,17 @@ Returns **[Promise][6]\** Appium: support Android and iOS Perform a swipe up on an element. ```js -let locator = "#io.selendroid.testapp:id/LinearLayout1"; -I.swipeUp(locator); // simple swipe -I.swipeUp(locator, 500); // set speed -I.swipeUp(locator, 1200, 1000); // set offset and speed +let locator = '#io.selendroid.testapp:id/LinearLayout1' +I.swipeUp(locator) // simple swipe +I.swipeUp(locator, 500) // set speed +I.swipeUp(locator, 1200, 1000) // set offset and speed ``` #### Parameters -* `locator` **([string][5] | [object][11])** -* `yoffset` **[number][10]?** (optional) (optional, default `1000`) -* `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) +- `locator` **([string][5] | [object][11])** +- `yoffset` **[number][10]?** (optional) (optional, default `1000`) +- `speed` **[number][10]** (optional), 1000 by default (optional, default `1000`) Returns **[Promise][6]\** Appium: support Android and iOS @@ -738,22 +744,23 @@ Perform a swipe in selected direction on an element to searchable element. ```js I.swipeTo( - "android.widget.CheckBox", // searchable element - "//android.widget.ScrollView/android.widget.LinearLayout", // scroll element - "up", // direction - 30, - 100, - 500); + 'android.widget.CheckBox', // searchable element + '//android.widget.ScrollView/android.widget.LinearLayout', // scroll element + 'up', // direction + 30, + 100, + 500, +) ``` #### Parameters -* `searchableLocator` **[string][5]** -* `scrollLocator` **[string][5]** -* `direction` **[string][5]** -* `timeout` **[number][10]** -* `offset` **[number][10]** -* `speed` **[number][10]** +- `searchableLocator` **[string][5]** +- `scrollLocator` **[string][5]** +- `direction` **[string][5]** +- `timeout` **[number][10]** +- `offset` **[number][10]** +- `speed` **[number][10]** Returns **[Promise][6]\** Appium: support Android and iOS @@ -763,45 +770,50 @@ Performs a specific touch action. The action object need to contain the action name, x/y coordinates ```js -I.touchPerform([{ +I.touchPerform([ + { action: 'press', options: { x: 100, - y: 200 - } -}, {action: 'release'}]) - -I.touchPerform([{ - action: 'tap', - options: { - element: '1', // json web element was queried before - x: 10, // x offset - y: 20, // y offset - count: 1 // number of touches - } -}]); + y: 200, + }, + }, + { action: 'release' }, +]) + +I.touchPerform([ + { + action: 'tap', + options: { + element: '1', // json web element was queried before + x: 10, // x offset + y: 20, // y offset + count: 1, // number of touches + }, + }, +]) ``` Appium: support Android and iOS #### Parameters -* `actions` **[Array][8]** Array of touch actions +- `actions` **[Array][8]** Array of touch actions ### pullFile Pulls a file from the device. ```js -I.pullFile('/storage/emulated/0/DCIM/logo.png', 'my/path'); +I.pullFile('/storage/emulated/0/DCIM/logo.png', 'my/path') // save file to output dir -I.pullFile('/storage/emulated/0/DCIM/logo.png', output_dir); +I.pullFile('/storage/emulated/0/DCIM/logo.png', output_dir) ``` #### Parameters -* `path` **[string][5]** -* `dest` **[string][5]** +- `path` **[string][5]** +- `dest` **[string][5]** Returns **[Promise][6]<[string][5]>** Appium: support Android and iOS @@ -810,7 +822,7 @@ Returns **[Promise][6]<[string][5]>** Appium: support Android and iOS Perform a shake action on the device. ```js -I.shakeDevice(); +I.shakeDevice() ``` Returns **[Promise][6]\** Appium: support only iOS @@ -827,12 +839,12 @@ See corresponding [webdriverio reference][15]. #### Parameters -* `x` -* `y` -* `duration` -* `radius` -* `rotation` -* `touchCount` +- `x` +- `y` +- `duration` +- `radius` +- `rotation` +- `touchCount` Returns **[Promise][6]\** Appium: support only iOS @@ -844,8 +856,8 @@ See corresponding [webdriverio reference][16]. #### Parameters -* `id` -* `value` +- `id` +- `value` Returns **[Promise][6]\** Appium: support only iOS @@ -854,14 +866,14 @@ Returns **[Promise][6]\** Appium: support only iOS Simulate Touch ID with either valid (match == true) or invalid (match == false) fingerprint. ```js -I.touchId(); // simulates valid fingerprint -I.touchId(true); // simulates valid fingerprint -I.touchId(false); // simulates invalid fingerprint +I.touchId() // simulates valid fingerprint +I.touchId(true) // simulates valid fingerprint +I.touchId(false) // simulates invalid fingerprint ``` #### Parameters -* `match` +- `match` Returns **[Promise][6]\** Appium: support only iOS TODO: not tested @@ -871,7 +883,7 @@ TODO: not tested Close the given application. ```js -I.closeApp(); +I.closeApp() ``` Returns **[Promise][6]\** Appium: support both Android and iOS @@ -882,15 +894,15 @@ Appends text to a input field or textarea. Field is located by name, label, CSS or XPath ```js -I.appendField('#myTextField', 'appended'); +I.appendField('#myTextField', 'appended') // typing secret -I.appendField('password', secret('123456')); +I.appendField('password', secret('123456')) ``` #### Parameters -* `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator -* `value` **[string][5]** text value to append. +- `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator +- `value` **[string][5]** text value to append. Returns **void** automatically synchronized promise through #recorder @@ -902,15 +914,15 @@ Element is located by label or name or CSS or XPath. The second parameter is a context (CSS or XPath locator) to narrow the search. ```js -I.checkOption('#agree'); -I.checkOption('I Agree to Terms and Conditions'); -I.checkOption('agree', '//form'); +I.checkOption('#agree') +I.checkOption('I Agree to Terms and Conditions') +I.checkOption('agree', '//form') ``` #### Parameters -* `field` **([string][5] | [object][11])** checkbox located by label | name | CSS | XPath | strict locator. -* `context` **([string][5]? | [object][11])** (optional, `null` by default) element located by CSS | XPath | strict locator. (optional, default `null`) +- `field` **([string][5] | [object][11])** checkbox located by label | name | CSS | XPath | strict locator. +- `context` **([string][5]? | [object][11])** (optional, `null` by default) element located by CSS | XPath | strict locator. (optional, default `null`) Returns **void** automatically synchronized promise through #recorder @@ -925,23 +937,23 @@ The second parameter is a context (CSS or XPath locator) to narrow the search. ```js // simple link -I.click('Logout'); +I.click('Logout') // button of form -I.click('Submit'); +I.click('Submit') // CSS button -I.click('#form input[type=submit]'); +I.click('#form input[type=submit]') // XPath -I.click('//form/*[@type=submit]'); +I.click('//form/*[@type=submit]') // link in context -I.click('Logout', '#nav'); +I.click('Logout', '#nav') // using strict locator -I.click({css: 'nav a.login'}); +I.click({ css: 'nav a.login' }) ``` #### Parameters -* `locator` **([string][5] | [object][11])** clickable link or button located by text, or any element located by CSS|XPath|strict locator. -* `context` **([string][5]? | [object][11] | null)** (optional, `null` by default) element to search in CSS|XPath|Strict locator. (optional, default `null`) +- `locator` **([string][5] | [object][11])** clickable link or button located by text, or any element located by CSS|XPath|strict locator. +- `context` **([string][5]? | [object][11] | null)** (optional, `null` by default) element to search in CSS|XPath|Strict locator. (optional, default `null`) Returns **void** automatically synchronized promise through #recorder @@ -950,14 +962,14 @@ Returns **void** automatically synchronized promise through #recorder Verifies that the specified checkbox is not checked. ```js -I.dontSeeCheckboxIsChecked('#agree'); // located by ID -I.dontSeeCheckboxIsChecked('I agree to terms'); // located by label -I.dontSeeCheckboxIsChecked('agree'); // located by name +I.dontSeeCheckboxIsChecked('#agree') // located by ID +I.dontSeeCheckboxIsChecked('I agree to terms') // located by label +I.dontSeeCheckboxIsChecked('agree') // located by name ``` #### Parameters -* `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. +- `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. Returns **void** automatically synchronized promise through #recorder @@ -966,12 +978,12 @@ Returns **void** automatically synchronized promise through #recorder Opposite to `seeElement`. Checks that element is not visible (or in DOM) ```js -I.dontSeeElement('.modal'); // modal is not shown +I.dontSeeElement('.modal') // modal is not shown ``` #### Parameters -* `locator` **([string][5] | [object][11])** located by CSS|XPath|Strict locator. +- `locator` **([string][5] | [object][11])** located by CSS|XPath|Strict locator. Returns **void** automatically synchronized promise through #recorder @@ -981,14 +993,14 @@ Checks that value of input field or textarea doesn't equal to given value Opposite to `seeInField`. ```js -I.dontSeeInField('email', 'user@user.com'); // field by name -I.dontSeeInField({ css: 'form input.email' }, 'user@user.com'); // field by CSS +I.dontSeeInField('email', 'user@user.com') // field by name +I.dontSeeInField({ css: 'form input.email' }, 'user@user.com') // field by CSS ``` #### Parameters -* `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. -* `value` **([string][5] | [object][11])** value to check. +- `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. +- `value` **([string][5] | [object][11])** value to check. Returns **void** automatically synchronized promise through #recorder @@ -998,14 +1010,14 @@ Opposite to `see`. Checks that a text is not present on a page. Use context parameter to narrow down the search. ```js -I.dontSee('Login'); // assume we are already logged in. -I.dontSee('Login', '.nav'); // no login inside .nav element +I.dontSee('Login') // assume we are already logged in. +I.dontSee('Login', '.nav') // no login inside .nav element ``` #### Parameters -* `text` **[string][5]** which is not present. -* `context` **([string][5] | [object][11])?** (optional) element located by CSS|XPath|strict locator in which to perfrom search. (optional, default `null`) +- `text` **[string][5]** which is not present. +- `context` **([string][5] | [object][11])?** (optional) element located by CSS|XPath|strict locator in which to perfrom search. (optional, default `null`) Returns **void** automatically synchronized promise through #recorder @@ -1016,19 +1028,19 @@ Field is located by name, label, CSS, or XPath. ```js // by label -I.fillField('Email', 'hello@world.com'); +I.fillField('Email', 'hello@world.com') // by name -I.fillField('password', secret('123456')); +I.fillField('password', secret('123456')) // by CSS -I.fillField('form#login input[name=username]', 'John'); +I.fillField('form#login input[name=username]', 'John') // or by strict locator -I.fillField({css: 'form#login input[name=username]'}, 'John'); +I.fillField({ css: 'form#login input[name=username]' }, 'John') ``` #### Parameters -* `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. -* `value` **([string][5] | [object][11])** text value to fill. +- `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. +- `value` **([string][5] | [object][11])** text value to fill. Returns **void** automatically synchronized promise through #recorder @@ -1038,12 +1050,12 @@ Retrieves all texts from an element located by CSS or XPath and returns it to te Resumes test execution, so **should be used inside async with `await`** operator. ```js -let pins = await I.grabTextFromAll('#pin li'); +let pins = await I.grabTextFromAll('#pin li') ``` #### Parameters -* `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. +- `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. Returns **[Promise][6]<[Array][8]<[string][5]>>** attribute value @@ -1053,14 +1065,14 @@ Retrieves a text from an element located by CSS or XPath and returns it to test. Resumes test execution, so **should be used inside async with `await`** operator. ```js -let pin = await I.grabTextFrom('#pin'); +let pin = await I.grabTextFrom('#pin') ``` If multiple elements found returns first element. #### Parameters -* `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. +- `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. Returns **[Promise][6]<[string][5]>** attribute value @@ -1070,12 +1082,12 @@ Grab number of visible elements by locator. Resumes test execution, so **should be used inside async function with `await`** operator. ```js -let numOfElements = await I.grabNumberOfVisibleElements('p'); +let numOfElements = await I.grabNumberOfVisibleElements('p') ``` #### Parameters -* `locator` **([string][5] | [object][11])** located by CSS|XPath|strict locator. +- `locator` **([string][5] | [object][11])** located by CSS|XPath|strict locator. Returns **[Promise][6]<[number][10]>** number of visible elements @@ -1088,13 +1100,13 @@ Resumes test execution, so **should be used inside async with `await`** operator If more than one element is found - attribute of first element is returned. ```js -let hint = await I.grabAttributeFrom('#tooltip', 'title'); +let hint = await I.grabAttributeFrom('#tooltip', 'title') ``` #### Parameters -* `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. -* `attr` **[string][5]** attribute name. +- `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. +- `attr` **[string][5]** attribute name. Returns **[Promise][6]<[string][5]>** attribute value @@ -1105,13 +1117,13 @@ Retrieves an array of attributes from elements located by CSS or XPath and retur Resumes test execution, so **should be used inside async with `await`** operator. ```js -let hints = await I.grabAttributeFromAll('.tooltip', 'title'); +let hints = await I.grabAttributeFromAll('.tooltip', 'title') ``` #### Parameters -* `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. -* `attr` **[string][5]** attribute name. +- `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. +- `attr` **[string][5]** attribute name. Returns **[Promise][6]<[Array][8]<[string][5]>>** attribute value @@ -1121,12 +1133,12 @@ Retrieves an array of value from a form located by CSS or XPath and returns it t Resumes test execution, so **should be used inside async function with `await`** operator. ```js -let inputs = await I.grabValueFromAll('//form/input'); +let inputs = await I.grabValueFromAll('//form/input') ``` #### Parameters -* `locator` **([string][5] | [object][11])** field located by label|name|CSS|XPath|strict locator. +- `locator` **([string][5] | [object][11])** field located by label|name|CSS|XPath|strict locator. Returns **[Promise][6]<[Array][8]<[string][5]>>** attribute value @@ -1137,12 +1149,12 @@ Resumes test execution, so **should be used inside async function with `await`** If more than one element is found - value of first element is returned. ```js -let email = await I.grabValueFrom('input[name=email]'); +let email = await I.grabValueFrom('input[name=email]') ``` #### Parameters -* `locator` **([string][5] | [object][11])** field located by label|name|CSS|XPath|strict locator. +- `locator` **([string][5] | [object][11])** field located by label|name|CSS|XPath|strict locator. Returns **[Promise][6]<[string][5]>** attribute value @@ -1152,12 +1164,12 @@ Saves a screenshot to ouput folder (set in codecept.conf.ts or codecept.conf.js) Filename is relative to output folder. ```js -I.saveScreenshot('debug.png'); +I.saveScreenshot('debug.png') ``` #### Parameters -* `fileName` **[string][5]** file name to save. +- `fileName` **[string][5]** file name to save. Returns **[Promise][6]\** @@ -1166,15 +1178,15 @@ Returns **[Promise][6]\** Scroll element into viewport. ```js -I.scrollIntoView('#submit'); -I.scrollIntoView('#submit', true); -I.scrollIntoView('#submit', { behavior: "smooth", block: "center", inline: "center" }); +I.scrollIntoView('#submit') +I.scrollIntoView('#submit', true) +I.scrollIntoView('#submit', { behavior: 'smooth', block: 'center', inline: 'center' }) ``` #### Parameters -* `locator` **([string][5] | [object][11])** located by CSS|XPath|strict locator. -* `scrollIntoViewOptions` **(ScrollIntoViewOptions | [boolean][7])** either alignToTop=true|false or scrollIntoViewOptions. See [https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView][17]. +- `locator` **([string][5] | [object][11])** located by CSS|XPath|strict locator. +- `scrollIntoViewOptions` **(ScrollIntoViewOptions | [boolean][7])** either alignToTop=true|false or scrollIntoViewOptions. See [https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView][17]. Returns **void** automatically synchronized promise through #recorderSupported only for web testing @@ -1183,14 +1195,14 @@ Returns **void** automatically synchronized promise through #recorderSupported o Verifies that the specified checkbox is checked. ```js -I.seeCheckboxIsChecked('Agree'); -I.seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms -I.seeCheckboxIsChecked({css: '#signup_form input[type=checkbox]'}); +I.seeCheckboxIsChecked('Agree') +I.seeCheckboxIsChecked('#agree') // I suppose user agreed to terms +I.seeCheckboxIsChecked({ css: '#signup_form input[type=checkbox]' }) ``` #### Parameters -* `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. +- `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. Returns **void** automatically synchronized promise through #recorder @@ -1200,12 +1212,12 @@ Checks that a given Element is visible Element is located by CSS or XPath. ```js -I.seeElement('#modal'); +I.seeElement('#modal') ``` #### Parameters -* `locator` **([string][5] | [object][11])** located by CSS|XPath|strict locator. +- `locator` **([string][5] | [object][11])** located by CSS|XPath|strict locator. Returns **void** automatically synchronized promise through #recorder @@ -1215,16 +1227,16 @@ Checks that the given input field or textarea equals to given value. For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath. ```js -I.seeInField('Username', 'davert'); -I.seeInField({css: 'form textarea'},'Type your comment here'); -I.seeInField('form input[type=hidden]','hidden_value'); -I.seeInField('#searchform input','Search'); +I.seeInField('Username', 'davert') +I.seeInField({ css: 'form textarea' }, 'Type your comment here') +I.seeInField('form input[type=hidden]', 'hidden_value') +I.seeInField('#searchform input', 'Search') ``` #### Parameters -* `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. -* `value` **([string][5] | [object][11])** value to check. +- `field` **([string][5] | [object][11])** located by label|name|CSS|XPath|strict locator. +- `value` **([string][5] | [object][11])** value to check. Returns **void** automatically synchronized promise through #recorder @@ -1234,15 +1246,15 @@ Checks that a page contains a visible text. Use context parameter to narrow down the search. ```js -I.see('Welcome'); // text welcome on a page -I.see('Welcome', '.content'); // text inside .content div -I.see('Register', {css: 'form.register'}); // use strict locator +I.see('Welcome') // text welcome on a page +I.see('Welcome', '.content') // text inside .content div +I.see('Register', { css: 'form.register' }) // use strict locator ``` #### Parameters -* `text` **[string][5]** expected on page. -* `context` **([string][5]? | [object][11])** (optional, `null` by default) element located by CSS|Xpath|strict locator in which to search for text. (optional, default `null`) +- `text` **[string][5]** expected on page. +- `context` **([string][5]? | [object][11])** (optional, `null` by default) element located by CSS|Xpath|strict locator in which to search for text. (optional, default `null`) Returns **void** automatically synchronized promise through #recorder @@ -1253,24 +1265,24 @@ Field is searched by label | name | CSS | XPath. Option is selected by visible text or by value. ```js -I.selectOption('Choose Plan', 'Monthly'); // select by label -I.selectOption('subscription', 'Monthly'); // match option by text -I.selectOption('subscription', '0'); // or by value -I.selectOption('//form/select[@name=account]','Premium'); -I.selectOption('form select[name=account]', 'Premium'); -I.selectOption({css: 'form select[name=account]'}, 'Premium'); +I.selectOption('Choose Plan', 'Monthly') // select by label +I.selectOption('subscription', 'Monthly') // match option by text +I.selectOption('subscription', '0') // or by value +I.selectOption('//form/select[@name=account]', 'Premium') +I.selectOption('form select[name=account]', 'Premium') +I.selectOption({ css: 'form select[name=account]' }, 'Premium') ``` Provide an array for the second argument to select multiple options. ```js -I.selectOption('Which OS do you use?', ['Android', 'iOS']); +I.selectOption('Which OS do you use?', ['Android', 'iOS']) ``` #### Parameters -* `select` **([string][5] | [object][11])** field located by label|name|CSS|XPath|strict locator. -* `option` **([string][5] | [Array][8]\)** visible text or value of option. +- `select` **([string][5] | [object][11])** field located by label|name|CSS|XPath|strict locator. +- `option` **([string][5] | [Array][8]\)** visible text or value of option. Returns **void** automatically synchronized promise through #recorderSupported only for web testing @@ -1280,14 +1292,14 @@ Waits for element to be present on 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.waitForElement('.btn.continue') +I.waitForElement('.btn.continue', 5) // wait for 5 secs ``` #### Parameters -* `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. -* `sec` **[number][10]?** (optional, `1` by default) time in seconds to wait (optional, default `null`) +- `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. +- `sec` **[number][10]?** (optional, `1` by default) time in seconds to wait (optional, default `null`) Returns **void** automatically synchronized promise through #recorder @@ -1297,13 +1309,13 @@ Waits for an element to become visible on a page (by default waits for 1sec). Element can be located by CSS or XPath. ```js -I.waitForVisible('#popup'); +I.waitForVisible('#popup') ``` #### Parameters -* `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. -* `sec` **[number][10]** (optional, `1` by default) time in seconds to wait (optional, default `1`) +- `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. +- `sec` **[number][10]** (optional, `1` by default) time in seconds to wait (optional, default `1`) Returns **void** automatically synchronized promise through #recorder @@ -1313,13 +1325,13 @@ Waits for an element to be removed or become invisible on a page (by default wai Element can be located by CSS or XPath. ```js -I.waitForInvisible('#popup'); +I.waitForInvisible('#popup') ``` #### Parameters -* `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. -* `sec` **[number][10]** (optional, `1` by default) time in seconds to wait (optional, default `1`) +- `locator` **([string][5] | [object][11])** element located by CSS|XPath|strict locator. +- `sec` **[number][10]** (optional, `1` by default) time in seconds to wait (optional, default `1`) Returns **void** automatically synchronized promise through #recorder @@ -1330,48 +1342,32 @@ Element can be located by CSS or XPath. Narrow down search results by providing context. ```js -I.waitForText('Thank you, form has been submitted'); -I.waitForText('Thank you, form has been submitted', 5, '#modal'); +I.waitForText('Thank you, form has been submitted') +I.waitForText('Thank you, form has been submitted', 5, '#modal') ``` #### Parameters -* `text` **[string][5]** to wait for. -* `sec` **[number][10]** (optional, `1` by default) time in seconds to wait (optional, default `1`) -* `context` **([string][5] | [object][11])?** (optional) element located by CSS|XPath|strict locator. (optional, default `null`) +- `text` **[string][5]** to wait for. +- `sec` **[number][10]** (optional, `1` by default) time in seconds to wait (optional, default `1`) +- `context` **([string][5] | [object][11])?** (optional) element located by CSS|XPath|strict locator. (optional, default `null`) Returns **void** automatically synchronized promise through #recorder [1]: http://codecept.io/helpers/WebDriver/ - [2]: https://appium.io/docs/en/2.1/ - [3]: https://codecept.io/mobile/#setting-up - [4]: https://github.com/appium/appium/blob/master/packages/appium/docs/en/guides/caps.md - [5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String - [6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise - [7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean - [8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array - [9]: https://webdriver.io/docs/api/chromium/#setnetworkconnection - [10]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number - [11]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object - [12]: https://developer.android.com/reference/android/view/KeyEvent.html - [13]: http://webdriver.io/api/mobile/touchAction.html - [14]: http://webdriver.io/api/mobile/swipe.html - [15]: http://webdriver.io/api/mobile/rotate.html - [16]: http://webdriver.io/api/mobile/setImmediateValue.html - [17]: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView diff --git a/docs/helpers/Detox.md b/docs/helpers/Detox.md index 4d5c46204..bfe37c6aa 100644 --- a/docs/helpers/Detox.md +++ b/docs/helpers/Detox.md @@ -6,7 +6,6 @@ title: Detox # Detox - ## Detox @@ -81,15 +80,15 @@ It's important to specify a package name under `require` section and current det Options: -* `configuration` - a detox configuration name. Required. -* `reloadReactNative` - should be enabled for React Native applications. -* `reuse` - reuse application for tests. By default, Detox reinstalls and relaunches app. -* `registerGlobals` - (default: true) Register Detox helper functions `by`, `element`, `expect`, `waitFor` globally. -* `url` - URL to open via deep-link each time the app is launched (android) or immediately afterwards (iOS). Useful for opening a bundle URL at the beginning of tests when working with Expo. +- `configuration` - a detox configuration name. Required. +- `reloadReactNative` - should be enabled for React Native applications. +- `reuse` - reuse application for tests. By default, Detox reinstalls and relaunches app. +- `registerGlobals` - (default: true) Register Detox helper functions `by`, `element`, `expect`, `waitFor` globally. +- `url` - URL to open via deep-link each time the app is launched (android) or immediately afterwards (iOS). Useful for opening a bundle URL at the beginning of tests when working with Expo. ### Parameters -* `config` +- `config` ### appendField @@ -97,27 +96,27 @@ Appends text into the field. A field can be located by text, accessibility id, id. ```js -I.appendField('name', 'davert'); +I.appendField('name', 'davert') ``` #### Parameters -* `field` **([string][5] | [object][6])** -* `value` **[string][5]** +- `field` **([string][5] | [object][6])** +- `value` **[string][5]** ### checkIfElementExists Checks if an element exists. ```js -I.checkIfElementExists('~edit'); // located by accessibility id -I.checkIfElementExists('~edit', '#menu'); // element inside #menu +I.checkIfElementExists('~edit') // located by accessibility id +I.checkIfElementExists('~edit', '#menu') // element inside #menu ``` #### Parameters -* `locator` **([string][5] | [object][6])** element to locate -* `context` **([string][5] | [object][6] | null)** context element (optional, default `null`) +- `locator` **([string][5] | [object][6])** element to locate +- `context` **([string][5] | [object][6] | null)** context element (optional, default `null`) ### clearField @@ -125,12 +124,12 @@ Clears a text field. A field can be located by text, accessibility id, id. ```js -I.clearField('~name'); +I.clearField('~name') ``` #### Parameters -* `field` **([string][5] | [object][6])** an input element to clear +- `field` **([string][5] | [object][6])** an input element to clear ### click @@ -142,17 +141,17 @@ The second parameter is a context (id | type | accessibility id) to narrow the s Same as [tap][7] ```js -I.click('Login'); // locate by text -I.click('~nav-1'); // locate by accessibility label -I.click('#user'); // locate by id -I.click('Login', '#nav'); // locate by text inside #nav -I.click({ ios: 'Save', android: 'SAVE' }, '#main'); // different texts on iOS and Android +I.click('Login') // locate by text +I.click('~nav-1') // locate by accessibility label +I.click('#user') // locate by id +I.click('Login', '#nav') // locate by text inside #nav +I.click({ ios: 'Save', android: 'SAVE' }, '#main') // different texts on iOS and Android ``` #### Parameters -* `locator` **([string][5] | [object][6])** -* `context` **([string][5] | [object][6] | null)** (optional, default `null`) +- `locator` **([string][5] | [object][6])** +- `context` **([string][5] | [object][6] | null)** (optional, default `null`) ### clickAtPoint @@ -160,15 +159,15 @@ Performs click on element with horizontal and vertical offset. An element is located by text, id, accessibility id. ```js -I.clickAtPoint('Save', 10, 10); -I.clickAtPoint('~save', 10, 10); // locate by accessibility id +I.clickAtPoint('Save', 10, 10) +I.clickAtPoint('~save', 10, 10) // locate by accessibility id ``` #### Parameters -* `locator` **([string][5] | [object][6])** -* `x` **[number][8]** horizontal offset (optional, default `0`) -* `y` **[number][8]** vertical offset (optional, default `0`) +- `locator` **([string][5] | [object][6])** +- `x` **[number][8]** horizontal offset (optional, default `0`) +- `y` **[number][8]** vertical offset (optional, default `0`) ### dontSee @@ -176,15 +175,15 @@ Checks text not to be visible. Use second parameter to narrow down the search. ```js -I.dontSee('Record created'); -I.dontSee('Record updated', '#message'); -I.dontSee('Record deleted', '~message'); +I.dontSee('Record created') +I.dontSee('Record updated', '#message') +I.dontSee('Record deleted', '~message') ``` #### Parameters -* `text` **[string][5]** to check invisibility -* `context` **([string][5] | [object][6] | null)** element in which to search for text (optional, default `null`) +- `text` **[string][5]** to check invisibility +- `context` **([string][5] | [object][6] | null)** element in which to search for text (optional, default `null`) ### dontSeeElement @@ -192,14 +191,14 @@ Checks that element is not visible. Use second parameter to narrow down the search. ```js -I.dontSeeElement('~edit'); // located by accessibility id -I.dontSeeElement('~edit', '#menu'); // element inside #menu +I.dontSeeElement('~edit') // located by accessibility id +I.dontSeeElement('~edit', '#menu') // element inside #menu ``` #### Parameters -* `locator` **([string][5] | [object][6])** element to locate -* `context` **([string][5] | [object][6] | null)** context element (optional, default `null`) +- `locator` **([string][5] | [object][6])** element to locate +- `context` **([string][5] | [object][6] | null)** context element (optional, default `null`) ### dontSeeElementExists @@ -207,14 +206,14 @@ Checks that element not exists. Use second parameter to narrow down the search. ```js -I.dontSeeElementExist('~edit'); // located by accessibility id -I.dontSeeElementExist('~edit', '#menu'); // element inside #menu +I.dontSeeElementExist('~edit') // located by accessibility id +I.dontSeeElementExist('~edit', '#menu') // element inside #menu ``` #### Parameters -* `locator` **([string][5] | [object][6])** element to locate -* `context` **([string][5] | [object][6])** context element (optional, default `null`) +- `locator` **([string][5] | [object][6])** element to locate +- `context` **([string][5] | [object][6])** context element (optional, default `null`) ### fillField @@ -222,22 +221,22 @@ Fills in text field in an app. A field can be located by text, accessibility id, id. ```js -I.fillField('Username', 'davert'); -I.fillField('~name', 'davert'); -I.fillField({ android: 'NAME', ios: 'name' }, 'davert'); +I.fillField('Username', 'davert') +I.fillField('~name', 'davert') +I.fillField({ android: 'NAME', ios: 'name' }, 'davert') ``` #### Parameters -* `field` **([string][5] | [object][6])** an input element to fill in -* `value` **[string][5]** value to fill +- `field` **([string][5] | [object][6])** an input element to fill in +- `value` **[string][5]** value to fill ### goBack Goes back on Android ```js -I.goBack(); // on Android only +I.goBack() // on Android only ``` ### grabPlatform @@ -245,7 +244,7 @@ I.goBack(); // on Android only Grab the device platform ```js -const platform = await I.grabPlatform(); +const platform = await I.grabPlatform() ``` ### installApp @@ -254,7 +253,7 @@ Installs a configured application. Application is installed by default. ```js -I.installApp(); +I.installApp() ``` ### launchApp @@ -262,7 +261,7 @@ I.installApp(); Launches an application. If application instance already exists, use [relaunchApp][9]. ```js -I.launchApp(); +I.launchApp() ``` ### longPress @@ -270,16 +269,16 @@ I.launchApp(); Taps an element and holds for a requested time. ```js -I.longPress('Login', 2); // locate by text, hold for 2 seconds -I.longPress('~nav', 1); // locate by accessibility label, hold for second -I.longPress('Update', 2, '#menu'); // locate by text inside #menu, hold for 2 seconds +I.longPress('Login', 2) // locate by text, hold for 2 seconds +I.longPress('~nav', 1) // locate by accessibility label, hold for second +I.longPress('Update', 2, '#menu') // locate by text inside #menu, hold for 2 seconds ``` #### Parameters -* `locator` **([string][5] | [object][6])** element to locate -* `sec` **[number][8]** number of seconds to hold tap -* `context` **([string][5] | [object][6] | null)** context element (optional, default `null`) +- `locator` **([string][5] | [object][6])** element to locate +- `sec` **[number][8]** number of seconds to hold tap +- `context` **([string][5] | [object][6] | null)** context element (optional, default `null`) ### multiTap @@ -290,24 +289,24 @@ Set the number of taps in second argument. Optionally define the context element by third argument. ```js -I.multiTap('Login', 2); // locate by text -I.multiTap('~nav', 2); // locate by accessibility label -I.multiTap('#user', 2); // locate by id -I.multiTap('Update', 2, '#menu'); // locate by id +I.multiTap('Login', 2) // locate by text +I.multiTap('~nav', 2) // locate by accessibility label +I.multiTap('#user', 2) // locate by id +I.multiTap('Update', 2, '#menu') // locate by id ``` #### Parameters -* `locator` **([string][5] | [object][6])** element to locate -* `num` **[number][8]** number of taps -* `context` **([string][5] | [object][6] | null)** context element (optional, default `null`) +- `locator` **([string][5] | [object][6])** element to locate +- `num` **[number][8]** number of taps +- `context` **([string][5] | [object][6] | null)** context element (optional, default `null`) ### relaunchApp Relaunches an application. ```js -I.relaunchApp(); +I.relaunchApp() ``` ### runOnAndroid @@ -316,14 +315,14 @@ Execute code only on Android ```js I.runOnAndroid(() => { - I.click('Button'); - I.see('Hi, Android'); -}); + I.click('Button') + I.see('Hi, Android') +}) ``` #### Parameters -* `fn` **[Function][10]** a function which will be executed on android +- `fn` **[Function][10]** a function which will be executed on android ### runOnIOS @@ -331,62 +330,62 @@ Execute code only on iOS ```js I.runOnIOS(() => { - I.click('Button'); - I.see('Hi, IOS'); -}); + I.click('Button') + I.see('Hi, IOS') +}) ``` #### Parameters -* `fn` **[Function][10]** a function which will be executed on iOS +- `fn` **[Function][10]** a function which will be executed on iOS ### saveScreenshot Saves a screenshot to the output dir ```js -I.saveScreenshot('main-window.png'); +I.saveScreenshot('main-window.png') ``` #### Parameters -* `name` **[string][5]** +- `name` **[string][5]** ### scrollDown Scrolls to the bottom of an element. ```js -I.scrollDown('#container'); +I.scrollDown('#container') ``` #### Parameters -* `locator` **([string][5] | [object][6])** +- `locator` **([string][5] | [object][6])** ### scrollLeft Scrolls to the left of an element. ```js -I.scrollLeft('#container'); +I.scrollLeft('#container') ``` #### Parameters -* `locator` **([string][5] | [object][6])** +- `locator` **([string][5] | [object][6])** ### scrollRight Scrolls to the right of an element. ```js -I.scrollRight('#container'); +I.scrollRight('#container') ``` #### Parameters -* `locator` **([string][5] | [object][6])** +- `locator` **([string][5] | [object][6])** ### scrollToElement @@ -394,22 +393,22 @@ Scrolls within a scrollable container to an element. #### Parameters -* `targetLocator` **([string][5] | [object][6])** Locator of the element to scroll to -* `containerLocator` **([string][5] | [object][6])** Locator of the scrollable container -* `direction` **[string][5]** 'up' or 'down' (optional, default `'down'`) -* `offset` **[number][8]** Offset for scroll, can be adjusted based on need (optional, default `100`) +- `targetLocator` **([string][5] | [object][6])** Locator of the element to scroll to +- `containerLocator` **([string][5] | [object][6])** Locator of the scrollable container +- `direction` **[string][5]** 'up' or 'down' (optional, default `'down'`) +- `offset` **[number][8]** Offset for scroll, can be adjusted based on need (optional, default `100`) ### scrollUp Scrolls to the top of an element. ```js -I.scrollUp('#container'); +I.scrollUp('#container') ``` #### Parameters -* `locator` **([string][5] | [object][6])** +- `locator` **([string][5] | [object][6])** ### see @@ -417,15 +416,15 @@ Checks text to be visible. Use second parameter to narrow down the search. ```js -I.see('Record created'); -I.see('Record updated', '#message'); -I.see('Record deleted', '~message'); +I.see('Record created') +I.see('Record updated', '#message') +I.see('Record deleted', '~message') ``` #### Parameters -* `text` **[string][5]** to check visibility -* `context` **([string][5] | [object][6] | null)** element inside which to search for text (optional, default `null`) +- `text` **[string][5]** to check visibility +- `context` **([string][5] | [object][6] | null)** element inside which to search for text (optional, default `null`) ### seeElement @@ -433,14 +432,14 @@ Checks for visibility of an element. Use second parameter to narrow down the search. ```js -I.seeElement('~edit'); // located by accessibility id -I.seeElement('~edit', '#menu'); // element inside #menu +I.seeElement('~edit') // located by accessibility id +I.seeElement('~edit', '#menu') // element inside #menu ``` #### Parameters -* `locator` **([string][5] | [object][6])** element to locate -* `context` **([string][5] | [object][6] | null)** context element (optional, default `null`) +- `locator` **([string][5] | [object][6])** element to locate +- `context` **([string][5] | [object][6] | null)** context element (optional, default `null`) ### seeElementExists @@ -448,21 +447,21 @@ Checks for existence of an element. An element can be visible or not. Use second parameter to narrow down the search. ```js -I.seeElementExists('~edit'); // located by accessibility id -I.seeElementExists('~edit', '#menu'); // element inside #menu +I.seeElementExists('~edit') // located by accessibility id +I.seeElementExists('~edit', '#menu') // element inside #menu ``` #### Parameters -* `locator` **([string][5] | [object][6])** element to locate -* `context` **([string][5] | [object][6])** context element (optional, default `null`) +- `locator` **([string][5] | [object][6])** element to locate +- `context` **([string][5] | [object][6])** context element (optional, default `null`) ### setLandscapeOrientation Switches device to landscape orientation ```js -I.setLandscapeOrientation(); +I.setLandscapeOrientation() ``` ### setPortraitOrientation @@ -470,7 +469,7 @@ I.setLandscapeOrientation(); Switches device to portrait orientation ```js -I.setPortraitOrientation(); +I.setPortraitOrientation() ``` ### shakeDevice @@ -478,7 +477,7 @@ I.setPortraitOrientation(); Shakes the device. ```js -I.shakeDevice(); +I.shakeDevice() ``` ### swipeDown @@ -487,13 +486,13 @@ Performs a swipe up inside an element. Can be `slow` or `fast` swipe. ```js -I.swipeUp('#container'); +I.swipeUp('#container') ``` #### Parameters -* `locator` **([string][5] | [object][6])** an element on which to perform swipe -* `speed` **[string][5]** a speed to perform: `slow` or `fast`. (optional, default `'slow'`) +- `locator` **([string][5] | [object][6])** an element on which to perform swipe +- `speed` **[string][5]** a speed to perform: `slow` or `fast`. (optional, default `'slow'`) ### swipeLeft @@ -501,13 +500,13 @@ Performs a swipe up inside an element. Can be `slow` or `fast` swipe. ```js -I.swipeUp('#container'); +I.swipeUp('#container') ``` #### Parameters -* `locator` **([string][5] | [object][6])** an element on which to perform swipe -* `speed` **[string][5]** a speed to perform: `slow` or `fast`. (optional, default `'slow'`) +- `locator` **([string][5] | [object][6])** an element on which to perform swipe +- `speed` **[string][5]** a speed to perform: `slow` or `fast`. (optional, default `'slow'`) ### swipeRight @@ -515,13 +514,13 @@ Performs a swipe up inside an element. Can be `slow` or `fast` swipe. ```js -I.swipeUp('#container'); +I.swipeUp('#container') ``` #### Parameters -* `locator` **([string][5] | [object][6])** an element on which to perform swipe -* `speed` **[string][5]** a speed to perform: `slow` or `fast`. (optional, default `'slow'`) +- `locator` **([string][5] | [object][6])** an element on which to perform swipe +- `speed` **[string][5]** a speed to perform: `slow` or `fast`. (optional, default `'slow'`) ### swipeUp @@ -529,13 +528,13 @@ Performs a swipe up inside an element. Can be `slow` or `fast` swipe. ```js -I.swipeUp('#container'); +I.swipeUp('#container') ``` #### Parameters -* `locator` **([string][5] | [object][6])** an element on which to perform swipe -* `speed` **[string][5]** a speed to perform: `slow` or `fast`. (optional, default `'slow'`) +- `locator` **([string][5] | [object][6])** an element on which to perform swipe +- `speed` **[string][5]** a speed to perform: `slow` or `fast`. (optional, default `'slow'`) ### tap @@ -547,17 +546,17 @@ The second parameter is a context element to narrow the search. Same as [click][11] ```js -I.tap('Login'); // locate by text -I.tap('~nav-1'); // locate by accessibility label -I.tap('#user'); // locate by id -I.tap('Login', '#nav'); // locate by text inside #nav -I.tap({ ios: 'Save', android: 'SAVE' }, '#main'); // different texts on iOS and Android +I.tap('Login') // locate by text +I.tap('~nav-1') // locate by accessibility label +I.tap('#user') // locate by id +I.tap('Login', '#nav') // locate by text inside #nav +I.tap({ ios: 'Save', android: 'SAVE' }, '#main') // different texts on iOS and Android ``` #### Parameters -* `locator` **([string][5] | [object][6])** -* `context` **([string][5] | [object][6] | null)** (optional, default `null`) +- `locator` **([string][5] | [object][6])** +- `context` **([string][5] | [object][6] | null)** (optional, default `null`) ### tapByLabel @@ -567,14 +566,14 @@ Element can be located by its label The second parameter is a context (id | type | accessibility id) to narrow the search. ```js -I.tapByLabel('Login'); // locate by text -I.tapByLabel('Login', '#nav'); // locate by text inside #nav +I.tapByLabel('Login') // locate by text +I.tapByLabel('Login', '#nav') // locate by text inside #nav ``` #### Parameters -* `locator` **([string][5] | [object][6])** -* `context` **([string][5] | [object][6] | null)** (optional, default `null`) +- `locator` **([string][5] | [object][6])** +- `context` **([string][5] | [object][6] | null)** (optional, default `null`) ### tapReturnKey @@ -582,84 +581,74 @@ Taps return key. A field can be located by text, accessibility id, id. ```js -I.tapReturnKey('Username'); -I.tapReturnKey('~name'); -I.tapReturnKey({ android: 'NAME', ios: 'name' }); +I.tapReturnKey('Username') +I.tapReturnKey('~name') +I.tapReturnKey({ android: 'NAME', ios: 'name' }) ``` #### Parameters -* `field` **([string][5] | [object][6])** an input element to fill in +- `field` **([string][5] | [object][6])** an input element to fill in ### wait Waits for number of seconds ```js -I.wait(2); // waits for 2 seconds +I.wait(2) // waits for 2 seconds ``` #### Parameters -* `sec` **[number][8]** number of seconds to wait +- `sec` **[number][8]** number of seconds to wait ### waitForElement Waits for an element to exist on page. ```js -I.waitForElement('#message', 1); // wait for 1 second +I.waitForElement('#message', 1) // wait for 1 second ``` #### Parameters -* `locator` **([string][5] | [object][6])** an element to wait for -* `sec` **[number][8]** number of seconds to wait, 5 by default (optional, default `5`) +- `locator` **([string][5] | [object][6])** an element to wait for +- `sec` **[number][8]** number of seconds to wait, 5 by default (optional, default `5`) ### waitForElementVisible Waits for an element to be visible on page. ```js -I.waitForElementVisible('#message', 1); // wait for 1 second +I.waitForElementVisible('#message', 1) // wait for 1 second ``` #### Parameters -* `locator` **([string][5] | [object][6])** an element to wait for -* `sec` **[number][8]** number of seconds to wait (optional, default `5`) +- `locator` **([string][5] | [object][6])** an element to wait for +- `sec` **[number][8]** number of seconds to wait (optional, default `5`) ### waitToHide Waits an elmenet to become not visible. ```js -I.waitToHide('#message', 2); // wait for 2 seconds +I.waitToHide('#message', 2) // wait for 2 seconds ``` #### Parameters -* `locator` **([string][5] | [object][6])** an element to wait for -* `sec` **[number][8]** number of seconds to wait (optional, default `5`) +- `locator` **([string][5] | [object][6])** an element to wait for +- `sec` **[number][8]** number of seconds to wait (optional, default `5`) [1]: https://github.com/wix/Detox - [2]: https://wix.github.io/Detox/docs/introduction/project-setup - [3]: https://wix.github.io/Detox/docs/introduction/project-setup#step-5-build-the-app - [4]: https://codecept.io - [5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String - [6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object - [7]: #tap - [8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number - [9]: #relaunchApp - [10]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function - [11]: #click diff --git a/docs/helpers/FileSystem.md b/docs/helpers/FileSystem.md index cd3d1351a..d85220a3f 100644 --- a/docs/helpers/FileSystem.md +++ b/docs/helpers/FileSystem.md @@ -15,10 +15,10 @@ Helper for testing filesystem. Can be easily used to check file structures: ```js -I.amInPath('test'); -I.seeFile('codecept.js'); -I.seeInThisFile('FileSystem'); -I.dontSeeInThisFile("WebDriver"); +I.amInPath('test') +I.seeFile('codecept.js') +I.seeInThisFile('FileSystem') +I.dontSeeInThisFile('WebDriver') ``` ## Configuration @@ -40,7 +40,7 @@ Starts from a current directory #### Parameters -* `openPath` **[string][1]** +- `openPath` **[string][1]** ### dontSeeFileContentsEqual @@ -48,8 +48,8 @@ Checks that contents of file found by `seeFile` doesn't equal to text. #### Parameters -* `text` **[string][1]** -* `encoding` **[string][1]** +- `text` **[string][1]** +- `encoding` **[string][1]** ### dontSeeInThisFile @@ -57,18 +57,18 @@ Checks that file found by `seeFile` doesn't include text. #### Parameters -* `text` **[string][1]** -* `encoding` **[string][1]** +- `text` **[string][1]** +- `encoding` **[string][1]** ### grabFileNames Returns file names in current directory. ```js -I.handleDownloads(); -I.click('Download Files'); -I.amInPath('output/downloads'); -const downloadedFileNames = I.grabFileNames(); +I.handleDownloads() +I.click('Download Files') +I.amInPath('output/downloads') +const downloadedFileNames = I.grabFileNames() ``` ### seeFile @@ -77,7 +77,7 @@ Checks that file exists #### Parameters -* `name` **[string][1]** +- `name` **[string][1]** ### seeFileContentsEqual @@ -85,8 +85,8 @@ Checks that contents of file found by `seeFile` equal to text. #### Parameters -* `text` **[string][1]** -* `encoding` **[string][1]** +- `text` **[string][1]** +- `encoding` **[string][1]** ### seeFileContentsEqualReferenceFile @@ -94,24 +94,24 @@ Checks that contents of the file found by `seeFile` equal to contents of the fil #### Parameters -* `pathToReferenceFile` **[string][1]** -* `encoding` **[string][1]** -* `encodingReference` **[string][1]** +- `pathToReferenceFile` **[string][1]** +- `encoding` **[string][1]** +- `encodingReference` **[string][1]** ### seeFileNameMatching Checks that file with a name including given text exists in the current directory. ```js -I.handleDownloads(); -I.click('Download as PDF'); -I.amInPath('output/downloads'); -I.seeFileNameMatching('.pdf'); +I.handleDownloads() +I.click('Download as PDF') +I.amInPath('output/downloads') +I.seeFileNameMatching('.pdf') ``` #### Parameters -* `text` **[string][1]** +- `text` **[string][1]** ### seeInThisFile @@ -119,24 +119,24 @@ Checks that file found by `seeFile` includes a text. #### Parameters -* `text` **[string][1]** -* `encoding` **[string][1]** +- `text` **[string][1]** +- `encoding` **[string][1]** ### waitForFile Waits for the file to be present in the current directory. ```js -I.handleDownloads('downloads/largeFilesName.txt'); -I.click('Download large File'); -I.amInPath('output/downloads'); -I.waitForFile('largeFilesName.txt', 10); // wait 10 seconds for file +I.handleDownloads('downloads/largeFilesName.txt') +I.click('Download large File') +I.amInPath('output/downloads') +I.waitForFile('largeFilesName.txt', 10) // wait 10 seconds for file ``` #### Parameters -* `name` **[string][1]** -* `sec` **[number][2]** seconds to wait +- `name` **[string][1]** +- `sec` **[number][2]** seconds to wait ### writeToFile @@ -144,9 +144,8 @@ Writes text to file #### Parameters -* `name` **[string][1]** -* `text` **[string][1]** +- `name` **[string][1]** +- `text` **[string][1]** [1]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String - [2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number diff --git a/docs/helpers/GraphQL.md b/docs/helpers/GraphQL.md index 7aa35c637..2daed8d04 100644 --- a/docs/helpers/GraphQL.md +++ b/docs/helpers/GraphQL.md @@ -16,10 +16,10 @@ GraphQL helper allows to send additional requests to a GraphQl endpoint during a ## Configuration -* endpoint: GraphQL base URL -* timeout: timeout for requests in milliseconds. 10000ms by default -* defaultHeaders: a list of default headers -* onRequest: a async function which can update request object. +- endpoint: GraphQL base URL +- timeout: timeout for requests in milliseconds. 10000ms by default +- defaultHeaders: a list of default headers +- onRequest: a async function which can update request object. ## Example @@ -38,33 +38,33 @@ Send GraphQL requests by accessing `_executeQuery` method: ```js this.helpers['GraphQL']._executeQuery({ - url, - data, -}); + url, + data, +}) ``` ## Methods ### Parameters -* `config` +- `config` -### _executeQuery +### \_executeQuery Executes query via axios call #### Parameters -* `request` **[object][2]** +- `request` **[object][2]** -### _prepareGraphQLRequest +### \_prepareGraphQLRequest Prepares request for axios call #### Parameters -* `operation` **[object][2]** -* `headers` **[object][2]** +- `operation` **[object][2]** +- `headers` **[object][2]** Returns **[object][2]** graphQLRequest @@ -79,7 +79,7 @@ I.amBearerAuthenticated(secret('heregoestoken')) #### Parameters -* `accessToken` **([string][3] | CodeceptJS.Secret)** Bearer access token +- `accessToken` **([string][3] | CodeceptJS.Secret)** Bearer access token ### haveRequestHeaders @@ -87,7 +87,7 @@ Sets request headers for all requests of this test #### Parameters -* `headers` **[object][2]** headers list +- `headers` **[object][2]** headers list ### sendMutation @@ -113,10 +113,10 @@ I.sendMutation(` #### Parameters -* `mutation` **[String][3]** -* `variables` **[object][2]?** that may go along with the mutation -* `options` **[object][2]?** are additional query options -* `headers` **[object][2]?** +- `mutation` **[String][3]** +- `variables` **[object][2]?** that may go along with the mutation +- `options` **[object][2]?** are additional query options +- `headers` **[object][2]?** Returns **any** Promise @@ -126,27 +126,21 @@ Send query to GraphQL endpoint over http. Returns a response as a promise. ```js - -const response = await I.sendQuery('{ users { name email }}'); +const response = await I.sendQuery('{ users { name email }}') // with variables -const response = await I.sendQuery( - 'query getUser($id: ID) { user(id: $id) { name email }}', - { id: 1 }, -) -const user = response.data.data; +const response = await I.sendQuery('query getUser($id: ID) { user(id: $id) { name email }}', { id: 1 }) +const user = response.data.data ``` #### Parameters -* `query` **[String][3]** -* `variables` **[object][2]?** that may go along with the query -* `options` **[object][2]?** are additional query options -* `headers` **[object][2]?** +- `query` **[String][3]** +- `variables` **[object][2]?** that may go along with the query +- `options` **[object][2]?** are additional query options +- `headers` **[object][2]?** Returns **any** Promise [1]: https://github.com/axios/axios - [2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object - [3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String diff --git a/docs/helpers/GraphQLDataFactory.md b/docs/helpers/GraphQLDataFactory.md index 277cf2cd6..6d1370ebb 100644 --- a/docs/helpers/GraphQLDataFactory.md +++ b/docs/helpers/GraphQLDataFactory.md @@ -28,9 +28,9 @@ If a web application has GraphQL support, it can be used to create and delete te By combining GraphQL with Factories you can easily create records for tests: ```js -I.mutateData('createUser', { name: 'davert', email: 'davert@mail.com' }); -let user = await I.mutateData('createUser', { name: 'davert'}); -I.mutateMultiple('createPost', 3, {post_id: user.id}); +I.mutateData('createUser', { name: 'davert', email: 'davert@mail.com' }) +let user = await I.mutateData('createUser', { name: 'davert' }) +I.mutateMultiple('createPost', 3, { post_id: user.id }) ``` To make this work you need @@ -53,17 +53,17 @@ See the example for Users factories: ```js // tests/factories/users.js -const { Factory } = require('rosie').Factory; -const { faker } = require('@faker-js/faker'); +const { Factory } = require('rosie').Factory +const { faker } = require('@faker-js/faker') // Used with a constructor function passed to Factory, so that the final build // object matches the necessary pattern to be sent as the variables object. -module.exports = new Factory((buildObj) => ({ - input: { ...buildObj }, +module.exports = new Factory(buildObj => ({ + input: { ...buildObj }, })) - // 'attr'-id can be left out depending on the GraphQl resolvers - .attr('name', () => faker.person.findName()) - .attr('email', () => faker.interact.email()) + // 'attr'-id can be left out depending on the GraphQl resolvers + .attr('name', () => faker.person.findName()) + .attr('email', () => faker.interact.email()) ``` For more options see [rosie documentation][1]. @@ -74,11 +74,11 @@ Then configure GraphQLDataHelper to match factories and GraphQL schema: GraphQLDataFactory has following config options: -* `endpoint`: URL for the GraphQL server. -* `cleanup` (default: true): should inserted records be deleted up after tests -* `factories`: list of defined factories -* `headers`: list of headers -* `GraphQL`: configuration for GraphQL requests. +- `endpoint`: URL for the GraphQL server. +- `cleanup` (default: true): should inserted records be deleted up after tests +- `factories`: list of defined factories +- `headers`: list of headers +- `GraphQL`: configuration for GraphQL requests. See the example: @@ -121,27 +121,27 @@ For instance, to set timeout you should add: Factory contains operations - -* `operation`: The operation/mutation that needs to be performed for creating a record in the backend. +- `operation`: The operation/mutation that needs to be performed for creating a record in the backend. Each operation must have the following: -* `query`: The mutation(query) string. It is expected to use variables to send data with the query. -* `factory`: The path to factory file. The object built by the factory in this file will be passed - as the 'variables' object to go along with the mutation. -* `revert`: A function called with the data returned when an item is created. The object returned by - this function is will be used to later delete the items created. So, make sure RELEVANT DATA IS RETURNED - when a record is created by a mutation. +- `query`: The mutation(query) string. It is expected to use variables to send data with the query. +- `factory`: The path to factory file. The object built by the factory in this file will be passed + as the 'variables' object to go along with the mutation. +- `revert`: A function called with the data returned when an item is created. The object returned by + this function is will be used to later delete the items created. So, make sure RELEVANT DATA IS RETURNED + when a record is created by a mutation. ### Requests Requests can be updated on the fly by using `onRequest` function. For instance, you can pass in current session from a cookie. ```js - onRequest: async (request) => { - // using global codeceptjs instance - let cookie = await codeceptjs.container.helpers('WebDriver').grabCookie('session'); - request.headers = { Cookie: `session=${cookie.value}` }; - } +onRequest: async request => { + // using global codeceptjs instance + let cookie = await codeceptjs.container.helpers('WebDriver').grabCookie('session') + request.headers = { Cookie: `session=${cookie.value}` } +} ``` ### Responses @@ -149,7 +149,7 @@ Requests can be updated on the fly by using `onRequest` function. For instance, By default `I.mutateData()` returns a promise with created data as specified in operation query string: ```js -let client = await I.mutateData('createClient'); +let client = await I.mutateData('createClient') ``` Data of created records are collected and used in the end of a test for the cleanup. @@ -158,27 +158,27 @@ Data of created records are collected and used in the end of a test for the clea ### Parameters -* `config` +- `config` -### _requestCreate +### \_requestCreate Executes request to create a record to the GraphQL endpoint. Can be replaced from a custom helper. #### Parameters -* `operation` **[string][4]** -* `variables` **any** to be sent along with the query +- `operation` **[string][4]** +- `variables` **any** to be sent along with the query -### _requestDelete +### \_requestDelete Executes request to delete a record to the GraphQL endpoint. Can be replaced from a custom helper. #### Parameters -* `operation` **[string][4]** -* `data` **any** of the record to be deleted. +- `operation` **[string][4]** +- `data` **any** of the record to be deleted. ### mutateData @@ -186,16 +186,16 @@ Generates a new record using factory, sends a GraphQL mutation to store it. ```js // create a user -I.mutateData('createUser'); +I.mutateData('createUser') // create user with defined email // and receive it when inside async function -const user = await I.mutateData('createUser', { email: 'user@user.com'}); +const user = await I.mutateData('createUser', { email: 'user@user.com' }) ``` #### Parameters -* `operation` **[string][4]** to be performed -* `params` **any** predefined parameters +- `operation` **[string][4]** to be performed +- `params` **any** predefined parameters ### mutateMultiple @@ -203,24 +203,20 @@ Generates bunch of records and sends multiple GraphQL mutation requests to store ```js // create 3 users -I.mutateMultiple('createUser', 3); +I.mutateMultiple('createUser', 3) // create 3 users of same age -I.mutateMultiple('createUser', 3, { age: 25 }); +I.mutateMultiple('createUser', 3, { age: 25 }) ``` #### Parameters -* `operation` **[string][4]** -* `times` **[number][5]** -* `params` **any** +- `operation` **[string][4]** +- `times` **[number][5]** +- `params` **any** [1]: https://github.com/rosiejs/rosie - [2]: https://www.npmjs.com/package/faker - [3]: http://codecept.io/helpers/GraphQL/ - [4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String - [5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number diff --git a/docs/helpers/JSONResponse.md b/docs/helpers/JSONResponse.md index e9c12ca9c..c29de46a9 100644 --- a/docs/helpers/JSONResponse.md +++ b/docs/helpers/JSONResponse.md @@ -13,15 +13,15 @@ title: JSONResponse This helper allows performing assertions on JSON responses paired with following helpers: -* REST -* GraphQL -* Playwright +- REST +- GraphQL +- Playwright It can check status codes, response data, response structure. ## Configuration -* `requestHelper` - a helper which will perform requests. `REST` by default, also `Playwright` or `GraphQL` can be used. Custom helpers must have `onResponse` hook in their config, which will be executed when request is performed. +- `requestHelper` - a helper which will perform requests. `REST` by default, also `Playwright` or `GraphQL` can be used. Custom helpers must have `onResponse` hook in their config, which will be executed when request is performed. ### Examples @@ -61,26 +61,26 @@ If you plan to add custom assertions it is recommended to create a helper that w ```js // inside custom helper -const response = this.helpers.JSONResponse.response; +const response = this.helpers.JSONResponse.response ``` ## Methods ### Parameters -* `config` +- `config` ### dontSeeResponseCodeIs Checks that response code is not equal to the provided one ```js -I.dontSeeResponseCodeIs(500); +I.dontSeeResponseCodeIs(500) ``` #### Parameters -* `code` **[number][1]** +- `code` **[number][1]** ### dontSeeResponseContainsJson @@ -89,7 +89,7 @@ Checks for deep inclusion of a provided json in a response data. ```js // response.data == { data: { user: 1 } } -I.dontSeeResponseContainsJson({ user: 2 }); +I.dontSeeResponseContainsJson({ user: 2 }) ``` If an array is received, checks that no element of array contains json: @@ -97,24 +97,24 @@ If an array is received, checks that no element of array contains json: ```js // response.data == [{ user: 1 }, { user: 3 }] -I.dontSeeResponseContainsJson({ user: 2 }); +I.dontSeeResponseContainsJson({ user: 2 }) ``` #### Parameters -* `json` **[object][2]** +- `json` **[object][2]** ### seeResponseCodeIs Checks that response code is equal to the provided one ```js -I.seeResponseCodeIs(200); +I.seeResponseCodeIs(200) ``` #### Parameters -* `code` **[number][1]** +- `code` **[number][1]** ### seeResponseCodeIsClientError @@ -134,7 +134,7 @@ Checks that the response code is 2xx Use it instead of seeResponseCodeIs(200) if server can return 204 instead. ```js -I.seeResponseCodeIsSuccessful(); +I.seeResponseCodeIsSuccessful() ``` ### seeResponseContainsJson @@ -144,7 +144,7 @@ Checks for deep inclusion of a provided json in a response data. ```js // response.data == { user: { name: 'jon', email: 'jon@doe.com' } } -I.seeResponseContainsJson({ user: { email: 'jon@doe.com' } }); +I.seeResponseContainsJson({ user: { email: 'jon@doe.com' } }) ``` If an array is received, checks that at least one element contains JSON @@ -152,12 +152,12 @@ If an array is received, checks that at least one element contains JSON ```js // response.data == [{ user: { name: 'jon', email: 'jon@doe.com' } }] -I.seeResponseContainsJson({ user: { email: 'jon@doe.com' } }); +I.seeResponseContainsJson({ user: { email: 'jon@doe.com' } }) ``` #### Parameters -* `json` **[object][2]** +- `json` **[object][2]** ### seeResponseContainsKeys @@ -166,7 +166,7 @@ Checks for deep inclusion of a provided json in a response data. ```js // response.data == { user: { name: 'jon', email: 'jon@doe.com' } } -I.seeResponseContainsKeys(['user']); +I.seeResponseContainsKeys(['user']) ``` If an array is received, check is performed for each element of array: @@ -174,12 +174,12 @@ If an array is received, check is performed for each element of array: ```js // response.data == [{ user: 'jon' }, { user: 'matt'}] -I.seeResponseContainsKeys(['user']); +I.seeResponseContainsKeys(['user']) ``` #### Parameters -* `keys` **[array][3]** +- `keys` **[array][3]** ### seeResponseEquals @@ -193,7 +193,7 @@ I.seeResponseEquals({ error: 'Not allowed' }) #### Parameters -* `resp` **[object][2]** +- `resp` **[object][2]** ### seeResponseMatchesJsonSchema @@ -223,7 +223,7 @@ I.seeResponseMatchesJsonSchema(joi.object({ #### Parameters -* `fnOrSchema` **any** +- `fnOrSchema` **any** ### seeResponseValidByCallback @@ -232,24 +232,19 @@ Use it to perform custom checks of response data ```js I.seeResponseValidByCallback(({ data, status }) => { - assert.strictEqual(status, 200); - assert('user' in data); - assert('company' in data); -}); + assert.strictEqual(status, 200) + assert('user' in data) + assert('company' in data) +}) ``` #### Parameters -* `fn` **[function][6]** +- `fn` **[function][6]** [1]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number - [2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object - [3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array - [4]: https://joi.dev - [5]: https://joi.dev/api/ - [6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function diff --git a/docs/helpers/MockRequest.md b/docs/helpers/MockRequest.md index 3fd179964..91f2adf46 100644 --- a/docs/helpers/MockRequest.md +++ b/docs/helpers/MockRequest.md @@ -6,7 +6,6 @@ title: MockRequest # MockRequest - ## MockRequest @@ -17,9 +16,9 @@ Another way of using is to emulate requests from server by passing prepared data MockRequest helper works in these [modes][1]: -* passthrough (default) - mock prefefined HTTP requests -* record - record all requests into a file -* replay - replay all recorded requests from a file +- passthrough (default) - mock prefefined HTTP requests +- record - record all requests into a file +- replay - replay all recorded requests from a file Combining record/replay modes allows testing websites with large datasets. @@ -27,16 +26,16 @@ To use in passthrough mode set rules to mock requests and they will be automatic ```js // default mode -I.mockRequest('GET', '/api/users', '[]'); +I.mockRequest('GET', '/api/users', '[]') ``` In record-replay mode start mocking to make HTTP requests recorded/replayed, and stop when you don't need to block requests anymore: ```js // record or replay all XHR for /users page -I.startMocking(); -I.amOnPage('/users'); -I.stopMocking(); +I.startMocking() +I.amOnPage('/users') +I.stopMocking() ``` ### Installations @@ -83,7 +82,7 @@ helpers: { } ``` -*** +--- **TROUBLESHOOTING**: Puppeteer does not mock requests in headless mode: @@ -104,7 +103,7 @@ Solution: update Puppeteer config to include `--disable-web-security` arguments: }, ``` -*** +--- #### With WebDriver @@ -129,17 +128,17 @@ helpers: { To intercept API requests and mock them use following API -* [startMocking()][4] - to enable request interception -* [mockRequest()][5] - to define mock in a simple way -* [mockServer()][6] - to use PollyJS server API to define complex mocks -* [stopMocking()][7] - to stop intercepting requests and disable mocks. +- [startMocking()][4] - to enable request interception +- [mockRequest()][5] - to define mock in a simple way +- [mockServer()][6] - to use PollyJS server API to define complex mocks +- [stopMocking()][7] - to stop intercepting requests and disable mocks. Calling `mockRequest` or `mockServer` will start mocking, if it was not enabled yet. ```js I.startMocking(); // optionally I.mockRequest('/google-analytics/*path', 200); -// return an empty successful response +// return an empty successful response I.mockRequest('GET', '/api/users', 200); // mock users api I.mockServer(server => { @@ -184,18 +183,18 @@ I.startMocking('users') // record requests under 'users' name Use `I.mockServer()` to customize which requests should be recorded and under which name: ```js -I.startMocking(); -I.mockServer((server) => { +I.startMocking() +I.mockServer(server => { // mock request only from ap1.com and api2.com and // store recording into two different files - server.any('https://api1.com/*').passthrough(false).recordingName('api1'); - server.any('https://api2.com/*').passthrough(false).recordingName('api2'); -}); + server.any('https://api1.com/*').passthrough(false).recordingName('api1') + server.any('https://api2.com/*').passthrough(false).recordingName('api2') +}) ``` To stop request recording/replaying use `I.stopMocking()`. -🎥 To record HTTP interactions execute tests with MOCK\_MODE environment variable set as "record": +🎥 To record HTTP interactions execute tests with MOCK_MODE environment variable set as "record": MOCK_MODE=record npx codeceptjs run --debug @@ -205,14 +204,14 @@ To stop request recording/replaying use `I.stopMocking()`. ### Parameters -* `config` +- `config` ### flushMocking Waits for all requests handled by MockRequests to be resolved: ```js -I.flushMocking(); +I.flushMocking() ``` ### mockRequest @@ -220,61 +219,60 @@ I.flushMocking(); Mock response status ```js -I.mockRequest('GET', '/api/users', 200); -I.mockRequest('ANY', '/secretsRoutes/*', 403); -I.mockRequest('POST', '/secrets', { secrets: 'fakeSecrets' }); -I.mockRequest('GET', '/api/users/1', 404, 'User not found'); +I.mockRequest('GET', '/api/users', 200) +I.mockRequest('ANY', '/secretsRoutes/*', 403) +I.mockRequest('POST', '/secrets', { secrets: 'fakeSecrets' }) +I.mockRequest('GET', '/api/users/1', 404, 'User not found') ``` Multiple requests ```js -I.mockRequest('GET', ['/secrets', '/v2/secrets'], 403); +I.mockRequest('GET', ['/secrets', '/v2/secrets'], 403) ``` #### Parameters -* `method` **[string][8]** request method. Can be `GET`, `POST`, `PUT`, etc or `ANY`. -* `oneOrMoreUrls` **([string][8] | [Array][9]<[string][8]>)** url(s) to mock. Can be exact URL, a pattern, or an array of URLs. -* `dataOrStatusCode` **([number][10] | [string][8] | [object][11])** status code when number provided. A response body otherwise -* `additionalData` **([string][8] | [object][11])** response body when a status code is set by previous parameter. (optional, default `null`) +- `method` **[string][8]** request method. Can be `GET`, `POST`, `PUT`, etc or `ANY`. +- `oneOrMoreUrls` **([string][8] | [Array][9]<[string][8]>)** url(s) to mock. Can be exact URL, a pattern, or an array of URLs. +- `dataOrStatusCode` **([number][10] | [string][8] | [object][11])** status code when number provided. A response body otherwise +- `additionalData` **([string][8] | [object][11])** response body when a status code is set by previous parameter. (optional, default `null`) ### mockServer Use PollyJS [Server Routes API][12] to declare mocks via callback function: ```js -I.mockServer((server) => { +I.mockServer(server => { // basic usage server.get('/api/v2/users').intercept((req, res) => { - res.sendStatus(200).json({ users }); - }); + res.sendStatus(200).json({ users }) + }) // passthrough requests to "/api/v2" - server.get('/api/v1').passthrough(); -}); + server.get('/api/v1').passthrough() +}) ``` In record replay mode you can define which routes should be recorded and where to store them: ```js -I.startMocking('mock'); -I.mockServer((server) => { - +I.startMocking('mock') +I.mockServer(server => { // record requests from cdn1.com and save them to data/recording/xml - server.any('https://cdn1.com/*').passthrough(false).recordingName('xml'); - + server.any('https://cdn1.com/*').passthrough(false).recordingName('xml') + // record requests from cdn2.com and save them to data/recording/svg - server.any('https://cdn2.com/*').passthrough(false).recordingName('svg'); + server.any('https://cdn2.com/*').passthrough(false).recordingName('svg') // record requests from /api and save them to data/recording/mock (default) - server.any('/api/*').passthrough(false); -}); + server.any('/api/*').passthrough(false) +}) ``` #### Parameters -* `configFn` +- `configFn` ### passthroughMocking @@ -282,7 +280,7 @@ Forces passthrough mode for mocking. Requires mocking to be started. ```js -I.passthroughMocking(); +I.passthroughMocking() ``` ### recordMocking @@ -291,7 +289,7 @@ Forces record mode for mocking. Requires mocking to be started. ```js -I.recordMocking(); +I.recordMocking() ``` ### replayMocking @@ -300,7 +298,7 @@ Forces replay mode for mocking. Requires mocking to be started. ```js -I.replayMocking(); +I.replayMocking() ``` ### startMocking @@ -313,31 +311,31 @@ If inside one test you plan to record/replay requests in several places, provide ```js // start mocking requests for a test -I.startMocking(); +I.startMocking() // start mocking requests for main page -I.startMocking('main-page'); +I.startMocking('main-page') // do actions -I.stopMocking(); -I.startMocking('login-page'); +I.stopMocking() +I.startMocking('login-page') ``` To update [PollyJS configuration][14] use secon argument: ```js // change mode -I.startMocking('comments', { mode: 'replay' }); +I.startMocking('comments', { mode: 'replay' }) // override config I.startMocking('users-loaded', { - recordFailedRequests: true + recordFailedRequests: true, }) ``` #### Parameters -* `title` **any** (optional, default `'Test'`) -* `config` (optional, default `{}`) +- `title` **any** (optional, default `'Test'`) +- `config` (optional, default `{}`) ### stopMocking @@ -345,33 +343,20 @@ Stops mocking requests. Must be called to save recorded requests into faile. ```js -I.stopMocking(); +I.stopMocking() ``` [1]: https://netflix.github.io/pollyjs/#/configuration?id=mode - [2]: https://netflix.github.io/pollyjs/#/configuration?id=configuration - [3]: https://netflix.github.io/pollyjs/#/examples?id=rest-persister - [4]: #startMocking - [5]: #mockRequest - [6]: #mockServer - [7]: #stopMocking - [8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String - [9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array - [10]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number - [11]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object - [12]: https://netflix.github.io/pollyjs/#/server/overview - [13]: https://netflix.github.io/pollyjs/#/api?id=recordingname - [14]: https://netflix.github.io/pollyjs/#/configuration diff --git a/docs/helpers/Nightmare.md b/docs/helpers/Nightmare.md index 12727861e..43f6d013f 100644 --- a/docs/helpers/Nightmare.md +++ b/docs/helpers/Nightmare.md @@ -22,28 +22,28 @@ Requires `nightmare` package to be installed. This helper should be configured in codecept.conf.ts or codecept.conf.js -* `url` - base url of website to be tested -* `restart` - restart browser between tests. -* `disableScreenshots` - don't save screenshot on failure. -* `uniqueScreenshotNames` - option to prevent screenshot override if you have scenarios with the same name in different suites. -* `fullPageScreenshots` - make full page screenshots on failure. -* `keepBrowserState` - keep browser state between tests when `restart` set to false. -* `keepCookies` - keep cookies between tests when `restart` set to false. -* `waitForAction`: (optional) how long to wait after click, doubleClick or PressKey actions in ms. Default: 500. -* `waitForTimeout`: (optional) default wait* timeout in ms. Default: 1000. -* `windowSize`: (optional) default window size. Set a dimension like `640x480`. +- `url` - base url of website to be tested +- `restart` - restart browser between tests. +- `disableScreenshots` - don't save screenshot on failure. +- `uniqueScreenshotNames` - option to prevent screenshot override if you have scenarios with the same name in different suites. +- `fullPageScreenshots` - make full page screenshots on failure. +- `keepBrowserState` - keep browser state between tests when `restart` set to false. +- `keepCookies` - keep cookies between tests when `restart` set to false. +- `waitForAction`: (optional) how long to wait after click, doubleClick or PressKey actions in ms. Default: 500. +- `waitForTimeout`: (optional) default wait\* timeout in ms. Default: 1000. +- `windowSize`: (optional) default window size. Set a dimension like `640x480`. -* options from [Nightmare configuration][2] +- options from [Nightmare configuration][2] ## Methods ### Parameters -* `config` +- `config` -### _locate +### \_locate Locate elements by different locator types, including strict locator. Should be used in custom helpers. @@ -55,17 +55,17 @@ client-side function: ```js // get an inner text of an element -let browser = this.helpers['Nightmare'].browser; -let value = this.helpers['Nightmare']._locate({name: 'password'}).then(function(els) { - return browser.evaluate(function(el) { - return codeceptjs.fetchElement(el).value; - }, els[0]); -}); +let browser = this.helpers['Nightmare'].browser +let value = this.helpers['Nightmare']._locate({ name: 'password' }).then(function (els) { + return browser.evaluate(function (el) { + return codeceptjs.fetchElement(el).value + }, els[0]) +}) ``` #### Parameters -* `locator` +- `locator` ### amOnPage @@ -73,15 +73,15 @@ Opens a web page in a browser. Requires relative or absolute url. If url starts with `/`, opens a web page of a site defined in `url` config parameter. ```js -I.amOnPage('/'); // opens main page of website -I.amOnPage('https://github.com'); // opens github -I.amOnPage('/login'); // opens a login page +I.amOnPage('/') // opens main page of website +I.amOnPage('https://github.com') // opens github +I.amOnPage('/login') // opens a login page ``` #### Parameters -* `url` **[string][3]** url path or global url. -* `headers` **[object][4]?** list of request headers can be passed +- `url` **[string][3]** url path or global url. +- `headers` **[object][4]?** list of request headers can be passed Returns **void** automatically synchronized promise through #recorder @@ -91,15 +91,15 @@ Appends text to a input field or textarea. Field is located by name, label, CSS or XPath ```js -I.appendField('#myTextField', 'appended'); +I.appendField('#myTextField', 'appended') // typing secret -I.appendField('password', secret('123456')); +I.appendField('password', secret('123456')) ``` #### Parameters -* `field` **([string][3] | [object][4])** located by label|name|CSS|XPath|strict locator -* `value` **[string][3]** text value to append. +- `field` **([string][3] | [object][4])** located by label|name|CSS|XPath|strict locator +- `value` **[string][3]** text value to append. Returns **void** automatically synchronized promise through #recorder @@ -110,14 +110,14 @@ Path to file is relative current codecept directory (where codecept.conf.ts or c File will be uploaded to remote system (if tests are running remotely). ```js -I.attachFile('Avatar', 'data/avatar.jpg'); -I.attachFile('form input[name=avatar]', 'data/avatar.jpg'); +I.attachFile('Avatar', 'data/avatar.jpg') +I.attachFile('form input[name=avatar]', 'data/avatar.jpg') ``` #### Parameters -* `locator` **([string][3] | [object][4])** field located by label|name|CSS|XPath|strict locator. -* `pathToFile` **[string][3]** local file path relative to codecept.conf.ts or codecept.conf.js config file. +- `locator` **([string][3] | [object][4])** field located by label|name|CSS|XPath|strict locator. +- `pathToFile` **[string][3]** local file path relative to codecept.conf.ts or codecept.conf.js config file. Returns **void** automatically synchronized promise through #recorderDoesn't work if the Chromium DevTools panel is open (as Chromium allows only one attachment to the debugger at a time. [See more][5]) @@ -129,15 +129,15 @@ Element is located by label or name or CSS or XPath. The second parameter is a context (CSS or XPath locator) to narrow the search. ```js -I.checkOption('#agree'); -I.checkOption('I Agree to Terms and Conditions'); -I.checkOption('agree', '//form'); +I.checkOption('#agree') +I.checkOption('I Agree to Terms and Conditions') +I.checkOption('agree', '//form') ``` #### Parameters -* `field` **([string][3] | [object][4])** checkbox located by label | name | CSS | XPath | strict locator. -* `context` **([string][3]? | [object][4])** (optional, `null` by default) element located by CSS | XPath | strict locator. +- `field` **([string][3] | [object][4])** checkbox located by label | name | CSS | XPath | strict locator. +- `context` **([string][3]? | [object][4])** (optional, `null` by default) element located by CSS | XPath | strict locator. Returns **void** automatically synchronized promise through #recorder @@ -147,28 +147,28 @@ Clears a cookie by name, if none provided clears all cookies. ```js -I.clearCookie(); -I.clearCookie('test'); +I.clearCookie() +I.clearCookie('test') ``` #### Parameters -* `cookie` **[string][3]?** (optional, `null` by default) cookie name +- `cookie` **[string][3]?** (optional, `null` by default) cookie name ### clearField Clears a `