diff --git a/.circleci/build.sh b/.circleci/build.sh new file mode 100755 index 000000000..a749511a1 --- /dev/null +++ b/.circleci/build.sh @@ -0,0 +1,5 @@ +cd test + +docker-compose build +docker-compose pull php selenium.chrome + diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 000000000..b27d52d24 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,50 @@ +version: 2 + +defaults: &defaults + machine: + image: circleci/classic:201710-02 + docker_layer_caching: false + steps: + - checkout + - run: .circleci/build.sh + - run: + command: docker-compose run --rm test-unit + working_directory: test + when: always + - run: + command: docker-compose run --rm test-rest + working_directory: test + when: always + - run: + command: docker-compose run --rm test-graphql + working_directory: test + when: always + - run: + command: docker-compose run --rm test-acceptance.webdriverio + working_directory: test + when: always + - run: + command: docker-compose run --rm test-acceptance.nightmare + working_directory: test + when: always + - run: + command: docker-compose run --rm test-acceptance.puppeteer + working_directory: test + when: always + - run: + command: docker-compose run --rm test-acceptance.protractor + working_directory: test + when: always + +jobs: + docker: + <<: *defaults + environment: + - NODE_VERSION: 12.8.0 + +workflows: + version: 2 + + test_all: + jobs: + - docker diff --git a/.circleci/test.sh b/.circleci/test.sh new file mode 100755 index 000000000..e08fcea74 --- /dev/null +++ b/.circleci/test.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e + +cd test + +docker-compose run --rm test-unit && +docker-compose run --rm test-rest && +docker-compose run --rm test-acceptance.webdriverio && +docker-compose run --rm test-acceptance.nightmare && +docker-compose run --rm test-acceptance.puppeteer && +docker-compose run --rm test-acceptance.protractor \ No newline at end of file diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..efb3112f1 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +**/node_modules +test \ No newline at end of file diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..65b969be4 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +test/data/output diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index f01b199b7..000000000 --- a/.eslintrc +++ /dev/null @@ -1,127 +0,0 @@ -{ - "extends": "eslint:recommended", - "env": { - "node": true, - "mocha": true, - "es6": true - }, - "ecmaFeatures": { - "jsx": true, - "modules": true - }, - "rules": { - "array-bracket-spacing": [ - 2, - "never" - ], - "brace-style": [ - 2, - "1tbs" - ], - "consistent-return": 0, - "indent": [ - 2, - 2 - ], - "no-multiple-empty-lines": [ - 2, - { - "max": 2 - } - ], - "no-use-before-define": [ - 2, - "nofunc" - ], - "one-var": [ - 2, - "never" - ], - "quote-props": [ - 2, - "as-needed" - ], - "space-after-keywords": [ - 2, - "always" - ], - "space-before-function-paren": [ - 2, - { - "anonymous": "always", - "named": "never" - } - ], - "space-in-parens": [ - 2, - "never" - ], - "curly": [ - 2, - "multi-line" - ], - "eol-last": 2, - "key-spacing": [ - 2, - { - "beforeColon": false, - "afterColon": true - } - ], - "no-with": 2, - "space-infix-ops": 2, - "dot-notation": [ - 2, - { - "allowKeywords": true - } - ], - "eqeqeq": 2, - "no-alert": 2, - "no-caller": 2, - "no-empty-label": 2, - "no-extend-native": 2, - "no-extra-bind": 2, - "no-implied-eval": 2, - "no-iterator": 2, - "no-label-var": 2, - "no-labels": 2, - "no-lone-blocks": 2, - "no-loop-func": 2, - "no-multi-spaces": 2, - "no-multi-str": 2, - "no-native-reassign": 2, - "no-new": 2, - "no-new-func": 2, - "no-new-wrappers": 2, - "no-octal-escape": 2, - "no-proto": 2, - "no-return-assign": 2, - "no-script-url": 2, - "no-sequences": 2, - "no-unused-expressions": 2, - "yoda": 2, - "no-shadow": 2, - "no-shadow-restricted-names": 2, - "no-undef-init": 2, - "camelcase": 2, - "comma-spacing": 2, - "new-cap": 2, - "new-parens": 2, - "no-array-constructor": 2, - "no-extra-parens": 2, - "no-new-object": 2, - "no-spaced-func": 2, - "no-trailing-spaces": 2, - "no-underscore-dangle": 2, - "semi": 2, - "semi-spacing": [ - 2, - { - "before": false, - "after": true - } - ], - "space-return-throw-case": 2 - } -} diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 000000000..33d9c6e9a --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,43 @@ +{ + "extends": "airbnb-base", + "env": { + "node": true + }, + "rules": { + "func-names": 0, + "no-use-before-define": 0, + "no-unused-vars": 0, + "no-underscore-dangle": 0, + "no-undef": 0, + "prefer-destructuring": 0, + "no-param-reassign": 0, + "max-len": 0, + "camelcase": 0, + "no-shadow": 0, + "consistent-return": 0, + "no-console": 0, + "global-require": 0, + "class-methods-use-this": 0, + "no-plusplus": 0, + "no-return-assign": 0, + "prefer-rest-params": 0, + "no-useless-escape": 0, + "no-restricted-syntax": 0, + "no-unused-expressions": 0, + "guard-for-in": 0, + "no-multi-assign": 0, + "require-yield": 0, + "prefer-spread": 0, + "import/no-dynamic-require": 0, + "no-continue": 0, + "no-mixed-operators": 0, + "default-case": 0, + "import/no-extraneous-dependencies": 0, + "no-cond-assign": 0, + "import/no-unresolved": 0, + "no-await-in-loop": 0, + "arrow-body-style": 0, + "no-loop-func": 0, + "arrow-parens": 0 + } +} diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..c636246c4 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,45 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at team@codeception.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 000000000..fa9f83b01 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,241 @@ +# Contributing + +Thanks for getting here. If you have a good will to improve CodeceptJS we are always glad to help. Ask questions, raise issues, ping in Twitter. + +To start you need: + +1. Fork the repo. +2. Run `npm install` to install all required libraries +3. Do the changes. +4. Add/Update Test (if possible) +5. Update documentation +6. Commit and Push to your fork +7. Make Pull Request + +To run codeceptjs from this repo use: + +``` +node bin/codecept.js +``` + +To run examples: + +``` +node bin/codecept.js run -c examples +``` + + +Depending on a type of a change you should do the following. + +## Helpers + +Please keep in mind that CodeceptJS have **unified API** for WebDriverIO, Appium, Protractor, Nightmare, Puppeteer, TestCafe. Tests written using those helpers should be compatible at syntax level. However, some of helpers may contain unique methods. That happens. If, for instance, WebDriverIO has method XXX and Nightmare doesn't, you can implement XXX inside Nightmare using the same method signature. + +### Updating a WebDriverIO | Nightmare + +*Whenever a new method or new behavior is added it should be documented in a docblock. Valid JS-example is required! Do **not edit** `docs/helpers/`, those files are generated from docblocks in corresponding helpers! * + +Working test is highly appreciated. To run the test suite you need: + +* selenium server + chromedriver +* PHP installed + +To launch PHP demo application run: + +```sh +php -S 127.0.0.1:8000 -t test/data/app +``` + +Execute test suite: + +```sh +mocha test/helper/WebDriverIO_test.js +mocha test/helper/Puppeteer_test.js +mocha test/helper/Nightmare_test.js +``` + +Use `--grep` to execute tests only for changed parts. + +If you need to add new HTML page for a test, please create new `.php` file in to `tests/data/app/view/form`: + +Adding `myexample` page: + +```sh +tests/data/app/view/form/myexample.php +``` + +Then is should be accessible at: + +```sh +http://localhost:8000/form/myexample +``` + +### Updating Protractor + +*Whenever a new method or new behavior is added it should be documented in a docblock. Valid JS-example is required! Do **not edit** `docs/helpers/`, those files are generated from docblocks in corresponding helpers! * + +Protractor helper is based on [Protractor library](http://www.protractortest.org) + +In case you do Protractor-specific change, please add a test:To run the test suite you need: + +* selenium server + chromedriver + +Demo application is located at: [http://davertmik.github.io/angular-demo-app](http://davertmik.github.io/angular-demo-app) + +### Updating REST | ApiDataFactory + +*Whenever a new method or new behavior is added it should be documented in a docblock. Valid JS-example is required!* + +Adding a test is highly appreciated. + +Start JSON server to run tests: + +```sh +npm run json-server +``` + +Edit a test at `test/rest/REST_test.js` or `test/rest/ApiDataFactory_test.js` + +## Appium + +*Whenever a new method or new behavior is added it should be documented in a docblock. Valid JS-example is required! Do **not edit** `docs/helpers/`, those files are generated from docblocks in corresponding helpers! * + +It is recommended to run mobile tests on CI. +So do the changes, make pull request, see the CI status. +Appium tests are executed at **Semaphore CI**. + +## Core Changes + +Before applying any Core changes please raise an issue to discuss that change with core team. +Please try to add corresponding testcase to runner or unit. + +## Documentation + +Documentation is stored in `/docs` directory in markdown format. + +**Documentation for helpers is a part of a source code**. + +> **Whenever you need to update docs for a helper do it inside a .js file.** + +After you updated docblock in JS file, generate markdown files with next command: + +``` +npm run docs +``` + +Documentation parts can be shared accross helpers. Those parts are located in `docs/webapi/*.mustache`. Inside a docblock those files can be included like this: + +```js + /** + * {{> click }} + */ + click() { + // ... + } +``` + +## Typings + +Typings is generated in `typings/` directory via `jsdoc` + +After you updated docblock in JS file, generate typing files with next command: + +``` +npm run def +``` + +## Testing + +Whenever you implemented a feature/bugfix + +Run unit tests: + +```sh +mocha test/unit +``` + +Run general tests: + +```sh +mocha test/runner +``` + +### Running tests in Dockerized environment + +Instead of manually running php, json_server and selenium for before tests you +can use `docker-compose` to run those automatically. +You can find `docker-compose.yml` file in `test` directory and run all commands +from this directory. Currently we provide following commands to run tests with +respective dependencies: + +#### Run unit tests + +```sh +docker-compose run --rm test-unit +``` + +#### Run helper tests + +```sh +docker-compose run --rm test-helpers + +# or pass path to helper test to run specific helper, +# for example to run only WebDriverIO tests: +docker-compose run --rm test-helpers test/helper/WebDriverIO_test.js + +# Or to run only rest and ApiDataFactory tests +docker-compose run --rm test-helpers test/rest +``` + +#### Run acceptance tests + +To that we provide three separate services respectively for WebDriverIO, Nightmare, Puppeteer and +Protractor tests: + +```sh +docker-compose run --rm test-acceptance.webdriverio +docker-compose run --rm test-acceptance.nightmare +docker-compose run --rm test-acceptance.puppeteer +docker-compose run --rm test-acceptance.protractor +``` + +#### Running against specific Node version + +By default dockerized tests are run against node 12.10.0, you can run it against +specific version as long as there is Docker container available for such +version. To do that you need to build codecept's Docker image prior to running +tests and pass `NODE_VERSION` as build argument. + +For example to prepare `test-helpers` containers based on node 9.4.0: + +```sh +docker-compose build --build-arg NODE_VERSION=9.4.0 test-helpers +``` + +And now every command based on `test-helpers` service will use node 9.4.0. The +same argument can be passed when building unit and acceptance tests services. + +### CI flow +We're currently using bunch of CI services to build and test codecept in +different environments. Here's short summary of what are differences between +separate services + +#### TravisCI +Travis CI uses runs tests against Node 8 and Node 9. In total it uses 8 jobs to +build each helper against both Node versions. For every job it runs unit tests +first, then `ApiDataFactory` and `REST` tests present in `test/rest` directory. +Finally if those pass we run specific helper tests found in `test/helper` +directory. It doesn't run acceptance tests. +Config is present in `.travis.yml` file. + +#### CircleCI +Here we use CodeceptJS docker image to build and execute tests inside it. We +start with building Docker container based on Dockerfile present in main project +directory. Then we run (in this order) unit tests, all helpers present in +`test/helpers`, then we go with `test/rest` directory and finally if everything +passed so far it executes acceptance tests. For easier maintenance and local +debugging CircleCI uses `docker-compose.yml` file from `test` directory. +You can find Circle config in `.circleci` directory. + +#### Semaphore +Currently Semaphore runs only Appium helper tests. diff --git a/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md similarity index 72% rename from ISSUE_TEMPLATE.md rename to .github/ISSUE_TEMPLATE.md index ebfaa83f4..5c6181a83 100644 --- a/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -7,19 +7,21 @@ ```bash # paste output here ``` + > Provide test source code if related -```php +```js // paste test ``` + ### Details -* CodeceptJS version: +* CodeceptJS version: * NodeJS Version: * Operating System: -* Protractor || WebDriverIO || Nightmare version (if related) +* puppeteer || webdriverio || protractor || testcafe version (if related) * Configuration file: ```js -# paste suite config here +# paste config here ``` diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..194360e18 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,46 @@ +## Motivation/Description of the PR +- Description of this PR, which problem it solves +- Resolves #issueId (if applicable). + +Applicable helpers: + +- [ ] WebDriver +- [ ] Puppeteer +- [ ] Nightmare +- [ ] REST +- [ ] FileHelper +- [ ] Appium +- [ ] Protractor +- [ ] TestCafe +- [ ] Playwright + +Applicable plugins: + +- [ ] allure +- [ ] autoDelay +- [ ] autoLogin +- [ ] customLocator +- [ ] pauseOnFail +- [ ] puppeteerCoverage +- [ ] retryFailedStep +- [ ] screenshotOnFail +- [ ] selenoid +- [ ] stepByStepReport +- [ ] wdio + +## Type of change + +- [ ] :fire: Breaking changes +- [ ] :rocket: New functionality +- [ ] :bug: Bug fix +- [ ] :clipboard: Documentation changes/updates +- [ ] :hotsprings: Hot fix +- [ ] :hammer: Markdown files fix - not related to source code +- [ ] :nail_care: Polish code + +## Checklist: + +- [ ] Tests have been added +- [ ] Documentation has been added (Run `npm run docs`) +- [ ] Lint checking (Run `npm run lint`) +- [ ] Local tests are passed (Run `npm test`) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 000000000..cea8185a5 --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,20 @@ +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + name: Check Tests + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - uses: testomatio/check-tests@master + with: + framework: mocha + tests: "./test/**/*_test.js" + token: ${{ secrets.GITHUB_TOKEN }} + has-tests-label: true + comment-on-empty: true + github-pat: ${{ secrets.GH_PAT }} + enable-documentation: true + documentation-branch: "master" diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 000000000..df5599968 --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,47 @@ +name: Playwright Tests + +on: + push: + branches: + - master + pull_request: + branches: + - master + +env: + CI: true + # Force terminal colors. @see https://www.npmjs.com/package/colors + FORCE_COLOR: 1 + +jobs: + build: + + runs-on: ubuntu-18.04 + + strategy: + matrix: + node-version: [12.x] + + steps: + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - uses: microsoft/playwright-github-action@v1 + - name: install required packages + run: | + sudo apt-get install php + - name: npm install + run: | + npm install + - name: start a server + run: "php -S 127.0.0.1:8000 -t test/data/app &" + - name: run chromium tests + run: "./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug" + - name: run firefox tests + run: "BROWSER=firefox node ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug" + - name: run webkit tests + run: "BROWSER=webkit node ./bin/codecept.js run -c test/acceptance/codecept.Playwright.js --grep @Playwright --debug" + - name: run unit tests + run: ./node_modules/.bin/mocha test/helper/Playwright_test.js diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..5818c4c92 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,21 @@ +name: Run Unit tests + +on: [push] + +jobs: + build: + + runs-on: ubuntu-18.04 + + strategy: + matrix: + node-version: [10.x, 12.x] + + steps: + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm install + - run: npm test diff --git a/.gitignore b/.gitignore index 40f2015d9..89adfd139 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,21 @@ coverage .vscode coverage site +docs/.vuepress/dist +docs/node_modules +docs/wiki +website .idea docs/build test/data/output -examples/output \ No newline at end of file +test/acceptance/output +examples/output +examples/selenoid-example/output +test/data/app/db +test/data/sandbox/steps.d.ts +testpullfilecache* +.DS_Store +package-lock.json +yarn.lock +/.vs +typings/types.d.ts diff --git a/.hound.yml b/.hound.yml new file mode 100644 index 000000000..6728a4cba --- /dev/null +++ b/.hound.yml @@ -0,0 +1,3 @@ +eslint: + enabled: true + config_file: .eslintrc.json \ No newline at end of file diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 000000000..73029d818 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,19 @@ +{ + "MD007": { + "indent": 4 + }, + "MD013": false, + "MD026": { + "punctuation": ".,;:!" + }, + "MD029": { + "style": "ordered" + }, + "MD030": { + "ul_multi": 1, + "ul_single": 1, + "ol_single": 2, + "ol_multi": 2 + }, + "MD036": false +} \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 15821580a..a1997238f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,38 +1,32 @@ language: node_js node_js: - - '4.3' - - '6.9.5' - - '7' - - +- 12 sudo: required dist: trusty - env: - - HELPER=Protractor + global: + - secure: vLPyF/U+KhmWAXMkcrYFben6Qo5Tsk9nExbb/YTxCCqtpu5FlCcKZ0h/7OXJT9sXR7t8dmz564VbAtbhazPU+2FdpxIoR/D6OUeZa1WhyB5GGfpfHmfIe1hQTsZg0B0zGrrpcLBeaTA1E7+0lBhIKj9S1FoApa6xfP21bju+IddpD881m0bdF/2gEiBrabWHoQieWLNgS4EzUI5IcOknz4bk3nx6ztldJOokwTqUy2RgtVbMkJf0v6LbBOxT5uCwlLYxllDwY6fIatPP7Gol5V2fxMYhp4k/QSeULy81EJBpVhW0Bw5FfGBBVnqk495fhCjRNbjwzcs2zz2dD1i99KeIFhfKYQsfto7odHbt0kasYgaQQUZEZsbY6ScYMDXnzprTCotolmPXJmqu0rHnUfa2ZZxl9/jNis1IoCdwsvJ+cemL13fw9llFvnMGtmqDc9ltjzKoRfi8rpUH5x6EbnUE6vdr0RDA+D3mUbFr2kxlMwQPTpujnxOghpuDnDc/2CGe17uklssw2g2vMxdIuiqxXvKkeN0xBddtlbUx2PwRrecjCmv7RE13j+ERsIysDQUkTMnXTWBumtVGmdxZpFhxD7wwmVFi3qjq4FGyO3f8alnfYOBspPhLgC2PTJGS/X23C9LC08tFl6MpeHD97HUaW6bx+ObI2/0jBsDXB3k= + - secure: OlLkzBUwlRFIa5xDWEs/It6ofSfC+pXRVt17kTyox8beH5qu5Ks3/Zwa48YMqHKnbNHI7hiRBO2YfsJgjYJoQ5/ovKPa3rvffNXdKeDZpt+lQqlhjJYpgp0pNgck45RKnFj1pKpQCVG6dWWcT59Gi8NoI8AsAVCVgFtO8McfV8qbks6G2UP0GdFR5s6tRyZTjfCVmMNtJX9veYuibwoiwRyFhh1FY+sw5BvAONSBdOWmcK7RdDm7IE+Oitzn3bRZnC6sgLNpy6qhncED/pbn4GFD5MRlu0UkDGDfXldsOyjOtqdaN5WbOGdhevaYgr/5VvSeMbO7fITlDXbhz9pViogl6fnxj0zELZvG6b6H7nAVV29uzHP4jofocP41h33rvYnQUTfNHN8HIRN4LVfekN2I27GDO+J1QFiWNN/36nhsRH9tWPwSNC2f9QLIf6OrD60FVUIMlQrFHqyrO4KZBZkRsGMgYzsa5XmGOGUATUBrmQVTynNQc+yhniJd4Q8LwwmXMDWNeoeg5eh0TFgERVDlkQ8tPaWOXmpHi6BL4JZlGz275SDWgZH4bnH2B1RzO1qcGN905vIo5snX8LwZbxSfXrt+4WP3jOi+1i8ZrFwACk7jlovJiJquQuZQ5dL7C9rBwpAWB8YjgOKNikDWvUrVnYGS/gLwrdN7+pRiims= + matrix: - HELPER=Nightmare - - HELPER=SeleniumWebdriver - - HELPER=WebDriverIO - + - HELPER=Puppeteer + - HELPER=ProtractorWeb + - HELPER=WebDriver + - HELPER=TestCafe addons: apt: packages: - - php5-cli - + - php5-cli services: - - docker - +- docker before_install: - - docker pull selenium/standalone-chrome:2.53.0 - +- docker pull selenium/standalone-chrome:3.141.59-oxygen before_script: - - docker run -d --net=host selenium/standalone-chrome:2.53.0 - - export DISPLAY=:99.0 - - sh -e /etc/init.d/xvfb start - - chmod -R 777 test/data - - "php -S 127.0.0.1:8000 -t test/data/app >/dev/null 2>&1 &" - - sleep 10 - +- docker run -d --net=host --shm-size=2g selenium/standalone-chrome:3.141.59-oxygen +- export DBUS_SESSION_BUS_ADDRESS=/dev/null +- export DISPLAY=:99.0 +- sleep 3 +- chmod -R 777 test/data +- php -S 127.0.0.1:8000 -t test/data/app >/dev/null 2>&1 & script: - - gulp test - - '[[ "$TRAVIS_NODE_VERSION" == "4.3" ]] || ./node_modules/.bin/mocha test/helper/${HELPER}_test.js' \ No newline at end of file +- mocha test/helper/${HELPER}_test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 67f822360..841870af0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,1367 @@ +## 2.6.11 + +* [Playwright] Playwright 1.4 compatibility +* [Playwright] Added `ignoreHTTPSErrors` config option (default: false). See #2566 by gurjeetbains +* Added French translation by @vimar +* [WebDriver] Updated `dragSlider` to work in WebDriver W3C protocol. Fixes #2557 by suniljaiswal01 + +## 2.6.10 + +* Fixed saving options for suite via `Feature('title', {key: value})` by @Diokuz. See #2553 and [Docs](https://codecept.io/advanced/#dynamic-configuration) + +## 2.6.9 + +* [Puppeteer][Playwright] SessionStorage is now cleared in after hook. See #2524 +* When helper load failed the error stack is now logged by @SkReD. See #2541 +* Small documentation fixes. + +## 2.6.8 + +* [WebDriver][Protractor][Playwright][Puppeteer][Nightmare] `saveElementScreenshot` method added to make screenshot of an element. By @suniljaiswal01 +* [Playwright][Puppeteer] Added `type` method to type a text using keyboard with an optional delay. +* [WebDriver] Added optional `delay` argument to `type` method to slow down typing. +* [Puppeteer] Fixed `amOnPage` freeze when `getPageTimeout` is 0"; set 30 sec as default timeout by @Vorobeyko. +* Fixed printing step with null argument in custom helper by @sjana-aj. See #2494 +* Fix missing screenshot on failure when REST helper is in use #2513 by @PeterNgTr +* Improve error logging in the `screenshotOnFail` plugin #2512 by @pablopaul + +## 2.6.7 + +* Add REST helper into `standardActingHelpers` array #2474 by @PeterNgTr +* Add missing `--invert` option for `run-workers` command #2504 by @pablopaul +* [WebDriver] Introduce `forceRightClick` method #2485 bylsuniljaiswal01 +* [Playwright] Fix `setCookie` method #2491 by @bmbarker90 +* [TypeScript] Update compilerOptions.target to es2017 #2483 by @shanplourde +* [Mocha] Honor reporter configuration #2465 by @trinhpham + +## 2.6.6 + +* Puppeteer 4.0 support. Important: MockRequest helper won't work with Puppeter > 3.3 +* Added `xFeature` and `Feature.skip` to skip all tests in a suite. By @Georgegriff +* [Appium] Fixed #2428 Android native locator support by @idxn +* [WebDriver] Fixed `waitNumberOfVisibleElements` to actually filter visible elements. By @ilangv +* [Puppeteer] Fixed handling error which is not an Error object. Fixes `cannot read property indexOf of undefined` error. Fix #2436 by @Georgegriff +* [Puppeteer] Print error on page crash by @Georgegriff + +## 2.6.5 + +* Added `test.skipped` event to run-workers, fixing allure reports with skipped tests in workers #2391. Fix #2387 by @koushikmohan1996 +* [Playwright] Fixed calling `waitFor*` methods with custom locators #2314. Fix #2389 by @Georgegriff + +## 2.6.4 + +* [Playwright] **Playwright 1.0 support** by @Georgegriff. + +## 2.6.3 + +* [stepByStepReport plugin] Fixed when using plugin with BeforeSuite. Fixes #2337 by @mirao +* [allure plugin] Fixed reporting of tests skipped by failure in before hook. Refer to #2349 & #2354. Fix by @koushikmohan1996 + +## 2.6.2 + +* [WebDriver][Puppeteer] Added `forceClick` method to emulate click event instead of using native events. +* [Playwright] Updated to 0.14 +* [Puppeteer] Updated to Puppeteer v3.0 +* [wdio] Fixed undefined output directory for wdio plugns. Fix By @PeterNgTr +* [Playwright] Introduced `handleDownloads` method to download file. Please note, this method has slightly different API than the same one in Puppeteer. +* [allure] Fixed undefined output directory for allure plugin on using custom runner. Fix by @charliepradeep +* [WebDriver] Fixed `waitForEnabled` fix for webdriver 6. Fix by @dsharapkou +* Workers: Fixed negative failure result if use scenario with the same names. Fix by @Vorobeyko +* [MockRequest] Updated documentation to match new helper version +* Fixed: skipped tests are not reported if a suite failed in `before`. Refer #2349 & #2354. Fix by @koushikmohan1996 + +## 2.6.1 + +* [screenshotOnFail plugin] Fixed saving screenshot of active session. +* [screenshotOnFail plugin] Fix issue #2301 when having the flag `uniqueScreenshotNames`=true results in `undefined` in screenshot file name by @PeterNgTr +* [WebDriver] Fixed `waitForElement` not applying the optional second argument to override the default timeout in webdriverio 6. Fix by @Mooksc +* [WebDriver] Updated `waitUntil` method which is used by all of the wait* functions. This updates the `waitForElement` by the same convention used to update `waitForVisible` and `waitInUrl` to be compatible with both WebDriverIO v5 & v6. See #2313 by @Mooksc + +## 2.6.0 + +* **[Playwright] Updated to Playwright 0.12** by @Georgegriff. + +Upgrade playwright to ^0.12: + +``` +npm i playwright@^0.12 --save +``` + +[Notable changes](https://github.com/microsoft/playwright/releases/tag/v0.12.0): + * Fixed opening two browsers on start + * `executeScript` - passed function now accepts only one argument. Pass in objects or arrays if you need multtple arguments: +```js +// Old style, does not work anymore: +I.executeScript((x, y) => x + y, x, y); +// New style, passing an object: +I.executeScript(({x, y}) => x + y, {x, y}); +``` + * `click` - automatically waits for element to become clickable (visible, not animated) and waits for navigation. + * `clickLink` - deprecated + * `waitForClickable` - deprecated + * `forceClick` - added + * Added support for custom locators. See #2277 + * Introduced [device emulation](/playwright/#device-emulation): + * globally via `emulate` config option + * per session + +**[WebDriver] Updated to webdriverio v6** by @PeterNgTr. + +Read [release notes](https://webdriver.io/blog/2020/03/26/webdriverio-v6-released.html), then +upgrade webdriverio to ^6.0: + +``` +npm i webdriverio@^6.0 --save +``` +*(webdriverio v5 support is deprecated and will be removed in CodeceptJS 3.0)* + +[WebDriver] Introduced [Shadow DOM support](/shadow) by @gkushang + +```js +I.click({ shadow: ['my-app', 'recipe-hello', 'button'] }); +``` + +* **Fixed parallel execution of `run-workers` for Gherkin** scenarios by @koushikmohan1996 +* [MockRequest] Updated and **moved to [standalone package](https://github.com/codecept-js/mock-request)**: + * full support for record/replay mode for Puppeteer + * added `mockServer` method to use flexible PollyJS API to define mocks + * fixed stale browser screen in record mode. +* [Playwright] Added support on for `screenshotOnFail` plugin by @amonkc +* Gherkin improvement: setting different tags per examples. See #2208 by @acuper +* [TestCafe] Updated `click` to take first visible element. Fixes #2226 by @theTainted +* [Puppeteer][WebDriver] Updated `waitForClickable` method to check for element overlapping. See #2261 by @PiQx +* [Puppeteer] Dropped `puppeteer-firefox` support, as Puppeteer supports Firefox natively. +* [REST] Rrespect Content-Type header. See #2262 by @pmarshall-legacy +* [allure plugin] Fixes BeforeSuite failures in allure reports. See #2248 by @Georgegriff +* [WebDriver][Puppeteer][Playwright] A screenshot of for an active session is saved in multi-session mode. See #2253 by @ChexWarrior +* Fixed `--profile` option by @pablopaul. Profile value to be passed into `run-multiple` and `run-workers`: + +``` +npx codecept run-workers 2 --profile firefox +``` + +Value is available at `process.env.profile` (previously `process.profile`). See #2302. Fixes #1968 #1315 + +* [commentStep Plugin introduced](/plugins#commentstep). Allows to annotate logical parts of a test: + +```js +__`Given`; +I.amOnPage('/profile') + +__`When`; +I.click('Logout'); + +__`Then`; +I.see('You are logged out'); +``` + +## 2.5.0 + +* **Experimental: [Playwright](/playwright) helper introduced**. + +> [Playwright](https://github.com/microsoft/playwright/) is an alternative to Puppeteer which works very similarly to it but adds cross-browser support with Firefox and Webkit. Until v1.0 Playwright API is not stable but we introduce it to CodeceptJS so you could try it. + +* [Puppeteer] Fixed basic auth support when running in multiple sessions. See #2178 by @ian-bartholomew +* [Puppeteer] Fixed `waitForText` when there is no `body` element on page (redirect). See #2181 by @Vorobeyko +* [Selenoid plugin] Fixed overriding current capabilities by adding deepMerge. Fixes #2183 by @koushikmohan1996 +* Added types for `Scenario.todo` by @Vorobeyko +* Added types for Mocha by @Vorobeyko. Fixed typing conflicts with Jest +* [FileSystem] Added methods by @nitschSB + * `waitForFile` + * `seeFileContentsEqualReferenceFile` +* Added `--colors` option to `run` and `run-multiple` so you force colored output in dockerized environment. See #2189 by @mirao +* [WebDriver] Added `type` command to enter value without focusing on a field. See #2198 by @xMutaGenx +* Fixed `codeceptjs gt` command to respect config pattern for tests. See #2200 and #2204 by @matheo + + +## 2.4.3 + +* Hotfix for interactive pause + +## 2.4.2 + +* **Interactive pause improvements** by @koushikmohan1996 + * allows using in page objects and variables: `pause({ loginPage, a })` + * enables custom commands inside pause with `=>` prefix: `=> loginPage.open()` +* [Selenoid plugin](/plugins#selenoid) added by by @koushikmohan1996 + * uses Selenoid to launch browsers inside Docker containers + * automatically **records videos** and attaches them to allure reports + * can delete videos for successful tests + * can automatically pull in and start Selenoid containers + * works with WebDriver helper +* Avoid failiure report on successful retry in worker by @koushikmohan1996 +* Added translation ability to Scenario, Feature and other context methods by @koushikmohan1996 + * 📢 Please help us translate context methods to your language! See [italian translation](https://github.com/codeceptjs/CodeceptJS/blob/master/translations/it-IT.js#L3) as an example and send [patches to vocabularies](https://github.com/codeceptjs/CodeceptJS/tree/master/translations). +* allurePlugin: Added `say` comments to allure reports by @PeterNgTr. +* Fixed no custom output folder created when executed with run-worker. Fix by @PeterNgTr +* [Puppeteer] Fixed error description for context element not found. See #2065. Fix by @PeterNgTr +* [WebDriver] Fixed `waitForClickable` to wait for exact number of seconds by @mirao. Resolves #2166 +* Fixed setting `compilerOptions` in `jsconfig.json` file on init by @PeterNgTr +* [Filesystem] Added method by @nitschSB + * `seeFileContentsEqualReferenceFile` + * `waitForFile` + + +## 2.4.1 + +* [Hotfix] - Add missing lib that prevents codeceptjs from initializing. + +## 2.4.0 + +* Improved setup wizard with `npx codecept init`: + * **enabled [retryFailedStep](/plugins/#retryfailedstep) plugin for new setups**. + * enabled [@codeceptjs/configure](/configuration/#common-configuration-patterns) to toggle headless/window mode via env variable + * creates a new test on init + * removed question on "steps file", create it by default. +* Added [pauseOnFail plugin](/plugins/#pauseonfail). *Sponsored by Paul Vincent Beigang and his book "[Practical End 2 End Testing with CodeceptJS](https://leanpub.com/codeceptjs/)"*. +* Added [`run-rerun` command](/commands/#run-rerun) to run tests multiple times to detect and fix flaky tests. By @Ilrilan and @Vorobeyko. +* Added [`Scenario.todo()` to declare tests as pending](/basics#todotest). See #2100 by @Vorobeyko +* Added support for absolute path for `output` dir. See #2049 by @elukoyanov +* Fixed error in `npx codecept init` caused by calling `console.print`. See #2071 by @Atinux. +* [Filesystem] Methods added by @aefluke: + * `seeFileNameMatching` + * `grabFileNames` +* [Puppeteer] Fixed grabbing attributes with hyphen by @Holorium +* [TestCafe] Fixed `grabAttributeFrom` method by @elukoyanov +* [MockRequest] Added support for [Polly config options](https://netflix.github.io/pollyjs/#/configuration?id=configuration) by @ecrmnn +* [TestCafe] Fixes exiting with zero code on failure. Fixed #2090 with #2106 by @koushikmohan1996 +* [WebDriver][Puppeteer] Added basicAuth support via config. Example: `basicAuth: {username: 'username', password: 'password'}`. See #1962 by @PeterNgTr +* [WebDriver][Appium] Added `scrollIntoView` by @pablopaul +* Fixed #2118: No error stack trace for syntax error by @senthillkumar +* Added `parse()` method to data table inside Cucumber tests. Use it to obtain rows and hashes for test data. See #2082 by @Sraime + +## 2.3.6 + +* Create better Typescript definition file through JSDoc. By @lemnis +* `run-workers` now can use glob pattern. By @Ilrilan +```js +// Example: +exports.config = { + tests: '{./workers/base_test.workers.js,./workers/test_grep.workers.js}', +} +``` +* Added new command `npx codeceptjs info` which print information about your environment and CodeceptJS configs. By @jamesgeorge007 +* Fixed some typos in documantation. By @pablopaul @atomicpages @EricTendian +* Added PULL_REQUEST template. +* [Puppeteer][WebDriver] Added `waitForClickable` for waiting clickable element on page. +* [TestCafe] Added support for remote connection. By @jvdieten +* [Puppeteer] Fixed `waitForText` XPath context now works correctly. By @Heavik +* [TestCafe] Fixed `clearField` clear field now awaits TestCafe's promise. By @orihomie +* [Puppeteer] Fixed fails when executing localStorage on services pages. See #2026 +* Fixed empty tags in test name. See #2038 + +## 2.3.5 + +* Set "parse-function" dependency to "5.2.11" to avoid further installation errors. + +## 2.3.4 + +* Fixed installation error "Cannot find module '@babel/runtime/helpers/interopRequireDefault'". The issue came from `parse-function` package. Fixed by @pablopaul. +* [Puppeteer] Fixed switching to iframe without an ID by @johnyb. See #1974 +* Added `--profile` option to `run-workers` by @orihomie +* Added a tag definition to `FeatureConfig` and `ScenarioConfig` by @sseliverstov + +## 2.3.3 + +* **[customLocator plugin](#customlocator) introduced**. Adds a locator strategy for special test attributes on elements. + +```js +// when data-test-id is a special test attribute +// enable and configure plugin to replace this +I.click({ css: '[data-test-id=register_button]'); +// with this +I.click('$register_button'); +``` +* [Puppeteer][WebDriver] `pressKey` improvements by @martomo: +Changed pressKey method to resolve issues and extend functionality. + * Did not properly recognize 'Meta' (or 'Command') as modifier key. + * Right modifier keys did not work in WebDriver using JsonWireProtocol. + * 'Shift' + 'key' combination would not reflect actual keyboard behavior. + * Respect sequence with multiple modifier keys passed to pressKey. + * Added support to automatic change operation modifier key based on operating system. +* [Puppeteer][WebDriver] Added `pressKeyUp` and `pressKeyDown` to press and release modifier keys like `Control` or `Shift`. By @martomo. +* [Puppeteer][WebDriver] Added `grabElementBoundingRect` by @PeterNgTr. +* [Puppeteer] Fixed speed degradation introduced in #1306 with accessibility locators support. See #1953. +* Added `Config.addHook` to add a function that will update configuration on load. +* Started [`@codeceptjs/configure`](https://github.com/codecept-js/configure) package with a collection of common configuration patterns. +* [TestCafe] port's management removed (left on TestCafe itself) by @orihomie. Fixes #1934. +* [REST] Headers are no more declared as singleton variable. Fixes #1959 +* Updated Docker image to include run tests in workers with `NUMBER_OF_WORKERS` env variable. By @PeterNgTr. + +## 2.3.2 + +* [Puppeteer] Fixed Puppeteer 1.20 support by @davertmik +* Fixed `run-workers` to run with complex configs. See #1887 by @nitschSB +* Added `--suites` option to `run-workers` to split suites by workers (tests of the same suite goes to teh same worker). Thanks @nitschSB. +* Added a guide on [Email Testing](https://codecept.io/email). +* [retryFailedStepPlugin] Improved to ignore wait* steps and others. Also added option to ignore this plugin per test bases. See [updated documentation](https://codecept.io/plugins#retryfailedstep). By @davertmik +* Fixed using PageObjects as classes by @Vorobeyko. See #1896 +* [WebDriver] Fixed opening more than one tab. See #1875 by @jplegoff. Fixes #1874 +* Fixed #1891 when `I.retry()` affected retries of next steps. By @davertmik + +## 2.3.1 + +* [MockRequest] Polly helper was renamed to MockRequest. +* [MockRequest][WebDriver] [Mocking requests](https://codecept.io/webdriver#mocking-requests) is now available in WebDriver. Thanks @radhey1851 +* [Puppeteer] Ensure configured user agent and/or window size is applied to all pages. See #1862 by @martomo +* Improve handling of xpath locators with round brackets by @nitschSB. See #1870 +* Use WebDriver capabilities config in wdio plugin. #1869 by @quekshuy + +## 2.3.0 + + +* **[Parallel testing by workers](https://codecept.io/parallel#parallel-execution-by-workers) introduced** by @VikalpP and @davertmik. Use `run-workers` command as faster and simpler alternative to `run-multiple`. Requires NodeJS v12 + +``` +# run all tests in parallel using 3 workers +npx codeceptjs run-workers 3 +``` +* [GraphQL][GraphQLDataFactory] **Helpers for data management over GraphQL** APIs added. By @radhey1851. + * Learn how to [use GraphQL helper](https://codecept.io/data#graphql) to access GarphQL API + * And how to combine it with [GraphQLDataFactory](https://codecept.io/data#graphql-data-factory) to generate and persist test data. +* **Updated to use Mocha 6**. See #1802 by @elukoyanov +* Added `dry-run` command to print steps of test scenarios without running them. Fails to execute scenarios with `grab*` methods or custom code. See #1825 for more details. + +``` +npx codeceptjs dry-run +``` + +* [Appium] Optimization when clicking, searching for fields by accessibility id. See #1777 by @gagandeepsingh26 +* [TestCafe] Fixed `switchTo` by @KadoBOT +* [WebDriver] Added geolocation actions by @PeterNgTr + * `grabGeoLocation()` + * `setGeoLocation()` +* [Polly] Check typeof arguments for mock requests by @VikalpP. Fixes #1815 +* CLI improvements by @jamesgeorge007 + * `codeceptjs` command prints list of all available commands + * added `codeceptjs -V` flag to print version information + * warns on unknown command +* Added TypeScript files support to `run-multiple` by @z4o4z +* Fixed element position bug in locator builder. See #1829 by @AnotherAnkor +* Various TypeScript typings updates by @elukoyanov and @Vorobeyko +* Added `event.step.comment` event for all comment steps like `I.say` or gherking steps. + +## 2.2.1 + +* [WebDriver] A [dedicated guide](https://codecept.io/webdriver) written. +* [TestCafe] A [dedicated guide](https://codecept.io/testcafe) written. +* [Puppeteer] A [chapter on mocking](https://codecept.io/puppeteer#mocking-requests) written +* [Puppeteer][Nightmare][TestCafe] Window mode is enabled by default on `codeceptjs init`. +* [TestCafe] Actions implemented by @hubidu + * `grabPageScrollPosition` + * `scrollPageToTop` + * `scrollPageToBottom` + * `scrollTo` + * `switchTo` +* Intellisense improvements. Renamed `tsconfig.json` to `jsconfig.json` on init. Fixed autocompletion for Visual Studio Code. +* [Polly] Take configuration values from Puppeteer. Fix #1766 by @VikalpP +* [Polly] Add preconditions to check for puppeteer page availability by @VikalpP. Fixes #1767 +* [WebDriver] Use filename for `uploadFile` by @VikalpP. See #1797 +* [Puppeteer] Configure speed of input with `pressKeyDelay` option. By @hubidu +* Fixed recursive loading of support objects by @davertmik. +* Fixed support object definitions in steps.d.ts by @johnyb. Fixes #1795 +* Fixed `Data().Scenario().injectDependencies()` is not a function by @andrerleao +* Fixed crash when using xScenario & Scenario.skip with tag by @VikalpP. Fixes #1751 +* Dynamic configuration of helpers can be performed with async function. See #1786 by @cviejo +* Added TS definitions for internal objects by @Vorobeyko +* BDD improvements: + * Fix for snippets command with a .feature file that has special characters by @asselin + * Fix `--path` option on `gherkin:snippets` command by @asselin. See #1790 + * Added `--feature` option to `gherkin:snippets` to enable creating snippets for a subset of .feature files. See #1803 by @asselin. +* Fixed: dynamic configs not reset after test. Fixes #1776 by @cviejo. + +## 2.2.0 + +* **EXPERIMENTAL** [**TestCafe** helper](https://codecept.io/helpers/TestCafe) introduced. TestCafe allows to run cross-browser tests it its own very fast engine. Supports all browsers including mobile. Thanks to @hubidu for implementation! Please test it and send us feedback. +* [Puppeteer] Mocking requests enabled by introducing [Polly.js helper](https://codecept.io/helpers/Polly). Thanks @VikalpP + +```js +// use Polly & Puppeteer helpers +I.mockRequest('GET', '/api/users', 200); +I.mockRequest('POST', '/users', { user: { name: 'fake' }}); +``` + +* **EXPERIMENTAL** [Puppeteer] [Firefox support](https://codecept.io/helpers/Puppeteer-firefox) introduced by @ngadiyak, see #1740 +* [stepByStepReportPlugin] use md5 hash to generate reports into unique folder. Fix #1744 by @chimurai +* Interactive pause improvements: + * print result of `grab` commands + * print message for successful assertions +* `run-multiple` (parallel execution) improvements: + * `bootstrapAll` must be called before creating chunks. #1741 by @Vorobeyko + * Bugfix: If value in config has falsy value then multiple config does not overwrite original value. #1756 by @LukoyanovE +* Fixed hooks broken in 2.1.5 by @Vorobeyko +* Fix references to support objects when using Dependency Injection. Fix by @johnyb. See #1701 +* Fix dynamic config applied for multiple helpers by @VikalpP #1743 + + +## 2.1.5 + +* **EXPERIMENTAL** [Wix Detox support](https://github.com/codeceptjs/detox-helper) introduced as standalone helper. Provides a faster alternative to Appium for mobile testing. +* Saving successful commands inside interactive pause into `_output/cli-history` file. By @hubidu +* Fixed hanging error handler inside scenario. See #1721 by @haily-lgc. +* Fixed by @Vorobeyko: tests did not fail when an exception was raised in async bootstrap. +* [WebDriver] Added window control methods by @emmonspired + * `grabAllWindowHandles` returns all window handles + * `grabCurrentWindowHandle` returns current window handle + * `switchToWindow` switched to window by its handle +* [Appium] Fixed using `host` as configuration by @trinhpham +* Fixed `run-multiple` command when `tests` config option is undefined (in Gherkin scenarios). By @gkushang. +* German translation introduced by @hubidu + +## 2.1.4 + +* [WebDriver][Puppeteer][Protractor][Nightmare] A11y locator support introduced by @Holorium. Clickable elements as well as fields can be located by following attributes: + * `aria-label` + * `title` + * `aria-labelledby` +* [Puppeteer] Added support for React locators. + * New [React Guide](https://codecept.io/react) added. +* [Puppeteer] Deprecated `downloadFile` +* [Puppeteer] Introduced `handleDownloads` replacing `downloadFile` +* [puppeteerCoverage plugin] Fixed path already exists error by @seta-tuha. +* Fixed 'ERROR: ENAMETOOLONG' creating directory names in `run-multiple` with long config. By @artvinn +* [REST] Fixed url autocompletion combining base and relative paths by @LukoyanovE +* [Nightmare][Protractor] `uncheckOption` method introduced by @PeterNgTr +* [autoLogin plugin] Enable to use without `await` by @tsuemura +* [Puppeteer] Fixed `UnhandledPromiseRejectionWarning: "Execution context was destroyed...` by @adrielcodeco +* [WebDriver] Keep browser window dimensions when starting a new session by @spiroid +* Replace Ghekrin plceholders with values in files that combine a scenerio outline and table by @medtoure18. +* Added Documentation to [locate elements in React Native](https://codecept.io/mobile-react-native-locators) apps. By @DimGun. +* Adding optional `path` parameter to `bdd:snippets` command to append snippets to a specific file. By @cthorsen31. +* Added optional `output` parameter to `def` command by @LukoyanovE. +* [Puppeteer] Added `grabDataFromPerformanceTiming` by @PeterNgTr. +* axios updated to `0.19.0` by @SteveShaffer +* TypeScript defitions updated by @LukoyanovE. Added `secret` and `inject` function. + +## 2.1.3 + +* Fixed autoLogin plugin to inject `login` function +* Fixed using `toString()` in DataTablewhen it is defined by @tsuemura + +## 2.1.2 + +* Fixed `inject` to load objects recursively. +* Fixed TypeScript definitions for locators by @LukoyanovE +* **EXPERIMENTAL** [WebDriver] ReactJS locators support with webdriverio v5.8+: + +```js +// locating React element by name, prop, state +I.click({ react: 'component-name', props: {}, state: {} }); +I.seeElement({ react: 'component-name', props: {}, state: {} }); +``` + +## 2.1.1 + +* Do not retry `within` and `session` calls inside `retryFailedStep` plugin. Fix by @tsuemura + +## 2.1.0 + +* Added global `inject()` function to require actor and page objects using dependency injection. Recommended to use in page objects, step definition files, support objects: + +```js +// old way +const I = actor(); +const myPage = require('../page/myPage'); + +// new way +const { I, myPage } = inject(); +``` + +* Added global `secret` function to fill in sensitive data. By @RohanHart: + +```js +I.fillField('password', secret('123456')); +``` + +* [wdioPlugin](https://codecept.io/plugins/#wdio) Added a plugin to **support webdriverio services** including *selenium-standalone*, *sauce*, *browserstack*, etc. **Sponsored by @GSasu** +* [Appium] Fixed `swipe*` methods by @PeterNgTr +* BDD Gherkin Improvements: + * Implemented `run-multiple` for feature files. **Sponsored by @GSasu** + * Added `--features` and `--tests` options to `run-multiple`. **Sponsored by @GSasu** + * Implemented `Before` and `After` hooks in [step definitions](https://codecept.io/bdd#before) +* Fixed running tests by absolute path. By @batalov. +* Enabled the adding screenshot to failed test for moch-junit-reporter by @PeterNgTr. +* [Puppeteer] Implemented `uncheckOption` and fixed behavior of `checkOption` by @aml2610 +* [WebDriver] Fixed `seeTextEquals` on empty strings by @PeterNgTr +* [Puppeteer] Fixed launch with `browserWSEndpoint` config by @ngadiyak. +* [Puppeteer] Fixed switching back to main window in multi-session mode by @davertmik. +* [autoLoginPlugin] Fixed using async functions for auto login by @nitschSB + +> This release was partly sponsored by @GSasu. Thanks for the support! +Do you want to improve this project? [Learn more about sponsorin CodeceptJS + + +## 2.0.8 + +* [Puppeteer] Added `downloadFile` action by @PeterNgTr. + +Use it with `FileSystem` helper to test availability of a file: +```js + const fileName = await I.downloadFile('a.file-link'); + I.amInPath('output'); + I.seeFile(fileName); +``` +> Actions `amInPath` and `seeFile` are taken from [FileSystem](https://codecept.io/helpers/FileSystem) helper + +* [Puppeteer] Fixed `autoLogin` plugin with Puppeteer by @davertmik +* [WebDriver] `seeInField` should throw error if element has no value attrubite. By @PeterNgTr +* [WebDriver] Fixed `seeTextEquals` passes for any string if element is empty by @PeterNgTr. +* [WebDriver] Internal refctoring to use `el.isDisplayed` to match latest webdriverio implementation. Thanks to @LukoyanovE +* [allure plugin] Add ability enable [screenshotDiff plugin](https://github.com/allure-framework/allure2/blob/master/plugins/screen-diff-plugin/README.md) by @Vorobeyko +* [Appium] Fixed `locator.stringify` call by @LukoyanovE + +## 2.0.7 + +* [WebDriver][Protractor][Nightmare] `rightClick` method implemented (fixed) in a standard way. By @davertmik +* [WebDriver] Updated WebDriver API calls in helper. By @PeterNgTr +* [stepByStepReportPlugin] Added `screenshotsForAllureReport` config options to automatically attach screenshots to allure reports. By @PeterNgTr +* [allurePlugin] Added `addLabel` method by @Vorobeyko +* Locator Builder: fixed `withChild` and `withDescendant` to match deep nested siblings by @Vorobeyko. + +## 2.0.6 + +* Introduced [Custom Locator Strategies](https://codecept.io/locators#custom-locators). +* Added [Visual Testing Guide](https://codecept.io/visual) by @puneet0191 and @MitkoTschimev. +* [Puppeteer] [`puppeteerCoverage`](https://codecept.io/plugins#puppeteercoverage) plugin added to collect code coverage in JS. By @dvillarama +* Make override option in `run-multiple` to respect the generated overridden config by @kinyat +* Fixed deep merge for `container.append()`. Introduced `lodash.merge()`. By @Vorobeyko +* Fixed saving screenshot on Windows by +* Fix errors on using interactive shell with Allure plugin by tsuemura +* Fixed using dynamic injections with `Scenario().injectDependencies` by @tsemura +* [WebDriver][Puppeteer][Nightmare][Protractor] Fixed url protocol detection for non-http urls by @LukoyanovE +* [WebDriver] Enabled compatibility with `stepByStepReport` by @tsuemura +* [WebDriver] Fixed `grabHTMLFrom` to return innerHTML value by @Holorium. Fixed compatibility with WebDriverIO. +* [WebDriver] `grabHTMLFrom` to return one HTML vlaue for one element matched, array if multiple elements found by @davertmik. +* [Nightmare] Added `grabHTMLFrom` by @davertmik +* Fixed `bootstrapAll` and `teardownAll` launch with path as argument by @LukoyanovE +* Fixed `bootstrapAll` and `teardownAll` calls from exported object by @LukoyanovE +* [WebDriver] Added possibility to define conditional checks interval for `waitUntil` by @LukoyanovE +* Fixed storing current data in data driven tests in a test object. By @Vorobeyko +* [WebDriver] Fixed `hostname` config option overwrite when setting a cloud provider. By @LukoyanovE +* [WebDriver] `dragSlider` method implemented by @DavertMik +* [WebDrover] Fixed `scrollTo` to use new webdriverio API by @PeterNgTr +* Added Japanese translation file by @tsemura +* Added `Locator.withDescendant()` method to find an element which contains a descendant (child, grandchild) by @Vorobeyko +* [WebDriver] Fixed configuring capabilities for Selenoid and IE by @Vorobeyko +* [WebDriver] Restore original window size when taking full size screenshot by @tsuemura +* Enabled `throws()`,` fails()`, `retry()`, `timeout()`, `config()` functions for data driven tests. By @jjm409 + +## 2.0.5 + +[Broken Release] + +## 2.0.4 + +* [WebDriver][Protractor][Nightmare][Puppeteer] `grabAttributeFrom` returns an array when multiple elements matched. By @PeterNgTr +* [autoLogin plugin] Fixed merging users config by @nealfennimore +* [autoDelay plugin] Added WebDriver to list of supported helpers by @mattin4d +* [Appium] Fixed using locators in `waitForElement`, `waitForVisible`, `waitForInvisible`. By @eduardofinotti +* [allure plugin] Add tags to allure reports by @Vorobeyko +* [allure plugin] Add skipped tests to allure reports by @Vorobeyko +* Fixed `Logged Test name | [object Object]` when used Data().Scenario(). By @Vorobeyko +* Fixed Data().only.Scenario() to run for all datasets. By @Vorobeyko +* [WebDriver] `attachFile` to work with hidden elements. Fixed in #1460 by @tsuemura + + + +## 2.0.3 + +* [**autoLogin plugin**](https://codecept.io/plugins#autologin) added. Allows to log in once and reuse browser session. When session expires - automatically logs in again. Can persist session between runs by saving cookies to file. +* Fixed `Maximum stack trace` issue in `retryFailedStep` plugin. +* Added `locate()` function into the interactive shell. +* [WebDriver] Disabled smartWait for interactive shell. +* [Appium] Updated methods to use for mobile locators + * `waitForElement` + * `waitForVisible` + * `waitForInvisible` +* Helper and page object generators no longer update config automatically. Please add your page objects and helpers manually. + +## 2.0.2 + +* [Puppeteer] Improved handling of connection with remote browser using Puppeteer by @martomo +* [WebDriver] Updated to webdriverio 5.2.2 by @martomo +* Interactive pause improvements by @davertmik + * Disable retryFailedStep plugin in in interactive mode + * Removes `Interface: parseInput` while in interactive pause +* [ApiDataFactory] Improvements + * added `fetchId` config option to override id retrieval from payload + * added `onRequest` config option to update request in realtime + * added `returnId` config option to return ids of created items instead of items themvelves + * added `headers` config option to override default headers. + * added a new chapter into [DataManagement](https://codecept.io/data#api-requests-using-browser-session) +* [REST] Added `onRequest` config option + + +## 2.0.1 + +* Fixed creating project with `codecept init`. +* Fixed error while installing webdriverio@5. +* Added code beautifier for generated configs. +* [WebDriver] Updated to webdriverio 5.1.0 + +## 2.0.0 + +* [WebDriver] **Breaking Change.** Updated to webdriverio v5. New helper **WebDriver** helper introduced. + + * **Upgrade plan**: + + 1. Install latest webdriverio + ``` + npm install webdriverio@5 --save + ``` + + 2. Replace `WebDriverIO` => `WebDriver` helper name in config. + 3. Read [webdriverio changelog](https://github.com/webdriverio/webdriverio/blob/master/CHANGELOG.md). If you were using webdriver API in your helpers, upgrade accordingly. + 4. We made WebDriver helper to be compatible with old API so no additional changes required. + + > If you face issues using webdriverio v5 you can still use webdriverio 4.x and WebDriverIO helper. Make sure you have `webdriverio: ^4.0` installed. + + * Known issues: `attachFile` doesn't work with proxy server. + +* [Appium] **Breaking Change.** Updated to use webdriverio v5 as well. See upgrade plan ↑ +* [REST] **Breaking Change.** Replaced `unirest` library with `axios`. + + * **Upgrade plan**: + + 1. Refer to [axios API](https://github.com/axios/axios). + 2. If you were using `unirest` requests/responses in your tests change them to axios format. +* **Breaking Change.** Generators support in tests removed. Use `async/await` in your tests +* **Using `codecept.conf.js` as default configuration format** +* Fixed "enametoolong" error when saving screenshots for data driven tests by @PeterNgTr +* Updated NodeJS to 10 in Docker image +* [Pupeteer] Add support to use WSEndpoint. Allows to execute tests remotely. [See #1350] by @gabrielcaires (https://github.com/codeceptjs/CodeceptJS/pull/1350) +* In interactive shell [Enter] goes to next step. Improvement by @PeterNgTr. +* `I.say` accepts second parameter as color to print colorful comments. Improvement by @PeterNgTr. + +```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 +``` +* Fixed allure reports for multi session testing by @PeterNgTr +* Fixed allure reports for hooks by @PeterNgTr + +## 1.4.6 + +* [Puppeteer] `dragSlider` action added by @PeterNgTr +* [Puppeteer] Fixed opening browser in shell mode by @allenhwkim +* [Puppeteer] Fixed making screenshot on additional sessions by @PeterNgTr. Fixes #1266 +* Added `--invert` option to `run-multiple` command by @LukoyanovE +* Fixed steps in Allure reports by @PeterNgTr +* Add option `output` to customize output directory in [stepByStepReport plugin](https://codecept.io/plugins/#stepbystepreport). By @fpsthirty +* Changed type definition of PageObjects to get auto completion by @rhicu +* Fixed steps output for async/arrow functions in CLI by @LukoyanovE. See #1329 + +## 1.4.5 + +* Add **require** param to main config. Allows to require Node modules before executing tests. By @LukoyanovE. For example: + * Use `ts-node/register` to register TypeScript parser + * Use `should` to register should-style assertions + +```js +"require": ["ts-node/register", "should"] +``` + +* [WebDriverIO] Fix timeouts definition to be compatible with W3C drivers. By @LukoyanovE +* Fixed: exception in Before block w/ Mocha causes test not to report failure. See #1292 by @PeterNgTr +* Command `run-parallel` now accepts `--override` flag. Thanks to @ClemCB +* Fixed Allure report with Before/BeforeSuite/After/AfterSuite steps. By @PeterNgTr +* Added `RUN_MULTIPLE` env variable to [Docker config](https://codecept.io/docker/). Allows to run tests in parallel inside a container. Thanks to @PeterNgTr +* [Mochawesome] Fixed showing screenshot on failure. Fix by @PeterNgTr +* Fixed running tests filtering by tag names defined via `Scenario.tag()` + +## 1.4.4 + +* [autoDelay plugin](https://codecept.io/plugins/#autoDelay) added. Adds tiny delay before and after an action so the page could react to actions performed. +* [Puppeteer] improvements by @luismanuel001 + * `click` no longer waits for navigation + * `clickLink` method added. Performs a click and waits for navigation. +* Bootstrap scripts to be started only for `run` command and ignored on `list`, `def`, etc. Fix by @LukoyanovE + + +## 1.4.3 + +* Groups renamed to Tags for compatibility with BDD layer +* Test and suite objects to contain tags property which can be accessed from internal API +* Fixed adding tags for Scenario Outline in BDD +* Added `tag()` method to ScenarioConfig and FeatureConfig: + +```js +Scenario('update user profile', () => { + // test goes here +}).tag('@slow'); +``` + +* Fixed attaching Allure screenshot on exception. Fix by @DevinWatson +* Improved type definitions for custom steps. By @Akxe +* Fixed setting `multiple.parallel.chunks` as environment variable in config. See #1238 by @ngadiyak + +## 1.4.2 + +* Fixed setting config for plugins (inclunding setting `outputDir` for allure) by @jplegoff + +## 1.4.1 + +* Added `plugins` option to `run-multiple` +* Minor output fixes +* Added Type Definition for Helper class by @Akxe +* Fixed extracing devault extension in generators by @Akxe + +## 1.4.0 + +* [**Allure Reporter Integration**](https://codecept.io/reports/#allure). Full inegration with Allure Server. Get nicely looking UI for tests,including steps, nested steps, and screenshots. Thanks **Natarajan Krishnamurthy @krish** for sponsoring this feature. +* [Plugins API introduced](https://codecept.io/hooks/#plugins). Create custom plugins for CodeceptJS by hooking into event dispatcher, and using promise recorder. +* **Official [CodeceptJS plugins](https://codecept.io/plugins) added**: + * **`stepByStepReport` - creates nicely looking report to see test execution as a slideshow**. Use this plugin to debug tests in headless environment without recording a video. + * `allure` - Allure reporter added as plugin. + * `screenshotOnFail` - saves screenshot on fail. Replaces similar functionality from helpers. + * `retryFailedStep` - to rerun each failed step. +* [Puppeteer] Fix `executeAsyncScript` unexpected token by @jonathanz +* Added `override` option to `run-multiple` command by @svarlet + +## 1.3.3 + +* Added `initGlobals()` function to API of [custom runner](https://codecept.io/hooks/#custom-runner). + +## 1.3.2 + +* Interactve Shell improvements for `pause()` + * Added `next` command for **step-by-step debug** when using `pause()`. + * Use `After(pause);` in a to start interactive console after last step. +* [Puppeteer] Updated to Puppeteer 1.6.0 + * Added `waitForRequest` to wait for network request. + * Added `waitForResponse` to wait for network response. +* Improved TypeScript definitions to support custom steps and page objects. By @xt1 +* Fixed XPath detection to accept XPath which starts with `./` by @BenoitZugmeyer + +## 1.3.1 + +* BDD-Gherkin: Fixed running async steps. +* [Puppeteer] Fixed process hanging for 30 seconds. Page loading timeout default via `getPageTimeout` set 0 seconds. +* [Puppeteer] Improved displaying client-side console messages in debug mode. +* [Puppeteer] Fixed closing sessions in `restart:false` mode for multi-session mode. +* [Protractor] Fixed `grabPopupText` to not throw error popup is not opened. +* [Protractor] Added info on using 'direct' Protractor driver to helper documentation by @xt1. +* [WebDriverIO] Added a list of all special keys to WebDriverIO helper by @davertmik and @xt1. +* Improved TypeScript definitions generator by @xt1 + +## 1.3.0 + +* **Cucumber-style BDD. Introduced [Gherkin support](https://codecept.io/bdd). Thanks to [David Vins](https://github.com/dvins) and [Omedym](https://www.omedym.com) for sponsoring this feature**. + +Basic feature file: + +```gherkin +Feature: Business rules + In order to achieve my goals + As a persona + I want to be able to interact with a system + + Scenario: do anything in my life + Given I need to open Google +``` + +Step definition: + +```js +const I = actor(); + +Given('I need to open Google', () => { + I.amOnPage('https://google.com'); +}); +``` + +Run it with `--features --steps` flag: + +``` +codeceptjs run --steps --features +``` + +--- + +* **Brekaing Chnage** `run` command now uses relative path + test name to run exactly one test file. + +Previous behavior (removed): +``` +codeceptjs run basic_test.js +``` +Current behavior (relative path to config + a test name) + +``` +codeceptjs run tests/basic_test.js +``` +This change allows using auto-completion when running a specific test. + +--- + +* Nested steps output enabled for page objects. + * to see high-level steps only run tests with `--steps` flag. + * to see PageObjects implementation run tests with `--debug`. +* PageObjects simplified to remove `_init()` extra method. Try updated generators and see [updated guide](https://codecept.io/pageobjects/#pageobject). +* [Puppeteer] [Multiple sessions](https://codecept.io/acceptance/#multiple-sessions) enabled. Requires Puppeteer >= 1.5 +* [Puppeteer] Stability improvement. Waits for for `load` event on page load. This strategy can be changed in config: + * `waitForNavigation` config option introduced. Possible options: `load`, `domcontentloaded`, `networkidle0`, `networkidle2`. See [Puppeteer API](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitfornavigationoptions) + * `getPageTimeout` config option to set maximum navigation time in milliseconds. Default is 30 seconds. + * `waitForNavigation` method added. Explicitly waits for navigation to be finished. +* [WebDriverIO][Protractor][Puppeteer][Nightmare] **Possible BC** `grabTextFrom` unified. Return a text for single matched element and an array of texts for multiple elements. +* [Puppeteer]Fixed `resizeWindow` by @sergejkaravajnij +* [WebDriverIO][Protractor][Puppeteer][Nightmare] `waitForFunction` added. Waits for client-side JavaScript function to return true by @GREENpoint. +* [Puppeteer] `waitUntil` deprecated in favor of `waitForFunction`. +* Added `filter` function to DataTable. +* Send non-nested array of files to custom parallel execution chunking by @mikecbrant. +* Fixed invalid output directory path for run-multiple by @mikecbrant. +* [WebDriverIO] `waitUntil` timeout accepts time in seconds (as all other wait* functions). Fix by @truesrc. +* [Nightmare] Fixed `grabNumberOfVisibleElements` to work similarly to `seeElement`. Thx to @stefanschenk and Jinbo Jinboson. +* [Protractor] Fixed alert handling error with message 'no such alert' by @truesrc. + + +## 1.2.1 + +* Fixed running `I.retry()` on multiple steps. +* Fixed parallel execution wih chunks. +* [Puppeteer] Fixed `grabNumberOfVisibleElements` to return `0` instead of throwing error if no elements are found. + +## 1.2.0 + +* [WebDriverIO][Protractor][Multiple Sessions](https://codecept.io/acceptance/#multiple-sessions). Run several browser sessions in one test. Introduced `session` command, which opens additional browser window and closes it after a test. + +```js +Scenario('run in different browsers', (I) => { + I.amOnPage('/hello'); + I.see('Hello!'); + session('john', () => { + I.amOnPage('/bye'); + I.dontSee('Hello'); + I.see('Bye'); + }); + I.see('Hello'); +}); +``` + +* [Parallel Execution](https://codecept.io/advanced/#parallel-execution) by @sveneisenschmidt. Run tests in parallel specifying number of chunks: + +```js +"multiple": { + "parallel": { + // run in 2 processes + "chunks": 2, + // run all tests in chrome + "browsers": ["chrome"] + }, +} +``` + +* [Locator Builder](https://codecept.io/locators). Write complex locators with simplest API combining CSS and XPath: + +```js +// select 'Edit' link inside 2nd row of a table +locate('//table') + .find('tr') + .at(2) + .find('a') + .withText('Edit'); +``` + +* [Dynamic configuration](https://codecept.io/advanced/#dynamic-configuration) to update helpers config per test or per suite. +* Added `event.test.finished` which fires synchronously for both failed and passed tests. +* [WebDriverIO][Protractor][Nightmare][Puppeteer] Full page screenshots on failure disabled by default. See [issue#1600. You can enabled them with `fullPageScreenshots: true`, however they may work unstable in Selenium. +* `within` blocks can return values. See [updated documentation](https://codecept.io/basics/#within). +* Removed doublt call to `_init` in helpers. Fixes issue #1036 +* Added scenario and feature configuration via fluent API: + +```js +Feature('checkout') + .timeout(3000) + .retry(2); + +Scenario('user can order in firefox', (I) => { + // see dynamic configuration +}).config({ browser: 'firefox' }) + .timeout(20000); + +Scenario('this test should throw error', (I) => { + // I.amOnPage +}).throws(new Error); +``` + +## 1.1.8 + +* Fixed generating TypeScript definitions with `codeceptjs def`. +* Added Chinese translation ("zh-CN" and "zh-TW") by @TechQuery. +* Fixed running tests from a different folder specified by `-c` option. +* [Puppeteer] Added support for hash handling in URL by @gavoja. +* [Puppeteer] Fixed setting viewport size by @gavoja. See [Puppeteer issue](https://github.com/GoogleChrome/puppeteer/issues/1183) + + +## 1.1.7 + +* Docker Image updateed. [See updated reference](https://codecept.io/docker/): + * codeceptjs package is mounted as `/codecept` insde container + * tests directory is expected to be mounted as `/tests` + * `codeceptjs` global runner added (symlink to `/codecept/bin/codecept.js`) +* [Protractor] Functions added by @reubenmiller: + * `_locateCheckable (only available from other helpers)` + * `_locateClickable (only available from other helpers)` + * `_locateFields (only available from other helpers)` + * `acceptPopup` + * `cancelPopup` + * `dragAndDrop` + * `grabBrowserLogs` + * `grabCssPropertyFrom` + * `grabHTMLFrom` + * `grabNumberOfVisibleElements` + * `grabPageScrollPosition (new)` + * `rightClick` + * `scrollPageToBottom` + * `scrollPageToTop` + * `scrollTo` + * `seeAttributesOnElements` + * `seeCssPropertiesOnElements` + * `seeInPopup` + * `seeNumberOfVisibleElements` + * `switchTo` + * `waitForEnabled` + * `waitForValue` + * `waitInUrl` + * `waitNumberOfVisibleElements` + * `waitToHide` + * `waitUntil` + * `waitUrlEquals` +* [Nightmare] added: + * `grabPageScrollPosition` (new) + * `seeNumberOfVisibleElements` + * `waitToHide` +* [Puppeteer] added: + * `grabPageScrollPosition` (new) +* [WebDriverIO] added" + * `grabPageScrollPosition` (new) +* [Puppeteer] Fixed running wait* functions without setting `sec` parameter. +* [Puppeteer][Protractor] Fixed bug with I.click when using an object selector with the xpath property. By @reubenmiller +* [WebDriverIO][Protractor][Nightmare][Puppeteer] Fixed I.switchTo(0) and I.scrollTo(100, 100) api inconsistencies between helpers. +* [Protractor] Fixing bug when `seeAttributesOnElements` and `seeCssPropertiesOnElement` were incorrectly passing when the attributes/properties did not match by @reubenmiller +* [WebDriverIO] Use inbuilt dragAndDrop function (still doesn't work in Firefox). By @reubenmiller +* Support for Nightmare 3.0 +* Enable glob patterns in `config.test` / `Codecept.loadTests` by @sveneisenschmidt +* Enable overriding of `config.tests` for `run-multiple` by @sveneisenschmidt + + +## 1.1.6 + +* Added support for `async I =>` functions syntax in Scenario by @APshenkin +* [WebDriverIO][Protractor][Puppeteer][Nightmare] `waitForInvisible` waits for element to hide or to be removed from page. By @reubenmiller +* [Protractor][Puppeteer][Nightmare] Added `grabCurrentUrl` function. By @reubenmiller +* [WebDriverIO] `grabBrowserUrl` deprecated in favor of `grabCurrentUrl` to unify the API. +* [Nightmare] Improved element visibility detection by @reubenmiller +* [Puppeteer] Fixing function calls when clearing the cookies and localstorage. By @reubenmiller +* [Puppeteer] Added `waitForEnabled`, `waitForValue` and `waitNumberOfVisibleElements` methods by @reubenmiller +* [WebDriverIO] Fixed `grabNumberOfVisibleElements` to return 0 when no visible elements are on page. By @michaltrunek +* Helpers API improvements (by @reubenmiller) + * `_passed` hook runs after a test passed successfully + * `_failed` hook runs on a failed test +* Hooks API. New events added by @reubenmiller: + * `event.all.before` - executed before all tests + * `event.all.after` - executed after all tests + * `event.multiple.before` - executed before all processes in run-multiple + * `event.multiple.after` - executed after all processes in run-multiple +* Multiple execution +* Allow `AfterSuite` and `After` test hooks to be defined after the first Scenario. By @reubenmiller +* [Nightmare] Prevent `I.amOnpage` navigation if the browser is already at the given url +* Multiple-Run: Added new `bootstrapAll` and `teardownAll` hooks to be executed before and after all processes +* `codeceptjs def` command accepts `--config` option. By @reubenmiller + +## 1.1.5 + +* [Puppeteer] Rerun steps failed due to "Cannot find context with specified id" Error. +* Added syntax to retry a single step: + +```js +// retry action once on failure +I.retry().see('Hello'); + +// retry action 3 times on failure +I.retry(3).see('Hello'); + +// retry action 3 times waiting for 0.1 second before next try +I.retry({ retries: 3, minTimeout: 100 }).see('Hello'); + +// retry action 3 times waiting no more than 3 seconds for last retry +I.retry({ retries: 3, maxTimeout: 3000 }).see('Hello'); + +// retry 2 times if error with message 'Node not visible' happens +I.retry({ + retries: 2, + when: err => err.message === 'Node not visible' +}).seeElement('#user'); +``` + +* `Scenario().injectDependencies` added to dynamically add objects into DI container by @Apshenkin. See [Dependency Injection section in PageObjects](https://codecept.io/pageobjects/#dependency-injection). +* Fixed using async/await functions inside `within` +* [WebDriverIO][Protractor][Puppeteer][Nightmare] **`waitUntilExists` deprecated** in favor of `waitForElement` +* [WebDriverIO][Protractor] **`waitForStalenessOf` deprecated** in favor of `waitForDetached` +* [WebDriverIO][Protractor][Puppeteer][Nightmare] `waitForDetached` added +* [Nightmare] Added `I.seeNumberOfElements()` by @pmoncadaisla +* [Nightmare] Load blank page when starting nightmare so that the .evaluate function will work if _failed/saveScreenshot is triggered by @reubenmiller +* Fixed using plain arrays for data driven tests by @reubenmiller +* [Puppeteer] Use default tab instead of opening a new tab when starting the browser by @reubenmiller +* [Puppeteer] Added `grabNumberOfTabs` function by @reubenmiller +* [Puppeteer] Add ability to set user-agent by @abidhahmed +* [Puppeteer] Add keepCookies and keepBrowserState @abidhahmed +* [Puppeteer] Clear value attribute instead of innerhtml for TEXTAREA by @reubenmiller +* [REST] fixed sending string payload by @michaltrunek +* Fixed unhandled rejection in async/await tests by @APshenkin + + +## 1.1.4 + +* Removed `yarn` call in package.json +* Fixed `console.log` in Puppeteer by @othree +* [Appium] `runOnAndroid` and `runOnIOS` can receive a function to check capabilities dynamically: + +```js +I.runOnAndroid(caps => caps.platformVersion >= 7, () => { + // run code only on Android 7+ +}); +``` + +## 1.1.3 + +* [Puppeteer] +25 Functions added by @reubenmiller + * `_locateCheckable` + * `_locateClickable` + * `_locateFields` + * `closeOtherTabs` + * `dragAndDrop` + * `grabBrowserLogs` + * `grabCssPropertyFrom` + * `grabHTMLFrom` + * `grabNumberOfVisibleElements` + * `grabSource` + * `rightClick` + * `scrollPageToBottom` + * `scrollPageToTop` + * `scrollTo` + * `seeAttributesOnElements` + * `seeCssPropertiesOnElements` + * `seeInField` + * `seeNumberOfElements` + * `seeNumberOfVisibleElements` + * `seeTextEquals` + * `seeTitleEquals` + * `switchTo` + * `waitForInvisible` + * `waitInUrl` + * `waitUrlEquals` +* [Protractor] +8 functions added by @reubenmiller + * `closeCurrentTab` + * `grabSource` + * `openNewTab` + * `seeNumberOfElements` + * `seeTextEquals` + * `seeTitleEquals` + * `switchToNextTab` + * `switchToPreviousTab` +* [Nightmare] `waitForInvisible` added by @reubenmiller +* [Puppeteer] Printing console.log information in debug mode. +* [Nightmare] Integrated with `nightmare-har-plugin` by mingfang. Added `enableHAR` option. Added HAR functions: + * `grabHAR` + * `saveHAR` + * `resetHAR` +* [WebDriverIO] Fixed execution stability for parallel requests with Chromedriver +* [WebDriverIO] Fixed resizeWindow when resizing to 'maximize' by @reubenmiller +* [WebDriverIO] Fixing resizing window to full screen when taking a screenshot by @reubenmiller + +## 1.1.2 + +* [Puppeteer] Upgraded to Puppeteer 1.0 +* Added `grep` option to config to set default matching pattern for tests. +* [Puppeteer] Added `acceptPopup`, `cancelPopup`, `seeInPopup` and `grabPopupText` functions by @reubenmiller +* [Puppeteer] `within` iframe and nested iframe support added by @reubenmiller +* [REST] Added support for JSON objects since payload (as a JSON) was automatically converted into "URL query" type of parameter by @Kalostrinho +* [REST] Added `resetRequestHeaders` method by @Kalostrinho +* [REST] Added `followRedirect` option and `amFollowingRequestRedirects`/`amNotFollowingRequestRedirects` methods by @Kalostrinho +* [WebDriverIO] `uncheckOption` implemented by @brunobg +* [WebDriverIO] Added `grabBrowserUrl` by @Kalostrinho +* Add ability to require helpers from node_modules by @APshenkin +* Added `--profile` option to `run-multiple` command by @jamie-beck +* Custom output name for multiple browser run by @tfiwm +* Fixed passing data to scenarios by @KennyRules + +## 1.1.1 + +* [WebDriverIO] fixed `waitForInvisible` by @Kporal + +## 1.1.0 + +Major update to CodeceptJS. **NodeJS v 8.9.1** is now minimal Node version required. +This brings native async-await support to CodeceptJS. It is recommended to start using await for tests instead of generators: + +```js +async () => { + I.amOnPage('/page'); + const url = await I.grabTextFrom('.nextPage'); + I.amOnPage(url); +} +``` + +Thanks to [@Apshenkin](https://github.com/apshenkin) for implementation. Also, most helpers were refactored to use async-await. This made our code simpler. We hope that this encourages more users to send pull requests! + +We also introduced strict ESLint policies for our codebase. Thanks to [@Galkin](https://github.com/galkin) for that. + +* **[Puppeteer] Helper introduced**. [Learn how to run tests headlessly with Google Chrome's Puppeteer](http://codecept.io/puppeteer/). +* [SeleniumWebdriver] Helper is deprecated, it is recommended to use Protractor with config option `angular: false` instead. +* [WebDriverIO] nested iframe support in the within block by @reubenmiller. Example: + +```js +within({frame: ['#wrapperId', '[name=content]']}, () => { + I.click('Sign in!'); + I.see('Email Address'); +}); +I.see('Nested Iframe test'); +I.dontSee('Email Address'); +}); +``` +* [WebDriverIO] Support for `~` locator to find elements by `aria-label`. This behavior is similar as it is in Appium and helps testing cross-platform React apps. Example: + +```html + + CodeceptJS is awesome + +``` +↑ This element can be located with `~foobar` in WebDriverIO and Appium helpers. Thanks to @flyskywhy + +* Allow providing arbitrary objects in config includes by @rlewan +* [REST] Prevent from mutating default headers by @alexashley. See #789 +* [REST] Fixed sending empty helpers with `haveRequestHeaders` in `sendPostRequest`. By @petrisorionel +* Fixed displaying undefined args in output by @APshenkin +* Fixed NaN instead of seconds in output by @APshenkin +* Add browser name to report file for `multiple-run` by @trollr +* Mocha updated to 4.x + + + +## 1.0.3 + +* [WebDriverIO][Protractor][Nightmare] method `waitUntilExists` implemented by @sabau +* Absolute path can be set for `output` dir by @APshenkin. Fix #571* Data table rows can be ignored by using `xadd`. By @APhenkin +* Added `Data(table).only.Scenario` to give ability to launch only Data tests. By @APhenkin +* Implemented `ElementNotFound` error by @BorisOsipov. +* Added TypeScript compiler / configs to check the JavaScript by @KennyRules +* [Nightmare] fix executeScript return value by @jploskonka +* [Nightmare] fixed: err.indexOf not a function when waitForText times out in nightmare by @joeypedicini92 +* Fixed: Retries not working when using .only. By @APhenkin + + +## 1.0.2 + +* Introduced generators support in scenario hooks for `BeforeSuite`/`Before`/`AfterSuite`/`After` +* [ApiDataFactory] Fixed loading helper; `requireg` package included. +* Fix #485`run-multiple`: the first browser-resolution combination was be used in all configurations +* Fixed unique test names: + * Fixed #447 tests failed silently if they have the same name as other tests. + * Use uuid in screenshot names when `uniqueScreenshotNames: true` +* [Protractor] Fixed testing non-angular application. `amOutsideAngularApp` is executed before each step. Fixes #458* Added output for steps in hooks when they fail + +## 1.0.1 + +* Reporters improvements: + * Allows to execute [multiple reporters](http://codecept.io/advanced/#Multi-Reports) + * Added [Mochawesome](http://codecept.io/helpers/Mochawesome/) helper + * `addMochawesomeContext` method to add custom data to mochawesome reports + * Fixed Mochawesome context for failed screenshots. +* [WebDriverIO] improved click on context to match clickable element with a text inside. Fixes #647* [Nightmare] Added `refresh` function by @awhanks +* fixed `Unhandled promise rejection (rejection id: 1): Error: Unknown wait type: pageLoad` +* support for tests with retries in html report +* be sure that change window size and timeouts completes before test +* [Nightmare] Fixed `[Wrapped Error] "codeceptjs is not defined"`; Reinjectiing client scripts to a webpage on changes. +* [Nightmare] Added more detailed error messages for `Wait*` methods +* [Nightmare] Fixed adding screenshots to Mochawesome +* [Nightmare] Fix unique screenshots names in Nightmare +* Fixed CodeceptJS work with hooks in helpers to finish codeceptJS correctly if errors appears in helpers hooks +* Create a new session for next test If selenium grid error received +* Create screenshots for failed hooks from a Feature file +* Fixed `retries` option + +## 1.0 + +CodeceptJS hits first stable release. CodeceptJS provides a unified API for [web testing for Webdriverio](http://codecept.io/acceptance/), [Protractor](http://codecept.io/angular/), and [NightmareJS](http://codecept.io/nightmare/). Since 1.0 you can also **test mobile applications** in the similar manner with Appium. + +Sample test: + +```js +I.seeAppIsInstalled("io.super.app"); +I.click('~startUserRegistrationCD'); +I.fillField('~email of the customer', 'Nothing special')); +I.see('davert@codecept.io', '~email of the customer')); +I.clearField('~email of the customer')); +I.dontSee('Nothing special', '~email of the customer')); +``` + +* Read [the Mobile Testing guide](http://codecept.io/mobile). +* Discover [Appium Helper](http://codecept.io/helpers/Appium/) + +--- + +We also introduced two new **helpers for data management**. +Using them you can easily prepare and cleanup data for your tests using public REST API. + +Sample test + +```js +// create a user using data factories and REST API +I.have('user', { name: 'davert', password: '123456' }); +// use it to login +I.amOnPage('/login'); +I.fillField('login', 'davert'); +I.fillField('password', '123456'); +I.click('Login'); +I.see('Hello, davert'); +// user will be removed after the test +``` + +* Read [Data Management guide](http://codecept.io/data) +* [REST Helper](http://codecept.io/helpers/REST) +* [ApiDataFactory](http://codecept.io/helpers/ApiDataFactory/) + +--- + +Next notable feature is **[SmartWait](http://codecept.io/acceptance/#smartwait)** for WebDriverIO, Protractor, SeleniumWebdriver. When `smartwait` option is set, script will wait for extra milliseconds to locate an element before failing. This feature uses implicit waits of Selenium but turns them on only in applicable pieces. For instance, implicit waits are enabled for `seeElement` but disabled for `dontSeeElement` + +* Read more about [SmartWait](http://codecept.io/acceptance/#smartwait) + +##### Changelog + +* Minimal NodeJS version is 6.11.1 LTS +* Use `within` command with generators. +* [Data Driven Tests](http://codecept.io/advanced/#data-driven-tests) introduced. +* Print execution time per step in `--debug` mode. #591 by @APshenkin +* [WebDriverIO][Protractor][Nightmare] Added `disableScreenshots` option to disable screenshots on fail by @Apshenkin +* [WebDriverIO][Protractor][Nightmare] Added `uniqueScreenshotNames` option to generate unique names for screenshots on failure by @Apshenkin +* [WebDriverIO][Nightmare] Fixed click on context; `click('text', '#el')` will throw exception if text is not found inside `#el`. +* [WebDriverIO][Protractor][SeleniumWebdriver] [SmartWait introduced](http://codecept.io/acceptance/#smartwait). +* [WebDriverIO][Protractor][Nightmare]Fixed `saveScreenshot` for PhantomJS, `fullPageScreenshots` option introduced by @HughZurname #549 +* [Appium] helper introduced by @APshenkin +* [REST] helper introduced by @atrevino in #504 +* [WebDriverIO][SeleniumWebdriver] Fixed "windowSize": "maximize" for Chrome 59+ version #560 by @APshenkin +* [Nightmare] Fixed restarting by @APshenkin #581 +* [WebDriverIO] Methods added by @APshenkin: + * [grabCssPropertyFrom](http://codecept.io/helpers/WebDriverIO/#grabcsspropertyfrom) + * [seeTitleEquals](http://codecept.io/helpers/WebDriverIO/#seetitleequals) + * [seeTextEquals](http://codecept.io/helpers/WebDriverIO/#seetextequals) + * [seeCssPropertiesOnElements](http://codecept.io/helpers/WebDriverIO/#seecsspropertiesonelements) + * [seeAttributesOnElements](http://codecept.io/helpers/WebDriverIO/#seeattributesonelements) + * [grabNumberOfVisibleElements](http://codecept.io/helpers/WebDriverIO/#grabnumberofvisibleelements) + * [waitInUrl](http://codecept.io/helpers/WebDriverIO/#waitinurl) + * [waitUrlEquals](http://codecept.io/helpers/WebDriverIO/#waiturlequals) + * [waitForValue](http://codecept.io/helpers/WebDriverIO/#waitforvalue) + * [waitNumberOfVisibleElements](http://codecept.io/helpers/WebDriverIO/#waitnumberofvisibleelements) + * [switchToNextTab](http://codecept.io/helpers/WebDriverIO/#switchtonexttab) + * [switchToPreviousTab](http://codecept.io/helpers/WebDriverIO/#switchtoprevioustab) + * [closeCurrentTab](http://codecept.io/helpers/WebDriverIO/#closecurrenttab) + * [openNewTab](http://codecept.io/helpers/WebDriverIO/#opennewtab) + * [refreshPage](http://codecept.io/helpers/WebDriverIO/#refreshpage) + * [scrollPageToBottom](http://codecept.io/helpers/WebDriverIO/#scrollpagetobottom) + * [scrollPageToTop](http://codecept.io/helpers/WebDriverIO/#scrollpagetotop) + * [grabBrowserLogs](http://codecept.io/helpers/WebDriverIO/#grabbrowserlogs) +* Use mkdirp to create output directory. #592 by @vkramskikh +* [WebDriverIO] Fixed `seeNumberOfVisibleElements` by @BorisOsipov #574 +* Lots of fixes for promise chain by @APshenkin #568 + * Fix #543- After block not properly executed if Scenario fails + * Expected behavior in promise chains: `_beforeSuite` hooks from helpers -> `BeforeSuite` from test -> `_before` hooks from helpers -> `Before` from test - > Test steps -> `_failed` hooks from helpers (if test failed) -> `After` from test -> `_after` hooks from helpers -> `AfterSuite` from test -> `_afterSuite` hook from helpers. + * if during test we got errors from any hook (in test or in helper) - stop complete this suite and go to another + * if during test we got error from Selenium server - stop complete this suite and go to another + * [WebDriverIO][Protractor] if `restart` option is false - close all tabs expect one in `_after`. + * Complete `_after`, `_afterSuite` hooks even After/AfterSuite from test was failed + * Don't close browser between suites, when `restart` option is false. We should start browser only one time and close it only after all tests. + * Close tabs and clear local storage, if `keepCookies` flag is enabled +* Fix TypeError when using babel-node or ts-node on node.js 7+ #586 by @vkramskikh +* [Nightmare] fixed usage of `_locate` + +Special thanks to **Andrey Pshenkin** for his work on this release and the major improvements. + +## 0.6.3 + +* Errors are printed in non-verbose mode. Shows "Selenium not started" and other important errors. +* Allowed to set custom test options: + +```js +Scenario('My scenario', { build_id: 123, type: 'slow' }, function (I) +``` +those options can be accessed as `opts` property inside a `test` object. Can be used in custom listeners. + +* Added `docs` directory to a package. +* [WebDriverIO][Protractor][SeleniumWebdriver] Bugfix: cleaning session when `restart: false` by @tfiwm #519 +* [WebDriverIO][Protractor][Nightmare] Added second parameter to `saveScreenshot` to allow a full page screenshot. By @HughZurname +* Added suite object to `suite.before` and `suite.after` events by @implico. #496 + +## 0.6.2 + +* Added `config` object to [public API](http://codecept.io/hooks/#api) +* Extended `index.js` to include `actor` and `helpers`, so they could be required: + +```js +const actor = require('codeceptjs').actor; +``` + +* Added [example for creating custom runner](http://codecept.io/hooks/#custom-runner) with public API. +* run command to create `output` directory if it doesn't exist +* [Protractor] fixed loading globally installed Protractor +* run-multiple command improvements: + * create output directories for each process + * print process ids in output + +## 0.6.1 + +* Fixed loading hooks + +## 0.6.0 + +Major release with extension API and parallel execution. + +* **Breaking** Removed path argument from `run`. To specify path other than current directory use `--config` or `-c` option: + +Instead of: `codeceptjs run tests` use: + +``` +# load config and run from tests directory +codeceptjs run -c tests/ + +# or load codecept.json from tests directory +codeceptjs run -c tests/codecept.json + +# run users_test.js inside tests directory +codeceptjs run users_test.js -c tests +``` + +* **Command `multiple-run` added**, to execute tests in several browsers in parallel by @APshenkin and @davertmik. [See documentation](http://codecept.io/advanced/#multiple-execution). +* **Hooks API added to extend CodeceptJS** with custom listeners and plugins. [See documentation](http://codecept.io/hooks/#hooks_1). +* [Nightmare][WebDriverIO] `within` can work with iframes by @imvetri. [See documentation](http://codecept.io/acceptance/#iframes). +* [WebDriverIO][SeleniumWebdriver][Protractor] Default browser changed to `chrome` +* [Nightmare] Fixed globally locating `nightmare-upload`. +* [WebDriverIO] added `seeNumberOfVisibleElements` method by @elarouche. +* Exit with non-zero code if init throws an error by @rincedd +* New guides published: + * [Installation](http://codecept.io/installation/) + * [Hooks](http://codecept.io/hooks/) + * [Advanced Usage](http://codecept.io/advanced/) +* Meta packages published: + * [codecept-webdriverio](https://www.npmjs.com/package/codecept-webdriverio) + * [codecept-protractor](https://www.npmjs.com/package/codecept-protractor) + * [codecept-nightmare](https://www.npmjs.com/package/codecept-nightmare) + + +## 0.5.1 + +* [Polish translation](http://codecept.io/translation/#polish) added by @limes. +* Update process exit code so that mocha saves reports before exit by @romanovma. +* [Nightmare] fixed `getAttributeFrom` for custom attributes by @robrkerr +* [Nightmare] Fixed *UnhandledPromiseRejectionWarning error* when selecting the dropdown using `selectOption` by @robrkerr. [Se PR. +* [Protractor] fixed `pressKey` method by @romanovma + ## 0.5.0 * Protractor ^5.0.0 support (while keeping ^4.0.9 compatibility) -* Fix 'fullTitle() is not a function' in exit.js by @hubidu. See [#388](https://github.com/Codeception/CodeceptJS/pull/388). -* [Nightmare] Fix for `waitTimeout` by @HughZurname. See [#391](https://github.com/Codeception/CodeceptJS/pull/391). Resolves [#236](https://github.com/Codeception/CodeceptJS/issues/236) -* Dockerized CodeceptJS setup by @artiomnist. [See reference](https://github.com/Codeception/CodeceptJS/blob/master/docker/README.md) +* Fix 'fullTitle() is not a function' in exit.js by @hubidu. See #388. +* [Nightmare] Fix for `waitTimeout` by @HughZurname. See #391. Resolves #236* Dockerized CodeceptJS setup by @artiomnist. [See reference](https://github.com/codeceptjs/CodeceptJS/blob/master/docker/README.md) ## 0.4.16 @@ -85,7 +1443,7 @@ Scenario('Not that complex', {timeout: 1000}, (I) => { }); ``` -* [WebDriverIO] Added `uniqueScreenshotNames` option to set unique screenshot names for failed tests. By @APshenkin. See [#299](https://github.com/Codeception/CodeceptJS/pull/299) +* [WebDriverIO] Added `uniqueScreenshotNames` option to set unique screenshot names for failed tests. By @APshenkin. See #299 * [WebDriverIO] `clearField` method improved to accept name/label locators and throw errors. * [Nightmare][SeleniumWebdriver][Protractor] `clearField` method added. * [Nightmare] Fixed `waitForElement`, and `waitForVisible` methods. @@ -102,7 +1460,7 @@ codeceptjs run -o '{ "bootstrap": "bootstrap.js"}' codeceptjs run -o '{ "helpers": {"WebDriverIO": {"browser": "chrome"}}}' ``` -* Added [regression tests](https://github.com/Codeception/CodeceptJS/tree/master/test/runner) for codeceptjs tests runner. +* Added [regression tests](https://github.com/codeceptjs/CodeceptJS/tree/master/test/runner) for codeceptjs tests runner. ## 0.4.11 @@ -136,12 +1494,12 @@ module.exports = function(done) { ## 0.4.8 * [Protractor][SeleniumWebdriver][Nightmare] added `moveCursorTo` method. -* [Protractor][SeleniumWebdriver][WebDriverIO] Added `manualStart` option to start browser manually in the beginning of test. By @cnworks. [PR #250](https://github.com/Codeception/CodeceptJS/pull/255) +* [Protractor][SeleniumWebdriver][WebDriverIO] Added `manualStart` option to start browser manually in the beginning of test. By @cnworks. [PR#250 * Fixed `codeceptjs init` to work with nested directories and file masks. * Fixed `codeceptjs gt` to generate test with proper file name suffix. By @Zougi. * [Nightmare] Fixed: Error is thrown when clicking on element which can't be locate. By @davetmik * [WebDriverIO] Fixed `attachFile` for file upload. By @giuband and @davetmik -* [WebDriverIO] Add support for timeouts in config and with `defineTimeouts` method. By @easternbloc [#258](https://github.com/Codeception/CodeceptJS/pull/258) and [#267](https://github.com/Codeception/CodeceptJS/pull/267) by @davetmik +* [WebDriverIO] Add support for timeouts in config and with `defineTimeouts` method. By @easternbloc #258 and #267 by @davetmik * Fixed hanging of CodeceptJS when error is thrown by event dispatcher. Fix by @Zougi and @davetmik @@ -185,7 +1543,7 @@ exports.config = { ## 0.4.2 -* Added ability to localize tests with translation [#189](https://github.com/Codeception/CodeceptJS/pull/189). Thanks to @abner +* Added ability to localize tests with translation #189. Thanks to @abner * [Translation] ru-RU translation added. * [Translation] pt-BR translation added. * [Protractor] Protractor 4.0.4 compatibility. @@ -315,4 +1673,4 @@ Whenever you need to create `I` object (in page objects, custom steps, but not i * [WebDriverIO] proxy configuration added by @petehouston * [WebDriverIO] fixed `waitForText` method by @roadhump. Fixes #11 * Fixed creating output dir when it already exists on init by @alfirin -* Fixed loading of custom helpers \ No newline at end of file +* Fixed loading of custom helpers diff --git a/Dockerfile b/Dockerfile index 4f2d777fa..05dee4522 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,29 +1,66 @@ -FROM node:6.9.5 -# LTS +ARG NODE_VERSION=12.10.0 +FROM node:${NODE_VERSION} - # Set grep as an ENV variable -ENV GREP=" " +# Add our user and group first to make sure their IDs get assigned consistently, +# regardless of whatever dependencies get added. +RUN groupadd --system nightmare && useradd --system --create-home --gid nightmare nightmare - # Set HOST ENV variable for Selenium Server -ENV HOST=selenium +# Installing the pre-required packages and libraries for electron & Nightmare +RUN apt-get update && \ + apt-get install -y libgtk2.0-0 libgconf-2-4 \ + libasound2 libxtst6 libxss1 libnss3 xvfb - # Add our user and group first to make sure their IDs get assigned consistently, - # regardless of whatever dependencies get added. -RUN groupadd --system nightmare && useradd --system --create-home --gid nightmare nightmare +# Install latest chrome dev package. +# Note: this installs the necessary libs to make the bundled version of Chromium that Puppeteer +# installs, work. +RUN apt-get update && apt-get install -y wget --no-install-recommends \ + && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \ + && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \ + && apt-get update \ + && apt-get install -y google-chrome-unstable \ + --no-install-recommends \ + && apt-get install -y libgbm1 \ + && rm -rf /var/lib/apt/lists/* \ + && apt-get purge --auto-remove -y curl \ + && rm -rf /src/*.deb - # Installing the pre-required packages and libraries for electron & Nightmare -RUN apt-get update && \ - apt-get install -y libgtk2.0-0 libgconf-2-4 \ - libasound2 libxtst6 libxss1 libnss3 xvfb +# Uncomment to skip the chromium download when installing puppeteer. If you do, +# you'll need to launch puppeteer with: +# browser.launch({executablePath: 'google-chrome-unstable'}) +# ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true -ADD . / - # Install latest version of Nightmare -RUN npm install +# Add pptr user. +RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \ + && mkdir -p /home/pptruser/Downloads \ + && chown -R pptruser:pptruser /home/pptruser \ + && chown -R pptruser:pptruser /home/pptruser - # Set the entrypoint for Nightmare -ENTRYPOINT ["/docker/entrypoint"] - # Run tests -CMD ["bash", "/docker/run.sh"] +#RUN mkdir /home/codecept +COPY . /codecept + +RUN chown -R pptruser:pptruser /codecept +RUN runuser -l pptruser -c 'npm install --loglevel=warn --prefix /codecept' + +RUN ln -s /codecept/bin/codecept.js /usr/local/bin/codeceptjs +RUN mkdir /tests +WORKDIR /tests + +# Allow to pass argument to codecept run via env variable +ENV CODECEPT_ARGS="" +ENV RUN_MULTIPLE=false +ENV NO_OF_WORKERS="" + +# Set HOST ENV variable for Selenium Server +ENV HOST=selenium + +# Run user as non privileged. +# USER pptruser + +# Set the entrypoint for Nightmare +ENTRYPOINT ["/codecept/docker/entrypoint"] + +# Run tests +CMD ["bash", "/codecept/docker/run.sh"] diff --git a/README.md b/README.md index 6634feba1..e858a93b5 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ -# CodeceptJS [![NPM version][npm-image]][npm-url] [![Build Status](https://travis-ci.org/Codeception/CodeceptJS.svg)](https://travis-ci.org/Codeception/CodeceptJS) [![Join the chat at https://gitter.im/Codeception/CodeceptJS](https://badges.gitter.im/Codeception/CodeceptJS.svg)](https://gitter.im/Codeception/CodeceptJS?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[](https://join.slack.com/t/codeceptjs/shared_invite/enQtMzA5OTM4NDM2MzA4LWE4MThhN2NmYTgxNTU5MTc4YzAyYWMwY2JkMmZlYWI5MWQ2MDM5MmRmYzZmYmNiNmY5NTAzM2EwMGIwOTNhOGQ) [](https://codecept.discourse.group) [![NPM version][npm-image]][npm-url] [![Build Status](https://travis-ci.org/Codeception/CodeceptJS.svg?branch=master)](https://travis-ci.org/Codeception/CodeceptJS) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/1823c38c74e44724b5555e3641f72621)](https://www.codacy.com/app/DavertMik/CodeceptJS?utm_source=github.com&utm_medium=referral&utm_content=Codeception/CodeceptJS&utm_campaign=badger) [![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com) -Reference: [Helpers API](https://github.com/Codeception/CodeceptJS/blob/master/docs) | [Demo](https://github.com/Codeception/codeceptjs-demo) +# CodeceptJS -## Modern Era Acceptance Testing Framework for NodeJS +Reference: [Helpers API](https://github.com/codeceptjs/CodeceptJS/blob/master/docs) | [Demo](https://github.com/codeceptjs/codeceptjs-demo) + +## Supercharged E2E Testing CodeceptJS is a new testing framework for end-to-end testing with WebDriver (or others). -It abstracts browser interaction to simple steps which is written from a user perspective. -A simple test that verifies that "Welcome" text is present on a main page of a site will look like: +It abstracts browser interaction to simple steps that are written from a user perspective. +A simple test that verifies the "Welcome" text is present on a main page of a site will look like: ```js Feature('CodeceptJS demo'); @@ -14,22 +16,24 @@ Feature('CodeceptJS demo'); Scenario('check Welcome page on site', (I) => { I.amOnPage('/'); I.see('Welcome'); -} +}); ``` -Codeception tests are: +CodeceptJS tests are: -* **Synchronous**. You don't need to care about callbacks, or promises, test scenarios are linear, your test should be too. +* **Synchronous**. You don't need to care about callbacks or promises or test scenarios which are linear. But, your tests should be linear. * Written from **user's perspective**. Every action is a method of `I`. That makes test easy to read, write and maintain even for non-tech persons. * Backend **API agnostic**. We don't know which WebDriver implementation is running this test. We can easily switch from WebDriverIO to Protractor or PhantomJS. -Codeception uses **Helper** modules to provide actions to `I` object. Currently CodeceptJS has these helpers: +CodeceptJS uses **Helper** modules to provide actions to `I` object. Currently CodeceptJS has these helpers: -* [**WebDriverIO**](https://github.com/Codeception/CodeceptJS/blob/master/docs/helpers/WebDriverIO.md) - wrapper on top of Selenium bindings library [WebDriverIO](http://webdriver.io/) -* [**Protractor**](https://github.com/Codeception/CodeceptJS/blob/master/docs/helpers/Protractor.md) - helper enpowered by [Protractor](http://protractortest.org/) framework for AngularJS testing -* [**Nightmare**](https://github.com/Codeception/CodeceptJS/blob/master/docs/helpers/Nightmare.md) - helper which for testing web applications indi Electron using NightmareJS. -* [**SeleniumWebdriver**](https://github.com/Codeception/CodeceptJS/blob/master/docs/helpers/SeleniumWebdriver.md) - helper which for selenium testing using official Selenium Webdriver JS bindings. -* [**FileSystem**](https://github.com/Codeception/CodeceptJS/blob/master/docs/helpers/FileSystem.md) - simple helper for testing filesystem. +* [**Puppeteer**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/Puppeteer.md) - uses Google Chrome's Puppeteer for fast headless testing. +* [**WebDriver**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/WebDriver.md) - uses [webdriverio](http://webdriver.io/) to run tests via WebDriver protocol. +* [**Protractor**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/Protractor.md) - helper empowered by [Protractor](http://protractortest.org/) to run tests via WebDriver protocol. +* [**TestCafe**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/TestCafe.md) - cheap and fast cross-browser test automation. +* [**Nightmare**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/Nightmare.md) - uses Electron and NightmareJS to run tests. +* [**Appium**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/Appium.md) - for **mobile testing** with Appium +* [**Detox**](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/Detox.md) - This is a wrapper on top of Detox library, aimed to unify testing experience for CodeceptJS framework. Detox provides a grey box testing for mobile applications, playing especially well for React Native apps. And more to come... @@ -37,8 +41,7 @@ And more to come... CodeceptJS is a successor of [Codeception](http://codeception.com), a popular full-stack testing framework for PHP. With CodeceptJS your scenario-driven functional and acceptance tests will be as simple and clean as they can be. -You don't need to worry about asynchronous nature of NodeJS or about various APIs of Selenium, PhantomJS, Protractor, etc, -as CodeceptJS unifies them and makes them work as they were synchronous. +You don't need to worry about asynchronous nature of NodeJS or about various APIs of Selenium, Puppeteer, Protractor, TestCafe, etc. as CodeceptJS unifies them and makes them work as they are synchronous. ## Features @@ -46,47 +49,46 @@ as CodeceptJS unifies them and makes them work as they were synchronous. * Designed for scenario driven acceptance testing in BDD-style * Uses ES6 natively without transpiler. * Also plays nice with TypeScript. -* Selenium WebDriver integration using [webdriverio](http://webdriver.io). * Smart locators: use names, labels, matching text, CSS or XPath to locate elements. * Interactive debugging shell: pause test at any point and try different commands in a browser. * Easily create tests, pageobjects, stepobjects with CLI generators. - ## Install ```sh -$ npm install -g codeceptjs +npm install codeceptjs --save ``` Move to directory where you'd like to have your tests (and codeceptjs config) stored, and run -``` -codeceptjs init +```sh +npx codeceptjs init ``` -to create and configure test environment. It is recommended to select WebDriverIO from the list of helpers, -if you need to write Selenium WebDriver tests. +to create and configure test environment. It is recommended to select WebDriverIO from the list of helpers, if you need to write Selenium WebDriver tests. After that create your first test by executing: -``` -codeceptjs generate:test +```sh +npx codeceptjs generate:test ``` Now test is created and can be executed with -``` -codeceptjs run +```sh +npx codeceptjs run ``` If you want to write your tests using TypeScript just generate standard Type Definitions by executing: -``` -codeceptjs def . +```sh +npx codeceptjs def . ``` Later you can even automagically update Type Definitions to include your own custom [helpers methods](docs/helpers.md). +Note that CodeceptJS requires Node.js version `8.9.1+` or later. + ## Usage Learn CodeceptJS by examples. Let's assume we have CodeceptJS installed and WebDriverIO helper enabled. @@ -94,6 +96,7 @@ Learn CodeceptJS by examples. Let's assume we have CodeceptJS installed and WebD ### Basics Let's see how we can handle basic form testing: + ```js Feature('CodeceptJS Demonstration'); @@ -110,17 +113,17 @@ Scenario('test some forms', (I) => { ``` All actions are performed by I object; assertions functions start with `see` function. -In this examples all methods of `I` are taken from WebDriverIO helper, see [reference](https://github.com/Codeception/CodeceptJS/blob/master/docs/helpers/WebDriverIO.md) to learn how to use them. +In this examples all methods of `I` are taken from WebDriver helper, see [reference](https://github.com/codeceptjs/CodeceptJS/blob/master/docs/helpers/WebDriver.md) to learn how to use them. Let's execute this test with `run` command. Additional option `--steps` will show us the running process. We recommend use `--steps` or `--debug` during development. -``` -codeceptjs run --steps +```sh +npx codeceptjs run --steps ``` This will produce an output: -``` +```sh CodeceptJS Demonstration -- test some forms • I am on page "http://simple-form-bootstrap.plataformatec.com.br/documentation" @@ -140,8 +143,8 @@ Just add `pause()` call at any place in a test and run it. Interactive shell can be started outside test context by running: -``` -codeceptjs shell +```sh +npx codeceptjs shell ``` ### Actions @@ -176,16 +179,16 @@ In this case 'User is valid' string will be searched only inside elements locate ### Grabbers In case you need to return a value from a webpage and use it directly in test, you should use methods with `grab` prefix. -They are expected to be used inside a generator functions, and their results will be available in test: +They are expected to be used inside async/await functions, and their results will be available in test: ```js -var assert = require('assert'); +const assert = require('assert'); Feature('CodeceptJS Demonstration'); -Scenario('test page title', function*(I) { +Scenario('test page title', async (I) => { I.amOnPage('http://simple-form-bootstrap.plataformatec.com.br/documentation'); - var title = yield I.grabTitle(); + const title = await I.grabTitle(); assert.equal(title, 'Example application with SimpleForm and Twitter Bootstrap'); }); ``` @@ -194,7 +197,7 @@ The same way you can grab text, attributes, or form values and use them in next ### Before/After -Common preperation steps like opening a web page, logging in a user, can be placed in `Before` or `Background`: +Common preparation steps like opening a web page, logging in a user, can be placed in `Before` or `Background`: ```js Feature('CodeceptJS Demonstration'); @@ -219,7 +222,7 @@ Scenario('test title', (I) => { CodeceptJS provides the most simple way to create and use page objects in your test. You can create one by running -``` +```sh codeceptjs generate pageobject ``` @@ -227,16 +230,9 @@ It will create a page object file for you and add it to config. Let's assume we created one named `docsPage`: ```js -'use strict'; - -let I; +const { I } = inject(); module.exports = { - - _init() { - I = actor(); - }, - fields: { email: '#user_basic_email', password: '#user_basic_password' @@ -267,14 +263,56 @@ Scenario('test some forms', (I, docsPage) => { }); ``` -## Current State - -CodeceptJS is in its early days. Any feedback, issues, and pull requests are welcome. Try it, and if you like it - help us make it better! +When using typescript, replace `module.exports` with `export` for autocompletion. + + +## Contributing + + - ### [Contributing Guide](https://github.com/codeceptjs/CodeceptJS/blob/master/.github/CONTRIBUTING.md) + - ### [Code of conduct](https://github.com/codeceptjs/CodeceptJS/blob/master/.github/CODE_OF_CONDUCT.md) + + +## Contributors + +Thanks all to those who are and will have contributing to this awesome project! + +[//]: contributor-faces + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +[//]: contributor-faces ## License -MIT © [DavertMik](http://codegyre.com) - +MIT © [CodeceptJS Team](http://codecept.io) [npm-image]: https://badge.fury.io/js/codeceptjs.svg [npm-url]: https://npmjs.org/package/codeceptjs diff --git a/RoboFile.php b/RoboFile.php deleted file mode 100644 index 6084e9809..000000000 --- a/RoboFile.php +++ /dev/null @@ -1,57 +0,0 @@ -taskGulpRun('docs') - ->run(); - $this->taskGitStack() - ->add('docs') - ->commit('updated docs') - ->run(); - } - - function publishSite() - { - $this->taskGitStack() - ->checkout('site') - ->merge('master') - ->run(); - $this->stopOnFail(); - $this->_copy('CHANGELOG.md', 'docs/changelog.md'); - $this->_copy('docker/README.md', 'docs/docker.md'); - $this->_exec('mkdocs gh-deploy'); - $this->_remove('docs/changelog.md'); - $this->taskGitStack() - ->checkout('master') - ->run(); - } - - function testServer() - { - $this->taskServer(8000) - ->dir('test/data/app') - ->run(); - } - - function release() - { - $package = json_decode(file_get_contents('package.json'), true); - $version = $package['version']; - $this->docs(); - $this->stopOnFail(); - $this->publishSite(); - $this->taskGitStack() - ->tag($version) - ->push('origin master --tags') - ->run(); - - $this->_exec('npm publish'); - $this->yell('It is released!'); - } -} \ No newline at end of file diff --git a/bin/codecept.js b/bin/codecept.js index 3ca800da7..b10873546 100755 --- a/bin/codecept.js +++ b/bin/codecept.js @@ -1,21 +1,30 @@ #!/usr/bin/env node -'use strict'; +const program = require('commander'); +const Codecept = require('../lib/codecept'); +const { print, error } = require('../lib/output'); -var program = require('commander'); -var path = require('path'); -var Config = require('../lib/config'); -var Codecept = require('../lib/codecept'); -var print = require('../lib/output'); -var fileExists = require('../lib/utils').fileExists; -var fs = require('fs'); +if (process.versions.node && process.versions.node.split('.') && process.versions.node.split('.')[0] < 8) { + error('NodeJS >= 8 is required to run.'); + print(); + print('Please upgrade your NodeJS engine'); + print(`Current NodeJS version: ${process.version}`); + process.exit(1); +} + +program.usage(' [options]'); +program.version(Codecept.version()); program.command('init [path]') .description('Creates dummy config in current dir or [path]') .action(require('../lib/command/init')); +program.command('migrate [path]') + .description('Migrate json config to js config in current dir or [path]') + .action(require('../lib/command/configMigrate')); + program.command('shell [path]') .alias('sh') - .description('Interative shell') + .description('Interactive shell') .option('--verbose', 'output internal logging information') .option('--profile [value]', 'configuration profile to be used') .action(require('../lib/command/interactive')); @@ -26,9 +35,32 @@ program.command('list [path]') .action(require('../lib/command/list')); program.command('def [path]') - .description('List all actions for I.') + .description('Generates TypeScript definitions for all I actions.') + .option('-c, --config [file]', 'configuration file to be used') + .option('-o, --output [folder]', 'target folder to paste definitions') .action(require('../lib/command/definitions')); +program.command('gherkin:init [path]') + .alias('bdd:init') + .description('Prepare CodeceptJS to run feature files.') + .option('-c, --config [file]', 'configuration file to be used') + .action(require('../lib/command/gherkin/init')); + +program.command('gherkin:steps [path]') + .alias('bdd:steps') + .description('Prints all defined gherkin steps.') + .option('-c, --config [file]', 'configuration file to be used') + .action(require('../lib/command/gherkin/steps')); + +program.command('gherkin:snippets [path]') + .alias('bdd:snippets') + .description('Generate step definitions from steps.') + .option('--dry-run', "don't save snippets to file") + .option('-c, --config [file]', 'configuration file to be used') + .option('--feature [file]', 'feature files(s) to scan') + .option('--path [file]', 'file in which to place the new snippets') + .action(require('../lib/command/gherkin/snippets')); + program.command('generate:test [path]') .alias('gt') .description('Generates an empty test') @@ -50,7 +82,7 @@ program.command('generate:helper [path]') .description('Generates a new helper') .action(require('../lib/command/generate').helper); -program.command('run [suite] [test]') +program.command('run [test]') .description('Executes tests') // codecept-only options @@ -59,16 +91,19 @@ program.command('run [suite] [test]') .option('--verbose', 'output internal logging information') .option('-o, --override [value]', 'override current config options') .option('--profile [value]', 'configuration profile to be used') - .option('--config [file]', 'configuration file to be used') + .option('-c, --config [file]', 'configuration file to be used') + .option('--features', 'run only *.feature files and skip tests') + .option('--tests', 'run only JS test files and skip features') + .option('-p, --plugins ', 'enable plugins, comma-separated') // mocha options - .option('-c, --colors', 'force enabling of colors') - .option('-C, --no-colors', 'force disabling of colors') + .option('--colors', 'force enabling of colors') + .option('--no-colors', 'force disabling of colors') .option('-G, --growl', 'enable growl notification support') .option('-O, --reporter-options ', 'reporter-specific options') .option('-R, --reporter ', 'specify the reporter to use') - .option('-S, --sort', "sort test files") - .option('-b, --bail', "bail after first test failure") + .option('-S, --sort', 'sort test files') + .option('-b, --bail', 'bail after first test failure') .option('-d, --debug', "enable node's debugger, synonym for node --debug") .option('-g, --grep ', 'only run tests matching ') .option('-f, --fgrep ', 'only run tests containing ') @@ -80,11 +115,113 @@ program.command('run [suite] [test]') .option('--no-exit', 'require a clean shutdown of the event loop: mocha will not call process.exit') .option('--recursive', 'include sub directories') .option('--trace', 'trace function calls') + .option('--child ', 'option for child processes') .action(require('../lib/command/run')); +program.command('run-rerun [test]') + .description('Executes tests in more than one test suite run') + + // codecept-only options + .option('--steps', 'show step-by-step execution') + .option('--debug', 'output additional information') + .option('--verbose', 'output internal logging information') + .option('-o, --override [value]', 'override current config options') + .option('--profile [value]', 'configuration profile to be used') + .option('-c, --config [file]', 'configuration file to be used') + .option('--features', 'run only *.feature files and skip tests') + .option('--tests', 'run only JS test files and skip features') + .option('-p, --plugins ', 'enable plugins, comma-separated') + + // mocha options + .option('--colors', 'force enabling of colors') + .option('--no-colors', 'force disabling of colors') + .option('-G, --growl', 'enable growl notification support') + .option('-O, --reporter-options ', 'reporter-specific options') + .option('-R, --reporter ', 'specify the reporter to use') + .option('-S, --sort', 'sort test files') + .option('-b, --bail', 'bail after first test failure') + .option('-d, --debug', "enable node's debugger, synonym for node --debug") + .option('-g, --grep ', 'only run tests matching ') + .option('-f, --fgrep ', 'only run tests containing ') + .option('-i, --invert', 'inverts --grep and --fgrep matches') + .option('--full-trace', 'display the full stack trace') + .option('--compilers :,...', 'use the given module(s) to compile files') + .option('--debug-brk', "enable node's debugger breaking on the first line") + .option('--inline-diffs', 'display actual/expected differences inline within each string') + .option('--no-exit', 'require a clean shutdown of the event loop: mocha will not call process.exit') + .option('--recursive', 'include sub directories') + .option('--trace', 'trace function calls') + .option('--child ', 'option for child processes') + + .action(require('../lib/command/run-rerun')); + +program.command('run-workers ') + .description('Executes tests in workers') + .option('-c, --config [file]', 'configuration file to be used') + .option('-g, --grep ', 'only run tests matching ') + .option('-i, --invert', 'inverts --grep matches') + .option('-o, --override [value]', 'override current config options') + .option('--suites', 'parallel execution of suites not single tests') + .option('--debug', 'output additional information') + .option('--verbose', 'output internal logging information') + .option('--features', 'run only *.feature files and skip tests') + .option('--tests', 'run only JS test files and skip features') + .option('--profile [value]', 'configuration profile to be used') + .option('-p, --plugins ', 'enable plugins, comma-separated') + .action(require('../lib/command/run-workers')); + +program.command('run-multiple [suites...]') + .description('Executes tests multiple') + .option('-c, --config [file]', 'configuration file to be used') + .option('--profile [value]', 'configuration profile to be used') + .option('--all', 'run all suites') + .option('--features', 'run only *.feature files and skip tests') + .option('--tests', 'run only JS test files and skip features') + .option('-g, --grep ', 'only run tests matching ') + .option('-f, --fgrep ', 'only run tests containing ') + .option('-i, --invert', 'inverts --grep and --fgrep matches') + .option('--steps', 'show step-by-step execution') + .option('--verbose', 'output internal logging information') + .option('--debug', 'output additional information') + .option('-p, --plugins ', 'enable plugins, comma-separated') + .option('-o, --override [value]', 'override current config options') + .option('-O, --reporter-options ', 'reporter-specific options') + .option('-R, --reporter ', 'specify the reporter to use') + .option('--recursive', 'include sub directories') + + // mocha options + .option('--colors', 'force enabling of colors') + + .action(require('../lib/command/run-multiple')); + +program.command('info [path]') + .description('Print debugging information concerning the local environment') + .option('-c, --config', 'your config file path') + .action(require('../lib/command/info')); + +program.command('dry-run [test]') + .description('Prints step-by-step scenario for a test without actually running it') + .option('-p, --plugins ', 'enable plugins, comma-separated') + .option('--bootstrap', 'enable bootstrap script for dry-run') + .option('-c, --config [file]', 'configuration file to be used') + .option('--all', 'run all suites') + .option('--features', 'run only *.feature files and skip tests') + .option('--tests', 'run only JS test files and skip features') + .option('-g, --grep ', 'only run tests matching ') + .option('-f, --fgrep ', 'only run tests containing ') + .option('-i, --invert', 'inverts --grep and --fgrep matches') + .option('--steps', 'show step-by-step execution') + .option('--verbose', 'output internal logging information') + .option('--debug', 'output additional information') + .action(require('../lib/command/dryRun')); + +program.on('command:*', (cmd) => { + console.log(`\nUnknown command ${cmd}\n`); + program.outputHelp(); +}); + if (process.argv.length <= 2) { - console.log('CodeceptJS v' + Codecept.version()); program.outputHelp(); } program.parse(process.argv); diff --git a/docker/README.md b/docker/README.md index 6feddfe5b..44362a70f 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,24 +1,34 @@ # Codeceptjs Docker -CodeceptJS packed into container with the Nightmare, Protractor, and WebDriverIO drivers. +CodeceptJS packed into container with the Nightmare, Protractor, Puppeteer, and WebDriverIO drivers. ## How to Use This image comes with the necessary dependencies and packages to execute CodeceptJS tests. Mount in your CodeceptJS config directory into the `/tests` directory in the docker container. -Sample mount: `-v path/to/codecept.json:/tests` +Sample mount: `-v path/to/codecept.conf.js:/tests` -### Locally +CodeceptJS runner is available inside container as `codeceptjs`. +### Locally -You can execute CodeceptJS with Nightmare locally with no extra configuration. +You can execute CodeceptJS with Puppeteer or Nightmare locally with no extra configuration. -``` +```sh docker run --net=host -v $PWD:/tests codeception/codeceptjs ``` -Nightmare helper must be enabled in codecept.json config. +To customize execution call `codeceptjs` command: + +```sh +# run tests with steps +docker run --net=host -v $PWD:/tests codeception/codeceptjs codeceptjs run --steps + +# run tests with @user in a name +docker run --net=host -v $PWD:/tests codeception/codeceptjs codeceptjs run --grep "@user" +``` + ### Docker Compose @@ -77,5 +87,51 @@ _Note: If running with the Nightmare driver, it is not necessary to run a seleni To build this image: ```sh -$ docker build -t codeception/codeceptjs . -``` \ No newline at end of file +docker build -t codeception/codeceptjs . +``` + +* this directory will be added as `/codecept` insde container +* tests directory is expected to be mounted as `/tests` +* `codeceptjs` is a synlink to `/codecept/bin/codecept.js` + +To build this image with your desired Node version: + +```sh +docker build -t codeception/codeceptjs . --build-arg NODE_VERSION=12.10.0 +``` + +### Passing Options + +Options can be passed by calling `codeceptjs`: + +``` +docker run -v $PWD:/tests codeception/codeceptjs codeceptjs run --debug +``` + +Alternatively arguments to `codecept run` command can be passed via `CODECEPT_ARGS` environment variable. For example to run your tests with debug +output: + +```yaml +version: '2' +services: + codeceptjs: + image: codeception/codeceptjs + environment: + - CODECEPT_ARGS=--debug + volumes: + - .:/tests +``` + +You can also use `run-workers`to run tests by passing `NO_OF_WORKERS`, additionally, you can pass more params like showing the debug info as the following example: + +```yaml +version: '2' +services: + codeceptjs: + image: codeception/codeceptjs + environment: + - NO_OF_WORKERS=3 + - CODECEPT_ARGS=--debug + volumes: + - .:/tests +``` diff --git a/docker/entrypoint b/docker/entrypoint index 8d30cfdad..0e313dc8a 100755 --- a/docker/entrypoint +++ b/docker/entrypoint @@ -1,8 +1,4 @@ #!/usr/bin/env bash set -e -# Start Xvfb -Xvfb -ac -screen scrn 1280x1024x24 :9.0 & -export DISPLAY=:9.0 - -exec "$@" \ No newline at end of file +xvfb-run -a --server-args="-screen 0 1024x768x24" "$@" diff --git a/docker/run.sh b/docker/run.sh index 697005455..cd9c41bc7 100755 --- a/docker/run.sh +++ b/docker/run.sh @@ -1,13 +1,28 @@ #!/usr/bin/env bash -source /docker/help.sh +source /codecept/docker/help.sh # Check if tests are correctly mounted if [[ -d "/tests/" ]]; then - echo "CodeceptJS directory has been found." + echo "CodeceptJS directory has been found." - # Run the tests - node bin/codecept.js run /tests/ $GREP + # Run the tests + cd /tests/ || exit + if [ "$RUN_MULTIPLE" = true ]; then + echo "Tests are split into chunks and executed in multiple processes." + if [ ! "$CODECEPT_ARGS" ]; then + echo "No CODECEPT_ARGS provided. Tests will procceed with --all option to run all configured runs" + codeceptjs run-multiple --all + else + codeceptjs run-multiple $CODECEPT_ARGS + fi else - display_usage -fi \ No newline at end of file + if [ ! "$NO_OF_WORKERS" ]; then + codeceptjs run $CODECEPT_ARGS + else + codeceptjs run-workers $NO_OF_WORKERS $CODECEPT_ARGS + fi + fi +else + display_usage +fi diff --git a/docs/acceptance.md b/docs/acceptance.md deleted file mode 100644 index 69f3d9d0d..000000000 --- a/docs/acceptance.md +++ /dev/null @@ -1,208 +0,0 @@ -# Acceptance Testing - -How does your client, manager, or tester, or any other non-technical person, know your web application is working? By opening the browser, accessing a site, clicking on links, filling in the forms, and actually seeing the content on a web page. - -Acceptance (also called End to End) tests can cover standard but complex scenarios from a user's perspective. With acceptance tests you can be confident that users, following all defined scenarios, won't get errors. We check **not just functionality of application but a user interface** (UI) as well. - -By default CodeceptJS uses [WebDriverIO](/helpers/WebDriverIO/) helper and **Selenium** to automate browser. Within web page you can locate elements, interact with them, and check that expected elements are present on a page. -However, you can also choose [SeleniumWebdriver](/helpers/SeleniumWebdriver) or [Protractor](/helpers/Protractor) helpers, driven by corresponding libraries. -No matter of helper and library you use for acceptance testing, CodeceptJS should execute same actions in similar manner. - -That is what a test look like. - -In case of CodeceptJS you can be sure that in code it will be as easy as it sounds. You just describe a test scenario with JavaScript DSL and allow the framework to handle the rest. - -```js -I.amOnPage('/login'); -I.fillField('Username', 'john'); -I.fillField('Password', '123456'); -I.click('Login'); -I.see('Welcome, John'); -``` - -This is how we can check that login form of a simple web application works. At first we opened `/login` page, then filled forms and in the end we saw the greetings text. - -## Locating Element - -Element can be found by CSS or XPath locators. Practically every steps -in WebDriverIO helper accept them both. - -```js -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 exact locator type you can pass a hash called **strict locator**. - -```js -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'}); -// locate element by text -I.seeElement({text: 'press me'}); -// locate element by id -I.seeElement({id: 'users'}); -``` - -## Clicking - -CodeceptJS provides a flexible syntax to specify an element to click. - -By default CodeceptJS tries to find button or link with exact text on it - -```js -// search for link or button -I.click('Login'); -``` - -If none found, CodeceptJS tries to find 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. - -To narrow down the results you can specify a context in second parameter. - -```js -I.click('Login', '.nav'); // search only in .nav -I.click('Login', {css: 'footer'}); // search only in footer -``` - -To skip the global search pass exact strict locator (or start locator with `//` or `.` or `#`). -In this case you are not limited to buttons and links. Any element found by that locator is clicked. - -```js -// click element by CSS -I.click('#signup'); -// click element located by name inside a form -I.click({name: 'submit'}, '#user>form'); -``` - -## Filling Fields - -Clicking the links is not what takes the most time during testing a web site. If your site consists only of links you can skip test automation. The most routine waste of time goes into the testing of forms. CodeceptJS provides several ways of doing that. - -Let's submit this sample form for a test: - -```html -
- - - - - - - -
-``` - -We need to fill in all those fields and click "Update" button. CodeceptJS matches form elements by their label, name, or by CSS or XPath locators. - -```js -// we are using label to match user_name field -I.fillField('Name', 'Miles'); -// we can use input name -I.fillField('user[email]','miles@davis.com'); -// select element by label, choose option by text -I.selectOption('Gender','Male'); -// click 'Update' button, found by text -I.click('Update'); -``` - -Alternative scenario: - -```js -// we are using CSS -I.fillField('#user_name', 'Miles'); -I.fillField('#user_email','miles@davis.com'); -// select element by label, option by value -I.selectOption('#user_gender','m'); -// click 'Update' button, found by name -I.click('submitButton', '#update_form'); -``` - -## Assertions - -In order to verify the expected behavior of a web application, web page connects should be checked. -CodeceptJS provides built-in assertions for that. They start with `see` (or `dontSee`) prefix, as they describe user's current vision. - -The most general and common assertion is `see`: - -```js -// Just a visible text on a page -I.see('Hello'); -// text inside .msg element -I.see('Hello', '.msg'); -// opposite -I.dontSee('Bye'); -``` - -You should provide a text as first argument, and optionally a locator to narrow the search context. - -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'); -``` - -Additional assertions: - -```js -I.seeInCurrentUrl('/user/miles'); -I.seeInField('user[name]', 'Miles'); -I.seeInTitle('My Website'); -``` - -To see all possible assertions see the helper's reference. - -## Grabbing - -Sometimes you need to retrieve a data from a page to use it in next steps of a scenario. -Imagine, application generates a password and you want to ensure that user can login using this password. - -```js -I.fillField('email', 'miles@davis.com') -I.click('Generate Password'); -$password = yield I.grabTextFrom('#password'); -I.click('Login'); -I.fillField('email', 'miles@davis.com'); -I.fillField('password', $password); -I.click('Log in!'); -``` - -`grabTextFrom` action is used here to retrieve text from an element. All actions starting with `grab` prefix are expected to return data. In order to synchronize this step with a scenario you should pause test execution with `yield` keyword of ES6. To make it work your test should be written inside a generator function (notice `*` in its definition): - -```js -Scenario('use page title', function*(I) { - // ... - var password = yield I.grabTextFrom('#password'); - I.fillField('password', password); -}); -``` - -## Waiting - -In modern web applications rendering is happen on client side. -Sometimes that may cause delays. A test may fail while trying to click an element which has not appeared on a page yet. -To handle this cases `wait*` methods introduced. - -```js -I.waitForElement('#agree_button', 30); // secs -// clicks a button only when it is visible -I.click('#agree_button'); -``` - -More wait actions can be found in helper's reference. - ---- - -### done() - -CodeceptJS through helpers provides user friendly API to interact with a webpage. In this section we described using WebDriverIO helper which allows to control browser through Selenium WebDriver. diff --git a/docs/advanced.md b/docs/advanced.md new file mode 100644 index 000000000..dfb661950 --- /dev/null +++ b/docs/advanced.md @@ -0,0 +1,293 @@ +--- +permalink: /advanced +title: Advanced Usage +--- + +# Advanced Usage + +## Data Driven Tests + +Execute the same scenario on a different data set. + +Let's say you want to test login for different user accounts. +In this case, you need to create a datatable and fill it in with credentials. +Then use `Data().Scenario` to include this data and generate multiple scenarios: + +```js +// Define data table inside a test or load from another module +let accounts = new DataTable(['login', 'password']); // +accounts.add(['davert', '123456']); // adding records to a table +accounts.add(['admin', '123456']); + +// You can skip some data. But add them to report as skipped (just like with usual scenarios): +accounts.xadd(['admin', '23456']) + +// Pass dataTable to Data() +// Use special param `current` to get current data set +Data(accounts).Scenario('Test Login', (I, current) => { + I.fillField('Username', current.login); // current is reserved! + I.fillField('Password', current.password); + I.click('Sign In'); + I.see('Welcome '+ current.login); +}); + + +// Also you can set only for Data tests. It will launch executes only the current test but with all data options +Data(accounts).only.Scenario('Test Login', (I, current) => { + I.fillField('Username', current.login); // current is reserved! + I.fillField('Password', current.password); + I.click('Sign In'); + I.see('Welcome '+ current.login); +}); +``` + +*Important: you can't use name `current` for pageObjects or helpers in data scenarios* + +This will produce 2 tests with different data sets. +Current data set is appended to a test name in output: + +```sh +✓ Test Login | {"login":"davert","password":"123456"} +✓ Test Login | {"login":"admin","password":"123456"} +S Test Login | {"login":"admin","password":"23456"} +``` + +```js +// You can filter your data table +Data(accounts.filter(account => account.login == 'admin') +.Scenario('Test Login', (I, current) => { + I.fillField('Username', current.login); + I.fillField('Password', current.password); + I.click('Sign In'); + I.see('Welcome '+ current.login); +}); +``` + +This will limit data sets accoring passed function: + +```sh +✓ Test Login | {"login":"admin","password":"123456"} +S Test Login | {"login":"admin","password":"23456"} +``` + +Data sets can also be defined with array, generator, or a function. + +```js +Data(function*() { + yield { user: 'davert'}; + yield { user: 'andrey'}; +}).Scenario() // ... +``` + +*HINT: If you don't use DataTable. add `toString()` method to each object added to data set, so the data could be pretty printed in a test name* + +## Tags + +Append `@tag` to your test name, so + +```js +Scenario('update user profile @slow') +``` + +Alternativly, use `tag` method of Scenario to set additional tags: + +```js +Scenario('update user profile', () => { + // test goes here +}).tag('@slow').tag('important'); +``` + +All tests with `@tag` could be executed with `--grep '@tag'` option. + +```sh +codeceptjs run --grep '@slow' +``` + +Use regex for more flexible filtering: + +* `--grep '(?=.*@smoke2)(?=.*@smoke3)'` - run tests with @smoke2 and @smoke3 in name +* `--grep "\@smoke2|\@smoke3"` - run tests with @smoke2 or @smoke3 in name +* `--grep '((?=.*@smoke2)(?=.*@smoke3))|@smoke4'` - run tests with (@smoke2 and @smoke3) or @smoke4 in name +* `--grep '(?=.*@smoke2)^(?!.*@smoke3)'` - run tests with @smoke2 but without @smoke3 in name +* `--grep '(?=.*)^(?!.*@smoke4)'` - run all tests except @smoke4 + + + +## Debug + +CodeceptJS provides a debug mode in which additional information is printed. +It can be turned on with `--debug` flag. + +```sh +codeceptjs run --debug +``` + +to receive even more information turn on `--verbose` flag: + +```sh +codeceptjs run --verbose +``` + +And don't forget that you can pause execution and enter **interactive console** mode by calling `pause()` inside your test. + +For advanced debugging use NodeJS debugger. In WebStorm IDE: + +```sh +node $NODE_DEBUG_OPTION ./node_modules/.bin/codeceptjs run +``` + +For Visual Studio Code, add the following configuration in launch.json: + +```json +{ + "type": "node", + "request": "launch", + "name": "codeceptjs", + "args": ["run", "--grep", "@your_test_tag"], + "program": "${workspaceFolder}/node_modules/.bin/codeceptjs" +} +``` + + +## Test Options + +Features and Scenarios have their options that can be set by passing a hash after their names: + +```js +Feature('My feature', {key: val}); + +Scenario('My scenario', {key: val}, (I) => {}); +``` + +You can use this options for build your own [plugins](https://codecept.io/hooks/#plugins) with [event listners](https://codecept.io/hooks/#api). Example: + +```js + // for test + event.dispatcher.on(event.test.before, (test) => { + ... + if (test.opts.key) { + ... + } + ... + }); + // or for suite + event.dispatcher.on(event.suite.before, (suite) => { + ... + if (suite.opts.key) { + ... + } + ... + }); +``` + +### Timeout + +By default there is no timeout for tests, however you can change this value for a specific suite: + +```js +Feature('Stop me').timeout(5000); // set timeout to 5s +``` + +or for the test: + +```js +// set timeout to 1s +Scenario("Stop me faster", (I) => { + // test goes here +}).timeout(1000); + +// alternative +Scenario("Stop me faster", {timeout: 1000}, (I) => {}); + +// disable timeout for this scenario +Scenario("Don't stop me", {timeout: 0}, (I) => {}); +``` + + +## Dynamic Configuration + +Helpers can be reconfigured per scenario or per feature. +This might be useful when some tests should be executed with different settings than others. +In order to reconfigure tests use `.config()` method of `Scenario` or `Feature`. + +```js +Scenario('should be executed in firefox', (I) => { + // I.amOnPage(..) +}).config({ browser: 'firefox' }) +``` + +In this case `config` overrides current config of the first helper. +To change config of specific helper pass two arguments: helper name and config values: + +```js +Scenario('should create data via v2 version of API', (I) => { + // I.amOnPage(..) +}).config('REST', { endpoint: 'https://api.mysite.com/v2' }) +``` + +Config can also be set by a function, in this case you can get a test object and specify config values based on it. +This is very useful when running tests against cloud providers, like BrowserStack. This function can also be asynchronous. + +```js +Scenario('should report to BrowserStack', (I) => { + // I.amOnPage(..) +}).config((test) => { + return { desiredCapabilities: { + project: test.suite.title, + name: test.title, + }} +}); +``` + +Config changes can be applied to all tests in suite: + +```js +Feature('Admin Panel').config({ url: 'https://mysite.com/admin' }); +``` + +Please note that some config changes can't be applied on the fly. For instance, if you set `restart: false` in your config and then changing value `browser` won't take an effect as browser is already started and won't be closed untill all tests finish. + +Configuration changes will be reverted after a test or a suite. + + +### Rerunning Flaky Tests Multiple Times + +End to end tests can be flaky for various reasons. Even when we can't do anything to solve this problem it we can do next two things: + +* Detect flaky tests in our suite +* Fix flaky tests by rerunning them. + +Both tasks can be achieved with [`run-rerun` command](/commands/#run-rerun) which runs tests multiple times until all tests are passed. + +You should set min and max runs boundaries so when few tests fail in a row you can rerun them until they are succeeded. + +```js +// inside to codecept.conf.js +exports.config = { // ... + rerun: { + // run 4 times until 1st success + minSuccess: 1, + maxReruns: 4, + } +} +``` + +If you want to check all your tests for stability you can set high boundaries for minimal success: + +```js +// inside to codecept.conf.js +exports.config = { // ... + rerun: { + // run all tests must pass exactly 5 times + minSuccess: 5, + maxReruns: 5, + } +} +``` + +Now execute tests with `run-rerun` command: + +``` +npx codeceptjs run-rerun +``` + diff --git a/docs/angular.md b/docs/angular.md index 625f7ac84..b61ddf4e4 100644 --- a/docs/angular.md +++ b/docs/angular.md @@ -1,23 +1,28 @@ -## AngularJS E2E Testing with CodeceptJS +--- +permalink: /angular +title: Testing with Protractor +--- -### Introduction +# Protractor Testing with CodeceptJS -CodeceptJS is an acceptance testing framework. In diversified world of JavaScript testing libraries it aims to create a unified high level API for end-to-end testing, powered by differnet backends. -CodeceptJS allows you to write a test and switch in config execution drivers: will it be *wedriverio*, *selenium-webdriver*, or *protractor* depends on you. -This way you aren't be bound to implementation, and your acceptance tests will work no matter of framework running them. +## Introduction -As you know, [Protractor](http://www.protractortest.org/#/) is an official tool for testing AngularJS applications. -CodeceptJS should not be considerend as alternative to Protractor but a testing framework utilizing this powerful library. +CodeceptJS is an acceptance testing framework. In the diversified world of JavaScript testing libraries, it aims to create a unified high-level API for end-to-end testing, powered by a variety of backends. +CodeceptJS allows you to write a test and switch the execution driver via config: whether it's *wedriverio*, *puppeteer*, or *protractor* depends on you. +This way you aren't bound to a specific implementation, and your acceptance tests will work no matter what framework is running them. -![](http://codecept.io/images/angular-protractor.png) +[Protractor](http://www.protractortest.org/#/) is an official tool for testing AngularJS applications. +CodeceptJS should not be considered as alternative to Protractor, but rather a testing framework that leverages this powerful library. -So there is no magic in testing of AngularJS application in CodeceptJS. -You just execute regular Protractor commands, packed in a simple high-level API. +![angular-protractor](/img/angular-protractor.png) -![](http://codecept.io/images/todo.png) +There is no magic in testing of AngularJS application in CodeceptJS. +You just execute regular Protractor commands, packaged into a simple, high-level API. -As an example we will use popular [TodoMVC application](http://todomvc.com/examples/angularjs/#/). -How would we test creating a new todo item in CodeceptJS? +![todo-mvc](/img/todo.png) + +As an example, we will use the popular [TodoMVC application](http://todomvc.com/examples/angularjs/#/). +How would we test creating a new todo item using CodeceptJS? ```js Scenario('create todo item', (I) => { @@ -30,7 +35,7 @@ Scenario('create todo item', (I) => { }); ``` -The similar test written in native syntax of Protractor (inherited from selenium-webdriver) would look like this: +A similar test written using Protractor's native syntax (inherited from selenium-webdriver) would look like this: ```js it('should create todo item', (I) => { @@ -45,16 +50,15 @@ it('should create todo item', (I) => { }); ``` -Comparing to the API proposed by CodeceptJS, this code looks a bit more complicated. -But what the more important, it's really really hard to read and follow its logic. -Readability is the most crucial part in acceptance testing. -You should easily change tests when changes specification or design. -Probably, only a person who writes Protractor tests in your company, -could do those changes, while CodeceptJS allows anyone to work with tests. -Contrary, CodeceptJS provides CodeceptJS provides scenario-driven approach, so test is just a step-by-step representation of real user actions. -This way you can easily read, and follow test scenario, and edit it when you need it to be changed. +Compared to the API proposed by CodeceptJS, the Protractor code looks more complicated. +Even more important, it's harder to read and follow the logic of the Protractor test. +Readability is a crucial part of acceptance testing. +Tests should be easy to modify when there are changes in the specification or design. +If the test is written in Protractor, it would likely require someone familiar with Protractor to make the change, whereas CodeceptJS allows anyone to understand and modify the test. +CodeceptJS provides scenario-driven approach, so a test is just a step-by-step representation of real user actions. +This means you can easily read and understand the steps in a test scenario, and edit the steps when the test needs to be changed. -In this way CodeceptJS is more similar to Cucumber, so if you run a test with `--steps` option you will see this output: +In this way, CodeceptJS is similar to Cucumber. If you run a test with `--steps` option you will see this output: ```bash TodoMvc -- @@ -68,67 +72,99 @@ TodoMvc -- ✓ OK in 968ms ``` -Unlike Cucumber, CodeceptJS is not about writing test scenarios above for business rules. -To say it again, its **goal is to provide standard action steps you can use for testing applications**. -Surely, it can't cover 100% of cases but it aims for 90%, for others you can write your own steps inside a [custom Helper](http://codecept.io/helpers/) using API of Protractor +Unlike Cucumber, CodeceptJS is not about writing test scenarios to satisfy business rules or requirements. +Instead, its **goal is to provide standard action steps you can use for testing applications**. +Although it can't cover 100% of use cases, CodeceptJS aims for 90%. For the remainder, you can write your own steps inside a [custom Helper](http://codecept.io/helpers/) using Protractor's API. ### Setting up CodeceptJS with Protractor -To start using CodeceptJS you will need to install it via NPM and initialize it in directory with tests. +To start using CodeceptJS you will need to install it via NPM and initialize it in a directory with tests. ```bash -npm install -g codeceptjs -codeceptjs init +npm install codeceptjs --save +npx codeceptjs init ``` -You will be asked questions about initial configuration, make sure you select Protractor helper. -If you didn't have Protracotr library it **will be installed**. -Please agree to extend steps, and use `http://todomvc.com/examples/angularjs/` as a url for Protractor helper. - -For TodoMVC application you will have following config created in `codecept.json` file: - -```json -{ - "tests": "./*_test.js", - "timeout": 10000, - "output": "./output", - "helpers": { - "Protractor": { - "url": "http://todomvc.com/examples/angularjs/", - "driver": "hosted", - "browser": "firefox", - "rootElement": "body" - } - }, - "include": { - "I": "./steps_file.js" - }, - "bootstrap": false, - "mocha": {}, - "name": "todoangular" +You will be asked questions about the initial configuration, make sure you select the Protractor helper. +If your project didn't already have the Protractor library, it **will be installed** as part of this process. +Please agree to extend steps, and use `http://todomvc.com/examples/angularjs/` as the url for Protractor helper. + +For TodoMVC application, you will have following config created in the `codecept.conf.js` file: + +```js +exports.config = { tests: './*_test.js', + timeout: 10000, + output: './output', + helpers: + { Protractor: + { url: 'http://todomvc.com/examples/angularjs/', + driver: 'hosted', + browser: 'chrome', + rootElement: 'body' } }, + include: { I: './steps_file.js' }, + bootstrap: false, + mocha: {}, + name: 'todoangular' } ``` -First test can be generated with `gt` command: +Your first test can be generated with the `gt` command: ```bash -codeceptjs gt +npx codeceptjs gt ``` -After that you can start writing your first CodeceptJS/Angular tests. -Please look into the reference of [Protractor helper])(http://codecept.io/helpers/Protractor/) for all available actions. -You can also run `list` command to see methods of I: +After that, you can start writing your first CodeceptJS/Angular tests. +Please refer to the [Protractor helper](http://codecept.io/helpers/Protractor/) documentation for a list of all available actions. +You can also run the `list` command to see methods of I: ```bash -codeceptjs list +npx codeceptjs list ``` -### Writing First Test +## Starting Selenium Server + +Protractor requires Selenium Server to be started and running. To start and stop Selenium automatically install `@wdio/selenium-standalone-service`. -Test scenario should always use `I` object to execute commands. -This is important as all methods of `I` are running in global promise chain, this way CodeceptJS makes sure everything is executed in right order. -At first a page should be opened to proceed, we use `amOnPage` command for that. As we already specified full URL to TodoMVC app, -we can pass relative path into it instead of absolute url: +``` +npm i @wdio/selenium-standalone-service --save +``` + +Enable it in the `codecept.conf.js` file, inside the plugins section: + +```js +exports.config = { + // ... + // inside codecept.conf.js + plugins: { + wdio: { + enabled: true, + services: ['selenium-standalone'] + } + } +} +``` + +## Testing non-Angular Applications + +Protractor can also be used to test applications built without AngularJS. In this case, you need to disable the angular synchronization feature inside the config: + +```js +helpers: { + Protractor: { + url: "http://todomvc.com/examples/angularjs/", + driver: "hosted", + browser: "firefox", + angular: false + } +} +``` + +## Writing Your First Test + +Your test scenario should always use the `I` object to execute commands. +This is important, as all methods of `I` are running in the global promise chain. This way, CodeceptJS makes sure everything is executed in right order. +To start with opening a webpage, use the `amOnPage` command for. Since we already specified the full URL to the TodoMVC app, we can pass the relative path for our url, instead of the absolute url: ```js Feature('Todo MVC'); @@ -138,7 +174,7 @@ Scenario('create todo item', (I) => { }); ``` -All scenarios should describe actions on site and assertions taken in the end. In CodeceptJS assertion commands have `see` or `dontSee` prefix: +All scenarios should describe actions on the site, with assertions at the end. In CodeceptJS, assertion commands have the `see` or `dontSee` prefix: ```js Feature('Todo MVC'); @@ -149,12 +185,13 @@ Scenario('create todo item', (I) => { }); ``` -A test can be executed with `run` command, we recommend to use `--steps` options to follow step-by-step execution: +A test can be executed with the `run` command, we recommend using the `--steps` option to print out the step-by-step execution: +```sh +npx codeceptjs run --steps ``` -$ codeceptjs run --steps -CodeceptJS v0.3.2 +``` Test root is assumed to be /home/davert/demos/todoangular Using the selenium server at http://localhost:4444/wd/hub @@ -164,13 +201,12 @@ TodoMvc -- • I dont see element "#todo-count" ``` -### Running Several Scenarios +## Running Several Scenarios -By writing a test in similar manner we will have a test shown in the beginning of this guide. Probably we would like not to finish with one test, -but have more, for testing editing of todo items, checking todo items, and more. +By now, you should have a test similar to the one shown in the beginning of this guide. We probably want to have multiple tests though, like testing the editing of todo items, checking todo items, etc. -Let's prepare our test for multiple scenarios. All test scenarios will need to open main page of application, so `amOnPage` can be moved into the `Before` hook: -Scenarios will probably deal with created todo items, so we can move logic of crating new todo into a function. +Let's prepare our test to contain multiple scenarios. All of our test scenarios will need to to start with with the main page of application open, so `amOnPage` can be moved into the `Before` hook: +Our scenarios will also probably deal with created todo items, so we can move the logic of creating a new todo into a function. ```js Feature('TodoMvc'); @@ -179,7 +215,7 @@ Before((I) => { I.amOnPage('/'); }); -var createTodo = function (I, name) { +const createTodo = function (I, name) { I.fillField({model: 'newTodo'}, name); I.pressKey('Enter'); } @@ -192,7 +228,7 @@ Scenario('create todo item', (I) => { }); ``` -and so we can add even more tests! +and now we can add even more tests! ```js Scenario('edit todo', (I) => { @@ -213,31 +249,33 @@ Scenario('check todo item', (I) => { }); ``` -### Locators +> This example is [available on GitHub](https://github.com/DavertMik/codeceptjs-angular-todomvc). -Like you may have noticed, CodeceptJS doesn't use `by.*` locators similar to Protractor or Selenium Webdriver. -Instead most of methods expect you to pass valid CSS or XPath. In case you don't want CodeceptJS to guess the type of locator, -you can specify them using so-called strict locators. This is an absolute analogy of `by`, so you can use angular specific locators (like models, repeaters, bindings, etc) in it: -``` +## Locators + +You may have noticed that CodeceptJS doesn't use `by.*` locators which are common in Protractor or Selenium Webdriver. +Instead, most methods expect you to pass valid CSS selectors or XPath. If you don't want CodeceptJS to guess the locator type, then you can specify the type using *strict locators*. This is the CodeceptJS version of `by`, so you can also reuse your angular specific locators (like models, repeaters, bindings, etc): + +```sh {css: 'button'} {repeater: "todo in todos"} {binding: 'latest'} ``` -When we deal with clicks, CodeceptJS can take a text and search a web page for a valid clickable element with that text. -So links and buttons can be searched by their text. -Same thing happens for form fields: they are searched by field names, labels, and so on. +When dealing with clicks, we can specify a text value. CodeceptJS will use that value to search the web page for a valid clickable element containing our specified text. +This enables us to search for links and buttons by their text. -Using such smart locators makes tests easy to write, however, searching an element by text is slower than using CSS|XPath and much slower than using strict locators. +The same is true for form fields: they can be searched by field name, label, and so on. -### Refactoring +Using smart locators makes tests easier to write, however searching an element by text is slower than searching via CSS|XPath, and is much slower than using strict locators. -In previous examples, we've moved actions into `createTodo` function. Is there a more elegant way of refactoring? -Can we have something like `I.createTodo()` to be used in code? Sure, we can do so by editing `steps_file.js` created by init command. +## Refactoring + +In the previous examples, we moved actions into the `createTodo` function. Is there a more elegant way of refactoring? +Can we instead write a function like `I.createTodo()` which we can reuse? In fact, we can do so by editing the `steps_file.js` file created by the init command. ```js -'use strict'; // in this file you can append custom step methods to 'I' object module.exports = function() { @@ -249,7 +287,8 @@ module.exports = function() { }); } ``` -And that's all, method is available to use as `I.createTodo(title)`: + +That's it, our method is now available to use as `I.createTodo(title)`: ```js Scenario('create todo item', (I) => { @@ -262,13 +301,13 @@ Scenario('create todo item', (I) => { To learn more about refactoring options in CodeceptJS read [PageObjects guide](http://codecept.io/pageobjects/). -### Extending -What if CodeceptJS doesn't provide some of Protractor functionality you actually need? Sure its API is to general, -and this case is possible. If you don't know how to do something with CodeceptJS - revert back to Protractor syntax! +## Extending + +What if CodeceptJS doesn't provide some specific Protractor functionality you need? If you don't know how to do something with CodeceptJS, you can simply revert back to using Protractor syntax! -Create custom helper, define methods for it, and use it inside the I object. Your Helper can access `browser` from Protractor -by accessing Protractor helper: +Create a custom helper, define methods for it, and use it inside the I object. Your Helper can access `browser` from Protractor +by accessing the Protractor helper: ```js let browser = this.helpers['Protractor'].browser; @@ -280,9 +319,7 @@ or use global `element` and `by` variables to locate elements: element.all(by.repeater('result in memory')); ``` -This way we recommend to implement all custom logic using low-level Protractor syntax and using it inside scenario tests. -Please see an [example of such helper](http://codecept.io/helpers/#protractor-example). +This is the recommended way to implement all custom logic using low-level Protractor syntax in order to reuse it inside of test scenarios. +For more information, see an [example of such a helper](http://codecept.io/helpers/#protractor-example). -### done() -Almost ) This example is [available on GitHub](https://github.com/DavertMik/codeceptjs-angular-todomvc). \ No newline at end of file diff --git a/docs/basics.md b/docs/basics.md index 0f4eb0a52..8fcb72e03 100644 --- a/docs/basics.md +++ b/docs/basics.md @@ -1,6 +1,11 @@ -# Basics +--- +permalink: /basics +title: Getting Started +--- + +# Getting Started -CodeceptJS is a modern end to end testing framework with a special BDD-style syntax. The test is written as a linear scenario of user's action on a site. +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'); @@ -8,65 +13,571 @@ Feature('CodeceptJS demo'); Scenario('check Welcome page on site', (I) => { I.amOnPage('/'); I.see('Welcome'); -}) +}); ``` -Tests are expected to be written in ECMAScript 6. -Each test is described inside a `Scenario` function with `I` object passed into it. -I object is an **actor**, an abstraction for a testing user. I is a proxy object for currently enabled **Helpers**. +Tests are expected to be written in **ECMAScript 7**. -```json - "helpers": { - "WebDriverIO": { - "url": "http://localhost", - "browser": "firefox" - } - } +Each test is described inside a `Scenario` function with the `I` object passed into it. +The `I` object is an **actor**, an abstraction for a testing user. The `I` is a proxy object for currently enabled **Helpers**. + +## Architecture + +CodeceptJS bypasses execution commands to helpers. Depending on the helper enabled, your tests will be executed differently. If you need cross-browser support you should choose Selenium-based WebDriver or TestCafé. If you are interested in speed - you should use Chrome-based Puppeteer. + +The following is a diagram of the CodeceptJS architecture: + +![architecture](/img/architecture.svg) + +All helpers share the same API, so it's easy to migrate tests from one backend to another. +However, because of the difference in backends and their limitations, they are not guaranteed to be compatible with each other. For instance, you can't set request headers in WebDriver or Protractor, but you can do so in Puppteer or Nightmare. + +**Pick one helper, as it defines how tests are executed.** If requirements change it's easy to migrate to another. + +--- + +Refer to following guides to more information on: + +* [▶ WebDriver](/webdriver) +* [▶ Protractor](/angular) +* [▶ Puppeteer](/puppeteer) +* [▶ Playwright](/playwright) +* [▶ Nightmare](/nightmare) +* [▶ TestCafe](/testcafe) + +> ℹ Depending on a helper selected a list of available actions may change. + +To list all available commands for the current configuration run `codeceptjs list` +or enable [auto-completion by generating TypeScript definitions](#intellisense). + + +## 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'); +// ... +``` + +### Opening a Page + +A test should usually start by navigating the browser to a website. + +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 +``` + +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 +``` + +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]'}); +``` + +Strict locators allow to specify additional locator types: + +```js +// locate form element by name +I.seeElement({name: 'password'}); +// locate element by React component and props +I.seeElement({react: 'user-profile', props: {name: 'davert'}}); +``` + +In [mobile testing](http://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. + +```js +// locate element by [aria-label] attribute in web +// or by accessibility id in mobile +I.seeElement('~username'); +``` + +> [▶ Learn more about using locators in CodeceptJS](/locators). + +### Clicking + +CodeceptJS provides a flexible syntax to specify an element to click. + +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'); ``` -For current config all methods of `I` will be taken from `WebDriverIO` helper. -This is done to allow easy switching of running backends so you could replace WebDriverIO with Protractor or Nightmare helpers. +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. + +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 +``` + +> 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. + +You are not limited to buttons and links. Any element can be found by passing in valid CSS or XPath: + +```js +// click element by CSS +I.click('#signup'); +// click element located by special test-id attribute +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. + +### Filling Fields + +Clicking the links is not what takes the most time during testing a web site. If your site consists only of links you can skip test automation. The most waste of time goes into the testing of forms. CodeceptJS provides several ways of doing that. + +Let's submit this sample form for a test: + +![](https://user-images.githubusercontent.com/220264/80355863-494a8280-8881-11ea-9b41-ba1f07abf094.png) + +```html +
+ +
+ +
+ +
+ +
+ +
+
+``` + +We need to fill in all those fields and click the "Update" button. CodeceptJS matches form elements by their label, name, or by CSS or XPath locators. + +```js +// we are using label to match user_name field +I.fillField('Name', 'Miles'); +// we can use input name +I.fillField('user[email]','miles@davis.com'); +// select element by label, choose option by text +I.selectOption('Role','Admin'); +// click 'Save' button, found by text +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. + +> ℹ `checkOption` also works only with standard `` HTML elements. If your checkbox 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. + +Alternative scenario: + +```js +// we are using CSS +I.fillField('#user_name', 'Miles'); +I.fillField('#user_email','miles@davis.com'); +// select element by label, option by value +I.selectOption('#user_role','1'); +// click 'Update' button, found by name +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')); +``` + +### Assertions + +In order to verify the expected behavior of a web application, its content should be checked. +CodeceptJS provides built-in assertions for that. They start with a `see` (or `dontSee`) prefix. + +The most general and common assertion is `see`, which checks visilibility of a text on a page: + +```js +// Just a visible text on a page +I.see('Hello'); +// text inside .msg element +I.see('Hello', '.msg'); +// opposite +I.dontSee('Bye'); +``` + +You should provide a text as first argument and, optionally, a locator to search for a text in a context. + +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'); +``` + +Additional assertions: + +```js +I.seeInCurrentUrl('/user/miles'); +I.seeInField('user[name]', 'Miles'); +I.seeInTitle('My Website'); +``` + +To see all possible assertions, check the helper's reference. + +> ℹ If you need custom assertions, you can install an assertion libarary like `chai`, use grabbers to obtain information from a browser and perform assertions. However, it is recommended to put custom assertions into a helper for further reuse. + +### Grabbing + +Sometimes you need to retrieve data from a page to use it in the following steps of a scenario. +Imagine the application generates a password, and you want to ensure that user can login using this password. + +```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'); +}); +``` + +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). + +```js +Scenario('use page title', async (I) => { + // ... + const password = await I.grabTextFrom('#password'); + I.fillField('password', password); +}); +``` + +### Waiting + +In modern web applications, rendering is done on the client-side. +Sometimes that may cause delays. A test may fail while trying to click an element which has not appeared on a page yet. +To handle these cases, the `wait*` methods has been introduced. + +```js +I.waitForElement('#agree_button', 30); // secs +// clicks a button only when it is visible +I.click('#agree_button'); +``` + +> ℹ See [helpers reference](/reference) for a complete list of all available commands for the helper you use. ## How It Works -Tests are written in synchronous way. Test scenarios should be linear, so tests by themseleves should not include promises or callbacks as well. -However, behind the scene **all actions are wrapped in promises** inside the `I` object. -[Global promise](https://github.com/Codeception/CodeceptJS/blob/master/lib/recorder.js) chain is initialized before each test and all `I.*` calls will be appended to it as well as setup and teardown. +Tests are written in a synchronous way. This improves the readability and maintainability of tests. +While writing tests you should not think about promises, and instead should focus on the test scenario. + +However, behind the scenes **all actions are wrapped in promises**, inside of the `I` object. +[Global promise](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/recorder.js) chain is initialized before each test and all `I.*` calls will be appended to it, as well as setup and teardown. -If you want to get information from a running test you can use `yield` inside a **generator function** and special methods of helpers started with `grab` prefix. +> 📺 [Learn how CodeceptJS](https://www.youtube.com/watch?v=MDLLpHAwy_s) works with promises by watching video on YouTube + +If you want to get information from a running test you can use `await` inside the **async function**, and utilize special methods of helpers started with the `grab` prefix. ```js -Scenario('try grabbers', function* (I) { - var title = yield I.grabTitle(); +Scenario('try grabbers', async (I) => { + let title = await I.grabTitle(); }); ``` then you can use those variables in assertions: ```js -var title = yield I.grabTitle(); +var title = await I.grabTitle(); var assert = require('assert'); assert.equal(title, 'CodeceptJS'); ``` -## Pause +## Running Tests + +To launch tests use the `run` command, and to execute tests in [multiple browsers](/advanced/#multiple-browsers-execution) or [multiple threads](/advanced/#parallel-execution) use the `run-multiple` command. + +### Level of Detail + +To see the step-by-step output of running tests, add the `--steps` flag: + +``` +npx codeceptjs run --steps +``` + +To see a more detailed output add the `--debug` flag: + +``` +npx codeceptjs run --debug +``` + +To see very detailed output informations use the `--verbose` flag: + +``` +npx codeceptjs run --verbose +``` + +### Filter + +A single test file can be executed if you provide a relative path to such a file: + +``` +npx codeceptjs run github_test.js + +# or + +npx codeceptjs run admin/login_test.js +``` + +To filter a test by name use the `--grep` parameter, which will execute all tests with names matching the regex pattern. + +To run all tests with the `slow` word in it: + +``` +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 + +Since CodeceptJS 2.3, you can run tests in parallel by using NodeJS workers. This feature requires NodeJS >= 11.6. Use `run-workers` command with the number of workers (threads) to split tests. + +``` +npx codeceptjs run-workers 3 +``` + +Tests are split by scenarios, not by files. Results are aggregated and shown up in the main process. + +## Configuration + +Configuration is set in the `codecept.conf.js` file which was created during the `init` process. +Inside the config file you can enable and configure helpers and plugins, and set bootstrap and teardown scripts. + +```js +exports.config = { + helpers: { + // enabled helpers with their configs + }, + plugins: { + // list of used plugins + }, + include: { + // current actor and page objects + } +} +``` + +> ▶ See complete [configuration reference](/configuration). + +You can have multiple configuration files for a the same project, in this case you can specify a config file to be used with `-c` when running. + +``` +npx codeceptjs run -c codecept.ci.conf.js +``` + +Tuning configuration for helpers like WebDriver, Puppeteer can be hard, as it requires good understanding of how these technologies work. Use the [`@codeceptjs/configure`](https://github.com/codeceptjs/configure) package with common configuration recipes. + +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'); + +// run headless when CI environment variable set +setHeadlessWhen(process.env.CI); +// set window size for any helper: Puppeteer, WebDriver, TestCafe +setWindowSize(1600, 1200); + +exports.config = { + // ... +} +``` + +> ▶ See more [configuration recipes](https://github.com/codeceptjs/configure) + +## Debug + +CodeceptJS allows to write and debug tests on the fly while keeping your browser opened. +By using the interactive shell you can stop execution at any point and type in any CodeceptJS commands. + +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(); +``` + +Try to perform your scenario step by step. Then copy succesful commands and insert them into a test. + +### Pause Test execution can be paused in any place of a test with `pause()` call. -This also launches interactive console where you can call actions of `I` object. +Variables can also be passed to `pause({data: 'hi', func: () => console.log('hello')})` which can be accessed in Interactive shell. + +This launches the interactive console where you can call any action from the `I` object. + +``` + Interactive shell started + Press ENTER to resume test + Use JavaScript syntax to try steps in action + - Press ENTER to run the next step + - Press TAB twice to see all available commands + - Type exit + Enter to exit the interactive shell + - Prefix => to run js commands + I. +``` + +Type in different actions to try them, copy and paste successful ones into the test file. + +Press `ENTER` to resume test execution. + +To **debug test step-by-step** press Enter, the next step will be executed and interactive shell will be shown again. + +To see all available commands, press TAB two times to see list of all actions included in the `I` object. + +> The interactive shell can be started outside of test context by running `npx codeceptjs shell` -![shell](/images/shell.png) +PageObjects and other variables can also be passed to as object: -You can also use `pause()` to check the web application in a browser. Press `ENTER` to resume test execution. +```js +pause({ loginPage, data: 'hi', func: () => console.log('hello') }); +``` -Interactive shell can be started outside test context by running +Inside a pause mode you can use `loginPage`, `data`, `func` variables. +Arbitrary JavaScript code can be executed when used `=> ` prefix: -```bash -codeceptjs shell +```js +I.=> loginPage.open() +I.=> func() +I.=> 2 + 5 ``` +### Pause on Failure + +To start interactive pause automatically for a failing test you can run tests with [pauseOnFail Plugin](/plugins/#pauseonfail). +When a test fails, the pause mode will be activated, so you can inspect current browser session before it is closed. + +This is an **essential feature to debug flaky tests**, as you can analyze them in the moment of failure. + +> ℹ To enable pause after a test without a plugin use `After(pause)` inside a test file. + + +### Screenshot on Failure + +By default CodeceptJS saves a screenshot of a failed test. +This can be configured in [screenshotOnFail Plugin](/plugins/#screenshotonfail) + +> **screenshotOnFail plugin is enabled by default** for new setups + +### Step By Step Report + +To see how the test was executed, use [stepByStepReport Plugin](/plugins/#stepbystepreport). It saves a screenshot of each passed step and shows them in a nice slideshow. + +## Retries + +### Auto Retry + +You can auto-retry a failed step by enabling [retryFailedStep Plugin](/plugins/#retryfailedstep). + +> **autoRetry plugin is enabled by default** for new setups since CodeceptJS 2.4 + +### Retry Step + +Unless you use retryFailedStep plugin you can manually control retries in your project. + +If you have a step which often fails, you can retry execution for this single step. +Use the `retry()` function before an action to ask CodeceptJS to retry it on failure: + +```js +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'); +``` + +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'); + +// retry action 3 times waiting no more than 3 seconds for last retry +I.retry({ retries: 3, maxTimeout: 3000 }).see('Hello'); + +// retry 2 times if error with message 'Node not visible' happens +I.retry({ + retries: 2, + when: err => err.message === 'Node not visible' +}).seeElement('#user'); +``` + +Pass a function to the `when` option to retry only when an error matches the expected one. + + +### Retry Scenario + +When you need to rerun scenarios a few times, add the `retries` option to the `Scenario` declaration. + +CodeceptJS implements retries the same way [Mocha does](https://mochajs.org#retry-tests); +You can set the number of a retries for a feature: + +```js +Scenario('Really complex', (I) => { + // test goes here +}).retry(2); + +// alternative +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 Feature + +To set this option for all scenarios in a file, add `retry` to a feature: + +```js +Feature('Complex JS Stuff').retry(3); +``` + +Every Scenario inside this feature will be rerun 3 times. +You can make an exception for a specific scenario by passing the `retries` option to a Scenario. + + ## Before -Common preparation steps like opening a web page, logging in a user, can be placed in `Before` or `Background` hook: +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'); @@ -90,9 +601,9 @@ Same as `Before` you can use `After` to run teardown for each scenario. ## BeforeSuite -If you need to run complex setup before all tests and teardown this afterwards you can use `BeforeSuite` and `AfterSuite` -functions. `BeforeSuite` and `AfterSuite` have access to `I` object, but `BeforeSuite/AfterSuite` don't have an access to the browser because it's not running at this moment. -You can use them to execute handlers that will setup your environment. `BeforeSuite/AfterSuite` will work only for a file where it was declared (so you can declare different setups for files) +If you need to run complex a setup before all tests and have to teardown this afterwards, you can use the `BeforeSuite` and `AfterSuite` functions. +`BeforeSuite` and `AfterSuite` have access to the `I` object, but `BeforeSuite/AfterSuite` don't have any access to the browser, because it's not running at this moment. +You can use them to execute handlers that will setup your environment. `BeforeSuite/AfterSuite` will work only for the file it was declared in (so you can declare different setups for files) ```js BeforeSuite((I) => { @@ -102,19 +613,21 @@ BeforeSuite((I) => { AfterSuite((I) => { I.syncUp('testfolder'); I.clearDir('testfolder'); -}) +}); ``` -[Here are some ideas](https://github.com/Codeception/CodeceptJS/pull/231#issuecomment-249554933) where to use BeforeSuite hooks. +[Here are some ideas](https://github.com/codeceptjs/CodeceptJS/pull/231#issuecomment-249554933) on where to use BeforeSuite hooks. ## Within -To specify the exact area on a page where actions can be performed you can use `within` function. +To specify the exact area on a page where actions can be performed you can use the `within` function. Everything executed in its context will be narrowed to context specified by locator: +Usage: `within('section', ()=>{})` + ```js I.amOnPage('https://github.com'); -within('.form-signup-home', function () { +within('.js-signup-form', () => { I.fillField('user[login]', 'User'); I.fillField('user[email]', 'user@user.com'); I.fillField('user[password]', 'user@user.com'); @@ -123,14 +636,48 @@ within('.form-signup-home', function () { I.see('There were problems creating your account.'); ``` -When running steps inside a within block will be shown with a shift: +> ⚠ `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. +> Since `within` returns a Promise, it may be necessary to `await` the result even when you're not intending to use the return value. + +`within` can also work with IFrames. A special `frame` locator is required to locate the iframe and get into its context. -![within](http://codecept.io/images/within.png) + +See example: + +```js +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, Nightmare & Puppeteer only)*: + +```js +within({frame: [".content", "#editor"]}, () => { + I.see('Page'); +}); +``` + +When running steps inside, a within block will be shown with a shift: + +![within](/img/within.png) + +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); +``` ## Comments -There is a simple way to add additional comments to your test scenario. -Use `say` command to print information to screen: +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'); @@ -138,105 +685,147 @@ I.say('I enter title and body'); I.say('I expect post is visible on site'); ``` -## Skipping - -Like in Mocha you can use `x` and `only` to skip tests or making a single test to run. +Use the second parameter to pass in a color value (ASCII). -* `xScenario` - skips current test -* `Scenario.only` - executes only the current test +```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 +``` -## Reporters -CodeceptJS supports [Mocha Reporters](https://mochajs.org/#reporters). -They can be used with `--reporter` options. -By default a custom console reporter is enabled. +## IntelliSense -We are currently working on improving reporters support. +![Edit](/img/edit.gif) -## Bootstrap +To get autocompletion when working with CodeceptJS, use Visual Studio Code or another IDE that supports TypeScript Definitions. -In case you need to execute arbitrary code before the tests, -you can place it into your bootstrap file and provide a relative path to it in `codecept.json` +Generate step definitions with: -```json -"bootstrap": "./run_server.js" +```sh +npx codeceptjs def ``` -To run `bootstrap` async, just export a function in your bootstrap file +Create a file called `jsconfig.json` in your project root directory, unless you already have one. -```js -module.exports = function(done) { - // async instructions - // call done() to continue execution - // otherwise call done('error description') +```jsconfig.json +{ + "compilerOptions": { + "allowJs": true, + } } ``` -## Teardown +Alternatively, you can include `/// ` into your test files +to get method autocompletion while writing tests. -In case you need to execute arbitrary code after the tests have run, -you can place it into your teardown file and provide a relative path to it in `codecept.json` -```json -"teardown": "./stop_server.js" -``` - -## Test Options +## Multiple Sessions -Features and Scenarios have their options that can be set by passing a hash after their names: +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 -Feature('My feature', {key: val}); - -Scenario('My scenario', {key: val}, (I) => {}); +Scenario('test app', (I) => { + 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'); + }); + // switching back to default session + I.fillField('message', 'Hi, john'); + // there is a message from current user + I.see('me: Hi, john', '.messages'); + session('john', () => { + // let's check if john received it + I.see('davert: Hi, john', '.messages'); + }); +}); ``` -### Timeout +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. -By default there is no timeout for tests, however you can change this value for a specific suite: +You can override the configuration for the session by passing a second parameter: ```js -Feature('Stop me', {timeout: 5000}); // set timeout to 5s +session('john', { browser: 'firefox' } , () => { + // run this steps in firefox + I.amOnPage('/'); +}); ``` -or for the test: +or just start the session without switching to it. Call `session` passing only its name: ```js -// set timeout to 1s -Scenario("Stop me faster", {timeout: 1000}, (I) => {}); +Scenario('test', (I) => { + // opens 3 additional browsers + session('john'); + session('mary'); + session('jane'); + + I.amOnPage('/'); -// disable timeout for this scenario -Scenario("Don't stop me", {timeout: 0}, (I) => {}); + // switch to session by its name + session('mary', () => { + I.amOnPage('/login'); + }); +} ``` +`session` can return a value which can be used in a scenario: -### Retries +```js +// inside async function +const val = await session('john', () => { + I.amOnPage('/info'); + return I.grabTextFrom({ css: 'h1' }); +}); +I.fillField('Description', val); +``` -Browser tests can be very fragile and some time you need to re run the few times just to make them pass. -This can be done with `retries` option added to `Feature` declaration. +Functions passed into a session can use the `I` object, page objects, and any other objects declared for the scenario. +This function can also be declared as async (but doesn't work as generator). -CodeceptJS implements retries the same way [Mocha do](https://mochajs.org#retry-tests); -You can set number of a retries for a feature: +Also, you can use `within` inside a session, but you can't call session from inside `within`. -```js -Feature('Complex JS Stuff', {retries: 3}) -``` -Every Scenario inside this feature will be rerun 3 times. -You can make an exception for a specific scenario by passing `retries` option to it: -```js -Feature('Complex JS Stuff', {retries: 3}) +## Skipping -Scenario('Not that complex', {retries: 1}, (I) => { - // test goes here -}); +Like in Mocha you can use `x` and `only` to skip tests or to run a single test. -Scenario('Really complex', (I) => { - // test goes here +* `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 + +You can use `Scenario.todo` when you are planning on writing tests. + +This test will be skipped like with regular `Scenario.skip` but with additional message "Test not implemented!": + +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 + */ }); ``` -"Really complex" test will be restarted 3 times, -while "Not that complex" test will be rerun only once. ---- +Or even without a test body: -### done() +```js +Scenario.todo('Test'); +``` diff --git a/docs/bdd.md b/docs/bdd.md new file mode 100644 index 000000000..6f5ab9131 --- /dev/null +++ b/docs/bdd.md @@ -0,0 +1,418 @@ +--- +permalink: /bdd +title: Behavior Driven Development +--- + +# Behavior Driven Development + +Behavior Driven Development (BDD) is a popular software development methodology. BDD is considered an extension of TDD, and is greatly inspired by [Agile](http://agilemanifesto.org/) practices. The primary reason to choose BDD as your development process is to break down communication barriers between business and technical teams. BDD encourages the use of automated testing to verify all documented features of a project from the very beginning. This is why it is common to talk about BDD in the context of test frameworks (like CodeceptJS). The BDD approach, however, is about much more than testing - it is a common language for all team members to use during the development process. + +## What is Behavior Driven Development + +BDD was introduced by [Dan North](https://dannorth.net/introducing-bdd/). He described it as: + +> outside-in, pull-based, multiple-stakeholder, multiple-scale, high-automation, agile methodology. It describes a cycle of interactions with well-defined outputs, resulting in the delivery of working, tested software that matters. + +BDD has its own evolution from the days it was born, started by replacing "test" to "should" in unit tests, and moving towards powerful tools like Cucumber and Behat, which made user stories (human readable text) to be executed as an acceptance test. + +The idea of story BDD can be narrowed to: + +* describe features in a scenario with a formal text +* use examples to make abstract things concrete +* implement each step of a scenario for testing +* write actual code implementing the feature + +By writing every feature in User Story format that is automatically executable as a test we ensure that: business, developers, QAs and managers are in the same boat. + +BDD encourages exploration and debate in order to formalize the requirements and the features that needs to be implemented by requesting to write the User Stories in a way that everyone can understand. + +By making tests to be a part of User Story, BDD allows non-technical personnel to write (or edit) Acceptance tests. + +With this procedure we also ensure that everyone in a team knows what has been developed, what has not, what has been tested and what has not. + +### Ubiquitous Language + +The ubiquitous language is always referred as *common* language. That is it's main benefit. It is not a couple of our business specification's words, and not a couple of developer's technical terms. It is a common words and terms that can be understood by people for whom we are building the software and should be understood by developers. Establishing correct communication between this two groups people is vital for building successful project that will fit the domain and fulfill all business needs. + +Each feature of a product should be born from a talk between + +* business (analysts, product owner) +* developers +* QAs + +which are known in BDD as "three amigos". + +Such talks should produce written stories. There should be an actor that doing some things, the feature that should be fulfilled within the story and the result achieved. + +We can try to write such simple story: + +``` +As a customer I want to buy several products +I put first product with $600 price to my cart +And then another one with $1000 price +When I go to checkout process +I should see that total number of products I want to buy is 2 +And my order amount is $1600 +``` + +As we can see this simple story highlights core concepts that are called *contracts*. We should fulfill those contracts to model software correctly. But how we can verify that those contracts are being satisfied? [Cucumber](http://cucumber.io) introduced a special language for such stories called **Gherkin**. Same story transformed to Gherkin will look like this: + +```gherkin +Feature: checkout process + In order to buy products + As a customer + I want to be able to buy several products + + Scenario: + Given I have product with $600 price in my cart + And I have product with $1000 price + When I go to checkout process + Then I should see that total number of products is 2 + And my order amount is $1600 +``` + +**CodeceptJS can execute this scenario step by step as an automated test**. +Every step in this scenario requires a code which defines it. + +## Gherkin + +Let's learn some more about Gherkin format and then we will see how to execute it with CodeceptJS. We can enable Gherkin for current project by running `gherkin:init` command on **already initialized project**: + +``` +npx codeceptjs gherkin:init +``` + +It will add `gherkin` section to the current config. It will also prepare directories for features and step definition. And it will create the first feature file for you. + +### Features + +Whenever you start writing a story you are describing a specific feature of an application, with a set of scenarios and examples describing this feature. Let's open a feature file created by `gherkin:init` command, which is `feature/basic.feature`. + +```gherkin +Feature: Business rules + In order to achieve my goals + As a persona + I want to be able to interact with a system + + Scenario: do something + Given I have a defined step +``` + +This text should be rewritten to follow your buisness rules. Don't think about a web interface for a while. +Think about how user interacts with your system and what goals they want to achieve. Then write interaction scenarios. + +#### Scenarios + +Scenarios are live examples of feature usage. Inside a feature file it should be written inside a *Feature* block. Each scenario should contain its title: + +```gherkin +Feature: checkout + In order to buy product + As a customer + I need to be able to checkout the selected products + +Scenario: order several products +``` + +Scenarios are written in step-by-step manner using Given-When-Then approach. At start, scenario should describe its context with **Given** keyword: + +```gherkin + Given I have product with $600 price in my cart + And I have product with $1000 price in my cart +``` + +Here we also use word **And** to extend the Given and not to repeat it in each line. + +This is how we described the initial conditions. Next, we perform some action. We use **When** keyword for it: + +```gherkin + When I go to checkout process +``` + +And in the end we are verifying our expectation using **Then** keyword. The action changed the initial given state, and produced some results. Let's check that those results are what we actually expect. + +```gherkin + Then I should see that total number of products is 2 + And my order amount is $1600 +``` + +This scenarios are nice as live documentation but they do not test anything yet. What we need next is to define how to run those steps. +Steps can be defined by executing `gherkin:snippets` command: + +```bash +npx codeceptjs gherkin:snippets [--path=PATH] [--feature=PATH] +``` + +This will produce code templates for all undefined steps in the .feature files. +By default, it will scan all of the .feature files specified in the gherkin.features section of the config and produce code templates for all undefined steps. If the `--feature` option is specified, it will scan the specified .feature file(s). +The stub definitions by default will be placed into the first file specified in the gherkin.steps section of the config. However, you may also use `--path` to specify a specific file in which to place all undefined steps. This file must exist and be in the gherkin.steps array of the config. +Our next step will be to define those steps and transforming feature-file into a valid test. + +### Step Definitions + +Step definitions are placed in JavaScript file with Given/When/Then functions that map strings from feature file to functions: + +```js +// use I and productPage via inject() function +const { I, productPage } = inject(); + +// you can provide RegEx to match corresponding steps +Given(/I have product with \$(\d+) price/, (price) => { + I.amOnPage('/products'); + productPage.create({ price }); + I.click('Add to cart'); +}); + +// or a simple string +When('I go to checkout process', () => { + I.click('Checkout'); +}); + +// parameters are passed in via Cucumber expressions +Then('I should see that total number of products is {int}', (num) => { + I.see(num, '.cart'); +}); +Then('my order amount is ${int}', (sum) => { // eslint-disable-line + I.see('Total: ' + sum); +}); +``` + +Steps can be either strings or regular expressions. Parameters from string are passed as function arguments. To define parameters in a string we use [Cucumber expressions](https://docs.cucumber.io/cucumber/cucumber-expressions/) + +To list all defined steps run `gherkin:steps` command: + +```bash +npx codeceptjs gherkin:steps +``` + +To run tests and see step-by step output use `--steps` optoin: + +``` +npx codeceptjs run --steps +``` + +To see not only business steps but an actual performed steps use `--debug` flag: + +``` +npx codeceptjs run --debug +``` + +## Advanced Gherkin + +Let's improve our BDD suite by using the advanced features of Gherkin language. + +### Background + +If a group of scenarios have the same initial steps, let's that for dashboard we need always need to be logged in as administrator. We can use *Background* section to do the required preparations and not to repeat same steps across scenarios. + +```gherkin +Feature: Dashboard + In order to view current state of business + As an owner + I need to be able to see reports on dashboard + + Background: + Given I am logged in as administrator + And I open dashboard page +``` + +Steps in background are defined the same way as in scenarios. + +### Tables + +Scenarios can become more descriptive when you represent repeating data as tables. Instead of writing several steps "I have product with :num1 $ price in my cart" we can have one step with multiple values in it. + +```gherkin + Given I have products in my cart + | name | category | price | + | Harry Potter | Books | 5 | + | iPhone 5 | Smartphones | 1200 | + | Nuclear Bomb | Weapons | 100000 | +``` + +Tables are the recommended way to pass arrays into test scenarios. +Inside a step definition data is stored in argument passed as `DataTable` JavaScript object. +You can iterate on it like this: + +```js +Given('I have products in my cart', (table) => { // eslint-disable-line + for (const id in table.rows) { + if (id < 1) { + continue; // skip a header of a table + } + + // go by row cells + const cells = table.rows[id].cells; + + // take values + const name = cells[0].value; + const category = cells[1].value; + const price = cells[2].value; + // ... + } +}); +``` + +You can also use the `parse()` method to obtain an object that allow you to get a simple version of the table parsed by column or row, with header (or not): + +- `raw()` - returns the table as a 2-D array +- `rows()` - returns the table as a 2-D array, without the first row +- `hashes()` - returns an array of objects where each row is converted to an object (column header is the key) + +If we use hashes() with the previous exemple : + +```js +Given('I have products in my cart', (table) => { // eslint-disable-line + //parse the table by header + const tableByHeader = table.parse().hashes(); + for (const row of tableByHeader) { + + // take values + const name = row.name; + const category = row.category; + const price = row.price; + // ... + } +}); +``` + +### Examples + +In case scenarios represent the same logic but differ on data, we can use *Scenario Outline* to provide different examples for the same behavior. Scenario outline is just like a basic scenario with some values replaced with placeholders, which are filled from a table. Each set of values is executed as a different test. + +```gherkin + Scenario Outline: order discount + Given I have product with price $ in my cart + And discount for orders greater than $20 is 10 % + When I go to checkout + Then I should see overall price is "" $ + + Examples: + | price | total | + | 10 | 10 | + | 20 | 20 | + | 21 | 18.9 | + | 30 | 27 | + | 50 | 45 | +``` + +### Long Strings + +Text values inside a scenarios can be set inside a `"""` block: + +```gherkin + Then i see in file "codecept.json" +""" +{ + "output": "./output", + "helpers": { + "Puppeteer": { + "url": "http://localhost", + "restart": true, + "windowSize": "1600x1200" + } +""" +``` + +This string can be accessed inside a `content` property of a last argument: + +```js +Then('Then i see in file {string}', (file, text) => { + // file is a value of {string} from a title + const fileContent = fs.readFileSync(file).toString(); + fileContent.should.include(text.content); // text.content is a value +}); +``` + +### Tags + +Gherkin scenarios and features can contain tags marked with `@`. Tags are appended to feature titles so you can easily filter by them when running tests: + +```bash +npx codeceptjs run --grep "@important" +``` + +Tag should be placed before *Scenario:* or before *Feature:* keyword. In the last case all scenarios of that feature will be added to corresponding group. + +## Configuration + +* `gherkin` + * `features` - path to feature files + * `steps` - array of files with step definitions + +```js +"gherkin": { + "features": "./features/*.feature", + "steps": [ + "./step_definitions/steps.js" + ] +} +``` + +## Before + +You can set up some before hooks inside step definition files. Use `Before` function to do that. +This function receives current test as a parameter, so you can apply additional configuration to it. + +```js +// inside step_definitions +Before((test) => { + // perform your code + test.retries(3); // retry test 3 times +}); +``` + +This can be used to keep state between steps: + +```js +let state = {}; + +// inside step_definitions +Before(() => { + state = {}; +}); + +Given('have a user', async () => { + state.user = await I.have('user'); +}); + +When('I open account page', () => { + I.amOnPage(`/user/${state.user.slug}`); +}) +``` + +## After + +Similarly to `Before` you can use `After` and `Fail` inside a scenario. `Fail` hook is activated on failure and receive two parameters: `test` and current `error`. + +```js +After(async () => { + await someService.cleanup(); +}); + +Fail((test, err) => { + // test didn't + console.log('Failed with', err); + pause(); +}); +``` + +## Tests vs Features + +It is common to think that BDD scenario is equal to test. But it's actually not. Not every test should be described as a feature. Not every test is written to test real business value. For instance, regression tests or negative scenario tests are not bringing any value to business. Business analysts don't care about scenario reproducing bug #13, or what error message is displayed when user tries to enter wrong password on login screen. Writing all the tests inside a feature files creates informational overflow. + +In CodeceptJS you can combine tests written in Gherkin format with classical acceptance tests. This way you can keep your feature files compact with minimal set of scenarios, and write regular tests to cover all cases. Please note, feature files will be executed before tests. + +To run only features use `--features` option: + +``` +npx codeceptjs run --features +``` + +You can run a specific feature file by its filename or by grepping by name or tag. + +To run only tests without features use `--tests` option: + +``` +npx codeceptjs run --tests +``` diff --git a/docs/best.md b/docs/best.md new file mode 100644 index 000000000..6b6d4927e --- /dev/null +++ b/docs/best.md @@ -0,0 +1,78 @@ +--- +permalink: /best +title: Best Practices +--- + +# Best Practices + +## Focus on Readability + +In CodeceptJS we encourage users to follow semantic elements on page while writing tests. +Instead of CSS/XPath locators try to stick to visible keywords on page. + +Take a look into the next example: + +```js +// it's fine but... +I.click({css: 'nav.user .user-login'}); +// can be better +I.click('Login', 'nav.user'); +``` + +If we replace raw CSS selector with a button title we can improve readability of such test. +Even a text on the button changes its much easier to update it. + +> If your code goes beyond using `I` object or page objects, you are probably doing something wrong. + +When it's hard to match text to element we recommend using [locator builder](/locators#locator-builder). It allows to build complex locators via fluent API. +So if you want to click an element which is not a button or a link and use its text you can use `locate()` to build a readable locator: + +```js +// clicks element Click me +I.click(locate('.button').withText('Click me')); +``` + +## Use Short Cuts + +To write simpler and effective tests we encourage to use short cuts. +Make test be focused on one feature and try to simplify everything that is not related directly to test. + +* If data is required for a test, try to create that data via API. See how to do it in [Data Management](/data) chapter. +* If user login is required, use [autoLogin plugin](/plugins#autoLogin) instead of putting login steps inside a test. +* Break a long test into few. Long test can be fragile and complicated to follow and update. +* Use [custom steps and page objects](/pageobjects) to hide steps which are not relevant to current test. + +Make test as simple as: + +```js +Scenario('editing a metric', async (I, loginAs, metricPage) => { + // login via autoLogin + loginAs('admin'); + // create data with ApiDataFactory + const metric = await I.have('metric', { type: 'memory', duration: 'day' }) + // use page object to open a page + metricPage.open(metric.id); + I.click('Edit'); + I.see('Editing Metric'); + // using a custom step + I.selectFromDropdown('duration', 'week'); + I.click('Save'); + I.see('Duration: Week', '.summary'); +}); +``` + +## Refactoring and PageObjects + +When a project is growing and more and more tests are required, it's time to think about reusing test code across the tests. Some common actions should be moved from tests to other files so to be accessible from different tests. + +Here is a recommended strategy what to store where: + +* Move site-wide actions into an **Actor** file (`custom_steps.js` file). Such actions like `login`, using site-wide common controls, like drop-downs, rich text editors, calendars. +* Move page-based actions and selectors into **Page Object**. All acitivities made on that page can go into methods of page object. If you test Single Page Application a PageObject should represent a screen of your application. +* When site-wide widgets are used, interactions with them should be placed in **Page Fragments**. This should be applied to global navigation, modals, widgets. +* A custom action that require some low-level driver access, should be placed into a **Helper**. For instance, database connections, complex mouse actions, email testing, filesystem, services access. + +> [Learn more](/pageobjects) about different refactoring options + +However, it's recommended to not overengineer and keep tests simple. If a test code doesn't require reusage at this point it should not be transformed to use page objects. + diff --git a/docs/books.md b/docs/books.md new file mode 100644 index 000000000..723c4ac89 --- /dev/null +++ b/docs/books.md @@ -0,0 +1,37 @@ +--- +permalink: /books +layout: Section +sidebar: false +title: Books & Posts +editLink: false +--- + +# Books & Posts +> Add your own books or posts to our [Wiki Page](https://github.com/codeceptjs/CodeceptJS/wiki/Books-&-Posts) +### [Practical End 2 End Testing with CodeceptJS](https://leanpub.com/codeceptjs/) + +A book by **Paul Vincent Beigang** + +[![](https://user-images.githubusercontent.com/220264/58870454-e2e8ce80-86c8-11e9-868e-7deefdde47ce.png)](https://leanpub.com/codeceptjs/) + +#### Contents: + +1. Preparation for End 2 End Testing with CodeceptJS +1. Setup CodeceptJS with WebdriverIO +1. Create Your First CodeceptJS Test +1. Run Your First CodeceptJS Test Locally +1. Run Test on BrowserStack Against with the Safari Browser +1. How to Debug & Fix a Failing E2E Test +1. Run a CodeceptJS Test in GitLab´s Continuous Integration (CI) Environment +1. Delicious Test Reports With Allure + +### Posts + +A list of good educational posts about CodeceptJS + +* [QA Automation From Zero-to-Hero with CodeceptJS End-to-End Testing](https://medium.com/@dan.ryan.emmons/qa-automation-from-zero-to-hero-with-codeceptjs-end-to-end-testing-719db9d6ff5c) by Dan Emmons +* [Effective End2End Tests with CodeceptJS](https://hackernoon.com/effective-end-2-end-testing-in-javascript-with-codeceptjs-37c8d7d6a928) by @davertmik +* [Customizing CodeceptJS Skeleton](https://medium.com/@successivetech/codeceptjs-skeleton-9ba86d3b45ec) +* [Running End to End tests as Google Cloud Functions](https://hackernoon.com/running-end-to-end-tests-as-google-cloud-functions-f5e34ffc3984) +* [End-To-End Testing With CodeceptJS](https://www.monterail.com/blog/end-to-end-testing-with-codeceptjs) by Piotr Michalski +* [Getting started with CodeceptJS and Selenium WebDriver](https://medium.com/@garrettvorce/getting-started-with-selenium-and-codeceptjs-c0698e8df677) \ No newline at end of file diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 000000000..3c751bc0a --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,1685 @@ +--- +permalink: /changelog +title: Releases +sidebar: false +layout: Section +--- + +# Releases + +## 2.6.11 + +* **[Playwright]** Playwright 1.4 compatibility +* **[Playwright]** Added `ignoreHTTPSErrors` config option (default: false). See [#2566](https://github.com/codeceptjs/CodeceptJS/issues/2566) by gurjeetbains +* Added French translation by **[vimar](https://github.com/vimar)** +* **[WebDriver]** Updated `dragSlider` to work in WebDriver W3C protocol. Fixes [#2557](https://github.com/codeceptjs/CodeceptJS/issues/2557) by suniljaiswal01 + +## 2.6.10 + +* Fixed saving options for suite via `Feature('title', {key: value})` by **[Diokuz](https://github.com/Diokuz)**. See [#2553](https://github.com/codeceptjs/CodeceptJS/issues/2553) and [Docs](https://codecept.io/advanced/#dynamic-configuration) + +## 2.6.9 + +* [Puppeteer][Playwright] SessionStorage is now cleared in after hook. See [#2524](https://github.com/codeceptjs/CodeceptJS/issues/2524) +* When helper load failed the error stack is now logged by **[SkReD](https://github.com/SkReD)**. See [#2541](https://github.com/codeceptjs/CodeceptJS/issues/2541) +* Small documentation fixes. + +## 2.6.8 + +* [WebDriver][Protractor][Playwright][Puppeteer][Nightmare] `saveElementScreenshot` method added to make screenshot of an element. By **[suniljaiswal01](https://github.com/suniljaiswal01)** +* [Playwright][Puppeteer] Added `type` method to type a text using keyboard with an optional delay. +* **[WebDriver]** Added optional `delay` argument to `type` method to slow down typing. +* **[Puppeteer]** Fixed `amOnPage` freeze when `getPageTimeout` is 0"; set 30 sec as default timeout by **[Vorobeyko](https://github.com/Vorobeyko)**. +* Fixed printing step with null argument in custom helper by **[sjana-aj](https://github.com/sjana-aj)**. See [#2494](https://github.com/codeceptjs/CodeceptJS/issues/2494) +* Fix missing screenshot on failure when REST helper is in use [#2513](https://github.com/codeceptjs/CodeceptJS/issues/2513) by **[PeterNgTr](https://github.com/PeterNgTr)** +* Improve error logging in the `screenshotOnFail` plugin [#2512](https://github.com/codeceptjs/CodeceptJS/issues/2512) by **[pablopaul](https://github.com/pablopaul)** + +## 2.6.7 + +* Add REST helper into `standardActingHelpers` array [#2474](https://github.com/codeceptjs/CodeceptJS/issues/2474) by **[PeterNgTr](https://github.com/PeterNgTr)** +* Add missing `--invert` option for `run-workers` command [#2504](https://github.com/codeceptjs/CodeceptJS/issues/2504) by **[pablopaul](https://github.com/pablopaul)** +* **[WebDriver]** Introduce `forceRightClick` method [#2485](https://github.com/codeceptjs/CodeceptJS/issues/2485) bylsuniljaiswal01 +* **[Playwright]** Fix `setCookie` method [#2491](https://github.com/codeceptjs/CodeceptJS/issues/2491) by **[bmbarker90](https://github.com/bmbarker90)** +* **[TypeScript]** Update compilerOptions.target to es2017 [#2483](https://github.com/codeceptjs/CodeceptJS/issues/2483) by **[shanplourde](https://github.com/shanplourde)** +* **[Mocha]** Honor reporter configuration [#2465](https://github.com/codeceptjs/CodeceptJS/issues/2465) by **[trinhpham](https://github.com/trinhpham)** + +## 2.6.6 + +* Puppeteer 4.0 support. Important: MockRequest helper won't work with Puppeter > 3.3 +* Added `xFeature` and `Feature.skip` to skip all tests in a suite. By **[Georgegriff](https://github.com/Georgegriff)** +* **[Appium]** Fixed [#2428](https://github.com/codeceptjs/CodeceptJS/issues/2428) Android native locator support by **[idxn](https://github.com/idxn)** +* **[WebDriver]** Fixed `waitNumberOfVisibleElements` to actually filter visible elements. By **[ilangv](https://github.com/ilangv)** +* **[Puppeteer]** Fixed handling error which is not an Error object. Fixes `cannot read property indexOf of undefined` error. Fix [#2436](https://github.com/codeceptjs/CodeceptJS/issues/2436) by **[Georgegriff](https://github.com/Georgegriff)** +* **[Puppeteer]** Print error on page crash by **[Georgegriff](https://github.com/Georgegriff)** + +## 2.6.5 + +* Added `test.skipped` event to run-workers, fixing allure reports with skipped tests in workers [#2391](https://github.com/codeceptjs/CodeceptJS/issues/2391). Fix [#2387](https://github.com/codeceptjs/CodeceptJS/issues/2387) by **[koushikmohan1996](https://github.com/koushikmohan1996)** +* **[Playwright]** Fixed calling `waitFor*` methods with custom locators [#2314](https://github.com/codeceptjs/CodeceptJS/issues/2314). Fix [#2389](https://github.com/codeceptjs/CodeceptJS/issues/2389) by **[Georgegriff](https://github.com/Georgegriff)** + +## 2.6.4 + +* **[Playwright]** **Playwright 1.0 support** by **[Georgegriff](https://github.com/Georgegriff)**. + +## 2.6.3 + +* [stepByStepReport plugin] Fixed when using plugin with BeforeSuite. Fixes [#2337](https://github.com/codeceptjs/CodeceptJS/issues/2337) by **[mirao](https://github.com/mirao)** +* [allure plugin] Fixed reporting of tests skipped by failure in before hook. Refer to [#2349](https://github.com/codeceptjs/CodeceptJS/issues/2349) & [#2354](https://github.com/codeceptjs/CodeceptJS/issues/2354). Fix by **[koushikmohan1996](https://github.com/koushikmohan1996)** + +## 2.6.2 + +* [WebDriver][Puppeteer] Added `forceClick` method to emulate click event instead of using native events. +* **[Playwright]** Updated to 0.14 +* **[Puppeteer]** Updated to Puppeteer v3.0 +* **[wdio]** Fixed undefined output directory for wdio plugns. Fix By **[PeterNgTr](https://github.com/PeterNgTr)** +* **[Playwright]** Introduced `handleDownloads` method to download file. Please note, this method has slightly different API than the same one in Puppeteer. +* **[allure]** Fixed undefined output directory for allure plugin on using custom runner. Fix by **[charliepradeep](https://github.com/charliepradeep)** +* **[WebDriver]** Fixed `waitForEnabled` fix for webdriver 6. Fix by **[dsharapkou](https://github.com/dsharapkou)** +* Workers: Fixed negative failure result if use scenario with the same names. Fix by **[Vorobeyko](https://github.com/Vorobeyko)** +* **[MockRequest]** Updated documentation to match new helper version +* Fixed: skipped tests are not reported if a suite failed in `before`. Refer [#2349](https://github.com/codeceptjs/CodeceptJS/issues/2349) & [#2354](https://github.com/codeceptjs/CodeceptJS/issues/2354). Fix by **[koushikmohan1996](https://github.com/koushikmohan1996)** + +## 2.6.1 + +* [screenshotOnFail plugin] Fixed saving screenshot of active session. +* [screenshotOnFail plugin] Fix issue [#2301](https://github.com/codeceptjs/CodeceptJS/issues/2301) when having the flag `uniqueScreenshotNames`=true results in `undefined` in screenshot file name by **[PeterNgTr](https://github.com/PeterNgTr)** +* **[WebDriver]** Fixed `waitForElement` not applying the optional second argument to override the default timeout in webdriverio 6. Fix by **[Mooksc](https://github.com/Mooksc)** +* **[WebDriver]** Updated `waitUntil` method which is used by all of the wait* functions. This updates the `waitForElement` by the same convention used to update `waitForVisible` and `waitInUrl` to be compatible with both WebDriverIO v5 & v6. See [#2313](https://github.com/codeceptjs/CodeceptJS/issues/2313) by **[Mooksc](https://github.com/Mooksc)** + +## 2.6.0 + +* **[Playwright] Updated to Playwright 0.12** by **[Georgegriff](https://github.com/Georgegriff)**. + +Upgrade playwright to ^0.12: + +``` +npm i playwright@^0.12 --save +``` + +[Notable changes](https://github.com/microsoft/playwright/releases/tag/v0.12.0): + * Fixed opening two browsers on start + * `executeScript` - passed function now accepts only one argument. Pass in objects or arrays if you need multtple arguments: +```js +// Old style, does not work anymore: +I.executeScript((x, y) => x + y, x, y); +// New style, passing an object: +I.executeScript(({x, y}) => x + y, {x, y}); +``` + * `click` - automatically waits for element to become clickable (visible, not animated) and waits for navigation. + * `clickLink` - deprecated + * `waitForClickable` - deprecated + * `forceClick` - added + * Added support for custom locators. See [#2277](https://github.com/codeceptjs/CodeceptJS/issues/2277) + * Introduced [device emulation](/playwright/#device-emulation): + * globally via `emulate` config option + * per session + +**[WebDriver] Updated to webdriverio v6** by **[PeterNgTr](https://github.com/PeterNgTr)**. + +Read [release notes](https://webdriver.io/blog/2020/03/26/webdriverio-v6-released.html), then +upgrade webdriverio to ^6.0: + +``` +npm i webdriverio@^6.0 --save +``` +*(webdriverio v5 support is deprecated and will be removed in CodeceptJS 3.0)* + **[WebDriver]** Introduced [Shadow DOM support](/shadow) by **[gkushang](https://github.com/gkushang)** + +```js +I.click({ shadow: ['my-app', 'recipe-hello', 'button'] }); +``` + +* **Fixed parallel execution of `run-workers` for Gherkin** scenarios by **[koushikmohan1996](https://github.com/koushikmohan1996)** +* **[MockRequest]** Updated and **moved to [standalone package](https://github.com/codecept-js/mock-request)**: + * full support for record/replay mode for Puppeteer + * added `mockServer` method to use flexible PollyJS API to define mocks + * fixed stale browser screen in record mode. +* **[Playwright]** Added support on for `screenshotOnFail` plugin by **[amonkc](https://github.com/amonkc)** +* Gherkin improvement: setting different tags per examples. See [#2208](https://github.com/codeceptjs/CodeceptJS/issues/2208) by **[acuper](https://github.com/acuper)** +* **[TestCafe]** Updated `click` to take first visible element. Fixes [#2226](https://github.com/codeceptjs/CodeceptJS/issues/2226) by **[theTainted](https://github.com/theTainted)** +* [Puppeteer][WebDriver] Updated `waitForClickable` method to check for element overlapping. See [#2261](https://github.com/codeceptjs/CodeceptJS/issues/2261) by **[PiQx](https://github.com/PiQx)** +* **[Puppeteer]** Dropped `puppeteer-firefox` support, as Puppeteer supports Firefox natively. +* **[REST]** Rrespect Content-Type header. See [#2262](https://github.com/codeceptjs/CodeceptJS/issues/2262) by **[pmarshall-legacy](https://github.com/pmarshall-legacy)** +* [allure plugin] Fixes BeforeSuite failures in allure reports. See [#2248](https://github.com/codeceptjs/CodeceptJS/issues/2248) by **[Georgegriff](https://github.com/Georgegriff)** +* [WebDriver][Puppeteer][Playwright] A screenshot of for an active session is saved in multi-session mode. See [#2253](https://github.com/codeceptjs/CodeceptJS/issues/2253) by **[ChexWarrior](https://github.com/ChexWarrior)** +* Fixed `--profile` option by **[pablopaul](https://github.com/pablopaul)**. Profile value to be passed into `run-multiple` and `run-workers`: + +``` +npx codecept run-workers 2 --profile firefox +``` + +Value is available at `process.env.profile` (previously `process.profile`). See [#2302](https://github.com/codeceptjs/CodeceptJS/issues/2302). Fixes [#1968](https://github.com/codeceptjs/CodeceptJS/issues/1968) [#1315](https://github.com/codeceptjs/CodeceptJS/issues/1315) + +* [commentStep Plugin introduced](/plugins#commentstep). Allows to annotate logical parts of a test: + +```js +__`Given`; +I.amOnPage('/profile') + +__`When`; +I.click('Logout'); + +__`Then`; +I.see('You are logged out'); +``` + +## 2.5.0 + +* **Experimental: [Playwright](/playwright) helper introduced**. + +> [Playwright](https://github.com/microsoft/playwright/) is an alternative to Puppeteer which works very similarly to it but adds cross-browser support with Firefox and Webkit. Until v1.0 Playwright API is not stable but we introduce it to CodeceptJS so you could try it. + +* **[Puppeteer]** Fixed basic auth support when running in multiple sessions. See [#2178](https://github.com/codeceptjs/CodeceptJS/issues/2178) by **[ian-bartholomew](https://github.com/ian-bartholomew)** +* **[Puppeteer]** Fixed `waitForText` when there is no `body` element on page (redirect). See [#2181](https://github.com/codeceptjs/CodeceptJS/issues/2181) by **[Vorobeyko](https://github.com/Vorobeyko)** +* [Selenoid plugin] Fixed overriding current capabilities by adding deepMerge. Fixes [#2183](https://github.com/codeceptjs/CodeceptJS/issues/2183) by **[koushikmohan1996](https://github.com/koushikmohan1996)** +* Added types for `Scenario.todo` by **[Vorobeyko](https://github.com/Vorobeyko)** +* Added types for Mocha by **[Vorobeyko](https://github.com/Vorobeyko)**. Fixed typing conflicts with Jest +* **[FileSystem]** Added methods by **[nitschSB](https://github.com/nitschSB)** + * `waitForFile` + * `seeFileContentsEqualReferenceFile` +* Added `--colors` option to `run` and `run-multiple` so you force colored output in dockerized environment. See [#2189](https://github.com/codeceptjs/CodeceptJS/issues/2189) by **[mirao](https://github.com/mirao)** +* **[WebDriver]** Added `type` command to enter value without focusing on a field. See [#2198](https://github.com/codeceptjs/CodeceptJS/issues/2198) by **[xMutaGenx](https://github.com/xMutaGenx)** +* Fixed `codeceptjs gt` command to respect config pattern for tests. See [#2200](https://github.com/codeceptjs/CodeceptJS/issues/2200) and [#2204](https://github.com/codeceptjs/CodeceptJS/issues/2204) by **[matheo](https://github.com/matheo)** + + +## 2.4.3 + +* Hotfix for interactive pause + +## 2.4.2 + +* **Interactive pause improvements** by **[koushikmohan1996](https://github.com/koushikmohan1996)** + * allows using in page objects and variables: `pause({ loginPage, a })` + * enables custom commands inside pause with `=>` prefix: `=> loginPage.open()` +* [Selenoid plugin](/plugins#selenoid) added by by **[koushikmohan1996](https://github.com/koushikmohan1996)** + * uses Selenoid to launch browsers inside Docker containers + * automatically **records videos** and attaches them to allure reports + * can delete videos for successful tests + * can automatically pull in and start Selenoid containers + * works with WebDriver helper +* Avoid failiure report on successful retry in worker by **[koushikmohan1996](https://github.com/koushikmohan1996)** +* Added translation ability to Scenario, Feature and other context methods by **[koushikmohan1996](https://github.com/koushikmohan1996)** + * 📢 Please help us translate context methods to your language! See [italian translation](https://github.com/codeceptjs/CodeceptJS/blob/master/translations/it-IT.js#L3) as an example and send [patches to vocabularies](https://github.com/codeceptjs/CodeceptJS/tree/master/translations). +* allurePlugin: Added `say` comments to allure reports by **[PeterNgTr](https://github.com/PeterNgTr)**. +* Fixed no custom output folder created when executed with run-worker. Fix by **[PeterNgTr](https://github.com/PeterNgTr)** +* **[Puppeteer]** Fixed error description for context element not found. See [#2065](https://github.com/codeceptjs/CodeceptJS/issues/2065). Fix by **[PeterNgTr](https://github.com/PeterNgTr)** +* **[WebDriver]** Fixed `waitForClickable` to wait for exact number of seconds by **[mirao](https://github.com/mirao)**. Resolves [#2166](https://github.com/codeceptjs/CodeceptJS/issues/2166) +* Fixed setting `compilerOptions` in `jsconfig.json` file on init by **[PeterNgTr](https://github.com/PeterNgTr)** +* **[Filesystem]** Added method by **[nitschSB](https://github.com/nitschSB)** + * `seeFileContentsEqualReferenceFile` + * `waitForFile` + + +## 2.4.1 + +* **[Hotfix]** - Add missing lib that prevents codeceptjs from initializing. + +## 2.4.0 + +* Improved setup wizard with `npx codecept init`: + * **enabled [retryFailedStep](/plugins/#retryfailedstep) plugin for new setups**. + * enabled [@codeceptjs/configure](/configuration/#common-configuration-patterns) to toggle headless/window mode via env variable + * creates a new test on init + * removed question on "steps file", create it by default. +* Added [pauseOnFail plugin](/plugins/#pauseonfail). *Sponsored by Paul Vincent Beigang and his book "[Practical End 2 End Testing with CodeceptJS](https://leanpub.com/codeceptjs/)"*. +* Added [`run-rerun` command](/commands/#run-rerun) to run tests multiple times to detect and fix flaky tests. By **[Ilrilan](https://github.com/Ilrilan)** and **[Vorobeyko](https://github.com/Vorobeyko)**. +* Added [`Scenario.todo()` to declare tests as pending](/basics#todotest). See [#2100](https://github.com/codeceptjs/CodeceptJS/issues/2100) by **[Vorobeyko](https://github.com/Vorobeyko)** +* Added support for absolute path for `output` dir. See [#2049](https://github.com/codeceptjs/CodeceptJS/issues/2049) by **[elukoyanov](https://github.com/elukoyanov)** +* Fixed error in `npx codecept init` caused by calling `console.print`. See [#2071](https://github.com/codeceptjs/CodeceptJS/issues/2071) by **[Atinux](https://github.com/Atinux)**. +* **[Filesystem]** Methods added by **[aefluke](https://github.com/aefluke)**: + * `seeFileNameMatching` + * `grabFileNames` +* **[Puppeteer]** Fixed grabbing attributes with hyphen by **[Holorium](https://github.com/Holorium)** +* **[TestCafe]** Fixed `grabAttributeFrom` method by **[elukoyanov](https://github.com/elukoyanov)** +* **[MockRequest]** Added support for [Polly config options](https://netflix.github.io/pollyjs/#/configuration?id=configuration) by **[ecrmnn](https://github.com/ecrmnn)** +* **[TestCafe]** Fixes exiting with zero code on failure. Fixed [#2090](https://github.com/codeceptjs/CodeceptJS/issues/2090) with [#2106](https://github.com/codeceptjs/CodeceptJS/issues/2106) by **[koushikmohan1996](https://github.com/koushikmohan1996)** +* [WebDriver][Puppeteer] Added basicAuth support via config. Example: `basicAuth: {username: 'username', password: 'password'}`. See [#1962](https://github.com/codeceptjs/CodeceptJS/issues/1962) by **[PeterNgTr](https://github.com/PeterNgTr)** +* [WebDriver][Appium] Added `scrollIntoView` by **[pablopaul](https://github.com/pablopaul)** +* Fixed [#2118](https://github.com/codeceptjs/CodeceptJS/issues/2118): No error stack trace for syntax error by **[senthillkumar](https://github.com/senthillkumar)** +* Added `parse()` method to data table inside Cucumber tests. Use it to obtain rows and hashes for test data. See [#2082](https://github.com/codeceptjs/CodeceptJS/issues/2082) by **[Sraime](https://github.com/Sraime)** + +## 2.3.6 + +* Create better Typescript definition file through JSDoc. By **[lemnis](https://github.com/lemnis)** +* `run-workers` now can use glob pattern. By **[Ilrilan](https://github.com/Ilrilan)** +```js +// Example: +exports.config = { + tests: '{./workers/base_test.workers.js,./workers/test_grep.workers.js}', +} +``` +* Added new command `npx codeceptjs info` which print information about your environment and CodeceptJS configs. By **[jamesgeorge007](https://github.com/jamesgeorge007)** +* Fixed some typos in documantation. By **[pablopaul](https://github.com/pablopaul)** **[atomicpages](https://github.com/atomicpages)** **[EricTendian](https://github.com/EricTendian)** +* Added PULL_REQUEST template. +* [Puppeteer][WebDriver] Added `waitForClickable` for waiting clickable element on page. +* **[TestCafe]** Added support for remote connection. By **[jvdieten](https://github.com/jvdieten)** +* **[Puppeteer]** Fixed `waitForText` XPath context now works correctly. By **[Heavik](https://github.com/Heavik)** +* **[TestCafe]** Fixed `clearField` clear field now awaits TestCafe's promise. By **[orihomie](https://github.com/orihomie)** +* **[Puppeteer]** Fixed fails when executing localStorage on services pages. See [#2026](https://github.com/codeceptjs/CodeceptJS/issues/2026) +* Fixed empty tags in test name. See [#2038](https://github.com/codeceptjs/CodeceptJS/issues/2038) + +## 2.3.5 + +* Set "parse-function" dependency to "5.2.11" to avoid further installation errors. + +## 2.3.4 + +* Fixed installation error "Cannot find module '@babel/runtime/helpers/interopRequireDefault'". The issue came from `parse-function` package. Fixed by **[pablopaul](https://github.com/pablopaul)**. +* **[Puppeteer]** Fixed switching to iframe without an ID by **[johnyb](https://github.com/johnyb)**. See [#1974](https://github.com/codeceptjs/CodeceptJS/issues/1974) +* Added `--profile` option to `run-workers` by **[orihomie](https://github.com/orihomie)** +* Added a tag definition to `FeatureConfig` and `ScenarioConfig` by **[sseliverstov](https://github.com/sseliverstov)** + +## 2.3.3 + +* **[customLocator plugin](#customlocator) introduced**. Adds a locator strategy for special test attributes on elements. + +```js +// when data-test-id is a special test attribute +// enable and configure plugin to replace this +I.click({ css: '[data-test-id=register_button]'); +// with this +I.click('$register_button'); +``` +* [Puppeteer][WebDriver] `pressKey` improvements by **[martomo](https://github.com/martomo)**: +Changed pressKey method to resolve issues and extend functionality. + * Did not properly recognize 'Meta' (or 'Command') as modifier key. + * Right modifier keys did not work in WebDriver using JsonWireProtocol. + * 'Shift' + 'key' combination would not reflect actual keyboard behavior. + * Respect sequence with multiple modifier keys passed to pressKey. + * Added support to automatic change operation modifier key based on operating system. +* [Puppeteer][WebDriver] Added `pressKeyUp` and `pressKeyDown` to press and release modifier keys like `Control` or `Shift`. By **[martomo](https://github.com/martomo)**. +* [Puppeteer][WebDriver] Added `grabElementBoundingRect` by **[PeterNgTr](https://github.com/PeterNgTr)**. +* **[Puppeteer]** Fixed speed degradation introduced in [#1306](https://github.com/codeceptjs/CodeceptJS/issues/1306) with accessibility locators support. See [#1953](https://github.com/codeceptjs/CodeceptJS/issues/1953). +* Added `Config.addHook` to add a function that will update configuration on load. +* Started [`@codeceptjs/configure`](https://github.com/codecept-js/configure) package with a collection of common configuration patterns. +* **[TestCafe]** port's management removed (left on TestCafe itself) by **[orihomie](https://github.com/orihomie)**. Fixes [#1934](https://github.com/codeceptjs/CodeceptJS/issues/1934). +* **[REST]** Headers are no more declared as singleton variable. Fixes [#1959](https://github.com/codeceptjs/CodeceptJS/issues/1959) +* Updated Docker image to include run tests in workers with `NUMBER_OF_WORKERS` env variable. By **[PeterNgTr](https://github.com/PeterNgTr)**. + +## 2.3.2 + +* **[Puppeteer]** Fixed Puppeteer 1.20 support by **[davertmik](https://github.com/davertmik)** +* Fixed `run-workers` to run with complex configs. See [#1887](https://github.com/codeceptjs/CodeceptJS/issues/1887) by **[nitschSB](https://github.com/nitschSB)** +* Added `--suites` option to `run-workers` to split suites by workers (tests of the same suite goes to teh same worker). Thanks **[nitschSB](https://github.com/nitschSB)**. +* Added a guide on [Email Testing](https://codecept.io/email). +* **[retryFailedStepPlugin]** Improved to ignore wait* steps and others. Also added option to ignore this plugin per test bases. See [updated documentation](https://codecept.io/plugins#retryfailedstep). By **[davertmik](https://github.com/davertmik)** +* Fixed using PageObjects as classes by **[Vorobeyko](https://github.com/Vorobeyko)**. See [#1896](https://github.com/codeceptjs/CodeceptJS/issues/1896) +* **[WebDriver]** Fixed opening more than one tab. See [#1875](https://github.com/codeceptjs/CodeceptJS/issues/1875) by **[jplegoff](https://github.com/jplegoff)**. Fixes [#1874](https://github.com/codeceptjs/CodeceptJS/issues/1874) +* Fixed [#1891](https://github.com/codeceptjs/CodeceptJS/issues/1891) when `I.retry()` affected retries of next steps. By **[davertmik](https://github.com/davertmik)** + +## 2.3.1 + +* **[MockRequest]** Polly helper was renamed to MockRequest. +* [MockRequest][WebDriver] [Mocking requests](https://codecept.io/webdriver#mocking-requests) is now available in WebDriver. Thanks **[radhey1851](https://github.com/radhey1851)** +* **[Puppeteer]** Ensure configured user agent and/or window size is applied to all pages. See [#1862](https://github.com/codeceptjs/CodeceptJS/issues/1862) by **[martomo](https://github.com/martomo)** +* Improve handling of xpath locators with round brackets by **[nitschSB](https://github.com/nitschSB)**. See [#1870](https://github.com/codeceptjs/CodeceptJS/issues/1870) +* Use WebDriver capabilities config in wdio plugin. [#1869](https://github.com/codeceptjs/CodeceptJS/issues/1869) by **[quekshuy](https://github.com/quekshuy)** + +## 2.3.0 + + +* **[Parallel testing by workers](https://codecept.io/parallel#parallel-execution-by-workers) introduced** by **[VikalpP](https://github.com/VikalpP)** and **[davertmik](https://github.com/davertmik)**. Use `run-workers` command as faster and simpler alternative to `run-multiple`. Requires NodeJS v12 + +``` +# run all tests in parallel using 3 workers +npx codeceptjs run-workers 3 +``` +* [GraphQL][GraphQLDataFactory] **Helpers for data management over GraphQL** APIs added. By **[radhey1851](https://github.com/radhey1851)**. + * Learn how to [use GraphQL helper](https://codecept.io/data#graphql) to access GarphQL API + * And how to combine it with [GraphQLDataFactory](https://codecept.io/data#graphql-data-factory) to generate and persist test data. +* **Updated to use Mocha 6**. See [#1802](https://github.com/codeceptjs/CodeceptJS/issues/1802) by **[elukoyanov](https://github.com/elukoyanov)** +* Added `dry-run` command to print steps of test scenarios without running them. Fails to execute scenarios with `grab*` methods or custom code. See [#1825](https://github.com/codeceptjs/CodeceptJS/issues/1825) for more details. + +``` +npx codeceptjs dry-run +``` + +* **[Appium]** Optimization when clicking, searching for fields by accessibility id. See [#1777](https://github.com/codeceptjs/CodeceptJS/issues/1777) by **[gagandeepsingh26](https://github.com/gagandeepsingh26)** +* **[TestCafe]** Fixed `switchTo` by **[KadoBOT](https://github.com/KadoBOT)** +* **[WebDriver]** Added geolocation actions by **[PeterNgTr](https://github.com/PeterNgTr)** + * `grabGeoLocation()` + * `setGeoLocation()` +* **[Polly]** Check typeof arguments for mock requests by **[VikalpP](https://github.com/VikalpP)**. Fixes [#1815](https://github.com/codeceptjs/CodeceptJS/issues/1815) +* CLI improvements by **[jamesgeorge007](https://github.com/jamesgeorge007)** + * `codeceptjs` command prints list of all available commands + * added `codeceptjs -V` flag to print version information + * warns on unknown command +* Added TypeScript files support to `run-multiple` by **[z4o4z](https://github.com/z4o4z)** +* Fixed element position bug in locator builder. See [#1829](https://github.com/codeceptjs/CodeceptJS/issues/1829) by **[AnotherAnkor](https://github.com/AnotherAnkor)** +* Various TypeScript typings updates by **[elukoyanov](https://github.com/elukoyanov)** and **[Vorobeyko](https://github.com/Vorobeyko)** +* Added `event.step.comment` event for all comment steps like `I.say` or gherking steps. + +## 2.2.1 + +* **[WebDriver]** A [dedicated guide](https://codecept.io/webdriver) written. +* **[TestCafe]** A [dedicated guide](https://codecept.io/testcafe) written. +* **[Puppeteer]** A [chapter on mocking](https://codecept.io/puppeteer#mocking-requests) written +* [Puppeteer][Nightmare][TestCafe] Window mode is enabled by default on `codeceptjs init`. +* **[TestCafe]** Actions implemented by **[hubidu](https://github.com/hubidu)** + * `grabPageScrollPosition` + * `scrollPageToTop` + * `scrollPageToBottom` + * `scrollTo` + * `switchTo` +* Intellisense improvements. Renamed `tsconfig.json` to `jsconfig.json` on init. Fixed autocompletion for Visual Studio Code. +* **[Polly]** Take configuration values from Puppeteer. Fix [#1766](https://github.com/codeceptjs/CodeceptJS/issues/1766) by **[VikalpP](https://github.com/VikalpP)** +* **[Polly]** Add preconditions to check for puppeteer page availability by **[VikalpP](https://github.com/VikalpP)**. Fixes [#1767](https://github.com/codeceptjs/CodeceptJS/issues/1767) +* **[WebDriver]** Use filename for `uploadFile` by **[VikalpP](https://github.com/VikalpP)**. See [#1797](https://github.com/codeceptjs/CodeceptJS/issues/1797) +* **[Puppeteer]** Configure speed of input with `pressKeyDelay` option. By **[hubidu](https://github.com/hubidu)** +* Fixed recursive loading of support objects by **[davertmik](https://github.com/davertmik)**. +* Fixed support object definitions in steps.d.ts by **[johnyb](https://github.com/johnyb)**. Fixes [#1795](https://github.com/codeceptjs/CodeceptJS/issues/1795) +* Fixed `Data().Scenario().injectDependencies()` is not a function by **[andrerleao](https://github.com/andrerleao)** +* Fixed crash when using xScenario & Scenario.skip with tag by **[VikalpP](https://github.com/VikalpP)**. Fixes [#1751](https://github.com/codeceptjs/CodeceptJS/issues/1751) +* Dynamic configuration of helpers can be performed with async function. See [#1786](https://github.com/codeceptjs/CodeceptJS/issues/1786) by **[cviejo](https://github.com/cviejo)** +* Added TS definitions for internal objects by **[Vorobeyko](https://github.com/Vorobeyko)** +* BDD improvements: + * Fix for snippets command with a .feature file that has special characters by **[asselin](https://github.com/asselin)** + * Fix `--path` option on `gherkin:snippets` command by **[asselin](https://github.com/asselin)**. See [#1790](https://github.com/codeceptjs/CodeceptJS/issues/1790) + * Added `--feature` option to `gherkin:snippets` to enable creating snippets for a subset of .feature files. See [#1803](https://github.com/codeceptjs/CodeceptJS/issues/1803) by **[asselin](https://github.com/asselin)**. +* Fixed: dynamic configs not reset after test. Fixes [#1776](https://github.com/codeceptjs/CodeceptJS/issues/1776) by **[cviejo](https://github.com/cviejo)**. + +## 2.2.0 + +* **EXPERIMENTAL** [**TestCafe** helper](https://codecept.io/helpers/TestCafe) introduced. TestCafe allows to run cross-browser tests it its own very fast engine. Supports all browsers including mobile. Thanks to **[hubidu](https://github.com/hubidu)** for implementation! Please test it and send us feedback. +* **[Puppeteer]** Mocking requests enabled by introducing [Polly.js helper](https://codecept.io/helpers/Polly). Thanks **[VikalpP](https://github.com/VikalpP)** + +```js +// use Polly & Puppeteer helpers +I.mockRequest('GET', '/api/users', 200); +I.mockRequest('POST', '/users', { user: { name: 'fake' }}); +``` + +* **EXPERIMENTAL** **[Puppeteer]** [Firefox support](https://codecept.io/helpers/Puppeteer-firefox) introduced by **[ngadiyak](https://github.com/ngadiyak)**, see [#1740](https://github.com/codeceptjs/CodeceptJS/issues/1740) +* **[stepByStepReportPlugin]** use md5 hash to generate reports into unique folder. Fix [#1744](https://github.com/codeceptjs/CodeceptJS/issues/1744) by **[chimurai](https://github.com/chimurai)** +* Interactive pause improvements: + * print result of `grab` commands + * print message for successful assertions +* `run-multiple` (parallel execution) improvements: + * `bootstrapAll` must be called before creating chunks. [#1741](https://github.com/codeceptjs/CodeceptJS/issues/1741) by **[Vorobeyko](https://github.com/Vorobeyko)** + * Bugfix: If value in config has falsy value then multiple config does not overwrite original value. [#1756](https://github.com/codeceptjs/CodeceptJS/issues/1756) by **[LukoyanovE](https://github.com/LukoyanovE)** +* Fixed hooks broken in 2.1.5 by **[Vorobeyko](https://github.com/Vorobeyko)** +* Fix references to support objects when using Dependency Injection. Fix by **[johnyb](https://github.com/johnyb)**. See [#1701](https://github.com/codeceptjs/CodeceptJS/issues/1701) +* Fix dynamic config applied for multiple helpers by **[VikalpP](https://github.com/VikalpP)** [#1743](https://github.com/codeceptjs/CodeceptJS/issues/1743) + + +## 2.1.5 + +* **EXPERIMENTAL** [Wix Detox support](https://github.com/codeceptjs/detox-helper) introduced as standalone helper. Provides a faster alternative to Appium for mobile testing. +* Saving successful commands inside interactive pause into `_output/cli-history` file. By **[hubidu](https://github.com/hubidu)** +* Fixed hanging error handler inside scenario. See [#1721](https://github.com/codeceptjs/CodeceptJS/issues/1721) by **[haily-lgc](https://github.com/haily-lgc)**. +* Fixed by **[Vorobeyko](https://github.com/Vorobeyko)**: tests did not fail when an exception was raised in async bootstrap. +* **[WebDriver]** Added window control methods by **[emmonspired](https://github.com/emmonspired)** + * `grabAllWindowHandles` returns all window handles + * `grabCurrentWindowHandle` returns current window handle + * `switchToWindow` switched to window by its handle +* **[Appium]** Fixed using `host` as configuration by **[trinhpham](https://github.com/trinhpham)** +* Fixed `run-multiple` command when `tests` config option is undefined (in Gherkin scenarios). By **[gkushang](https://github.com/gkushang)**. +* German translation introduced by **[hubidu](https://github.com/hubidu)** + +## 2.1.4 + +* [WebDriver][Puppeteer][Protractor][Nightmare] A11y locator support introduced by **[Holorium](https://github.com/Holorium)**. Clickable elements as well as fields can be located by following attributes: + * `aria-label` + * `title` + * `aria-labelledby` +* **[Puppeteer]** Added support for React locators. + * New [React Guide](https://codecept.io/react) added. +* **[Puppeteer]** Deprecated `downloadFile` +* **[Puppeteer]** Introduced `handleDownloads` replacing `downloadFile` +* [puppeteerCoverage plugin] Fixed path already exists error by **[seta-tuha](https://github.com/seta-tuha)**. +* Fixed 'ERROR: ENAMETOOLONG' creating directory names in `run-multiple` with long config. By **[artvinn](https://github.com/artvinn)** +* **[REST]** Fixed url autocompletion combining base and relative paths by **[LukoyanovE](https://github.com/LukoyanovE)** +* [Nightmare][Protractor] `uncheckOption` method introduced by **[PeterNgTr](https://github.com/PeterNgTr)** +* [autoLogin plugin] Enable to use without `await` by **[tsuemura](https://github.com/tsuemura)** +* **[Puppeteer]** Fixed `UnhandledPromiseRejectionWarning: "Execution context was destroyed...` by **[adrielcodeco](https://github.com/adrielcodeco)** +* **[WebDriver]** Keep browser window dimensions when starting a new session by **[spiroid](https://github.com/spiroid)** +* Replace Ghekrin plceholders with values in files that combine a scenerio outline and table by **[medtoure18](https://github.com/medtoure18)**. +* Added Documentation to [locate elements in React Native](https://codecept.io/mobile-react-native-locators) apps. By **[DimGun](https://github.com/DimGun)**. +* Adding optional `path` parameter to `bdd:snippets` command to append snippets to a specific file. By **[cthorsen31](https://github.com/cthorsen31)**. +* Added optional `output` parameter to `def` command by **[LukoyanovE](https://github.com/LukoyanovE)**. +* **[Puppeteer]** Added `grabDataFromPerformanceTiming` by **[PeterNgTr](https://github.com/PeterNgTr)**. +* axios updated to `0.19.0` by **[SteveShaffer](https://github.com/SteveShaffer)** +* TypeScript defitions updated by **[LukoyanovE](https://github.com/LukoyanovE)**. Added `secret` and `inject` function. + +## 2.1.3 + +* Fixed autoLogin plugin to inject `login` function +* Fixed using `toString()` in DataTablewhen it is defined by **[tsuemura](https://github.com/tsuemura)** + +## 2.1.2 + +* Fixed `inject` to load objects recursively. +* Fixed TypeScript definitions for locators by **[LukoyanovE](https://github.com/LukoyanovE)** +* **EXPERIMENTAL** **[WebDriver]** ReactJS locators support with webdriverio v5.8+: + +```js +// locating React element by name, prop, state +I.click({ react: 'component-name', props: {}, state: {} }); +I.seeElement({ react: 'component-name', props: {}, state: {} }); +``` + +## 2.1.1 + +* Do not retry `within` and `session` calls inside `retryFailedStep` plugin. Fix by **[tsuemura](https://github.com/tsuemura)** + +## 2.1.0 + +* Added global `inject()` function to require actor and page objects using dependency injection. Recommended to use in page objects, step definition files, support objects: + +```js +// old way +const I = actor(); +const myPage = require('../page/myPage'); + +// new way +const { I, myPage } = inject(); +``` + +* Added global `secret` function to fill in sensitive data. By **[RohanHart](https://github.com/RohanHart)**: + +```js +I.fillField('password', secret('123456')); +``` + +* [wdioPlugin](https://codecept.io/plugins/#wdio) Added a plugin to **support webdriverio services** including *selenium-standalone*, *sauce*, *browserstack*, etc. **Sponsored by **[GSasu](https://github.com/GSasu)**** +* **[Appium]** Fixed `swipe*` methods by **[PeterNgTr](https://github.com/PeterNgTr)** +* BDD Gherkin Improvements: + * Implemented `run-multiple` for feature files. **Sponsored by **[GSasu](https://github.com/GSasu)**** + * Added `--features` and `--tests` options to `run-multiple`. **Sponsored by **[GSasu](https://github.com/GSasu)**** + * Implemented `Before` and `After` hooks in [step definitions](https://codecept.io/bdd#before) +* Fixed running tests by absolute path. By **[batalov](https://github.com/batalov)**. +* Enabled the adding screenshot to failed test for moch-junit-reporter by **[PeterNgTr](https://github.com/PeterNgTr)**. +* **[Puppeteer]** Implemented `uncheckOption` and fixed behavior of `checkOption` by **[aml2610](https://github.com/aml2610)** +* **[WebDriver]** Fixed `seeTextEquals` on empty strings by **[PeterNgTr](https://github.com/PeterNgTr)** +* **[Puppeteer]** Fixed launch with `browserWSEndpoint` config by **[ngadiyak](https://github.com/ngadiyak)**. +* **[Puppeteer]** Fixed switching back to main window in multi-session mode by **[davertmik](https://github.com/davertmik)**. +* **[autoLoginPlugin]** Fixed using async functions for auto login by **[nitschSB](https://github.com/nitschSB)** + +> This release was partly sponsored by **[GSasu](https://github.com/GSasu)**. Thanks for the support! +Do you want to improve this project? [Learn more about sponsorin CodeceptJS + + +## 2.0.8 + +* **[Puppeteer]** Added `downloadFile` action by **[PeterNgTr](https://github.com/PeterNgTr)**. + +Use it with `FileSystem` helper to test availability of a file: +```js + const fileName = await I.downloadFile('a.file-link'); + I.amInPath('output'); + I.seeFile(fileName); +``` +> Actions `amInPath` and `seeFile` are taken from [FileSystem](https://codecept.io/helpers/FileSystem) helper + +* **[Puppeteer]** Fixed `autoLogin` plugin with Puppeteer by **[davertmik](https://github.com/davertmik)** +* **[WebDriver]** `seeInField` should throw error if element has no value attrubite. By **[PeterNgTr](https://github.com/PeterNgTr)** +* **[WebDriver]** Fixed `seeTextEquals` passes for any string if element is empty by **[PeterNgTr](https://github.com/PeterNgTr)**. +* **[WebDriver]** Internal refctoring to use `el.isDisplayed` to match latest webdriverio implementation. Thanks to **[LukoyanovE](https://github.com/LukoyanovE)** +* [allure plugin] Add ability enable [screenshotDiff plugin](https://github.com/allure-framework/allure2/blob/master/plugins/screen-diff-plugin/README.md) by **[Vorobeyko](https://github.com/Vorobeyko)** +* **[Appium]** Fixed `locator.stringify` call by **[LukoyanovE](https://github.com/LukoyanovE)** + +## 2.0.7 + +* [WebDriver][Protractor][Nightmare] `rightClick` method implemented (fixed) in a standard way. By **[davertmik](https://github.com/davertmik)** +* **[WebDriver]** Updated WebDriver API calls in helper. By **[PeterNgTr](https://github.com/PeterNgTr)** +* **[stepByStepReportPlugin]** Added `screenshotsForAllureReport` config options to automatically attach screenshots to allure reports. By **[PeterNgTr](https://github.com/PeterNgTr)** +* **[allurePlugin]** Added `addLabel` method by **[Vorobeyko](https://github.com/Vorobeyko)** +* Locator Builder: fixed `withChild` and `withDescendant` to match deep nested siblings by **[Vorobeyko](https://github.com/Vorobeyko)**. + +## 2.0.6 + +* Introduced [Custom Locator Strategies](https://codecept.io/locators#custom-locators). +* Added [Visual Testing Guide](https://codecept.io/visual) by **[puneet0191](https://github.com/puneet0191)** and **[MitkoTschimev](https://github.com/MitkoTschimev)**. +* **[Puppeteer]** [`puppeteerCoverage`](https://codecept.io/plugins#puppeteercoverage) plugin added to collect code coverage in JS. By **[dvillarama](https://github.com/dvillarama)** +* Make override option in `run-multiple` to respect the generated overridden config by **[kinyat](https://github.com/kinyat)** +* Fixed deep merge for `container.append()`. Introduced `lodash.merge()`. By **[Vorobeyko](https://github.com/Vorobeyko)** +* Fixed saving screenshot on Windows by +* Fix errors on using interactive shell with Allure plugin by tsuemura +* Fixed using dynamic injections with `Scenario().injectDependencies` by **[tsemura](https://github.com/tsemura)** +* [WebDriver][Puppeteer][Nightmare][Protractor] Fixed url protocol detection for non-http urls by **[LukoyanovE](https://github.com/LukoyanovE)** +* **[WebDriver]** Enabled compatibility with `stepByStepReport` by **[tsuemura](https://github.com/tsuemura)** +* **[WebDriver]** Fixed `grabHTMLFrom` to return innerHTML value by **[Holorium](https://github.com/Holorium)**. Fixed compatibility with WebDriverIO. +* **[WebDriver]** `grabHTMLFrom` to return one HTML vlaue for one element matched, array if multiple elements found by **[davertmik](https://github.com/davertmik)**. +* **[Nightmare]** Added `grabHTMLFrom` by **[davertmik](https://github.com/davertmik)** +* Fixed `bootstrapAll` and `teardownAll` launch with path as argument by **[LukoyanovE](https://github.com/LukoyanovE)** +* Fixed `bootstrapAll` and `teardownAll` calls from exported object by **[LukoyanovE](https://github.com/LukoyanovE)** +* **[WebDriver]** Added possibility to define conditional checks interval for `waitUntil` by **[LukoyanovE](https://github.com/LukoyanovE)** +* Fixed storing current data in data driven tests in a test object. By **[Vorobeyko](https://github.com/Vorobeyko)** +* **[WebDriver]** Fixed `hostname` config option overwrite when setting a cloud provider. By **[LukoyanovE](https://github.com/LukoyanovE)** +* **[WebDriver]** `dragSlider` method implemented by **[DavertMik](https://github.com/DavertMik)** +* **[WebDrover]** Fixed `scrollTo` to use new webdriverio API by **[PeterNgTr](https://github.com/PeterNgTr)** +* Added Japanese translation file by **[tsemura](https://github.com/tsemura)** +* Added `Locator.withDescendant()` method to find an element which contains a descendant (child, grandchild) by **[Vorobeyko](https://github.com/Vorobeyko)** +* **[WebDriver]** Fixed configuring capabilities for Selenoid and IE by **[Vorobeyko](https://github.com/Vorobeyko)** +* **[WebDriver]** Restore original window size when taking full size screenshot by **[tsuemura](https://github.com/tsuemura)** +* Enabled `throws()`,` fails()`, `retry()`, `timeout()`, `config()` functions for data driven tests. By **[jjm409](https://github.com/jjm409)** + +## 2.0.5 + +[Broken Release] + +## 2.0.4 + +* [WebDriver][Protractor][Nightmare][Puppeteer] `grabAttributeFrom` returns an array when multiple elements matched. By **[PeterNgTr](https://github.com/PeterNgTr)** +* [autoLogin plugin] Fixed merging users config by **[nealfennimore](https://github.com/nealfennimore)** +* [autoDelay plugin] Added WebDriver to list of supported helpers by **[mattin4d](https://github.com/mattin4d)** +* **[Appium]** Fixed using locators in `waitForElement`, `waitForVisible`, `waitForInvisible`. By **[eduardofinotti](https://github.com/eduardofinotti)** +* [allure plugin] Add tags to allure reports by **[Vorobeyko](https://github.com/Vorobeyko)** +* [allure plugin] Add skipped tests to allure reports by **[Vorobeyko](https://github.com/Vorobeyko)** +* Fixed `Logged Test name | [object Object]` when used Data().Scenario(). By **[Vorobeyko](https://github.com/Vorobeyko)** +* Fixed Data().only.Scenario() to run for all datasets. By **[Vorobeyko](https://github.com/Vorobeyko)** +* **[WebDriver]** `attachFile` to work with hidden elements. Fixed in [#1460](https://github.com/codeceptjs/CodeceptJS/issues/1460) by **[tsuemura](https://github.com/tsuemura)** + + + +## 2.0.3 + +* [**autoLogin plugin**](https://codecept.io/plugins#autologin) added. Allows to log in once and reuse browser session. When session expires - automatically logs in again. Can persist session between runs by saving cookies to file. +* Fixed `Maximum stack trace` issue in `retryFailedStep` plugin. +* Added `locate()` function into the interactive shell. +* **[WebDriver]** Disabled smartWait for interactive shell. +* **[Appium]** Updated methods to use for mobile locators + * `waitForElement` + * `waitForVisible` + * `waitForInvisible` +* Helper and page object generators no longer update config automatically. Please add your page objects and helpers manually. + +## 2.0.2 + +* **[Puppeteer]** Improved handling of connection with remote browser using Puppeteer by **[martomo](https://github.com/martomo)** +* **[WebDriver]** Updated to webdriverio 5.2.2 by **[martomo](https://github.com/martomo)** +* Interactive pause improvements by **[davertmik](https://github.com/davertmik)** + * Disable retryFailedStep plugin in in interactive mode + * Removes `Interface: parseInput` while in interactive pause +* **[ApiDataFactory]** Improvements + * added `fetchId` config option to override id retrieval from payload + * added `onRequest` config option to update request in realtime + * added `returnId` config option to return ids of created items instead of items themvelves + * added `headers` config option to override default headers. + * added a new chapter into [DataManagement](https://codecept.io/data#api-requests-using-browser-session) +* **[REST]** Added `onRequest` config option + + +## 2.0.1 + +* Fixed creating project with `codecept init`. +* Fixed error while installing webdriverio@5. +* Added code beautifier for generated configs. +* **[WebDriver]** Updated to webdriverio 5.1.0 + +## 2.0.0 + +* **[WebDriver]** **Breaking Change.** Updated to webdriverio v5. New helper **WebDriver** helper introduced. + + * **Upgrade plan**: + + 1. Install latest webdriverio + ``` + npm install webdriverio@5 --save + ``` + + 2. Replace `WebDriverIO` => `WebDriver` helper name in config. + 3. Read [webdriverio changelog](https://github.com/webdriverio/webdriverio/blob/master/CHANGELOG.md). If you were using webdriver API in your helpers, upgrade accordingly. + 4. We made WebDriver helper to be compatible with old API so no additional changes required. + + > If you face issues using webdriverio v5 you can still use webdriverio 4.x and WebDriverIO helper. Make sure you have `webdriverio: ^4.0` installed. + + * Known issues: `attachFile` doesn't work with proxy server. + +* **[Appium]** **Breaking Change.** Updated to use webdriverio v5 as well. See upgrade plan ↑ +* **[REST]** **Breaking Change.** Replaced `unirest` library with `axios`. + + * **Upgrade plan**: + + 1. Refer to [axios API](https://github.com/axios/axios). + 2. If you were using `unirest` requests/responses in your tests change them to axios format. +* **Breaking Change.** Generators support in tests removed. Use `async/await` in your tests +* **Using `codecept.conf.js` as default configuration format** +* Fixed "enametoolong" error when saving screenshots for data driven tests by **[PeterNgTr](https://github.com/PeterNgTr)** +* Updated NodeJS to 10 in Docker image +* **[Pupeteer]** Add support to use WSEndpoint. Allows to execute tests remotely. [See [#1350](https://github.com/codeceptjs/CodeceptJS/issues/1350)] by **[gabrielcaires](https://github.com/gabrielcaires)** (https://github.com/codeceptjs/CodeceptJS/pull/1350) +* In interactive shell **[Enter]** goes to next step. Improvement by **[PeterNgTr](https://github.com/PeterNgTr)**. +* `I.say` accepts second parameter as color to print colorful comments. Improvement by **[PeterNgTr](https://github.com/PeterNgTr)**. + +```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 +``` +* Fixed allure reports for multi session testing by **[PeterNgTr](https://github.com/PeterNgTr)** +* Fixed allure reports for hooks by **[PeterNgTr](https://github.com/PeterNgTr)** + +## 1.4.6 + +* **[Puppeteer]** `dragSlider` action added by **[PeterNgTr](https://github.com/PeterNgTr)** +* **[Puppeteer]** Fixed opening browser in shell mode by **[allenhwkim](https://github.com/allenhwkim)** +* **[Puppeteer]** Fixed making screenshot on additional sessions by **[PeterNgTr](https://github.com/PeterNgTr)**. Fixes [#1266](https://github.com/codeceptjs/CodeceptJS/issues/1266) +* Added `--invert` option to `run-multiple` command by **[LukoyanovE](https://github.com/LukoyanovE)** +* Fixed steps in Allure reports by **[PeterNgTr](https://github.com/PeterNgTr)** +* Add option `output` to customize output directory in [stepByStepReport plugin](https://codecept.io/plugins/#stepbystepreport). By **[fpsthirty](https://github.com/fpsthirty)** +* Changed type definition of PageObjects to get auto completion by **[rhicu](https://github.com/rhicu)** +* Fixed steps output for async/arrow functions in CLI by **[LukoyanovE](https://github.com/LukoyanovE)**. See [#1329](https://github.com/codeceptjs/CodeceptJS/issues/1329) + +## 1.4.5 + +* Add **require** param to main config. Allows to require Node modules before executing tests. By **[LukoyanovE](https://github.com/LukoyanovE)**. For example: + * Use `ts-node/register` to register TypeScript parser + * Use `should` to register should-style assertions + +```js +"require": ["ts-node/register", "should"] +``` + +* **[WebDriverIO]** Fix timeouts definition to be compatible with W3C drivers. By **[LukoyanovE](https://github.com/LukoyanovE)** +* Fixed: exception in Before block w/ Mocha causes test not to report failure. See [#1292](https://github.com/codeceptjs/CodeceptJS/issues/1292) by **[PeterNgTr](https://github.com/PeterNgTr)** +* Command `run-parallel` now accepts `--override` flag. Thanks to **[ClemCB](https://github.com/ClemCB)** +* Fixed Allure report with Before/BeforeSuite/After/AfterSuite steps. By **[PeterNgTr](https://github.com/PeterNgTr)** +* Added `RUN_MULTIPLE` env variable to [Docker config](https://codecept.io/docker/). Allows to run tests in parallel inside a container. Thanks to **[PeterNgTr](https://github.com/PeterNgTr)** +* **[Mochawesome]** Fixed showing screenshot on failure. Fix by **[PeterNgTr](https://github.com/PeterNgTr)** +* Fixed running tests filtering by tag names defined via `Scenario.tag()` + +## 1.4.4 + +* [autoDelay plugin](https://codecept.io/plugins/#autoDelay) added. Adds tiny delay before and after an action so the page could react to actions performed. +* **[Puppeteer]** improvements by **[luismanuel001](https://github.com/luismanuel001)** + * `click` no longer waits for navigation + * `clickLink` method added. Performs a click and waits for navigation. +* Bootstrap scripts to be started only for `run` command and ignored on `list`, `def`, etc. Fix by **[LukoyanovE](https://github.com/LukoyanovE)** + + +## 1.4.3 + +* Groups renamed to Tags for compatibility with BDD layer +* Test and suite objects to contain tags property which can be accessed from internal API +* Fixed adding tags for Scenario Outline in BDD +* Added `tag()` method to ScenarioConfig and FeatureConfig: + +```js +Scenario('update user profile', () => { + // test goes here +}).tag('@slow'); +``` + +* Fixed attaching Allure screenshot on exception. Fix by **[DevinWatson](https://github.com/DevinWatson)** +* Improved type definitions for custom steps. By **[Akxe](https://github.com/Akxe)** +* Fixed setting `multiple.parallel.chunks` as environment variable in config. See [#1238](https://github.com/codeceptjs/CodeceptJS/issues/1238) by **[ngadiyak](https://github.com/ngadiyak)** + +## 1.4.2 + +* Fixed setting config for plugins (inclunding setting `outputDir` for allure) by **[jplegoff](https://github.com/jplegoff)** + +## 1.4.1 + +* Added `plugins` option to `run-multiple` +* Minor output fixes +* Added Type Definition for Helper class by **[Akxe](https://github.com/Akxe)** +* Fixed extracing devault extension in generators by **[Akxe](https://github.com/Akxe)** + +## 1.4.0 + +* [**Allure Reporter Integration**](https://codecept.io/reports/#allure). Full inegration with Allure Server. Get nicely looking UI for tests,including steps, nested steps, and screenshots. Thanks **Natarajan Krishnamurthy **[krish](https://github.com/krish)**** for sponsoring this feature. +* [Plugins API introduced](https://codecept.io/hooks/#plugins). Create custom plugins for CodeceptJS by hooking into event dispatcher, and using promise recorder. +* **Official [CodeceptJS plugins](https://codecept.io/plugins) added**: + * **`stepByStepReport` - creates nicely looking report to see test execution as a slideshow**. Use this plugin to debug tests in headless environment without recording a video. + * `allure` - Allure reporter added as plugin. + * `screenshotOnFail` - saves screenshot on fail. Replaces similar functionality from helpers. + * `retryFailedStep` - to rerun each failed step. +* **[Puppeteer]** Fix `executeAsyncScript` unexpected token by **[jonathanz](https://github.com/jonathanz)** +* Added `override` option to `run-multiple` command by **[svarlet](https://github.com/svarlet)** + +## 1.3.3 + +* Added `initGlobals()` function to API of [custom runner](https://codecept.io/hooks/#custom-runner). + +## 1.3.2 + +* Interactve Shell improvements for `pause()` + * Added `next` command for **step-by-step debug** when using `pause()`. + * Use `After(pause);` in a to start interactive console after last step. +* **[Puppeteer]** Updated to Puppeteer 1.6.0 + * Added `waitForRequest` to wait for network request. + * Added `waitForResponse` to wait for network response. +* Improved TypeScript definitions to support custom steps and page objects. By **[xt1](https://github.com/xt1)** +* Fixed XPath detection to accept XPath which starts with `./` by **[BenoitZugmeyer](https://github.com/BenoitZugmeyer)** + +## 1.3.1 + +* BDD-Gherkin: Fixed running async steps. +* **[Puppeteer]** Fixed process hanging for 30 seconds. Page loading timeout default via `getPageTimeout` set 0 seconds. +* **[Puppeteer]** Improved displaying client-side console messages in debug mode. +* **[Puppeteer]** Fixed closing sessions in `restart:false` mode for multi-session mode. +* **[Protractor]** Fixed `grabPopupText` to not throw error popup is not opened. +* **[Protractor]** Added info on using 'direct' Protractor driver to helper documentation by **[xt1](https://github.com/xt1)**. +* **[WebDriverIO]** Added a list of all special keys to WebDriverIO helper by **[davertmik](https://github.com/davertmik)** and **[xt1](https://github.com/xt1)**. +* Improved TypeScript definitions generator by **[xt1](https://github.com/xt1)** + +## 1.3.0 + +* **Cucumber-style BDD. Introduced [Gherkin support](https://codecept.io/bdd). Thanks to [David Vins](https://github.com/dvins) and [Omedym](https://www.omedym.com) for sponsoring this feature**. + +Basic feature file: + +```gherkin +Feature: Business rules + In order to achieve my goals + As a persona + I want to be able to interact with a system + + Scenario: do anything in my life + Given I need to open Google +``` + +Step definition: + +```js +const I = actor(); + +Given('I need to open Google', () => { + I.amOnPage('https://google.com'); +}); +``` + +Run it with `--features --steps` flag: + +``` +codeceptjs run --steps --features +``` + +--- + +* **Brekaing Chnage** `run` command now uses relative path + test name to run exactly one test file. + +Previous behavior (removed): +``` +codeceptjs run basic_test.js +``` +Current behavior (relative path to config + a test name) + +``` +codeceptjs run tests/basic_test.js +``` +This change allows using auto-completion when running a specific test. + +--- + +* Nested steps output enabled for page objects. + * to see high-level steps only run tests with `--steps` flag. + * to see PageObjects implementation run tests with `--debug`. +* PageObjects simplified to remove `_init()` extra method. Try updated generators and see [updated guide](https://codecept.io/pageobjects/#pageobject). +* **[Puppeteer]** [Multiple sessions](https://codecept.io/acceptance/#multiple-sessions) enabled. Requires Puppeteer >= 1.5 +* **[Puppeteer]** Stability improvement. Waits for for `load` event on page load. This strategy can be changed in config: + * `waitForNavigation` config option introduced. Possible options: `load`, `domcontentloaded`, `networkidle0`, `networkidle2`. See [Puppeteer API](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitfornavigationoptions) + * `getPageTimeout` config option to set maximum navigation time in milliseconds. Default is 30 seconds. + * `waitForNavigation` method added. Explicitly waits for navigation to be finished. +* [WebDriverIO][Protractor][Puppeteer][Nightmare] **Possible BC** `grabTextFrom` unified. Return a text for single matched element and an array of texts for multiple elements. +* [Puppeteer]Fixed `resizeWindow` by **[sergejkaravajnij](https://github.com/sergejkaravajnij)** +* [WebDriverIO][Protractor][Puppeteer][Nightmare] `waitForFunction` added. Waits for client-side JavaScript function to return true by **[GREENpoint](https://github.com/GREENpoint)**. +* **[Puppeteer]** `waitUntil` deprecated in favor of `waitForFunction`. +* Added `filter` function to DataTable. +* Send non-nested array of files to custom parallel execution chunking by **[mikecbrant](https://github.com/mikecbrant)**. +* Fixed invalid output directory path for run-multiple by **[mikecbrant](https://github.com/mikecbrant)**. +* **[WebDriverIO]** `waitUntil` timeout accepts time in seconds (as all other wait* functions). Fix by **[truesrc](https://github.com/truesrc)**. +* **[Nightmare]** Fixed `grabNumberOfVisibleElements` to work similarly to `seeElement`. Thx to **[stefanschenk](https://github.com/stefanschenk)** and Jinbo Jinboson. +* **[Protractor]** Fixed alert handling error with message 'no such alert' by **[truesrc](https://github.com/truesrc)**. + + +## 1.2.1 + +* Fixed running `I.retry()` on multiple steps. +* Fixed parallel execution wih chunks. +* **[Puppeteer]** Fixed `grabNumberOfVisibleElements` to return `0` instead of throwing error if no elements are found. + +## 1.2.0 + +* [WebDriverIO][Protractor][Multiple Sessions](https://codecept.io/acceptance/#multiple-sessions). Run several browser sessions in one test. Introduced `session` command, which opens additional browser window and closes it after a test. + +```js +Scenario('run in different browsers', (I) => { + I.amOnPage('/hello'); + I.see('Hello!'); + session('john', () => { + I.amOnPage('/bye'); + I.dontSee('Hello'); + I.see('Bye'); + }); + I.see('Hello'); +}); +``` + +* [Parallel Execution](https://codecept.io/advanced/#parallel-execution) by **[sveneisenschmidt](https://github.com/sveneisenschmidt)**. Run tests in parallel specifying number of chunks: + +```js +"multiple": { + "parallel": { + // run in 2 processes + "chunks": 2, + // run all tests in chrome + "browsers": ["chrome"] + }, +} +``` + +* [Locator Builder](https://codecept.io/locators). Write complex locators with simplest API combining CSS and XPath: + +```js +// select 'Edit' link inside 2nd row of a table +locate('//table') + .find('tr') + .at(2) + .find('a') + .withText('Edit'); +``` + +* [Dynamic configuration](https://codecept.io/advanced/#dynamic-configuration) to update helpers config per test or per suite. +* Added `event.test.finished` which fires synchronously for both failed and passed tests. +* [WebDriverIO][Protractor][Nightmare][Puppeteer] Full page screenshots on failure disabled by default. See [issue[#1600](https://github.com/codeceptjs/CodeceptJS/issues/1600). You can enabled them with `fullPageScreenshots: true`, however they may work unstable in Selenium. +* `within` blocks can return values. See [updated documentation](https://codecept.io/basics/#within). +* Removed doublt call to `_init` in helpers. Fixes issue [#1036](https://github.com/codeceptjs/CodeceptJS/issues/1036) +* Added scenario and feature configuration via fluent API: + +```js +Feature('checkout') + .timeout(3000) + .retry(2); + +Scenario('user can order in firefox', (I) => { + // see dynamic configuration +}).config({ browser: 'firefox' }) + .timeout(20000); + +Scenario('this test should throw error', (I) => { + // I.amOnPage +}).throws(new Error); +``` + +## 1.1.8 + +* Fixed generating TypeScript definitions with `codeceptjs def`. +* Added Chinese translation ("zh-CN" and "zh-TW") by **[TechQuery](https://github.com/TechQuery)**. +* Fixed running tests from a different folder specified by `-c` option. +* **[Puppeteer]** Added support for hash handling in URL by **[gavoja](https://github.com/gavoja)**. +* **[Puppeteer]** Fixed setting viewport size by **[gavoja](https://github.com/gavoja)**. See [Puppeteer issue](https://github.com/GoogleChrome/puppeteer/issues/1183) + + +## 1.1.7 + +* Docker Image updateed. [See updated reference](https://codecept.io/docker/): + * codeceptjs package is mounted as `/codecept` insde container + * tests directory is expected to be mounted as `/tests` + * `codeceptjs` global runner added (symlink to `/codecept/bin/codecept.js`) +* **[Protractor]** Functions added by **[reubenmiller](https://github.com/reubenmiller)**: + * `_locateCheckable (only available from other helpers)` + * `_locateClickable (only available from other helpers)` + * `_locateFields (only available from other helpers)` + * `acceptPopup` + * `cancelPopup` + * `dragAndDrop` + * `grabBrowserLogs` + * `grabCssPropertyFrom` + * `grabHTMLFrom` + * `grabNumberOfVisibleElements` + * `grabPageScrollPosition (new)` + * `rightClick` + * `scrollPageToBottom` + * `scrollPageToTop` + * `scrollTo` + * `seeAttributesOnElements` + * `seeCssPropertiesOnElements` + * `seeInPopup` + * `seeNumberOfVisibleElements` + * `switchTo` + * `waitForEnabled` + * `waitForValue` + * `waitInUrl` + * `waitNumberOfVisibleElements` + * `waitToHide` + * `waitUntil` + * `waitUrlEquals` +* **[Nightmare]** added: + * `grabPageScrollPosition` (new) + * `seeNumberOfVisibleElements` + * `waitToHide` +* **[Puppeteer]** added: + * `grabPageScrollPosition` (new) +* **[WebDriverIO]** added" + * `grabPageScrollPosition` (new) +* **[Puppeteer]** Fixed running wait* functions without setting `sec` parameter. +* [Puppeteer][Protractor] Fixed bug with I.click when using an object selector with the xpath property. By **[reubenmiller](https://github.com/reubenmiller)** +* [WebDriverIO][Protractor][Nightmare][Puppeteer] Fixed I.switchTo(0) and I.scrollTo(100, 100) api inconsistencies between helpers. +* **[Protractor]** Fixing bug when `seeAttributesOnElements` and `seeCssPropertiesOnElement` were incorrectly passing when the attributes/properties did not match by **[reubenmiller](https://github.com/reubenmiller)** +* **[WebDriverIO]** Use inbuilt dragAndDrop function (still doesn't work in Firefox). By **[reubenmiller](https://github.com/reubenmiller)** +* Support for Nightmare 3.0 +* Enable glob patterns in `config.test` / `Codecept.loadTests` by **[sveneisenschmidt](https://github.com/sveneisenschmidt)** +* Enable overriding of `config.tests` for `run-multiple` by **[sveneisenschmidt](https://github.com/sveneisenschmidt)** + + +## 1.1.6 + +* Added support for `async I =>` functions syntax in Scenario by **[APshenkin](https://github.com/APshenkin)** +* [WebDriverIO][Protractor][Puppeteer][Nightmare] `waitForInvisible` waits for element to hide or to be removed from page. By **[reubenmiller](https://github.com/reubenmiller)** +* [Protractor][Puppeteer][Nightmare] Added `grabCurrentUrl` function. By **[reubenmiller](https://github.com/reubenmiller)** +* **[WebDriverIO]** `grabBrowserUrl` deprecated in favor of `grabCurrentUrl` to unify the API. +* **[Nightmare]** Improved element visibility detection by **[reubenmiller](https://github.com/reubenmiller)** +* **[Puppeteer]** Fixing function calls when clearing the cookies and localstorage. By **[reubenmiller](https://github.com/reubenmiller)** +* **[Puppeteer]** Added `waitForEnabled`, `waitForValue` and `waitNumberOfVisibleElements` methods by **[reubenmiller](https://github.com/reubenmiller)** +* **[WebDriverIO]** Fixed `grabNumberOfVisibleElements` to return 0 when no visible elements are on page. By **[michaltrunek](https://github.com/michaltrunek)** +* Helpers API improvements (by **[reubenmiller](https://github.com/reubenmiller)**) + * `_passed` hook runs after a test passed successfully + * `_failed` hook runs on a failed test +* Hooks API. New events added by **[reubenmiller](https://github.com/reubenmiller)**: + * `event.all.before` - executed before all tests + * `event.all.after` - executed after all tests + * `event.multiple.before` - executed before all processes in run-multiple + * `event.multiple.after` - executed after all processes in run-multiple +* Multiple execution +* Allow `AfterSuite` and `After` test hooks to be defined after the first Scenario. By **[reubenmiller](https://github.com/reubenmiller)** +* **[Nightmare]** Prevent `I.amOnpage` navigation if the browser is already at the given url +* Multiple-Run: Added new `bootstrapAll` and `teardownAll` hooks to be executed before and after all processes +* `codeceptjs def` command accepts `--config` option. By **[reubenmiller](https://github.com/reubenmiller)** + +## 1.1.5 + +* **[Puppeteer]** Rerun steps failed due to "Cannot find context with specified id" Error. +* Added syntax to retry a single step: + +```js +// retry action once on failure +I.retry().see('Hello'); + +// retry action 3 times on failure +I.retry(3).see('Hello'); + +// retry action 3 times waiting for 0.1 second before next try +I.retry({ retries: 3, minTimeout: 100 }).see('Hello'); + +// retry action 3 times waiting no more than 3 seconds for last retry +I.retry({ retries: 3, maxTimeout: 3000 }).see('Hello'); + +// retry 2 times if error with message 'Node not visible' happens +I.retry({ + retries: 2, + when: err => err.message === 'Node not visible' +}).seeElement('#user'); +``` + +* `Scenario().injectDependencies` added to dynamically add objects into DI container by **[Apshenkin](https://github.com/Apshenkin)**. See [Dependency Injection section in PageObjects](https://codecept.io/pageobjects/#dependency-injection). +* Fixed using async/await functions inside `within` +* [WebDriverIO][Protractor][Puppeteer][Nightmare] **`waitUntilExists` deprecated** in favor of `waitForElement` +* [WebDriverIO][Protractor] **`waitForStalenessOf` deprecated** in favor of `waitForDetached` +* [WebDriverIO][Protractor][Puppeteer][Nightmare] `waitForDetached` added +* **[Nightmare]** Added `I.seeNumberOfElements()` by **[pmoncadaisla](https://github.com/pmoncadaisla)** +* **[Nightmare]** Load blank page when starting nightmare so that the .evaluate function will work if _failed/saveScreenshot is triggered by **[reubenmiller](https://github.com/reubenmiller)** +* Fixed using plain arrays for data driven tests by **[reubenmiller](https://github.com/reubenmiller)** +* **[Puppeteer]** Use default tab instead of opening a new tab when starting the browser by **[reubenmiller](https://github.com/reubenmiller)** +* **[Puppeteer]** Added `grabNumberOfTabs` function by **[reubenmiller](https://github.com/reubenmiller)** +* **[Puppeteer]** Add ability to set user-agent by **[abidhahmed](https://github.com/abidhahmed)** +* **[Puppeteer]** Add keepCookies and keepBrowserState **[abidhahmed](https://github.com/abidhahmed)** +* **[Puppeteer]** Clear value attribute instead of innerhtml for TEXTAREA by **[reubenmiller](https://github.com/reubenmiller)** +* **[REST]** fixed sending string payload by **[michaltrunek](https://github.com/michaltrunek)** +* Fixed unhandled rejection in async/await tests by **[APshenkin](https://github.com/APshenkin)** + + +## 1.1.4 + +* Removed `yarn` call in package.json +* Fixed `console.log` in Puppeteer by **[othree](https://github.com/othree)** +* **[Appium]** `runOnAndroid` and `runOnIOS` can receive a function to check capabilities dynamically: + +```js +I.runOnAndroid(caps => caps.platformVersion >= 7, () => { + // run code only on Android 7+ +}); +``` + +## 1.1.3 + +* **[Puppeteer]** +25 Functions added by **[reubenmiller](https://github.com/reubenmiller)** + * `_locateCheckable` + * `_locateClickable` + * `_locateFields` + * `closeOtherTabs` + * `dragAndDrop` + * `grabBrowserLogs` + * `grabCssPropertyFrom` + * `grabHTMLFrom` + * `grabNumberOfVisibleElements` + * `grabSource` + * `rightClick` + * `scrollPageToBottom` + * `scrollPageToTop` + * `scrollTo` + * `seeAttributesOnElements` + * `seeCssPropertiesOnElements` + * `seeInField` + * `seeNumberOfElements` + * `seeNumberOfVisibleElements` + * `seeTextEquals` + * `seeTitleEquals` + * `switchTo` + * `waitForInvisible` + * `waitInUrl` + * `waitUrlEquals` +* **[Protractor]** +8 functions added by **[reubenmiller](https://github.com/reubenmiller)** + * `closeCurrentTab` + * `grabSource` + * `openNewTab` + * `seeNumberOfElements` + * `seeTextEquals` + * `seeTitleEquals` + * `switchToNextTab` + * `switchToPreviousTab` +* **[Nightmare]** `waitForInvisible` added by **[reubenmiller](https://github.com/reubenmiller)** +* **[Puppeteer]** Printing console.log information in debug mode. +* **[Nightmare]** Integrated with `nightmare-har-plugin` by mingfang. Added `enableHAR` option. Added HAR functions: + * `grabHAR` + * `saveHAR` + * `resetHAR` +* **[WebDriverIO]** Fixed execution stability for parallel requests with Chromedriver +* **[WebDriverIO]** Fixed resizeWindow when resizing to 'maximize' by **[reubenmiller](https://github.com/reubenmiller)** +* **[WebDriverIO]** Fixing resizing window to full screen when taking a screenshot by **[reubenmiller](https://github.com/reubenmiller)** + +## 1.1.2 + +* **[Puppeteer]** Upgraded to Puppeteer 1.0 +* Added `grep` option to config to set default matching pattern for tests. +* **[Puppeteer]** Added `acceptPopup`, `cancelPopup`, `seeInPopup` and `grabPopupText` functions by **[reubenmiller](https://github.com/reubenmiller)** +* **[Puppeteer]** `within` iframe and nested iframe support added by **[reubenmiller](https://github.com/reubenmiller)** +* **[REST]** Added support for JSON objects since payload (as a JSON) was automatically converted into "URL query" type of parameter by **[Kalostrinho](https://github.com/Kalostrinho)** +* **[REST]** Added `resetRequestHeaders` method by **[Kalostrinho](https://github.com/Kalostrinho)** +* **[REST]** Added `followRedirect` option and `amFollowingRequestRedirects`/`amNotFollowingRequestRedirects` methods by **[Kalostrinho](https://github.com/Kalostrinho)** +* **[WebDriverIO]** `uncheckOption` implemented by **[brunobg](https://github.com/brunobg)** +* **[WebDriverIO]** Added `grabBrowserUrl` by **[Kalostrinho](https://github.com/Kalostrinho)** +* Add ability to require helpers from node_modules by **[APshenkin](https://github.com/APshenkin)** +* Added `--profile` option to `run-multiple` command by **[jamie-beck](https://github.com/jamie-beck)** +* Custom output name for multiple browser run by **[tfiwm](https://github.com/tfiwm)** +* Fixed passing data to scenarios by **[KennyRules](https://github.com/KennyRules)** + +## 1.1.1 + +* **[WebDriverIO]** fixed `waitForInvisible` by **[Kporal](https://github.com/Kporal)** + +## 1.1.0 + +Major update to CodeceptJS. **NodeJS v 8.9.1** is now minimal Node version required. +This brings native async-await support to CodeceptJS. It is recommended to start using await for tests instead of generators: + +```js +async () => { + I.amOnPage('/page'); + const url = await I.grabTextFrom('.nextPage'); + I.amOnPage(url); +} +``` + +Thanks to [@Apshenkin](https://github.com/apshenkin) for implementation. Also, most helpers were refactored to use async-await. This made our code simpler. We hope that this encourages more users to send pull requests! + +We also introduced strict ESLint policies for our codebase. Thanks to [@Galkin](https://github.com/galkin) for that. + +* **[Puppeteer] Helper introduced**. [Learn how to run tests headlessly with Google Chrome's Puppeteer](http://codecept.io/puppeteer/). +* **[SeleniumWebdriver]** Helper is deprecated, it is recommended to use Protractor with config option `angular: false` instead. +* **[WebDriverIO]** nested iframe support in the within block by **[reubenmiller](https://github.com/reubenmiller)**. Example: + +```js +within({frame: ['#wrapperId', '[name=content]']}, () => { + I.click('Sign in!'); + I.see('Email Address'); +}); +I.see('Nested Iframe test'); +I.dontSee('Email Address'); +}); +``` +* **[WebDriverIO]** Support for `~` locator to find elements by `aria-label`. This behavior is similar as it is in Appium and helps testing cross-platform React apps. Example: + +```html + + CodeceptJS is awesome + +``` +↑ This element can be located with `~foobar` in WebDriverIO and Appium helpers. Thanks to **[flyskywhy](https://github.com/flyskywhy)** + +* Allow providing arbitrary objects in config includes by **[rlewan](https://github.com/rlewan)** +* **[REST]** Prevent from mutating default headers by **[alexashley](https://github.com/alexashley)**. See [#789](https://github.com/codeceptjs/CodeceptJS/issues/789) +* **[REST]** Fixed sending empty helpers with `haveRequestHeaders` in `sendPostRequest`. By **[petrisorionel](https://github.com/petrisorionel)** +* Fixed displaying undefined args in output by **[APshenkin](https://github.com/APshenkin)** +* Fixed NaN instead of seconds in output by **[APshenkin](https://github.com/APshenkin)** +* Add browser name to report file for `multiple-run` by **[trollr](https://github.com/trollr)** +* Mocha updated to 4.x + + + +## 1.0.3 + +* [WebDriverIO][Protractor][Nightmare] method `waitUntilExists` implemented by **[sabau](https://github.com/sabau)** +* Absolute path can be set for `output` dir by **[APshenkin](https://github.com/APshenkin)**. Fix [#571](https://github.com/codeceptjs/CodeceptJS/issues/571)* Data table rows can be ignored by using `xadd`. By **[APhenkin](https://github.com/APhenkin)** +* Added `Data(table).only.Scenario` to give ability to launch only Data tests. By **[APhenkin](https://github.com/APhenkin)** +* Implemented `ElementNotFound` error by **[BorisOsipov](https://github.com/BorisOsipov)**. +* Added TypeScript compiler / configs to check the JavaScript by **[KennyRules](https://github.com/KennyRules)** +* **[Nightmare]** fix executeScript return value by **[jploskonka](https://github.com/jploskonka)** +* **[Nightmare]** fixed: err.indexOf not a function when waitForText times out in nightmare by **[joeypedicini92](https://github.com/joeypedicini92)** +* Fixed: Retries not working when using .only. By **[APhenkin](https://github.com/APhenkin)** + + +## 1.0.2 + +* Introduced generators support in scenario hooks for `BeforeSuite`/`Before`/`AfterSuite`/`After` +* **[ApiDataFactory]** Fixed loading helper; `requireg` package included. +* Fix [#485](https://github.com/codeceptjs/CodeceptJS/issues/485)`run-multiple`: the first browser-resolution combination was be used in all configurations +* Fixed unique test names: + * Fixed [#447](https://github.com/codeceptjs/CodeceptJS/issues/447) tests failed silently if they have the same name as other tests. + * Use uuid in screenshot names when `uniqueScreenshotNames: true` +* **[Protractor]** Fixed testing non-angular application. `amOutsideAngularApp` is executed before each step. Fixes [#458](https://github.com/codeceptjs/CodeceptJS/issues/458)* Added output for steps in hooks when they fail + +## 1.0.1 + +* Reporters improvements: + * Allows to execute [multiple reporters](http://codecept.io/advanced/#Multi-Reports) + * Added [Mochawesome](http://codecept.io/helpers/Mochawesome/) helper + * `addMochawesomeContext` method to add custom data to mochawesome reports + * Fixed Mochawesome context for failed screenshots. +* **[WebDriverIO]** improved click on context to match clickable element with a text inside. Fixes [#647](https://github.com/codeceptjs/CodeceptJS/issues/647)* **[Nightmare]** Added `refresh` function by **[awhanks](https://github.com/awhanks)** +* fixed `Unhandled promise rejection (rejection id: 1): Error: Unknown wait type: pageLoad` +* support for tests with retries in html report +* be sure that change window size and timeouts completes before test +* **[Nightmare]** Fixed `[Wrapped Error] "codeceptjs is not defined"`; Reinjectiing client scripts to a webpage on changes. +* **[Nightmare]** Added more detailed error messages for `Wait*` methods +* **[Nightmare]** Fixed adding screenshots to Mochawesome +* **[Nightmare]** Fix unique screenshots names in Nightmare +* Fixed CodeceptJS work with hooks in helpers to finish codeceptJS correctly if errors appears in helpers hooks +* Create a new session for next test If selenium grid error received +* Create screenshots for failed hooks from a Feature file +* Fixed `retries` option + +## 1.0 + +CodeceptJS hits first stable release. CodeceptJS provides a unified API for [web testing for Webdriverio](http://codecept.io/acceptance/), [Protractor](http://codecept.io/angular/), and [NightmareJS](http://codecept.io/nightmare/). Since 1.0 you can also **test mobile applications** in the similar manner with Appium. + +Sample test: + +```js +I.seeAppIsInstalled("io.super.app"); +I.click('~startUserRegistrationCD'); +I.fillField('~email of the customer', 'Nothing special')); +I.see('davert@codecept.io', '~email of the customer')); +I.clearField('~email of the customer')); +I.dontSee('Nothing special', '~email of the customer')); +``` + +* Read [the Mobile Testing guide](http://codecept.io/mobile). +* Discover [Appium Helper](http://codecept.io/helpers/Appium/) + +--- + +We also introduced two new **helpers for data management**. +Using them you can easily prepare and cleanup data for your tests using public REST API. + +Sample test + +```js +// create a user using data factories and REST API +I.have('user', { name: 'davert', password: '123456' }); +// use it to login +I.amOnPage('/login'); +I.fillField('login', 'davert'); +I.fillField('password', '123456'); +I.click('Login'); +I.see('Hello, davert'); +// user will be removed after the test +``` + +* Read [Data Management guide](http://codecept.io/data) +* [REST Helper](http://codecept.io/helpers/REST) +* [ApiDataFactory](http://codecept.io/helpers/ApiDataFactory/) + +--- + +Next notable feature is **[SmartWait](http://codecept.io/acceptance/#smartwait)** for WebDriverIO, Protractor, SeleniumWebdriver. When `smartwait` option is set, script will wait for extra milliseconds to locate an element before failing. This feature uses implicit waits of Selenium but turns them on only in applicable pieces. For instance, implicit waits are enabled for `seeElement` but disabled for `dontSeeElement` + +* Read more about [SmartWait](http://codecept.io/acceptance/#smartwait) + +##### Changelog + +* Minimal NodeJS version is 6.11.1 LTS +* Use `within` command with generators. +* [Data Driven Tests](http://codecept.io/advanced/#data-driven-tests) introduced. +* Print execution time per step in `--debug` mode. [#591](https://github.com/codeceptjs/CodeceptJS/issues/591) by **[APshenkin](https://github.com/APshenkin)** +* [WebDriverIO][Protractor][Nightmare] Added `disableScreenshots` option to disable screenshots on fail by **[Apshenkin](https://github.com/Apshenkin)** +* [WebDriverIO][Protractor][Nightmare] Added `uniqueScreenshotNames` option to generate unique names for screenshots on failure by **[Apshenkin](https://github.com/Apshenkin)** +* [WebDriverIO][Nightmare] Fixed click on context; `click('text', '#el')` will throw exception if text is not found inside `#el`. +* [WebDriverIO][Protractor][SeleniumWebdriver] [SmartWait introduced](http://codecept.io/acceptance/#smartwait). +* [WebDriverIO][Protractor][Nightmare]Fixed `saveScreenshot` for PhantomJS, `fullPageScreenshots` option introduced by **[HughZurname](https://github.com/HughZurname)** [#549](https://github.com/codeceptjs/CodeceptJS/issues/549) +* **[Appium]** helper introduced by **[APshenkin](https://github.com/APshenkin)** +* **[REST]** helper introduced by **[atrevino](https://github.com/atrevino)** in [#504](https://github.com/codeceptjs/CodeceptJS/issues/504) +* [WebDriverIO][SeleniumWebdriver] Fixed "windowSize": "maximize" for Chrome 59+ version [#560](https://github.com/codeceptjs/CodeceptJS/issues/560) by **[APshenkin](https://github.com/APshenkin)** +* **[Nightmare]** Fixed restarting by **[APshenkin](https://github.com/APshenkin)** [#581](https://github.com/codeceptjs/CodeceptJS/issues/581) +* **[WebDriverIO]** Methods added by **[APshenkin](https://github.com/APshenkin)**: + * [grabCssPropertyFrom](http://codecept.io/helpers/WebDriverIO/#grabcsspropertyfrom) + * [seeTitleEquals](http://codecept.io/helpers/WebDriverIO/#seetitleequals) + * [seeTextEquals](http://codecept.io/helpers/WebDriverIO/#seetextequals) + * [seeCssPropertiesOnElements](http://codecept.io/helpers/WebDriverIO/#seecsspropertiesonelements) + * [seeAttributesOnElements](http://codecept.io/helpers/WebDriverIO/#seeattributesonelements) + * [grabNumberOfVisibleElements](http://codecept.io/helpers/WebDriverIO/#grabnumberofvisibleelements) + * [waitInUrl](http://codecept.io/helpers/WebDriverIO/#waitinurl) + * [waitUrlEquals](http://codecept.io/helpers/WebDriverIO/#waiturlequals) + * [waitForValue](http://codecept.io/helpers/WebDriverIO/#waitforvalue) + * [waitNumberOfVisibleElements](http://codecept.io/helpers/WebDriverIO/#waitnumberofvisibleelements) + * [switchToNextTab](http://codecept.io/helpers/WebDriverIO/#switchtonexttab) + * [switchToPreviousTab](http://codecept.io/helpers/WebDriverIO/#switchtoprevioustab) + * [closeCurrentTab](http://codecept.io/helpers/WebDriverIO/#closecurrenttab) + * [openNewTab](http://codecept.io/helpers/WebDriverIO/#opennewtab) + * [refreshPage](http://codecept.io/helpers/WebDriverIO/#refreshpage) + * [scrollPageToBottom](http://codecept.io/helpers/WebDriverIO/#scrollpagetobottom) + * [scrollPageToTop](http://codecept.io/helpers/WebDriverIO/#scrollpagetotop) + * [grabBrowserLogs](http://codecept.io/helpers/WebDriverIO/#grabbrowserlogs) +* Use mkdirp to create output directory. [#592](https://github.com/codeceptjs/CodeceptJS/issues/592) by **[vkramskikh](https://github.com/vkramskikh)** +* **[WebDriverIO]** Fixed `seeNumberOfVisibleElements` by **[BorisOsipov](https://github.com/BorisOsipov)** [#574](https://github.com/codeceptjs/CodeceptJS/issues/574) +* Lots of fixes for promise chain by **[APshenkin](https://github.com/APshenkin)** [#568](https://github.com/codeceptjs/CodeceptJS/issues/568) + * Fix [#543](https://github.com/codeceptjs/CodeceptJS/issues/543)- After block not properly executed if Scenario fails + * Expected behavior in promise chains: `_beforeSuite` hooks from helpers -> `BeforeSuite` from test -> `_before` hooks from helpers -> `Before` from test - > Test steps -> `_failed` hooks from helpers (if test failed) -> `After` from test -> `_after` hooks from helpers -> `AfterSuite` from test -> `_afterSuite` hook from helpers. + * if during test we got errors from any hook (in test or in helper) - stop complete this suite and go to another + * if during test we got error from Selenium server - stop complete this suite and go to another + * [WebDriverIO][Protractor] if `restart` option is false - close all tabs expect one in `_after`. + * Complete `_after`, `_afterSuite` hooks even After/AfterSuite from test was failed + * Don't close browser between suites, when `restart` option is false. We should start browser only one time and close it only after all tests. + * Close tabs and clear local storage, if `keepCookies` flag is enabled +* Fix TypeError when using babel-node or ts-node on node.js 7+ [#586](https://github.com/codeceptjs/CodeceptJS/issues/586) by **[vkramskikh](https://github.com/vkramskikh)** +* **[Nightmare]** fixed usage of `_locate` + +Special thanks to **Andrey Pshenkin** for his work on this release and the major improvements. + +## 0.6.3 + +* Errors are printed in non-verbose mode. Shows "Selenium not started" and other important errors. +* Allowed to set custom test options: + +```js +Scenario('My scenario', { build_id: 123, type: 'slow' }, function (I) +``` +those options can be accessed as `opts` property inside a `test` object. Can be used in custom listeners. + +* Added `docs` directory to a package. +* [WebDriverIO][Protractor][SeleniumWebdriver] Bugfix: cleaning session when `restart: false` by **[tfiwm](https://github.com/tfiwm)** [#519](https://github.com/codeceptjs/CodeceptJS/issues/519) +* [WebDriverIO][Protractor][Nightmare] Added second parameter to `saveScreenshot` to allow a full page screenshot. By **[HughZurname](https://github.com/HughZurname)** +* Added suite object to `suite.before` and `suite.after` events by **[implico](https://github.com/implico)**. [#496](https://github.com/codeceptjs/CodeceptJS/issues/496) + +## 0.6.2 + +* Added `config` object to [public API](http://codecept.io/hooks/#api) +* Extended `index.js` to include `actor` and `helpers`, so they could be required: + +```js +const actor = require('codeceptjs').actor; +``` + +* Added [example for creating custom runner](http://codecept.io/hooks/#custom-runner) with public API. +* run command to create `output` directory if it doesn't exist +* **[Protractor]** fixed loading globally installed Protractor +* run-multiple command improvements: + * create output directories for each process + * print process ids in output + +## 0.6.1 + +* Fixed loading hooks + +## 0.6.0 + +Major release with extension API and parallel execution. + +* **Breaking** Removed path argument from `run`. To specify path other than current directory use `--config` or `-c` option: + +Instead of: `codeceptjs run tests` use: + +``` +# load config and run from tests directory +codeceptjs run -c tests/ + +# or load codecept.json from tests directory +codeceptjs run -c tests/codecept.json + +# run users_test.js inside tests directory +codeceptjs run users_test.js -c tests +``` + +* **Command `multiple-run` added**, to execute tests in several browsers in parallel by **[APshenkin](https://github.com/APshenkin)** and **[davertmik](https://github.com/davertmik)**. [See documentation](http://codecept.io/advanced/#multiple-execution). +* **Hooks API added to extend CodeceptJS** with custom listeners and plugins. [See documentation](http://codecept.io/hooks/#hooks_1). +* [Nightmare][WebDriverIO] `within` can work with iframes by **[imvetri](https://github.com/imvetri)**. [See documentation](http://codecept.io/acceptance/#iframes). +* [WebDriverIO][SeleniumWebdriver][Protractor] Default browser changed to `chrome` +* **[Nightmare]** Fixed globally locating `nightmare-upload`. +* **[WebDriverIO]** added `seeNumberOfVisibleElements` method by **[elarouche](https://github.com/elarouche)**. +* Exit with non-zero code if init throws an error by **[rincedd](https://github.com/rincedd)** +* New guides published: + * [Installation](http://codecept.io/installation/) + * [Hooks](http://codecept.io/hooks/) + * [Advanced Usage](http://codecept.io/advanced/) +* Meta packages published: + * [codecept-webdriverio](https://www.npmjs.com/package/codecept-webdriverio) + * [codecept-protractor](https://www.npmjs.com/package/codecept-protractor) + * [codecept-nightmare](https://www.npmjs.com/package/codecept-nightmare) + + +## 0.5.1 + +* [Polish translation](http://codecept.io/translation/#polish) added by **[limes](https://github.com/limes)**. +* Update process exit code so that mocha saves reports before exit by **[romanovma](https://github.com/romanovma)**. +* **[Nightmare]** fixed `getAttributeFrom` for custom attributes by **[robrkerr](https://github.com/robrkerr)** +* **[Nightmare]** Fixed *UnhandledPromiseRejectionWarning error* when selecting the dropdown using `selectOption` by **[robrkerr](https://github.com/robrkerr)**. [Se PR. +* **[Protractor]** fixed `pressKey` method by **[romanovma](https://github.com/romanovma)** + +## 0.5.0 + +* Protractor ^5.0.0 support (while keeping ^4.0.9 compatibility) +* Fix 'fullTitle() is not a function' in exit.js by **[hubidu](https://github.com/hubidu)**. See [#388](https://github.com/codeceptjs/CodeceptJS/issues/388). +* **[Nightmare]** Fix for `waitTimeout` by **[HughZurname](https://github.com/HughZurname)**. See [#391](https://github.com/codeceptjs/CodeceptJS/issues/391). Resolves [#236](https://github.com/codeceptjs/CodeceptJS/issues/236)* Dockerized CodeceptJS setup by **[artiomnist](https://github.com/artiomnist)**. [See reference](https://github.com/codeceptjs/CodeceptJS/blob/master/docker/README.md) + +## 0.4.16 + +* Fixed steps output synchronization (regression since 0.4.14). +* [WebDriverIO][Protractor][SeleniumWebdriver][Nightmare] added `keepCookies` option to keep cookies between tests with `restart: false`. +* **[Protractor]** added `waitForTimeout` config option to set default waiting time for all wait* functions. +* Fixed `_test` hook for helpers by **[cjhille](https://github.com/cjhille)**. + +## 0.4.15 + +* Fixed regression in recorder sessions: `oldpromise is not defined`. + +## 0.4.14 + +* `_beforeStep` and `_afterStep` hooks in helpers are synchronized. Allows to perform additional actions between steps. + +Example: fail if JS error occur in custom helper using WebdriverIO: + +```js +_before() { + this.err = null; + this.helpers['WebDriverIO'].browser.on('error', (e) => this.err = e); +} + +_afterStep() { + if (this.err) throw new Error('Browser JS error '+this.err); +} +``` + +Example: fail if JS error occur in custom helper using Nightmare: + +```js +_before() { + this.err = null; + this.helpers['Nightmare'].browser.on('page', (type, message, stack) => { + this.err = `${message} ${stack}`; + }); +} + +_afterStep() { + if (this.err) throw new Error('Browser JS error '+this.err); +} +``` + +* Fixed `codecept list` and `codecept def` commands. +* Added `I.say` method to print arbitrary comments. + +```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'); +``` + +* **[Nightmare]** `restart` option added. `restart: false` allows to run all tests in a single window, disabled by default. By **[nairvijays99](https://github.com/nairvijays99)** +* **[Nightmare]** Fixed `resizeWindow` command. +* [Protractor][SeleniumWebdriver] added `windowSize` config option to resize window on start. +* Fixed "Scenario.skip causes 'Cannot read property retries of undefined'" by **[MasterOfPoppets](https://github.com/MasterOfPoppets)** +* Fixed providing absolute paths for tests in config by **[lennym](https://github.com/lennym)** + +## 0.4.13 + +* Added **retries** option `Feature` and `Scenario` to rerun fragile tests: + +```js +Feature('Complex JS Stuff', {retries: 3}); + +Scenario('Not that complex', {retries: 1}, (I) => { + // test goes here +}); +``` + +* Added **timeout** option `Feature` and `Scenario` to specify timeout. + +```js +Feature('Complex JS Stuff', {timeout: 5000}); + +Scenario('Not that complex', {timeout: 1000}, (I) => { + // test goes here +}); +``` + +* **[WebDriverIO]** Added `uniqueScreenshotNames` option to set unique screenshot names for failed tests. By **[APshenkin](https://github.com/APshenkin)**. See [#299](https://github.com/codeceptjs/CodeceptJS/issues/299) +* **[WebDriverIO]** `clearField` method improved to accept name/label locators and throw errors. +* [Nightmare][SeleniumWebdriver][Protractor] `clearField` method added. +* **[Nightmare]** Fixed `waitForElement`, and `waitForVisible` methods. +* **[Nightmare]** Fixed `resizeWindow` by **[norisk-it](https://github.com/norisk-it)** +* Added italian [translation](http://codecept.io/translation/#italian). + +## 0.4.12 + +* Bootstrap / Teardown improved with [Hooks](http://codecept.io/configuration/#hooks). Various options for setup/teardown provided. +* Added `--override` or `-o` option for runner to dynamically override configs. Valid JSON should be passed: + +``` +codeceptjs run -o '{ "bootstrap": "bootstrap.js"}' +codeceptjs run -o '{ "helpers": {"WebDriverIO": {"browser": "chrome"}}}' +``` + +* Added [regression tests](https://github.com/codeceptjs/CodeceptJS/tree/master/test/runner) for codeceptjs tests runner. + +## 0.4.11 + +* Fixed regression in 0.4.10 +* Added `bootstrap`/`teardown` config options to accept functions as parameters by **[pscanf](https://github.com/pscanf)**. See updated [config reference](http://codecept.io/configuration/) [#319](https://github.com/codeceptjs/CodeceptJS/issues/319) + +## 0.4.10 + +* **[Protractor]** Protrctor 4.0.12+ support. +* Enabled async bootstrap file by **[abachar](https://github.com/abachar)**. Use inside `bootstrap.js`: + +```js +module.exports = function(done) { + // async instructions + // call done() to continue execution + // otherwise call done('error description') +} +``` + +* Changed 'pending' to 'skipped' in reports by **[timja-kainos](https://github.com/timja-kainos)**. See [#315](https://github.com/codeceptjs/CodeceptJS/issues/315) + +## 0.4.9 + +* [SeleniumWebdriver][Protractor][WebDriverIO][Nightmare] fixed `executeScript`, `executeAsyncScript` to work and return values. +* [Protractor][SeleniumWebdriver][WebDriverIO] Added `waitForInvisible` and `waitForStalenessOf` methods by **[Nighthawk14](https://github.com/Nighthawk14)**. +* Added `--config` option to `codeceptjs run` to manually specify config file by **[cnworks](https://github.com/cnworks)** +* **[Protractor]** Simplified behavior of `amOutsideAngularApp` by using `ignoreSynchronization`. Fixes [#278](https://github.com/codeceptjs/CodeceptJS/issues/278) +* Set exit code to 1 when test fails at `Before`/`After` hooks. Fixes [#279](https://github.com/codeceptjs/CodeceptJS/issues/279) + + +## 0.4.8 + +* [Protractor][SeleniumWebdriver][Nightmare] added `moveCursorTo` method. +* [Protractor][SeleniumWebdriver][WebDriverIO] Added `manualStart` option to start browser manually in the beginning of test. By **[cnworks](https://github.com/cnworks)**. [PR[#250](https://github.com/codeceptjs/CodeceptJS/issues/250) +* Fixed `codeceptjs init` to work with nested directories and file masks. +* Fixed `codeceptjs gt` to generate test with proper file name suffix. By **[Zougi](https://github.com/Zougi)**. +* **[Nightmare]** Fixed: Error is thrown when clicking on element which can't be locate. By **[davetmik](https://github.com/davetmik)** +* **[WebDriverIO]** Fixed `attachFile` for file upload. By **[giuband](https://github.com/giuband)** and **[davetmik](https://github.com/davetmik)** +* **[WebDriverIO]** Add support for timeouts in config and with `defineTimeouts` method. By **[easternbloc](https://github.com/easternbloc)** [#258](https://github.com/codeceptjs/CodeceptJS/issues/258) and [#267](https://github.com/codeceptjs/CodeceptJS/issues/267) by **[davetmik](https://github.com/davetmik)** +* Fixed hanging of CodeceptJS when error is thrown by event dispatcher. Fix by **[Zougi](https://github.com/Zougi)** and **[davetmik](https://github.com/davetmik)** + + +## 0.4.7 + +* Improved docs for `BeforeSuite`; fixed its usage with `restart: false` option by **[APshenkin](https://github.com/APshenkin)**. +* Added `Nightmare` to list of available helpers on `init`. +* **[Nightmare]** Removed double `resizeWindow` implementation. + +## 0.4.6 + +* Added `BeforeSuite` and `AfterSuite` hooks to scenario by **[APshenkin](https://github.com/APshenkin)**. See [updated documentation](http://codecept.io/basics/#beforesuite) + +## 0.4.5 + +* Fixed running `codecept def` command by **[jankaspar](https://github.com/jankaspar)** +* [Protractor][SeleniumWebdriver] Added support for special keys in `pressKey` method. Fixes [#216](https://github.com/codeceptjs/CodeceptJS/issues/216) + +## 0.4.4 + +* Interactive shell fixed. Start it by running `codeceptjs shell` +* Added `--profile` option to `shell` command to use dynamic configuration. +* Added `--verbose` option to `shell` command for most complete output. + +## 0.4.3 + +* **[Protractor]** Regression fixed to ^4.0.0 support +* Translations included into package. +* `teardown` option added to config (opposite to `bootstrap`), expects a JS file to be executed after tests stop. +* [Configuration](http://codecept.io/configuration/) can be set via JavaScript file `codecept.conf.js` instead of `codecept.json`. It should export `config` object: + +```js +// inside codecept.conf.js +exports.config = { + // contents of codecept.json +} +``` +* Added `--profile` option to pass its value to `codecept.conf.js` as `process.profile` for [dynamic configuration](http://codecept.io/configuration#dynamic-configuration). +* Documentation for [StepObjects, PageFragments](http://codecept.io/pageobjects#PageFragments) updated. +* Documentation for [Configuration](http://codecept.io/configuration/) added. + +## 0.4.2 + +* Added ability to localize tests with translation [#189](https://github.com/codeceptjs/CodeceptJS/issues/189). Thanks to **[abner](https://github.com/abner)** + * **[Translation]** ru-RU translation added. + * **[Translation]** pt-BR translation added. +* **[Protractor]** Protractor 4.0.4 compatibility. +* [WebDriverIO][SeleniumWebdriver][Protractor] Fixed single browser session mode for `restart: false` +* Fixed using of 3rd party reporters (xunit, mocha-junit-reporter, mochawesome). Added guide. +* Documentation for [Translation](http://codecept.io/translation/) added. +* Documentation for [Reports](http://codecept.io/reports/) added. + +## 0.4.1 + +* Added custom steps to step definition list. See [#174](https://github.com/codeceptjs/CodeceptJS/issues/174) by **[jayS-de](https://github.com/jayS-de)** +* **[WebDriverIO]** Fixed using `waitForTimeout` option by **[stephane-ruhlmann](https://github.com/stephane-ruhlmann)**. See [#178](https://github.com/codeceptjs/CodeceptJS/issues/178) + +## 0.4.0 + +* **[Nightmare](http://codecept.io/nightmare) Helper** added for faster web testing. +* [Protractor][SeleniumWebdriver][WebDriverIO] added `restart: false` option to reuse one browser between tests (improves speed). +* **Protractor 4.0** compatibility. Please upgrade Protractor library. +* Added `--verbose` option for `run` command to log and print global promise and events. +* Fixed errors with shutting down and cleanup. +* Fixed starting interactive shell with `codeceptjs shell`. +* Fixed handling of failures inside within block + +## 0.3.5 + +* Introduced IDE autocompletion support for Visual Studio Code and others. Added command for generating TypeScript definitions for `I` object. Use it as + +``` +codeceptjs def +``` + +to generate steps definition file and include it into tests by reference. By **[kaflan](https://github.com/kaflan)** + +## 0.3.4 + +* **[Protractor]** version 3.3.0 comptaibility, NPM 3 compatibility. Please update Protractor! +* allows using absolute path for helpers, output, in config and in command line. By **[denis-sokolov](https://github.com/denis-sokolov)** +* Fixes 'Cannot read property '1' of null in generate.js:44' by **[seethislight](https://github.com/seethislight)** + +## 0.3.3 + +**Fixed global installation**. CodeceptJS can now locate globally located modules. +CodeceptJS is also recommended for local installation. +Depending on installation type additional modules (webdriverio, protractor, ...) will be loaded either from local or from global path. + +## 0.3.2 + +* Added `codeceptjs list` command which shows all available methods of `I` object. +* [Protractor][SeleniumWebdriver] fixed closing browser instances +* [Protractor][SeleniumWebdriver] `doubleClick` method added +* [WebDriverIO][Protractor][SeleniumWebdriver] `doubleClick` method to locate clickable elements by text, `context` option added. +* Fixed using assert in generator without yields [#89](https://github.com/codeceptjs/CodeceptJS/issues/89) + +## 0.3.1 + +* Fixed `init` command + +## 0.3.0 + +**Breaking Change**: webdriverio package removed from dependencies list. You will need to install it manually after the upgrade. +Starting from 0.3.0 webdriverio is not the only backend for running selenium tests, so you are free to choose between Protractor, SeleniumWebdriver, and webdriverio and install them. + +* **[Protractor] helper added**. Now you can test AngularJS applications by using its official library within the unigied CodeceptJS API! +* **[SeleniumWebdriver] helper added**. You can switch to official JS bindings for Selenium. +* **[WebDriverIO]** **updated to webdriverio v 4.0** +* **[WebDriverIO]** `clearField` method added by **[fabioel](https://github.com/fabioel)** +* **[WebDriverIO]** added `dragAndDrop` by **[fabioel](https://github.com/fabioel)** +* **[WebDriverIO]** fixed `scrollTo` method by **[sensone](https://github.com/sensone)** +* **[WebDriverIO]** fixed `windowSize: maximize` option in config +* **[WebDriverIO]** `seeElement` and `dontSeeElement` check element for visibility by **[fabioel](https://github.com/fabioel)** and **[davertmik](https://github.com/davertmik)** +* **[WebDriverIO]** `seeElementInDOM`, `dontSeeElementInDOM` added to check element exists on page. +* **[WebDriverIO]** fixed saving screenshots on failure. Fixes [#70](https://github.com/codeceptjs/CodeceptJS/issues/70) +* fixed `within` block doesn't end in output not [#79](https://github.com/codeceptjs/CodeceptJS/issues/79) + + +## 0.2.8 + +* **[WebDriverIO]** added `seeNumberOfElements` by **[fabioel](https://github.com/fabioel)** + +## 0.2.7 + +* process ends with exit code 1 on error or failure [#49](https://github.com/codeceptjs/CodeceptJS/issues/49) +* fixed registereing global Helper [#57](https://github.com/codeceptjs/CodeceptJS/issues/57) +* fixed handling error in within block [#50](https://github.com/codeceptjs/CodeceptJS/issues/50) + +## 0.2.6 + +* Fixed `done() was called multiple times` +* **[WebDriverIO]** added `waitToHide` method by **[fabioel](https://github.com/fabioel)** +* Added global `Helper` (alias `codecept_helper)`, object use for writing custom Helpers. Generator updated. Changes to [#48](https://github.com/codeceptjs/CodeceptJS/issues/48) + +## 0.2.5 + +* Fixed issues with using yield inside a test [#45](https://github.com/codeceptjs/CodeceptJS/issues/45) [#47](https://github.com/codeceptjs/CodeceptJS/issues/47) [#43](https://github.com/codeceptjs/CodeceptJS/issues/43) +* Fixed generating a custom helper. Helper class is now accessible with `codecept_helper` var. Fixes [#48](https://github.com/codeceptjs/CodeceptJS/issues/48) + +## 0.2.4 + +* Fixed accessing helpers from custom helper by **[pim](https://github.com/pim)**. + +## 0.2.3 + +* **[WebDriverIO]** fixed `seeInField` to work with single value elements like: input[type=text], textareas, and multiple: select, input[type=radio], input[type=checkbox] +* **[WebDriverIO]** fixed `pressKey`, key modifeiers (Control, Command, Alt, Shift) are released after the action + +## 0.2.2 + +Fixed generation of custom steps file and page objects. +Please replace `require('codeceptjs/actor')` to `actor` in your `custom_steps.js`. +Whenever you need to create `I` object (in page objects, custom steps, but not in tests) just call `actor()`; + +## 0.2.0 + +* **within** context hook added +* `--reporter` option supported +* **[WebDriverIO]** added features and methods: + - elements: `seeElement`, ... + - popups: `acceptPopup`, `cancelPopup`, `seeInPopup`,... + - navigation: `moveCursorTo`, `scrollTo` + - saving screenshots on failure; `saveScreenshot` + - cookies: `setCookie`, `seeCookie`, ... + - source: `seeInSource` + - form: `seeCheckboxIsChecked`, `selectOption` to support multiple selects + - keyboard: `appendField`, `pressKey` + - mouse: `rightClick` +* tests added +* **[WebDriverIO]** proxy configuration added by **[petehouston](https://github.com/petehouston)** +* **[WebDriverIO]** fixed `waitForText` method by **[roadhump](https://github.com/roadhump)**. Fixes [#11](https://github.com/codeceptjs/CodeceptJS/issues/11) +* Fixed creating output dir when it already exists on init by **[alfirin](https://github.com/alfirin)** +* Fixed loading of custom helpers + diff --git a/docs/commands.md b/docs/commands.md index c401369e3..c1132dd36 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -1,136 +1,238 @@ +--- +permalink: /commands +title: Commands +--- + # Commands ## Run -Executes tests. Requires `codecept.json` config to be present in provided path. +Executes tests. Requires `codecept.conf.js` config to be present in provided path. --- Run all tests from current dir -``` -codeceptjs run +```sh +npx codeceptjs run ``` -Run tests from `test` dir +Load config and run tests from `test` dir -``` -codeceptjs run test +```sh +npx codeceptjs run -c test ``` Run only tests with "signin" word in name +```sh +npx codeceptjs run --grep "signin" ``` -codeceptjs run --grep "signin" + +Run all tests without "@IEOnly" word in name + +```sh +npx codeceptjs run --grep "@IEOnly" --invert ``` Run single test [path to codecept.js] [test filename] -``` -codeceptjs run . github_test.js +```sh +npx codeceptjs run github_test.js ``` Run single test with steps printed -``` -codeceptjs run . github_test.js --steps +```sh +npx codeceptjs run github_test.js --steps ``` Run single test in debug mode -``` -codeceptjs run . github_test.js --debug +```sh +npx codeceptjs run github_test.js --debug ``` Run test with internal logs printed (global promises, and events). +```sh +npx codeceptjs run github_test.js --verbose ``` -codeceptjs run . github_test.js --verbose + +Select config file manually (`-c` or `--config` option) + +```sh +npx codeceptjs run -c my.codecept.conf.js +npx codeceptjs run --config path/to/codecept.json ``` -Select config file manually +Override config on the fly. Provide valid JSON which will be merged into current config: +```sh +npx codeceptjs run --override '{ "helpers": {"WebDriver": {"browser": "chrome"}}}' ``` -codeceptjs run --config my.codecept.conf.js` + +Run tests and produce xunit report: + +```sh +npx codeceptjs run --reporter xunit ``` -Override config on the fly. Provide valid JSON which will be merged into current config: +Use any of [Mocha reporters](https://github.com/mochajs/mocha/tree/master/lib/reporters) used. + +## Run Workers + +Run tests in parallel threads. ``` -codeceptjs run --override '{ "helpers": {"WebDriverIO": {"browser": "chrome"}}}' +npx codeceptjs run-workers 3 ``` -Run tests and produce xunit report: +## Run Rerun + +Run tests multiple times to detect and fix flaky tests. ``` -codeceptjs run --reporter xunit +npx codeceptjs run-rerun ``` -Use any of [Mocha reporters](https://github.com/mochajs/mocha/tree/master/lib/reporters) used. +For this command configuration is required: -## Init +```js +{ + // inside codecept.conf.js + rerun: { + // how many times all tests should pass + minSuccess: 2, + + // how many times to try to rerun all tests + maxReruns: 4, + } +} +``` + +Use Cases: + +* `minSuccess: 1, maxReruns: 5` - run all tests no more than 5 times, until first successful run. +* `minSuccess: 3, maxReruns: 5` - run all tests no more than 5 times, until reaching 3 successfull runs. +* `minSuccess: 10, maxReruns: 10` - run all tests exactly 10 times, to check their stability. + + +## Dry Run + +Prints test scenarios without executing them + +``` +npx codeceptjs dry-run +``` -Creates `codecept.json` file in current directory: +When passed `--steps` or `--debug` option runs tests, disabling all plugins and helpers, so you can get step-by-step report with no tests actually executed. ``` -codeceptjs init +npx codeceptjs dry-run --steps +``` + +If a plugin needs to be enabled in `dry-run` mode, pass its name in `-p` option: + +``` +npx codeceptjs dry-run --steps -p allure +``` + +To enable bootstrap script in dry-run mode, pass in `--bootstrap` option when running with `--steps` or `--debug` + +``` +npx codeceptjs dry-run --steps --bootstrap +``` + +## Run Multiple + +Run multiple suites. Unlike `run-workers` spawns processes to execute tests. +[Requires additional configuration](/advanced#multiple-browsers-execution) and can be used to execute tests in multiple browsers. + +```sh +npx codeceptjs run-multiple smoke:chrome regression:firefox +``` + +## Init + +Creates `codecept.conf.js` file in current directory: + +```sh +npx codeceptjs init ``` Or in provided path +```sh +npx codecept init test ``` -codecept init test + +## Migrate + +Migrate your current `codecept.json` to `codecept.conf.js` + +```sh +npx codeceptjs migrate ``` ## Shell Interactive shell. Allows to try `I.` commands in runtime -``` -codeceptjs shell +```sh +npx codeceptjs shell ``` ## Generators Create new test -``` -codeceptjs generate test +```sh +npx codeceptjs generate:test ``` Create new pageobject -``` -codeceptjs generate pageobject +```sh +npx codeceptjs generate:pageobject ``` Create new helper -``` -codeceptjs generate helper +```sh +npx codeceptjs generate:helper ``` ## TypeScript Definitions TypeScript Definitions allows IDEs to provide autocompletion when writing tests. -``` -codeceptjs def +```sh +npx codeceptjs def +npx codeceptjs def --config path/to/codecept.json ``` -Produces `steps.d.ts` file, which refrerenced in the very beginning of a test file. +After doing that IDE should provide autocompletion for `I` object inside `Scenario` and `within` blocks. -```js -/// -Feature('My new test'); -``` +Add optional parameter `output` (or shortcut `-o`), if you want to place your definition file in specific folder: -After doing that IDE should provide autocompletion for `I` object inside `Scenario` and `within` blocks. +```sh +npx codeceptjs def --output ./tests/typings +npx codeceptjs def -o ./tests/typings +``` ## List Commands -Prints all avialable methods of `I` to console +Prints all available methods of `I` to console + +```sh +npx codeceptjs list +``` + +## Local Environment Information + +Prints debugging information concerning the local environment +```sh +npx codeceptjs info ``` -codeceptjs list -``` \ No newline at end of file diff --git a/docs/community-helpers.md b/docs/community-helpers.md new file mode 100644 index 000000000..ef758229e --- /dev/null +++ b/docs/community-helpers.md @@ -0,0 +1,54 @@ +--- +permalink: /community-helpers +title: Community Helpers +editLink: false +--- + +# Community Helpers +> Share your helpers at our [Wiki Page](https://github.com/codeceptjs/CodeceptJS/wiki/Community-Helpers) + +Here is the list of helpers created by our community. +Please **add your own** by editing this page. + +## Email Checking + +* [MailCatcher](https://gist.github.com/schmkr/026732dfa1627b927ff3a08dc31ee884) - to check emails via Mailcatcher locally. +* [codeceptjs-mailhog-helper](https://github.com/tsuemura/codeceptjs-mailhog-helper) - to check emails via Mailhog locally. + +## Data Sources + +* [codeceptjs-httpmock](https://github.com/testphony/codeceptjs-httpMock) - a helper which wraps mockttp library to manage http mock in tests. +* [codeceptjs-http](https://github.com/testphony/codeceptjs-http) - a helper which wraps then-request library to process HTTP requests. It's alternative helper that provides more flexible request management. +* [codeceptjs-dbhelper](https://github.com/thiagodp/codeceptjs-dbhelper) - allows you to execute queries or commands to databases using database-js. + +## Cloud Providers +* [codeceptjs-saucehelper](https://github.com/puneet0191/codeceptjs-saucehelper/) - a helper which updates `Test Names` & `Test Results` on Saucelabs +* [codeceptjs-bshelper](https://github.com/PeterNgTr/codeceptjs-bshelper) - a helper which updates `Test Names` & `Test Results` on Browserstack +* [codeceptjs-tbhelper](https://github.com/testingbot/codeceptjs-tbhelper) - a helper which updates `Test Names` & `Test Results` on TestingBot + +## Integrations +* [codeceptjs-testrail](https://github.com/PeterNgTr/codeceptjs-testrail) - a plugin to integrate with [Testrail](https://www.gurock.com/testrail) + +## Visual-Testing +* [codeceptjs-resemblehelper](https://github.com/puneet0191/codeceptjs-resemblehelper) - a helper which helps with visual testing using resemble.js. +* [codeceptjs-applitoolshelper](https://www.npmjs.com/package/codeceptjs-applitoolshelper) - a helper which helps interaction with [Applitools](https://applitools.com) + +## Reporters +* [codeceptjs-rphelper](https://github.com/reportportal/agent-js-codecept) is a CodeceptJS helper which can publish tests results on ReportPortal after execution. +* [codeceptjs-xray-helper](https://www.npmjs.com/package/codeceptjs-xray-helper) is a CodeceptJS helper which can publish tests results on [XRAY](https://confluence.xpand-it.com/display/XRAYCLOUD/Import+Execution+Results+-+REST). +* [codeceptjs-slack-reporter](https://www.npmjs.com/package/codeceptjs-slack-reporter) Get a Slack notification when one or more scenarios fail. + +## Page Object Code Generator +* [codeceptjs-CodeGenerator](https://github.com/senthillkumar/CodeCeptJS-PageObject) is a CodeceptJS custom wrapper which can create page class with action methods from the page object file(JSON) and project setup(Folder Structure). + +## Browser request control +* [codeceptjs-resources-check](https://github.com/luarmr/codeceptjs-resources-check) Load a URL with Puppeteer and listen to the requests while the page is loading. Enabling count the number or check the sizes of the requests. + +## Assertion & Validations +* [codeceptjs-chai](https://www.npmjs.com/package/codeceptjs-chai) is a CodeceptJS helper which wraps +[chai](https://www.chaijs.com/) library to complete chai assertion steps with CodeceptJS logging. + +## Other + +* [codeceptjs-cmdhelper](https://github.com/thiagodp/codeceptjs-cmdhelper) allows you to run commands in the terminal/console +* [eslint-plugin-codeceptjs](https://www.npmjs.com/package/eslint-plugin-codeceptjs) Eslint rules for CodeceptJS. \ No newline at end of file diff --git a/docs/configuration.md b/docs/configuration.md index aa88428f4..481b5ee43 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,29 +1,59 @@ +--- +permalink: /configuration +title: Configuration +--- + # Configuration -CodeceptJS configuration is set in `codecept.js` file. +CodeceptJS configuration is set in `codecept.conf.js` file. After running `codeceptjs init` it should be saved in test root. Here is an overview of available options with their defaults: -* **tests**: `"./*_test.js"` - pattern to locate tests -* **include**: `{}` - actors and pageobjects to be registered in DI container and included in tests. +* **tests**: `"./*_test.js"` - pattern to locate tests. Allows to enter [glob pattern](https://github.com/isaacs/node-glob). +* **grep**: - pattern to filter tests by name +* **include**: `{}` - actors and page objects to be registered in DI container and included in tests. Accepts objects and module `require` paths * **timeout**: `10000` - default tests timeout * **output**: `"./output"` - where to store failure screenshots, etc * **helpers**: `{}` - list of enabled helpers * **mocha**: `{}` - mocha options, [reporters](http://codecept.io/reports/) can be configured here -* **name**: `"tests"` - test suite name (not used) -* **bootstrap**: `"./bootstrap.js"` - an option to run code _before_ tests are run. See [Hooks](#hooks)). -* **teardown**: - an option to run code _after_ tests are run. See [Hooks](#hooks)). -* **translation**: - [locale](http://codecept.io/translation/) to be used to print steps output, as well as used in source code. +* **multiple**: `{}` - multiple options, see [Multiple Execution](http://codecept.io/parallel#multiple-browsers-execution) +* **bootstrap**: `"./bootstrap.js"` - an option to run code _before_ tests are run. See [Hooks](http://codecept.io/hooks/#bootstrap-teardown)). +* **bootstrapAll**: `"./bootstrap.js"` - an option to run code _before_ all test suites are run when using the run-multiple mode. See [Hooks](http://codecept.io/hooks/#bootstrap-teardown)). +* **teardown**: - an option to run code _after_ all test suites are run when using the run-multiple mode. See [Hooks](http://codecept.io/hooks/#bootstrap-teardown). +* **teardownAll**: - an option to run code _after_ tests are run. See [Hooks](http://codecept.io/hooks/#bootstrap-teardown). +* **noGlobals**: `false` - disable registering global variables like `Actor`, `Helper`, `pause`, `within`, `DataTable` +* **hooks**: - include custom listeners to plug into execution workflow. See [Custom Hooks](http://codecept.io/hooks/#custom-hooks) +* **translation**: - [locale](http://codecept.io/translation/) to be used to print s teps output, as well as used in source code. +* **require**: `[]` - array of module names to be required before codecept starts. See [Require](#require) + + +## Require +Requires described module before run. This option is useful for assertion libraries, so you may `--require should` instead of manually invoking `require('should')` within each test file. It can be used with relative paths, e.g. `"require": ["/lib/somemodule"]`, and installed packages. + +You can register ts-node, so you can use Typescript in tests with ts-node package +```js +exports.config = { + tests: './*_test.js', + timeout: 10000, + output: '', + helpers: {}, + include: {}, + bootstrap: false, + mocha: {}, + // require modules + require: ["ts-node/register", "should"] +} +``` ## Dynamic Configuration By default `codecept.json` is used for configuration. You can override its values in runtime by using `--override` or `-o` option in command line, passing valid JSON as a value: -``` -codeceptjs run -o '{ "helpers": {"WebDriverIO": {"browser": "firefox"}}}' +```sh +codeceptjs run -o '{ "helpers": {"WebDriver": {"browser": "firefox"}}}' ``` You can also switch to JS configuration format for more dynamic options. @@ -34,7 +64,7 @@ codeceptjs run -o '{ "helpers": {"WebDriverIO": {"browser": "firefox"}}}' ```js exports.config = { helpers: { - WebDriverIO: { + WebDriver: { // load variables from the environment and provide defaults url: process.env.CODECEPT_URL || 'http://localhost:3000', @@ -42,12 +72,17 @@ exports.config = { key: process.env.CLOUDSERVICE_KEY, coloredLogs: true, - waitforTimeout: 10000 + waitForTimeout: 10000 } }, // don't build monolithic configs mocha: require('./mocha.conf.js') || {}, + include: { + I: './src/steps_file.js', + loginPage: './src/pages/login_page', + dashboardPage: new DashboardPage() + } // here goes config as it was in codecept.json // .... @@ -56,102 +91,50 @@ exports.config = { (Don't copy-paste this config, it's just demo) -## Hooks - -Hooks are implemented as `bootstrap` and `teardown` options in config. You can use them to prepare test environment before execution and cleanup after. -They can be used to launch stop webserver, selenium server, etc. There are different sync and async ways to define bootstrap and teardown functions. - -`bootstrap` and `teardown` options can be: - -* JS file, executed as is (synchronously). -* JS file exporting a function; If function accepts a callback is executed asynchronously. See example: - -Config (`codecept.json`): +If you prefer to store your configuration files in a different location, or with a different name, you can do that with `--config` or `-c: -```js - "bootstrap": "./bootstrap.js" +```sh +codeceptjs run --config=./path/to/my/config.js ``` -Bootstrap file (`bootstrap.js`): +## Common Configuration Patterns -```js -// bootstrap.js -var server = require('./app_server'); -module.exports = function(done) { - // on error call done('error description') to stop - if (!server.validateConfig()) { - done("Can't execute server with invalid config, tests stopped"); - } - // call done() to continue execution - server.launch(done); -} -``` - -Pass error description inside a callback (`done('error')`) to prevent test execution on bootstrap. +> 📺 [Watch this material](https://www.youtube.com/watch?v=onBnfo_rJa4&t=4s) on YouTube -* JS file exporting an object with `bootstrap` and (or) `teardown` methods for corresponding hooks. +[`@codeceptjs/configure` package](https://github.com/codeceptjs/configure) contains shared recipes for common configuration patterns. This allows to set meta-configuration, independent from a current helper enabled. -Config (`codecept.json`): +Install it and enable to easily switch to headless/window mode, change window size, etc. ```js - "bootstrap": "./bootstrap.js" - "teardown": "./bootstrap.js" -``` +const { setHeadlessWhen, setWindowSize } = require('@codeceptjs/configure'); -Bootstrap file (`bootstrap.js`): - -```js -// bootstrap.js -var server = require('./app_server'); -module.exports = { - bootstrap: function(done) { - server.launch(done); - }, - teardown: function(done) { - server.stop(done); - } -} -``` - -* JS function in case of dynamic config. If function accepts a callback is executed asynchronously. See example: - -Config JS (`codecept.conf.js`): - -```js -var server = require('./app_server'); +setHeadlessWhen(process.env.CI); +setWindowSize(1600, 1200); exports.config = { - bootstrap: function(done) { - server.launch(done); - }, - teardown: function(done) { - server.stop(done); - } // ... - // other config options } - ``` ## Profile -Using values from `process.profile` you can change the config dynamically. +Using `process.env.profile` you can change the config dynamically. It provides value of `--profile` option passed to runner. Use its value to change config value on the fly. For instance, with the config above we can change browser value using `profile` option -``` +```sh codeceptjs run --profile firefox ``` ```js exports.config = { helpers: { - WebDriverIO: { + WebDriver: { url: 'http://localhost:3000', // load value from `profile` - browser: process.profile || 'firefox' + browser: process.env.profile || 'firefox' } } diff --git a/docs/continuous-integration.md b/docs/continuous-integration.md new file mode 100644 index 000000000..4c8efff2e --- /dev/null +++ b/docs/continuous-integration.md @@ -0,0 +1,22 @@ +--- +permalink: /continuous-integration +title: Continuous Integration +--- + + + +# Continuous Integration + +> Help us improve this article. [Write how did you set up CodeceptJS for CI](https://codecept.discourse.group/c/CodeceptJS-issues-in-general/ci/9) and see your post listed here! + +Continuous Integration services allows you to delegate the control of running tests to external system. +CodeceptJS plays well with all types of CI even when there is no documentation on this topic, it is still easy to set up with any kind of hosted or cloud CI. +Our community prepared some valuable recipes for setting up CI systems with CodeceptJS. + +## Recipes + +* ### [CodeceptJS - Codefresh Integration](https://codecept.discourse.group/t/codeceptjs-codefresh-integration/) +* ### [CodeceptJS GitLab Integration](https://codecept.discourse.group/t/codeceptjs-gitlab-integration/) +* ### [CodeceptJS - Jenkins Integration](https://codecept.discourse.group/t/codeceptjs-jenkins-integration/) +* ### [CodeceptJS Integration with TeamCity](https://codecept.discourse.group/t/codeceptjs-integration-with-teamcity/) + diff --git a/docs/custom-helpers.md b/docs/custom-helpers.md new file mode 100644 index 000000000..23b4e19ba --- /dev/null +++ b/docs/custom-helpers.md @@ -0,0 +1,330 @@ +--- +permalink: /helpers +title: Custom Helpers +--- + +# Extending CodeceptJS With Custom Helpers + +Helper is the core concept of CodeceptJS. Helper is a wrapper on top of various libraries providing unified interface around them. + +Methods of Helper class will be available in tests in `I` object. This abstracts test scenarios from the implementation and allows switching between backends seamlessly. + +Functionality of CodeceptJS could be extended by writing custom helpers. + +Helpers can also be installed as Node packages and required by corresponding Node modules. + +You can either access core Helpers (and underlying libraries) or create a new from scratch. + +## Development + +Helpers can be created by running a generator command: + +```bash +npx codeceptjs gh +``` + +*(or `npx codeceptjs generate:helper`)* + +This command generates a basic helper and appends it to `helpers` section of config file: + +```js +helpers: { + WebDriver: { }, + MyHelper: { + require: './path/to/module' + } +} +``` + +Helpers are ES6 classes inherited from [corresponding abstract class](https://github.com/codeceptjs/CodeceptJS/blob/master/lib/helper.js). +Generated Helper will be added to `codecept.conf.js` config file. It should look like this: + +```js +const Helper = codecept_helper; + +class MyHelper extends Helper { + + // before/after hooks + _before() { + // remove if not used + } + + _after() { + // remove if not used + } + + // add custom methods here + // If you need to access other helpers + // use: this.helpers['helperName'] + +} + +module.exports = MyHelper; +``` + +All methods except those starting from `_` will be added to `I` object and treated as test actions. +Every method should return a value in order to be appended into promise chain. + +After writing your own custom helpers here you can always update CodeceptJS TypeScript Type Definitions running: + +```sh +npx codeceptjs def . +``` + +This way, if your tests are written with TypeScript, your IDE will be able to leverage features like autocomplete and so on. + +## WebDriver Example + +Next example demonstrates how to use WebDriver library to create your own test action. +Method `seeAuthentication` will use `client` instance of WebDriver to get access to cookies. +Standard NodeJS assertion library will be used (you can use any). + +```js +const Helper = codecept_helper; + +// use any assertion library you like +const assert = require('assert'); + +class MyHelper extends Helper { + /** + * checks that authentication cookie is set + */ + async seeAuthentication() { + // access current client of WebDriver helper + let client = this.helpers['WebDriver'].browser; + + // get all cookies according to http://webdriver.io/api/protocol/cookie.html + // any helper method should return a value in order to be added to promise chain + const res = await client.cookie(); + // get values + let cookies = res.value; + for (let k in cookies) { + // check for a cookie + if (cookies[k].name != 'logged_in') continue; + assert.equal(cookies[k].value, 'yes'); + return; + } + assert.fail(cookies, 'logged_in', "Auth cookie not set"); + } +} + +module.exports = MyHelper; +``` + +## Puppeteer Example + +Puppeteer has [nice and elegant API](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md) which you can use inside helpers. Accessing `page` instance via `this.helpers.Puppeteer.page` from inside a helper. + +Let's see how we can use [emulate](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pageemulateoptions) function to emulate iPhone browser in a test. + +```js +const Helper = codecept_helper; +const puppeteer = require('puppeteer'); +const iPhone = puppeteer.devices['iPhone 6']; + +class MyHelper extends Helper { + + async emulateIPhone() { + const { page } = this.helpers.Puppeteer; + await page.emulate(iPhone); + } + +} + +module.exports = MyHelper; +``` + +## Protractor Example + +Protractor example demonstrates usage of global `element` and `by` objects. +However `browser` should be accessed from a helper instance via `this.helpers['Protractor']`; +We also use `chai-as-promised` library to have nice assertions with promises. + +```js +const Helper = codecept_helper; + +// use any assertion library you like +const chai = require('chai'); +const chaiAsPromised = require('chai-as-promised'); +chai.use(chaiAsPromised); +const expect = chai.expect; + +class MyHelper extends Helper { + /** + * checks that authentication cookie is set + */ + seeInHistory(historyPosition, value) { + // access browser instance from Protractor helper + this.helpers['Protractor'].browser.refresh(); + + // you can use `element` as well as in protractor + const history = element.all(by.repeater('result in memory')); + + // use chai as promised for better assertions + // end your method with `return` to handle promises + return expect(history.get(historyPosition).getText()).to.eventually.equal(value); + } +} + +module.exports = MyHelper; +``` + +## Accessing Elements + +WebDriver, Puppeteer, Playwright, and Protractor drivers provide API for web elements. +However, CodeceptJS do not expose them to tests by design, keeping test to be action focused. +If you need to get access to web elements, it is recommended to implement operations for web elements in a custom helper. + +To get access for elements, connect to a corresponding helper and use `_locate` function to match web elements by CSS or XPath, like you usually do: + +### Acessing Elements in WebDriver + +```js +// inside a custom helper +async clickOnEveryElement(locator) { + const { WebDriver } = this.helpers; + const els = await WebDriver._locate(locator); + + for (let el of els) { + await el.click(); + } +} +``` +In this case an an instance of webdriverio element is used. +To get a [complete API of an element](https://webdriver.io/docs/api/) refer to webdriverio docs. + +### Accessing Elements in Playwright & Puppeteer + +Similar method can be implemented for Playwright & Puppeteer: + +```js +// inside a custom helper +async clickOnEveryElement(locator) { + const { Playwright } = this.helpers; + const els = await Playwright._locate(locator); + + for (let el of els) { + await el.click(); + } +} +``` + +In this case `el` will be an instance of [ElementHandle](https://playwright.dev/#version=master&path=docs%2Fapi.md&q=class-elementhandle) which is similar for Playwright & [Puppeteer](https://pptr.dev/#?product=Puppeteer&version=master&show=api-class-elementhandle). + +> ℹ There are more `_locate*` methods in each helper. Take a look on documentation of a helper you use to see which exact method it exposes. + +## Configuration + +Helpers should be enabled inside `codecept.json` or `codecept.conf.js` files. Command `generate helper` +does that for you, however you can enable them manually by placing helper to `helpers` section inside config file. +You can also pass additional config options to your helper from a config - **(please note, this example contains comments, while JSON format doesn't support them)**: + +```js +helpers: { + // here goes standard helpers: + // WebDriver, Protractor, Nightmare, etc... + // and their configuration + MyHelper: { + require: "./my_helper.js", // path to module + defaultHost: "http://mysite.com" // custom config param + } + +} +``` + +Config values will be stored inside helper in `this.config`. To get `defaultHost` value you can use + +```js +this.config.defaultHost +``` + +in any place of your helper. You can also redefine config options inside a constructor: + +```js +constructor(config) { + config.defaultHost += '/api'; + console.log(config.defaultHost); // http://mysite.com/api + super(config); +} +``` + +## Hooks + +Helpers may contain several hooks you can use to handle events of a test. +Implement corresponding methods to them. + +* `_init` - before all tests +* `_finishTest` - after all tests +* `_before` - before a test +* `_after` - after a test +* `_beforeStep` - before each step +* `_afterStep` - after each step +* `_beforeSuite` - before each suite +* `_afterSuite` - after each suite +* `_passed` - after a test passed +* `_failed` - after a test failed + +Each implemented method should return a value as they will be added to global promise chain as well. + +### Hook Usage Examples + +1) Failing if JS error occurs in WebDriver: + +```js +class JSFailure extends codecept_helper { + + _before() { + this.err = null; + this.helpers['WebDriver'].browser.on('error', (e) => this.err = e); + } + + _afterStep() { + if (this.err) throw new Error(`Browser JS error ${this.err}`); + } +} + +module.exports = JSFailure; +``` + +2) Wait for Ajax requests to complete after `click`: + +```js +class JSWait extends codecept_helper { + + _afterStep(step) { + if (step.name == 'click') { + var jqueryActive = () => jQuery.active == 0; + return this.helpers['WebDriver'].waitUntil(jqueryActive); + } + } +} + +module.exports = JSWait; +``` + +## Conditional Retries + +It is possible to execute global conditional retries to handle unforseen errors. +Lost connections and network issues are good candidates to be retried whenever they appear. + +This can be done inside a helper using the global [promise recorder](/hooks/#api): + +Example: Retrying rendering errors in Puppeteer. + +```js +_before() { + const recorder = require('codeceptjs').recorder; + recorder.retry({ + retries: 2, + when: err => err.message.indexOf('Cannot find context with specified id') > -1, + }); +} +``` + +`recorder.retry` acts similarly to `I.retry()` and accepts the same parameters. It expects the `when` parameter to be set so it would handle only specific errors and not to retry for every failed step. + +Retry rules are available in array `recorder.retries`. The last retry rule can be disabled by running `recorder.retries.pop()`; + +## Using Typescript + +With Typescript, just simply replacing `module.exports` with `export` for autocompletion. diff --git a/docs/data.md b/docs/data.md new file mode 100644 index 000000000..fefdfcf85 --- /dev/null +++ b/docs/data.md @@ -0,0 +1,375 @@ +--- +permalink: /data +title: Data Management +--- + +# Data Management + +> This chapter describes data management for external sources. If you are looking for using Data Sets in tests, see [Data Driven Tests](http://codecept.io/advanced/#data-drivern-tests) section* + +Managing data for tests is always a tricky issue. How isolate data between tests, how to prepare data for different tests, etc. +There are different approaches to solve it: + +1. reset database completely between tests +2. create unique non-intersecting data sets per each test +3. create and delete data for a test + +The most efficient way would be to allow test to control its data, i.e. the 3rd option. +However, accessing database directly is not a good idea as database vendor, schema and data are used by application internally and are out of scope of acceptance test. + +Today all modern web applications have REST or GraphQL API . So it is a good idea to use it to create data for a test and delete it after. +API is supposed to be a stable interface and it can be used by acceptance tests. CodeceptJS provides 4 helpers for Data Management via REST and GraphQL API. + +## REST + +[REST helper](http://codecept.io/helpers/REST/) allows sending raw HTTP requests to application. +This is a tool to make shortcuts and create your data pragmatically via API. However, it doesn't provide tools for testing APIs, so it should be paired with WebDriver, Nightmare or Protractor helpers for browser testing. + +Enable REST helper in the config. It is recommended to set `endpoint`, a base URL for all API requests. If you need some authorization you can optionally set default headers too. + +See the sample config: + +```js +helpers: { + REST: { + endpoint: "http://localhost/api/v1/", + defaultHeaders: { + 'Auth': '11111', + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + }, + WebDriver : { + url: 'http://localhost', + browser: 'chrome' + } +} +``` + +REST helper provides basic methods to send requests to application: + +```js +I.sendGetRequest() +I.sendPostRequest() +I.sendPutRequest() +I.sendPatchRequest() +I.sendDeleteRequest() +``` + +As well as a method for setting headers: `haveRequestHeaders`. + +Here is a usage example: + +```js +let postId = null; + +Scenario('check post page', async (I) => { + // valid access token + I.haveRequestHeaders({auth: '1111111'}); + // get the first user + let user = await I.sendGetRequest('/api/users/1'); + // create a post and save its Id + postId = await I.sendPostRequest('/api/posts', { author: user.id, body: 'some text' }); + // open browser page of new post + I.amOnPage('/posts/2.html'); + I.see('some text', 'p.body'); +}); + +// cleanup created data +After((I) => { + I.sendDeleteRequest('/api/posts/'+postId); +}); +``` + +This can also be used to emulate Ajax requests: + +```js +I.sendPostRequest('/update-status', {}, { http_x_requested_with: 'xmlhttprequest' }); +``` + +> See complete reference on [REST](http://codecept.io/helpers/REST) helper + +## GraphQL + +[GraphQL helper](http://codecept.io/helpers/GraphQL/) allows sending GraphQL queries and mutations to application, over Http. +This is a tool to make shortcuts and create your data pragmatically via GraphQL endpoint. However, it doesn't provide tools for testing the endpoint, so it should be paired with WebDriver, Nightmare or Protractor helpers for browser testing. + +Enable GraphQL helper in the config. It is recommended to set `endpoint`, the URL to which the requests go to. If you need some authorization you can optionally set default headers too. + +See the sample config: + +```js +helpers: { + GraphQL: { + endpoint: "http://localhost/graphql/", + defaultHeaders: { + 'Auth': '11111', + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + }, + WebDriver : { + url: 'http://localhost', + browser: 'chrome' + } +} +``` + +GraphQL helper provides two basic methods to queries and mutations to application: + +```js +I.sendQuery() +I.sendMutation() +``` + +As well as a method for setting headers: `haveRequestHeaders`. + +Here is a usage example: + +```js +let postData = null; + +Scenario('check post page', async (I) => { + // valid access token + I.haveRequestHeaders({auth: '1111111'}); + // get the first user + let response = await I.sendQuery('{ user(id:1) { id }}'); + let user = response.data; + // create a post and save its Id + response = await I.sendMutation( + 'mutation createPost($input: PostInput!) { createPost(input: $input) { id }}', + { + input : { + author: user.data.id, + body: 'some text', + } + }, + ); + postData = response.data.data['createPost']; + // open browser page of new post + I.amOnPage(`/posts/${postData.slug}.html`); + I.see(postData.body, 'p.body'); +}); + +// cleanup created data +After((I) => { + I.sendMutation( + 'mutation deletePost($permalink: /ID!) { deletePost(permalink: /$id) }', + { permalink: /postData.id}, + ); +}); +``` + +> See complete reference on [GraphQL](http://codecept.io/helpers/GraphQL) helper + +## Data Generation with Factories + +This concept is extended by: +- [ApiDataFactory](http://codecept.io/helpers/ApiDataFactory/) helper, and, +- [GraphQLDataFactory](http://codecept.io/helpers/GraphQLDataFactory/) helper. + +These helpers build data according to defined rules and use REST API or GraphQL mutations to store them and automatically clean them up after a test. + +Just define how many items of any kind you need and the data factory helper will create them for you. + +To make this work some preparations are required. + +At first, you need data generation libraries which are [Rosie](https://github.com/rosiejs/rosie) and [Faker](https://www.npmjs.com/package/faker). Faker can generate random names, emails, texts, and Rosie uses them +to generate objects using factories. + +Install rosie and faker to create a first factory: + +```js +npm i rosie faker --save-dev +``` + +Then create a module which will export a factory for an entity. +And add that module as a part of the configuration for the helper. + +Please look at the respective Factory sections for examples for factory modules and configuration. + +### API Data Factory + +This helper uses REST API to store the built data and automatically clean them up after a test, +The way for setting data for a test is as simple as writing: + +```js +// inside async function +let post = await I.have('post'); +I.haveMultiple('comment', 5, { postpermalink: /post.id}); +``` + +After completing the preparations under 'Data Generation with Factories', create a factory module which will export a factory. + +See the example providing a factory for User generation: + +```js +// factories/post.js +var Factory = require('rosie').Factory; +var faker = require('faker'); + +module.exports = new Factory() + .attr('name', () => faker.name.findName()) + .attr('email', () => faker.internet.email()); +``` + +Next is to configure helper to match factories with API: + +```js + ApiDataFactory: { + endpoint: "http://user.com/api", + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + factories: { + user: { + uri: "/users", + factory: "./factories/user" + } + } + } +``` + +Then, calling `I.have('user')` inside a test will create a new user for you. +This is done by sending POST request to `/api/users` URL. Response is returned and can be used in tests. + +At the end of a test ApiDataFactory will clean up created record for you. This is done by collecting +ids from crated records and running `DELETE /api/users/{id}` requests at the end of a test. +This rules can be customized in helper configuration. + +> See complete reference on [ApiDataFactory](http://codecept.io/helpers/ApiDataFactory) helper + +### GraphQL Data Factory + +The helper uses GraphQL mutations to store the built data and automatically clean them up after a test. +This way for setting data for a test is as simple as writing: + +```js +// inside async function +let post = await I.mutateData('createPost'); +I.mutateMultiple('createComment', 5, { postpermalink: /post.id}); +``` + + + +After completing the preparations under 'Data Generation with Factories', create a factory module which will export a factory. + +The object built by the factory is sent as the variables object along with the mutation. So make sure it matches the argument type as detailed in the GraphQL schema. You may want to pass a constructor to the factory to achieve that. + +See the example providing a factory for User generation: + +```js +// factories/post.js +var Factory = require('rosie').Factory; +var faker = require('faker'); + +module.exports = new Factory((buildObj) => { + return { + input: { ...buildObj }, + } +}) + .attr('name', () => faker.name.findName()) + .attr('email', () => faker.internet.email()); +``` + +Next is to configure helper to match factories with API: + +```js +GraphQLDataFactory: { + endpoint: "http://user.com/graphql", + cleanup: true, + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + factories: { + createUser: { + query: 'mutation createUser($input: UserInput!) { createUser(input: $input) { id name }}', + factory: './factories/users', + revert: (data) => ({ + query: 'mutation deleteUser($permalink: /ID!) { deleteUser(permalink: /$id) }', + variables: { id : data.id}, + }), + }, + } +``` + +Then, calling `I.mutateData('createUser')` inside a test will create a new user for you. +This is done by sending a GraphQL mutation request over Http to `/graphql` endpoint. Response is returned and can be used in tests. + +At the end of a test GraphQLDataFactory will clean up created record for you. This is done by collecting +data from crated records, creating deletion mutation objects by passing the data to the `revert` function provided, and sending deletion mutation objects as requests at the end of a test. +This behavior is according the `revert` function be customized in helper configuration. +The revert function returns an object, that contains the query for deletion, and the variables object to go along with it. + +> See complete reference on [GraphQLDataFactory](http://codecept.io/helpers/GraphQLDataFactory) helper + +## Requests Using Browser Session + +All the REST, GraphQL, GraphQLDataFactory, and ApiDataFactory helpers allow override requests before sending. +This feature can be used to fetch current browser cookies and set them to REST API or GraphQL client. +By doing this we can make requests within the current browser session without a need of additional authentication. + +> Sharing browser session with ApiDataFactory or GraphQLDataFactory can be especially useful when you test Single Page Applications + +Since CodeceptJS 2.3.3 there is a simple way to enable shared session for browser and data helpers. +Install [`@codeceptjs/configure`](https://github.com/codeceptjs/configure) package: + +``` +npm i @codeceptjs/configure --save +``` + +Import `setSharedCookies` function and call it inside a config: + +```js +// in codecept.conf.js +const { setSharedCookies } = require('@codeceptjs/configure'); + +// share cookies between browser helpers and REST/GraphQL +setSharedCookies(); + +exports.config = {} +``` + +Without `setSharedCookies` you will need to update the config manually, so a data helper could receive cookies from a browser to make a request. If you would like to configure this process manually, here is an example of doing so: + +```js + +let cookies; // share cookies + +exports.config = { +helpers: { + ApiDataFactory: { + endpoint: 'http://local.app/api', + cleanup: true, + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + factories: { + user: { + uri: "/users", + factory: "./factories/user", + } + }, + onRequest: async (request) => { + // get a cookie if it's not obtained yet + if (cookies) cookies = await codeceptjs.container.helpers('WebDriver').grabCookie(); + // add cookies to request for a current request + request.headers = { Cookie: cookies.map(c => `${c.name}=${c.value}`).join('; ') }; + }, + } + WebDriver: { + url: 'https://local.app/', + browser: 'chrome', + } +} +``` + +In this case we are accessing WebDriver helper. However, you can replace WebDriver with any helper you use. + +The same can be done with GraphQLDataFactory. + +The order of helpers is important! ApiDataFactory will clean up created users after a test, +so it needs browser to be still opened to obtain its cookies. diff --git a/docs/detox.md b/docs/detox.md new file mode 100644 index 000000000..8787599e7 --- /dev/null +++ b/docs/detox.md @@ -0,0 +1,235 @@ +--- +permalink: /detox +title: Testing React Native with Detox +--- + +> Warning! Detox support in CodeceptJS is experimental. Please try it and help us to test it and improve it. [See Detox helper repository](https://github.com/codeceptjs/detox-helper). + +Automated mobile testing can be slow, hard, and ineffective. The price of it goes high, if we take into account fragility of applications, slowness of emulators, and the complexity of debug. [Appium](/mobile) helps writing mobile tests but not all apps can be tested effectively with it. That's why you should consider using an alternative approach. + +Meet [Detox](https://github.com/wix/Detox) - grey-box testing solution for mobile testing by Wix. + +Unlike, Appium, Detox requires to update mobile application to include test instrumentation, so an application could receive commands from a test, and act accordingly. Let's see pros and cons of such approach: + + +**Pros**: + +* faster tests +* synchronization with application +* plays nicely with React Native + +**Cons**: + +* application should be built in a special way +* no hybrid applications +* native Android apps not supported (except React Native) +* no cloud testing with SauceLabs or BrowserStack + +CodeceptJS allows you to try different options and choose the one which works best for you. Both Appium and Detox helpers share the same syntax for testing mobile applications, interactive pause, automatic retries, and other useful features. + +CodeceptJS provides next features over standard Detox: + +* **Unified API**. The same test can be executed in Appium or Detox. Unified API helps different teams to use the same syntax and easy port tests from one engine to another. +* [Interactive pause](/basics#pause). When starting/stopping an application takes a long time, debugging and writing tests can be hard. CodeceptJS solves this by pausing an execution and letting you try different commands and locators. With this feature a test can be writtern during one running session. +* [Auto-retries](/basics#retries) using `retryFailedStepPlugin` and `I.retry()` +* **Cross-Platform testing** - one test can be executed on different engines. When needed, platform-specific actions and locators can be easily applied. + +## A Test + +Compare a test written for Detox using its native syntax: + +```js +await expect(element(by.text('Welcome'))).toBeVisible(); +await expect(element(by.id('createdAndVisibleText'))).toNotExist(); +await element(by.id('GoButton')).tap(); +await waitFor(element(by.id('createdAndVisibleText'))).toExist().withTimeout(20000); +await expect(element(by.id('createdAndVisibleText'))).toExist(); +``` + +with the same test written using CodeceptJS syntax: + +```js +I.see('Welcome'); +I.dontSeeElement('#createdAndVisibleText'); +I.click('#GoButton'); +I.waitForElement('#createdAndVisibleText', 20); +I.seeElement('#createdAndVisibleText'); +``` + +As you see, CodeceptJS test is shorter and easier to follow. By simplifying the code and reducing visual noise we make tests easier to follow. But before writing a test we need to prepare an application to be testable with Detox. + +## Setup + +It is important to follow [Detox guide](https://github.com/wix/Detox/blob/master/docs/Introduction.GettingStarted.md) to build an application with Detox test instrouments included. + +After you install Detox, create configuration and build an application using `detox build` command, you are ready to integrate Detox with CodeceptJS. + +You need to install Detox CodeceptJS helper: + +``` +npm i @codeceptjs/detox-helper --save-dev +``` + +Then enable this helper in `codecept.conf.js`: + +```js +helpers: { + Detox: { + require: '@codeceptjs/detox-helper', + configuration: '', + reloadReactNative: true, + } +} +``` + +Enable `reloadReactNative: true` if you test React Native application. + +## Actions + +Create test as usual, by running command: + +``` +npx codeceptjs gt +``` + +A test starts when emulator starts and loads an application. So you can begin testing an application. + +```js +// inside a created test +Scenario('test React Native app', (I) => { + I.see('Welcome'); + I.tap('Start'); + I.see('Started!'); +}); +``` + +The most common actions are: + +* `tap` (or `click`) +* `multiTap` - perform multiple taps on element +* `longPress` - longer press +* `fillField` - fill in value of text field +* `clearField` - clear value in text field +* `appendField` - append value in a field +* `swipeUp`, `swipeDown`, `swipeLeft`, `swipeRigth` + +There are also common assertions: + +* `see` - to check visibility of text +* `seeElement` - to check visibility of element +* `seeElementExists` - to check that element exists + +> For more details on actions refer to the [API reference of Detox helper](https://github.com/codeceptjs/detox-helper#api). + +## Locators + +To write a test you need to learn about available locators in Detox. +Unlike, Appium there are no XPath locators. Possible locators limited to `text`, `id`, `accessibility id`, and element `type`. Thus, again, an application should be prepared for testing, to ensure that all active elements are accessible. + +Let's see how they can be used: + +* For **ID locators** use `#` prefix (same as in CSS). Example: + +```js +I.seeElement('#WelcomeScreen') +``` +* For **accessibility ID** use `~` prefix (as in Appium helper). Example: + +```js +I.seeElement('~welcome') +``` + +* Locating elements **by text** requires no prefix, but can be applied only for actions accepting semantic locators. + +```js +I.tap('Start') +I.fillField('Username', 'davert') +I.clearField('Username') +I.see('Welcome, davert') +``` + +* Locating elements **by type** also use no prefix but can be used only where for elements. + +```js +I.seeElement('Button') +``` + +Text locators can be combined with others, as methods `tap`, `click` and `see` can receive a second paramater, which defines a context where to perfrom a search. + +```js +// tap "Start" inside "#Layout" +I.tap('Start', '#Layout'); +// see text "Welcome" inside "~msg" +I.see('Welcome', '~msg'); +``` + +Alternatively, you can use specify locator by using *strict locator*, passing an object as a locator: + +```js +I.click({ type: 'Button' }); +I.seeElement({ label: 'welcome' }); +``` + +> If you are familiar with Detox API, this is how locators are actually translated: `{label: 'welcome'}` => `by.label('welcome')`. + +### Cross Platform Testing + +If element differs on on iOS and Android you can use **cross platform locators**. + +```js +// locate element by text on Android +// locate element by accessibility id on iOS +I.click({ android: /'Start', ios: '~start' }); +``` + +When application behavior differs on Android and iOS use platform-specific actions: + +```js +I.runOnIOS(() => { + // this will be executed only on IOS + I.see('Hello iOS'); +}); +I.runOnAndroid(() => { + // this will be executed only on Android + I.see('Hello Android'); +}); +``` + +### Sample Test + +Finally, you can get a test looking like this + +```js +Feature('My Detox App'); + +Scenario('save in application', (I) => { + I.setLandscapeOrientation(); + I.fillField('#text', 'a new text'); + I.see('a new text', '#textValue'); + I.dontSeeElement('#createdAndVisibleText'); + I.click({ ios: '#GoButton', android: /'Button' }); + I.waitForElement('#createdAndVisibleText', 20); + I.seeElement('#createdAndVisibleText'); + I.runOnAndroid(() => { + I.click('Save'); + I.see('Text Saved', '#message'); + }); + I.runOnIOS(() => { + I.click('SAVE'); + I.see('SAVED!'); + }); +}); +``` + +To execute it use `codeceptjs run` command + +``` +npx codeceptjs run +``` +If you want to use detox configuration other than is set in `codecept.conf.js` use `--configuration` argument: + +``` +npx codeceptjs run --configuration android.test.ci +``` + +You can also pass all [other arguments that Detox CLI supports](https://github.com/wix/Detox/blob/master/docs/APIRef.DetoxCLI.md#test). diff --git a/docs/docker.md b/docs/docker.md new file mode 100644 index 000000000..44362a70f --- /dev/null +++ b/docs/docker.md @@ -0,0 +1,137 @@ +# Codeceptjs Docker + +CodeceptJS packed into container with the Nightmare, Protractor, Puppeteer, and WebDriverIO drivers. + +## How to Use + +This image comes with the necessary dependencies and packages to execute CodeceptJS tests. +Mount in your CodeceptJS config directory into the `/tests` directory in the docker container. + +Sample mount: `-v path/to/codecept.conf.js:/tests` + +CodeceptJS runner is available inside container as `codeceptjs`. + +### Locally + +You can execute CodeceptJS with Puppeteer or Nightmare locally with no extra configuration. + +```sh +docker run --net=host -v $PWD:/tests codeception/codeceptjs +``` + +To customize execution call `codeceptjs` command: + +```sh +# run tests with steps +docker run --net=host -v $PWD:/tests codeception/codeceptjs codeceptjs run --steps + +# run tests with @user in a name +docker run --net=host -v $PWD:/tests codeception/codeceptjs codeceptjs run --grep "@user" +``` + + +### Docker Compose + +```yaml +version: '2' +services: + codeceptjs: + image: codeception/codeceptjs + depends_on: + - firefox + - web + volumes: + - .:/tests + web: + image: node + command: node app/server.js + volumes: + - .:/app + firefox: + image: selenium/standalone-firefox-debug:2.53.0 + ports: + - '4444' + - '5900' +``` + +### Linking Containers + +If using the Protractor or WebDriverIO drivers, link the container with a Selenium Standalone docker container with an alias of `selenium`. Additionally, make sure your `codeceptjs.conf.js` contains the following to allow CodeceptJS to identify where Selenium is running. + +```javascript + ... + helpers: { + WebDriverIO: { + ... + host: process.env.HOST + ... + } + } + ... +``` + +```sh +$ docker run -d -P --name selenium-chrome selenium/standalone-chrome + +# Alternatively, selenium/standalone-firefox can be used + +$ docker run -it --rm -v //:/tests/ --link selenium-chrome:selenium codeception/codeceptjs +``` + +You may run use `-v $(pwd)/:tests/` if running this from the root of your CodeceptJS tests directory. +_Note: The output of your test run will appear in your local directory if your output path is `./output` in the CodeceptJS config_ +_Note: If running with the Nightmare driver, it is not necessary to run a selenium docker container and link it. So `--link selenium-chrome:selenium` may be omitted_ + +### Build + +To build this image: + +```sh +docker build -t codeception/codeceptjs . +``` + +* this directory will be added as `/codecept` insde container +* tests directory is expected to be mounted as `/tests` +* `codeceptjs` is a synlink to `/codecept/bin/codecept.js` + +To build this image with your desired Node version: + +```sh +docker build -t codeception/codeceptjs . --build-arg NODE_VERSION=12.10.0 +``` + +### Passing Options + +Options can be passed by calling `codeceptjs`: + +``` +docker run -v $PWD:/tests codeception/codeceptjs codeceptjs run --debug +``` + +Alternatively arguments to `codecept run` command can be passed via `CODECEPT_ARGS` environment variable. For example to run your tests with debug +output: + +```yaml +version: '2' +services: + codeceptjs: + image: codeception/codeceptjs + environment: + - CODECEPT_ARGS=--debug + volumes: + - .:/tests +``` + +You can also use `run-workers`to run tests by passing `NO_OF_WORKERS`, additionally, you can pass more params like showing the debug info as the following example: + +```yaml +version: '2' +services: + codeceptjs: + image: codeception/codeceptjs + environment: + - NO_OF_WORKERS=3 + - CODECEPT_ARGS=--debug + volumes: + - .:/tests +``` diff --git a/docs/email.md b/docs/email.md new file mode 100644 index 000000000..795d0e491 --- /dev/null +++ b/docs/email.md @@ -0,0 +1,183 @@ +--- +permalink: /email +title: Email Testing +--- + +# Email Testing + +In End 2 End testing we need to interact with emails. +Email delivery can't tested locally or mocked while testing. +That's why for an end to end test you need to use a real emails to be sent and real email address to receive that emails. + +Setting up an email server can be hard. So we recommend to use a [MailSlurp](https://mailslurp.com/) - a service designed for testing emails. It creates disposable mailboxes and provides you an access to those mailboxes via REST API. + +> You no longer need to open your gmail account in a browser to check for an email! + +## Installation + +MailSlurp is a commercial service with a free plan available. To start, [create an account at MailSlurp](https://app.mailslurp.com/) and receive API key to use it. Once received install mailslurp helper from npm: + +``` +npm i @codeceptjs/mailslurp-helper --save-dev +``` + +Then enable a helper in `codecept.conf.js`: + +```js +helpers: { + + MailSlurp: { + require: '@codeceptjs/mailslurp-helper', + apiKey: '' + } +} +``` + +After a helper is added, regenerate TypeScript definitions for auto-completion support: + +``` +npx codeceptjs def +``` + +## Creating Mailbox + +MailSlurp allows you to create disposable mailboxes. It means that an email address is created for a one test only and is deleted afterwards. So you can be confident that no other emails are received at that address. + +To create a mailbox use `I.haveNewMailbox()` command: + +```js +// inside async/await function +const mailbox = await I.haveNewMailbox(); +``` + +mailbox object contains: + +* `id` - which is used in next commands +* `emailAddress` - randomly generated address of a created mailbox. + +> See [MailSlurp's guide](https://www.mailslurp.com/guides/getting-started/#create-email-addresses) for details. + +Mailbox is opened on creation. If you need more than one mailboxes and you want to switch between them use `openMailbox` method: + +```js +const mailbox1 = await I.haveNewMailbox(); +const mailbox2 = await I.haveNewMailbox(); +// mailbox2 is now default mailbox +// switch back to mailbox1 +I.openMailbox(mailbox); +``` + +## Receiving An Email + +A last created mailbox will be activated. It means that it will be used by default to check for emails. + +After an action that triggers sending an email is performed on a website you should wait for this email to be received. +A timeout for waiting an email can be set globally for a helper or for a one call. + +Use `waitForLatestEmail` function to return the first email from a mailbox: + +```js +// to wait for default time (10 secs by default) +I.waitForLatestEmail(); + +// or specify number of time to wait +I.waitForLatestEmail(30); +``` + +To specify the exact email to match use `waitForEmailMatching` function: + +```js +// wait for an email with partial match in subject +I.waitForEmailMatching({ subject: 'Restore password' }); + +// wait 30 seconds for email with exact subject +I.waitForEmailMatching({ subject: '=Forgot password' }, 30); + +// wait a last email from any address @mysite.com +I.waitForEmailMatching({ + from: '@mysite.com', // find anything from mysite + subject: 'Restore password', // with Restore password in subject +}); +``` + +## Opening An Email + +All wait* functions return a matched email as a result. So you can use it in a test: + +```js +const email = await I.waitForLatestEmail(); +``` +> Please note, that we use `await` to assign email. This should be declared inside async function + +An `email` object contains following fields: + +* `subject` +* `for` +* `to` +* `body` + +So you can analyze them inside a test. For instance, you can extract an URL from email body and open it. +This is how we can emulate "click on this link" behavior in email: + +```js +// clicking a link in email +const email = await I.waitForLatestEmail(); +// extract a link by RegExp +const url = email.body.match(/http(s):\/\/(.*?)\s/)[0]; +// open URL +I.amOnPage(url); +``` + +## Assertions + +Assertions are performed on the currently opened email.Email is opened on `waitFor` email call, however, you can open an exact email by using `openEmail` function. + +```js +const email1 = await I.waitForLatestEmail(); +// test proceeds... +const email2 = await I.waitForLatestEmail(); +I.openEmail(email1); // open previous email +``` + +After opening an email assertion methods are available. + +* `seeInEmailSubject` +* `seeEmailIsFrom` +* `seeInEmailBody` +* `dontSeeInEmailBody` +* `seeNumberOfEmailAttachments` +* `seeEmailAttachment` + +And here is an example of their usage: + +```js +I.waitForLatestEmail() +I.seeEmailIsFrom('@mysite.com'); +I.seeInEmailSubject('Awesome Proposal!'); +I.seeInEmailBody('To unsubscribe click here'); +I.seeNumberOfEmailAttachments(2); +I.seeEmailAttachment('Attachment_1.pdf') +I.seeEmailAttachment('Attachment_2.pdf') +``` + +> More methods are listed in [helper's API reference](https://github.com/codeceptjs/mailslurp-helper/blob/master/README.md#api) + +## Listing All Emails + +Use `grabAllEmailsFromMailbox` to get all emails from a current mailbox: + +```js +const emails = await I.grabAllEmailsFromMailbox(); +``` + +## Sending an Email + +You can also send an email from an active mailbox: + +```js +I.sendEmail({ + to: ['user@site.com'], + subject: 'Hello', + body: 'World' +}); +``` diff --git a/docs/examples.md b/docs/examples.md new file mode 100644 index 000000000..314a9c089 --- /dev/null +++ b/docs/examples.md @@ -0,0 +1,158 @@ +--- +permalink: /examples +layout: Section +sidebar: false +title: Examples +editLink: false +--- + +# Examples +> Add your own examples to our [Wiki Page](https://github.com/codeceptjs/CodeceptJS/wiki/Examples) +## [TodoMVC Examples](https://github.com/codecept-js/examples) + +![](https://github.com/codecept-js/examples/raw/master/todo.png) + +Playground repository where you can run tests in different helpers on a basic single-page website. + +Tests repository demonstrate usage of + +* Puppeteer helper +* WebDriver helper +* TestCafe plugin +* Toggle headless mode with env variables +* PageObjects +* Cucumber syntax + +## [Basic Examples](https://github.com/Codeception/CodeceptJS/tree/master/examples) + +CodeceptJS repo contains basic tests (both failing and passing) just to show how it works. +Our team uses it to test new features and run simple scenarios. + + +## [Testing Single Page Application](https://github.com/bugiratracker/codeceptjs-demo) + +![](https://user-images.githubusercontent.com/220264/56353972-56975080-61db-11e9-8b23-06e8b4620995.png) + +End 2 end tests for [Bugira Bugtracker](https://bugira.com) app built with Rails & EmberJS. Bugira is a SaaS application that helps collecting users' feedbacks and transforming them into professional bug reports. + +Tests repository demonstrate usage of + +* Puppeteer helper +* ApiDataFactory helper +* autoLogin plugin +* Dynamic config with profiles + +## [Practical E2E Tests](https://gitlab.com/paulvincent/codeceptjs-e2e-testing) + +Examples from the book [Practical End 2 End Testing with CodeceptJS](https://leanpub.com/codeceptjs/) by **Paul Vincent Beigang**. + +This repository demonstrates usage of: + +* dynamic config with profiles +* testing WYSIWYG editor +* GitLab CI + +## [CodeceptJS Cucumber E2E Framework](https://github.com/gkushang/codeceptjs-e2e) + +This repository contains complete E2E framework for CodeceptJS with Cucumber and SauceLabs Integration + +* CodecepJS-Cucumber E2E Framework +* Saucelabs Integration +* Run Cross Browser tests in Parallel on SauceLabs with a simple command +* Run tests on `chrome:headless` +* Page Objects +* `Should.js` Assertion Library +* Uses `wdio` service (selenium-standalone, sauce) +* Allure HTML Reports +* Uses shared Master configuration +* Sample example and feature files of GitHub Features + +## [Amazon Tests v2](https://gitlab.com/thanhnguyendh/codeceptjs-wdio-services) + +Testing Amazon website using Selenium WebDriver. + +This repository demonstrates usage of: + +* WebDriver helper +* Page Objects +* wdio services (selenium-standalone) +* Parallel execution +* GitLab CI setup + +## [Amazon Tests v1](https://github.com/PeterNgTr/amazon-ui-tests) + +Previous version of Amazon Tests, still valid but quite different. + +This repository demonstrates usage of: + +* WebDriver helper +* Page Objects +* Bootstrap and teardown +* Parallel execution + +## [Tests with Docker Compose](https://github.com/mathesouza/codeceptjs-docker-compose) + +Running CodeceptJS tests with Docker Compose + +This repository demonstrates usage of: + +* CodeceptJS Docker image +* WebDriver helper +* Allure plugin + + +## [ModusCreate Tests](https://github.com/ModusCreateOrg/codeceptjs-nightmare-harness) + +Test automation by ModusCreate agency with NightmareJS. + +This repository demonstrates usage of: + +* Nightmare helper +* Reports with Mochawesome +* Docker +* Page objects and page fragments + +## [AngularJS Example Tests](https://github.com/armno/angular-e2e-codeceptjs-example) + +Based on [Setting up End-to-End Testing in Angular Project with CodeceptJS](https://medium.com/@armno/setting-up-end-to-end-testing-in-angular-project-with-codeceptjs-ac1784de3420) post by Armno Prommarak. + +This repository demonstrates usage of + +* Puppeteer helper +* Working with Angular CLI +* Reports with Mochawesome helper + +## [REST Example Tests](https://github.com/PeterNgTr/codeceptjs-rest-demo) + +This repository demonstrates usage of + +* REST helper + +## [Automation Starter](https://github.com/sjorrillo/automation-starter) + +The purpose of this application is for learning the basics and how to use good practices and useful tools in automation. + +* Puppeteer helper +* Working with gherkin, also it has type definitions and to be able to use them inside when, given and then make sure you add `declare function inject(): { I: CodeceptJS.I, [key: string]: any; };`in the `steps.d.ts`file +* Linting `airbnb-base`, `codeceptjs/codeceptjs` and full ES6 support + +## [Example for using: Puppeteer, Gherkin, Allure with parallel execution](https://github.com/SchnuckySchuster/codeceptJSExample) + +This is a ready to use example that shows how to integrate CodeceptJS with Puppeteer and Allure as reporting tool. + +* detailed ReadMe +* tests written in cucumber alongside tests written in the codeceptJS DSL +* puppeteer helper example +* test steps, pages, fragments +* examples for sequential and parallel execution +* generation of allure test results + +## [Framework with UI and API test support : CodeceptJS , Puppeteer , REST , ESLint](https://github.com/avighub/CodeceptJS-puppeteer) +This is a basic framework with Puppeteer , REST helpers which can support both UI and API actions within same test. +More improvements and features will be added and will be updated. +Suggestions and improvements are welcome , please raise a ticket in Issue tab. + +* Step by step setup in README +* Two helpers are added. UI - Puppeteer , API - REST and chai-codeceptJS for assetion +* ESLint for code check +* Upcoming : API generic functions , Adaptor design pattern , More utilities \ No newline at end of file diff --git a/docs/helpers.md b/docs/helpers.md deleted file mode 100644 index 76a35463e..000000000 --- a/docs/helpers.md +++ /dev/null @@ -1,232 +0,0 @@ -# Helpers - -Helpers is a core concept of CodeceptJS. Helper is a wrapper around various libraries providing unified interface around them. -Methods of Helper class will be available in tests in `I` object. This abstracts test scenarios from the implementation and allows easy switching between backends. -Functionality of CodeceptJS should be extended by writing a custom helpers. - -You can either access core Helpers (and underlying libraries) or create a new from scratch. - -## Development - -Helpers can be created by running a generator command: - -```bash -codeceptjs gh -``` - -*(or `generate helper`)* - -This command generates a basic helper and appends it to `helpers` section of config file: - -```json -"helpers": { - "WebDriverIO": { }, - "MyHelper": { - "require": "./path/to/module.js" - } -} -``` - -Helpers are ES6 classes inherited from [corresponding abstract class](https://github.com/Codeception/CodeceptJS/blob/master/lib/helper.js). -Generated Helper will be added to `codecept.json` config. It should look like this: - -```js -'use strict'; - -let Helper = codecept_helper; - -class MyHelper extends Helper { - - // before/after hooks - _before() { - // remove if not used - } - - _after() { - // remove if not used - } - - // add custom methods here - // If you need to access other helpers - // use: this.helpers['helperName'] - -} - -module.exports = MyHelper; -``` - -All methods except those starting from `_` will be added to `I` object and treated as test actions. -Every method should return a value in order to be appended into promise chain. - -After writing your own custom helpers here you can always update CodeceptJS TypeScript Type Definitions running: - -``` -codeceptjs def . -``` - -This way, if your tests are written with TypeScript, your IDE will be able to leverage features like autocomplete and so on. - -## WebDriverIO Example - -Next example demonstrates how to use WebDriverIO library to create your own test action. -Method `seeAuthentication` will use `client` instance of WebDriverIO to get access to cookies. -Standard NodeJS assertion library will be used (you can use any). - -```js -'use strict'; -let Helper = codecept_helper; - -// use any assertion library you like -let assert = require('assert'); - -class MyHelper extends Helper { - /** - * checks that authentication cookie is set - */ - seeAuthentication() { - // access current client of WebDriverIO helper - let client = this.helpers['WebDriverIO'].browser; - - // get all cookies according to http://webdriver.io/api/protocol/cookie.html - // any helper method should return a value in order to be added to promise chain - return client.cookie(function(err, res) { - // get values - let cookies = res.value; - for (let k in cookies) { - // check for a cookie - if (cookies[k].name != 'logged_in') continue; - assert.equal(cookies[k].value, 'yes'); - return; - } - assert.fail(cookies, 'logged_in', "Auth cookie not set"); - }); - } -} - -module.exports = MyHelper; -``` - -## Protractor Example - -Protractor example demonstrates usage of global `element` and `by` objects. -However `browser` should be accessed from a helper instance via `this.helpers['Protractor']`; -We also use `chai-as-promised` library to have nice assertions with promises. - - -```js -'use strict'; -let Helper = codecept_helper; - -// use any assertion library you like -var chai = require('chai'); -var chaiAsPromised = require('chai-as-promised'); -chai.use(chaiAsPromised); -var expect = chai.expect; - -class MyHelper extends Helper { - /** - * checks that authentication cookie is set - */ - seeInHistory(historyPosition, value) { - // access browser instance from Protractor helper - this.helpers['Protractor'].browser.refresh(); - - // you can use `element` as well as in protractor - var history = element.all(by.repeater('result in memory')); - - // use chai as promised for better assertions - // end your method with `return` to handle promises - return expect(history.get(historyPosition).getText()).to.eventually.equal(value); - } -} - -module.exports = MyHelper; -``` - -## Configuration - -Helpers should be enabled inside `codecept.json` or `codecept.conf.js` files. Command `generate helper` -does that for you, however you can enable them manually by placing helper to `helpers` section inside config file. -You can also pass additional config options to your helper from a config: - -```js -"helpers": { - // here goes standard helpers: - // WebDriverIO, Protractor, Nightmare, etc... - // and their configuration - "MyHelper": { - "require": "./my_helper.js", // path to module - "defaultHost": "http://mysite.com" // custom config param - } - -} -``` -*(please note, this example contains comments, while JSON format doesn't support them)* - -Config values will be stored inside helper in `this.config`. To get `defaultHost` value you can use - -```js -this.config.defaultHost -``` - -in any place of your helper. You can also redefine config options inside a constructor: - -```js -constructor(config) { - config.defaultHost += '/api'; - console.log(config.defaultHost); // http://mysite.com/api - super(config); -} -``` - -## Hooks - -Helpers may contain several hooks you can use to handle events of a test. -Implement corresponding methods to them. - -* `_init` - before all tests -* `_before` - before a test -* `_beforeStep` - before each step -* `_afterStep` - after each step -* `_beforeSuite` - before each suite -* `_afterSuite` - after each suite - -Each implemented method should return a value as they will be added to global promise chain as well. - -### Hook Usage Examples - -1) Failing if JS error occur in WebDriverIO: - -```js -class JSFailure extends codecept_helper { - - _before() { - this.err = null; - this.helpers['WebDriverIO'].browser.on('error', (e) => this.err = e); - } - - _afterStep() { - if (this.err) throw new Error('Browser JS error '+this.err); - } -} - -module.exports = JSFailure; -``` - -2) Wait for Ajax requests to complete after `click`: - -```js -class JSWait extends codecept_helper { - - _afterStep(step) { - if (step.name == 'click') { - var jqueryActive = () => jQuery.active == 0; - return this.helpers['WebDriverIO'].waitUntil(jqueryActive); - } - } -} - -module.exports = JSWait; -``` - -### done() diff --git a/docs/helpers/ApiDataFactory.md b/docs/helpers/ApiDataFactory.md new file mode 100644 index 000000000..bb837d773 --- /dev/null +++ b/docs/helpers/ApiDataFactory.md @@ -0,0 +1,255 @@ +--- +permalink: /helpers/ApiDataFactory +editLink: false +sidebar: auto +title: ApiDataFactory +--- + + + +## ApiDataFactory + +**Extends Helper** + +Helper for managing remote data using REST API. +Uses data generators like [rosie][1] or factory girl to create new record. + +By defining a factory you set the rules of how data is generated. +This data will be saved on server via REST API and deleted in the end of a test. + +## Use Case + +Acceptance tests interact with a websites using UI and real browser. +There is no way to create data for a specific test other than from user interface. +That makes tests slow and fragile. Instead of testing a single feature you need to follow all creation/removal process. + +This helper solves this problem. +Most of web application have API, and it can be used to create and delete test records. +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}); +``` + +To make this work you need + +1. REST API endpoint which allows to perform create / delete requests and +2. define data generation rules + +### Setup + +Install [Rosie][1] and [Faker][2] libraries. + +```sh +npm i rosie faker --save-dev +``` + +Create a factory file for a resource. + +See the example for Posts factories: + +```js +// tests/factories/posts.js + +var Factory = require('rosie').Factory; +var faker = require('faker'); + +module.exports = new Factory() + // no need to set id, it will be set by REST API + .attr('author', () => faker.name.findName()) + .attr('title', () => faker.lorem.sentence()) + .attr('body', () => faker.lorem.paragraph()); +``` + +For more options see [rosie documentation][1]. + +Then configure ApiDataHelper to match factories and REST API: + +### Configuration + +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 + +See the example: + +```js + ApiDataFactory: { + endpoint: "http://user.com/api", + cleanup: true, + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + factories: { + post: { + uri: "/posts", + factory: "./factories/post", + }, + comment: { + factory: "./factories/comment", + create: { post: "/comments/create" }, + delete: { post: "/comments/delete/{id}" }, + fetchId: (data) => data.result.id + } + } +} +``` + +It is required to set REST API `endpoint` which is the baseURL for all API requests. +Factory file is expected to be passed via `factory` option. + +This Helper uses [REST][3] helper and accepts its configuration in "REST" section. +For instance, to set timeout you should add: + +```js +"ApiDataFactory": { + "REST": { + "timeout": "100000", + } +} +``` + +### Requests + +By default to create a record ApiDataFactory will use endpoint and plural factory name: + +- 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` + +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}" }` + +Requests can also be overridden with a function which returns [axois request config][4]. + +```js +create: (data) => ({ method: 'post', url: '/posts', data }), +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}` }; + } +``` + +### Responses + +By default `I.have()` returns a promise with a created data: + +```js +let client = await I.have('client'); +``` + +Ids of created records are collected and used in the end of a test for the cleanup. +If you need to receive `id` instead of full response enable `returnId` in a helper config: + +```js +// returnId: false +let clientId = await I.have('client'); +// clientId == 1 + +// returnId: true +let clientId = await I.have('client'); +// client == { name: 'John', email: 'john@snow.com' } +``` + +By default `id` property of response is taken. This behavior can be changed by setting `fetchId` function in a factory config. + +```js + factories: { + post: { + uri: "/posts", + factory: "./factories/post", + fetchId: (data) => data.result.posts[0].id + } + } +``` + +## Methods + +### Parameters + +- `config` + +### _requestCreate + +Executes request to create a record in API. +Can be replaced from a in custom helper. + +#### Parameters + +- `factory` **any** +- `data` **any** + +### _requestDelete + +Executes request to delete a record in API +Can be replaced from a custom helper. + +#### Parameters + +- `factory` **any** +- `id` **any** + +### have + +Generates a new record using factory and saves API request to store it. + +```js +// create a 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'}); +``` + +#### Parameters + +- `factory` **any** factory to use +- `params` **any** predefined parameters + +### haveMultiple + +Generates bunch of records and saves multiple API requests to store them. + +```js +// create 3 posts +I.haveMultiple('post', 3); + +// create 3 posts by one author +I.haveMultiple('post', 3, { author: 'davert' }); +``` + +#### Parameters + +- `factory` **any** +- `times` **any** +- `params` **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 diff --git a/docs/helpers/Appium.md b/docs/helpers/Appium.md new file mode 100644 index 000000000..8a1a24815 --- /dev/null +++ b/docs/helpers/Appium.md @@ -0,0 +1,1833 @@ + + +## Appium + +**Extends Webdriver** + +Appium helper extends [Webriver][1] helper. + It supports all browser methods and also includes special methods for mobile apps testing. + You can use this helper to test Web on desktop and mobile devices and mobile apps. + +## Appium Installation + +Appium is an open source test automation framework for use with native, hybrid and mobile web apps that implements the WebDriver protocol. +It allows you to run Selenium tests on mobile devices and also test native, hybrid and mobile web apps. + +Download and install [Appium][2] + +```sh +npm install -g appium +``` + +Launch the daemon: `appium` + +## Helper configuration + +This helper should be configured in codecept.json or codecept.conf.js + +- `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: + +```js +{ + helpers: { + Appium: { + platform: "Android", + desiredCapabilities: { + appPackage: "com.example.android.myApp", + appActivity: "MainActivity", + deviceName: "OnePlus3", + platformVersion: "6.0.1" + } + } + } +} +``` + +Example iOS Mobile Web with local Appium: + +```js +{ +helpers: { + Appium: { + platform: "iOS", + url: "https://the-internet.herokuapp.com/", + desiredCapabilities: { + deviceName: "iPhone X", + platformVersion: "12.0", + browserName: "safari" + } + } +} +} +``` + +Example iOS Mobile Web on BrowserStack: + +```js +{ +helpers: { + Appium: { + host: "hub-cloud.browserstack.com", + port: 4444, + user: process.env.BROWSERSTACK_USER, + key: process.env.BROWSERSTACK_KEY, + platform: "iOS", + url: "https://the-internet.herokuapp.com/", + desiredCapabilities: { + realMobile: "true", + device: "iPhone 8", + os_version: "12", + browserName: "safari" + } + } +} +} +``` + +Additional configuration params can be used from [https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/caps.md][3] + +## Access From Helpers + +Receive a Appium client from a custom helper by accessing `browser` property: + +```js +let browser = this.helpers['Appium'].browser +``` + +## Methods + +### Parameters + +- `config` + +### runOnIOS + +Execute code only on iOS + +```js +I.runOnIOS(() => { + 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'},() => { + // ... +}); +``` + +Also capabilities can be checked by a function. + +```js +I.runOnAndroid((caps) => { + // caps is current config of desiredCapabiliites + return caps.platformVersion >= 6 +},() => { + // ... +}); +``` + +#### Parameters + +- `caps` **any** +- `fn` **any** + +### runOnAndroid + +Execute code only on Android + +```js +I.runOnAndroid(() => { + 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'},() => { + // ... +}); +``` + +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 +},() => { + // ... +}); +``` + +#### Parameters + +- `caps` **any** +- `fn` **any** + +### runInWeb + +Execute code only in Web mode. + +```js +I.runInWeb(() => { + I.waitForElement('#data'); + I.seeInCurrentUrl('/data'); +}); +``` + +#### Parameters + +- `fn` **any** + +### seeAppIsInstalled + +Check if an app is installed. + +```js +I.seeAppIsInstalled("com.example.android.apis"); +``` + +#### Parameters + +- `bundleId` **[string][4]** String ID of bundled appAppium: support only Android + +### seeAppIsNotInstalled + +Check if an app is not installed. + +```js +I.seeAppIsNotInstalled("com.example.android.apis"); +``` + +#### Parameters + +- `bundleId` **[string][4]** String ID of bundled appAppium: support only Android + +### installApp + +Install an app on device. + +```js +I.installApp('/path/to/file.apk'); +``` + +#### Parameters + +- `path` **[string][4]** path to apk fileAppium: support only Android + +### removeApp + +Remove an app from the device. + +```js +I.removeApp('appName', 'com.example.android.apis'); +``` + +#### Parameters + +- `appId` **[string][4]** +- `bundleId` **[string][4]** String ID of bundleAppium: support only Android + +### seeCurrentActivityIs + +Check current activity on an Android device. + +```js +I.seeCurrentActivityIs(".HomeScreenActivity") +``` + +#### Parameters + +- `currentActivity` **[string][4]** Appium: support only Android + +### seeDeviceIsLocked + +Check whether the device is locked. + +```js +I.seeDeviceIsLocked(); +``` + +Appium: support only Android + +### seeDeviceIsUnlocked + +Check whether the device is not locked. + +```js +I.seeDeviceIsUnlocked(); +``` + +Appium: support only Android + +### seeOrientationIs + +Check the device orientation + +```js +I.seeOrientationIs('PORTRAIT'); +I.seeOrientationIs('LANDSCAPE') +``` + +#### Parameters + +- `orientation` **(`"LANDSCAPE"` \| `"PORTRAIT"`)** LANDSCAPE or PORTRAITAppium: support Android and iOS + +### setOrientation + +Set a device orientation. Will fail, if app will not set orientation + +```js +I.setOrientation('PORTRAIT'); +I.setOrientation('LANDSCAPE') +``` + +#### Parameters + +- `orientation` **(`"LANDSCAPE"` \| `"PORTRAIT"`)** LANDSCAPE or PORTRAITAppium: support Android and iOS + +### grabAllContexts + +Get list of all available contexts + + let contexts = await I.grabAllContexts(); + +Appium: support Android and iOS + +### grabContext + +Retrieve current context + +```js +let context = await I.grabContext(); +``` + +Appium: support Android and iOS + +### grabCurrentActivity + +Get current device activity. + +```js +let activity = await I.grabCurrentActivity(); +``` + +Appium: support only Android + +### grabNetworkConnection + +Get information about the current network connection (Data/WIFI/Airplane). +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(); +``` + +Appium: support only Android + +### grabOrientation + +Get current orientation. + +```js +let orientation = await I.grabOrientation(); +``` + +Appium: support Android and iOS + +### grabSettings + +Get all the currently specified settings. + +```js +let settings = await I.grabSettings(); +``` + +Appium: support Android and iOS + +### \_switchToContext + +Switch to the specified context. + +#### Parameters + +- `context` **any** the context to switch to + +### switchToWeb + +Switches to web context. +If no context is provided switches to the first detected web context + +```js +// switch to first web context +I.switchToWeb(); + +// or set the context explicitly +I.switchToWeb('WEBVIEW_io.selendroid.testapp'); +``` + +#### Parameters + +- `context` **[string][4]?** + +### switchToNative + +Switches to native context. +By default switches to NATIVE_APP context unless other specified. + +```js +I.switchToNative(); + +// or set context explicitly +I.switchToNative('SOME_OTHER_CONTEXT'); +``` + +#### Parameters + +- `context` **any** (optional, default `null`) + +### startActivity + +Start an arbitrary Android activity during a session. + +```js +I.startActivity('io.selendroid.testapp', '.RegisterUserActivity'); +``` + +Appium: support only Android + +#### Parameters + +- `appPackage` +- `appActivity` + +### setNetworkConnection + +Set network connection mode. + +- airplane mode +- wifi mode +- data data + +```js +I.setNetworkConnection(0) // airplane mode off, wifi off, data off +I.setNetworkConnection(1) // airplane mode on, wifi off, data off +I.setNetworkConnection(2) // airplane mode off, wifi on, data off +I.setNetworkConnection(4) // airplane mode off, wifi off, data on +I.setNetworkConnection(6) // airplane mode off, wifi on, data on +``` + +See corresponding [webdriverio reference][5]. + +Appium: support only Android + +#### Parameters + +- `value` + +### setSettings + +Update the current setting on the device + +```js +I.setSettings({cyberdelia: 'open'}); +``` + +#### Parameters + +- `settings` **[object][6]** objectAppium: support Android and iOS + +### hideDeviceKeyboard + +Hide the keyboard. + +```js +// taps outside to hide keyboard per default +I.hideDeviceKeyboard(); +I.hideDeviceKeyboard('tapOutside'); + +// or by pressing key +I.hideDeviceKeyboard('pressKey', 'Done'); +``` + +#### Parameters + +- `strategy` **(`"tapOutside"` \| `"pressKey"`)** desired strategy to close keyboard (‘tapOutside’ or ‘pressKey’)Appium: support Android and iOS +- `key` + +### sendDeviceKeyEvent + +Send a key event to the device. +List of keys: [https://developer.android.com/reference/android/view/KeyEvent.html][7] + +```js +I.sendDeviceKeyEvent(3); +``` + +#### Parameters + +- `keyValue` **[number][8]** Device specific key valueAppium: support only Android + +### openNotifications + +Open the notifications panel on the device. + +```js +I.openNotifications(); +``` + +Appium: support only Android + +### makeTouchAction + +The Touch Action API provides the basis of all gestures that can be +automated in Appium. At its core is the ability to chain together ad hoc +individual actions, which will then be applied to an element in the +application on the device. +[See complete documentation][9] + +```js +I.makeTouchAction("~buttonStartWebviewCD", 'tap'); +``` + +Appium: support Android and iOS + +#### Parameters + +- `locator` +- `action` + +### tap + +Taps on element. + +```js +I.tap("~buttonStartWebviewCD"); +``` + +Shortcut for `makeTouchAction` + +#### Parameters + +- `locator` **any** + +### swipe + +Perform a swipe on the screen or an element. + +```js +let locator = "#io.selendroid.testapp:id/LinearLayout1"; +I.swipe(locator, 800, 1200, 1000); +``` + +[See complete reference][10] + +#### Parameters + +- `locator` **([string][4] \| [object][6])** +- `xoffset` **[number][8]** +- `yoffset` **[number][8]** +- `speed` **[number][8]** (optional), 1000 by defaultAppium: support Android and iOS (optional, default `1000`) + +### performSwipe + +Perform a swipe on the screen. + +```js +I.performswipe(100,200); +``` + +#### Parameters + +- `from` **[number][8]** +- `to` **[number][8]** 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 +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** +- `yoffset` **[number][8]?** (optional) (optional, default `1000`) +- `speed` **[number][8]** (optional), 1000 by defaultAppium: support Android and iOS (optional, default `1000`) + +### swipeLeft + +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 +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** +- `xoffset` **[number][8]?** (optional) (optional, default `1000`) +- `speed` **[number][8]** (optional), 1000 by defaultAppium: support Android and iOS (optional, default `1000`) + +### swipeRight + +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 +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** +- `xoffset` **[number][8]?** (optional) (optional, default `1000`) +- `speed` **[number][8]** (optional), 1000 by defaultAppium: support Android and iOS (optional, default `1000`) + +### swipeUp + +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 +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** +- `yoffset` **[number][8]?** (optional) (optional, default `1000`) +- `speed` **[number][8]** (optional), 1000 by defaultAppium: support Android and iOS (optional, default `1000`) + +### swipeTo + +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); +``` + +#### Parameters + +- `searchableLocator` **[string][4]** +- `scrollLocator` **[string][4]** +- `direction` **[string][4]** +- `timeout` **[number][8]** +- `offset` **[number][8]** +- `speed` **[number][8]** Appium: support Android and iOS + +### touchPerform + +Performs a specific touch action. +The action object need to contain the action name, x/y coordinates + +```js +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 + } +}]); +``` + +Appium: support Android and iOS + +#### Parameters + +- `actions` + +### pullFile + +Pulls a file from the device. + +```js +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); +``` + +Appium: support Android and iOS + +#### Parameters + +- `path` +- `dest` + +### shakeDevice + +Perform a shake action on the device. + +```js +I.shakeDevice(); +``` + +Appium: support only iOS + +### rotate + +Perform a rotation gesture centered on the specified element. + +```js +I.rotate(120, 120) +``` + +See corresponding [webdriverio reference][11]. + +Appium: support only iOS + +#### Parameters + +- `x` +- `y` +- `duration` +- `radius` +- `rotation` +- `touchCount` + +### setImmediateValue + +Set immediate value in app. + +See corresponding [webdriverio reference][12]. + +Appium: support only iOS + +#### Parameters + +- `id` +- `value` + +### simulateTouchId + +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 +``` + +Appium: support only iOS +TODO: not tested + +#### Parameters + +- `match` + +### closeApp + +Close the given application. + +```js +I.closeApp(); +``` + +Appium: support only iOS + +### appendField + +Appends text to a input field or textarea. +Field is located by name, label, CSS or XPath + +```js +I.appendField('#myTextField', 'appended'); +``` + +#### Parameters + +- `field` **([string][4] \| [object][6])** located by label|name|CSS|XPath|strict locator +- `value` **[string][4]** text value to append. + +### checkOption + +Selects a checkbox or radio button. +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'); +``` + +#### Parameters + +- `field` **([string][4] \| [object][6])** checkbox located by label | name | CSS | XPath | strict locator. +- `context` **([string][4]? | [object][6])** (optional, `null` by default) element located by CSS | XPath | strict locator. (optional, default `null`) + +### click + +Perform a click on a link or a button, given by a locator. +If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string. +For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched. +For images, the "alt" attribute and inner text of any parent links are searched. + +The second parameter is a context (CSS or XPath locator) to narrow the search. + +```js +// simple link +I.click('Logout'); +// button of form +I.click('Submit'); +// CSS button +I.click('#form input[type=submit]'); +// XPath +I.click('//form/*[@type=submit]'); +// link in context +I.click('Logout', '#nav'); +// using strict locator +I.click({css: 'nav a.login'}); +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** clickable link or button located by text, or any element located by CSS|XPath|strict locator. +- `context` **([string][4]? | [object][6])** (optional, `null` by default) element to search in CSS|XPath|Strict locator. (optional, default `null`) + +### dontSeeCheckboxIsChecked + +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 +``` + +#### Parameters + +- `field` **([string][4] \| [object][6])** located by label|name|CSS|XPath|strict locator. + +### dontSeeElement + +Opposite to `seeElement`. Checks that element is not visible (or in DOM) + +```js +I.dontSeeElement('.modal'); // modal is not shown +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** located by CSS|XPath|Strict locator. + +### dontSeeInField + +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 +``` + +#### Parameters + +- `field` **([string][4] \| [object][6])** located by label|name|CSS|XPath|strict locator. +- `value` **[string][4]** value to check. + +### dontSee + +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 +``` + +#### Parameters + +- `text` **[string][4]** which is not present. +- `context` **([string][4] \| [object][6])?** (optional) element located by CSS|XPath|strict locator in which to perfrom search. (optional, default `null`) + +### fillField + +Fills a text field or textarea, after clearing its value, with the given string. +Field is located by name, label, CSS, or XPath. + +```js +// by label +I.fillField('Email', 'hello@world.com'); +// by name +I.fillField('password', secret('123456')); +// by CSS +I.fillField('form#login input[name=username]', 'John'); +// or by strict locator +I.fillField({css: 'form#login input[name=username]'}, 'John'); +``` + +#### Parameters + +- `field` **([string][4] \| [object][6])** located by label|name|CSS|XPath|strict locator. +- `value` **[string][4]** text value to fill. + +### grabTextFrom + +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'); +``` + +If multiple elements found returns an array of texts. + +#### Parameters + +- `locator` **([string][4] \| [object][6])** element located by CSS|XPath|strict locator. + +Returns **[Promise][13]<([string][4] \| [Array][14]<[string][4]>)>** attribute value + +### grabValueFrom + +Retrieves a value from a form element located by CSS or XPath and returns it to test. +Resumes test execution, so **should be used inside async function with `await`** operator. + +```js +let email = await I.grabValueFrom('input[name=email]'); +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** field located by label|name|CSS|XPath|strict locator. + +Returns **[Promise][13]<[string][4]>** attribute value + +### scrollIntoView + +Scroll element into viewport. + +```js +I.scrollIntoView('#submit'); +I.scrollIntoView('#submit', true); +I.scrollIntoView('#submit', { behavior: "smooth", block: "center", inline: "center" }); +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** located by CSS|XPath|strict locator. +- `scrollIntoViewOptions` +- `alignToTop` **([boolean][15] \| [object][6])** (optional) or scrollIntoViewOptions (optional), see [https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView][16].Supported only for web testing + +### seeCheckboxIsChecked + +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]'}); +``` + +#### Parameters + +- `field` **([string][4] \| [object][6])** located by label|name|CSS|XPath|strict locator. + +### seeElement + +Checks that a given Element is visible +Element is located by CSS or XPath. + +```js +I.seeElement('#modal'); +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** located by CSS|XPath|strict locator. + +### seeInField + +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'); +``` + +#### Parameters + +- `field` **([string][4] \| [object][6])** located by label|name|CSS|XPath|strict locator. +- `value` **[string][4]** value to check. + +### see + +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 +``` + +#### Parameters + +- `text` **[string][4]** expected on page. +- `context` **([string][4]? | [object][6])** (optional, `null` by default) element located by CSS|Xpath|strict locator in which to search for text. (optional, default `null`) + +### selectOption + +Selects an option in a drop-down select. +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'); +``` + +Provide an array for the second argument to select multiple options. + +```js +I.selectOption('Which OS do you use?', ['Android', 'iOS']); +``` + +#### Parameters + +- `select` **([string][4] \| [object][6])** field located by label|name|CSS|XPath|strict locator. +- `option` **([string][4] \| [Array][14]<any>)** visible text or value of option.Supported only for web testing + +### waitForElement + +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 +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** element located by CSS|XPath|strict locator. +- `sec` **[number][8]?** (optional, `1` by default) time in seconds to wait (optional, default `null`) + +### waitForVisible + +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'); +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** element located by CSS|XPath|strict locator. +- `sec` **[number][8]** (optional, `1` by default) time in seconds to wait (optional, default `1`) + +### waitForInvisible + +Waits for an element to be removed or become invisible on a page (by default waits for 1sec). +Element can be located by CSS or XPath. + +```js +I.waitForInvisible('#popup'); +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** element located by CSS|XPath|strict locator. +- `sec` **[number][8]** (optional, `1` by default) time in seconds to wait (optional, default `1`) + +### waitForText + +Waits for a text to appear (by default waits for 1sec). +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'); +``` + +#### Parameters + +- `text` **[string][4]** to wait for. +- `sec` **[number][8]** (optional, `1` by default) time in seconds to wait (optional, default `1`) +- `context` **([string][4] \| [object][6])?** (optional) element located by CSS|XPath|strict locator. (optional, default `null`) + +### \_isShadowLocator + +Check if locator is type of "Shadow" + +#### Parameters + +- `locator` **[object][6]** + +### \_locateShadow + +Locate Element within the Shadow Dom + +#### Parameters + +- `locator` **[object][6]** + +### \_smartWait + +Smart Wait to locate an element + +#### Parameters + +- `locator` **[object][6]** + +### \_locate + +Get elements by different locator types, including strict locator. +Should be used in custom helpers: + +```js +this.helpers['WebDriver']._locate({name: 'password'}).then //... +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** element located by CSS|XPath|strict locator. +- `smartWait` (optional, default `false`) + +### \_locateCheckable + +Find a checkbox by providing human readable text: + +```js +this.helpers['WebDriver']._locateCheckable('I agree with terms and conditions').then // ... +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** element located by CSS|XPath|strict locator. + +### \_locateClickable + +Find a clickable element by providing human readable text: + +```js +const els = await this.helpers.WebDriver._locateClickable('Next page'); +const els = await this.helpers.WebDriver._locateClickable('Next page', '.pages'); +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** element located by CSS|XPath|strict locator. +- `context` + +### \_locateFields + +Find field elements by providing human readable text: + +```js +this.helpers['WebDriver']._locateFields('Your email').then // ... +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** element located by CSS|XPath|strict locator. + +### defineTimeout + +Set [WebDriver timeouts][17] in realtime. + +Timeouts are expected to be passed as object: + +```js +I.defineTimeout({ script: 5000 }); +I.defineTimeout({ implicit: 10000, pageLoad: 10000, script: 5000 }); +``` + +#### Parameters + +- `timeouts` **WebdriverIO.Timeouts** WebDriver timeouts object. + +### amOnPage + +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 +``` + +#### Parameters + +- `url` **[string][4]** url path or global url. + +### forceClick + +Perform an emulated click on a link or a button, given by a locator. +Unlike normal click instead of sending native event, emulates a click with JavaScript. +This works on hidden, animated or inactive elements as well. + +If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string. +For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched. +For images, the "alt" attribute and inner text of any parent links are searched. + +The second parameter is a context (CSS or XPath locator) to narrow the search. + +```js +// simple link +I.forceClick('Logout'); +// button of form +I.forceClick('Submit'); +// CSS button +I.forceClick('#form input[type=submit]'); +// XPath +I.forceClick('//form/*[@type=submit]'); +// link in context +I.forceClick('Logout', '#nav'); +// using strict locator +I.forceClick({css: 'nav a.login'}); +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** clickable link or button located by text, or any element located by CSS|XPath|strict locator. +- `context` **([string][4]? | [object][6])** (optional, `null` by default) element to search in CSS|XPath|Strict locator.{{ react }} (optional, default `null`) + +### doubleClick + +Performs a double-click on an element matched by link|button|label|CSS or XPath. +Context can be specified as second parameter to narrow search. + +```js +I.doubleClick('Edit'); +I.doubleClick('Edit', '.actions'); +I.doubleClick({css: 'button.accept'}); +I.doubleClick('.btn.edit'); +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** clickable link or button located by text, or any element located by CSS|XPath|strict locator. +- `context` **([string][4]? | [object][6])** (optional, `null` by default) element to search in CSS|XPath|Strict locator.{{ react }} (optional, default `null`) + +### rightClick + +Performs right click on a clickable element matched by semantic locator, CSS or XPath. + +```js +// right click element with id el +I.rightClick('#el'); +// right click link or button with text "Click me" +I.rightClick('Click me'); +// right click button with text "Click me" inside .context +I.rightClick('Click me', '.context'); +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** clickable element located by CSS|XPath|strict locator. +- `context` **([string][4]? | [object][6])** (optional, `null` by default) element located by CSS|XPath|strict locator.{{ react }} (optional, default `null`) + +### forceRightClick + +Emulates right click on an element. +Unlike normal click instead of sending native event, emulates a click with JavaScript. +This works on hidden, animated or inactive elements as well. + +If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string. +For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched. +For images, the "alt" attribute and inner text of any parent links are searched. + +The second parameter is a context (CSS or XPath locator) to narrow the search. + +```js +// simple link +I.forceRightClick('Menu'); +``` + +#### Parameters + +- `locator` **([string][4] \| [object][6])** clickable link or button located by text, or any element located by CSS|XPath|strict locator. +- `context` **([string][4]? | [object][6])** (optional, `null` by default) element to search in CSS|XPath|Strict locator.{{ react }} (optional, default `null`) + +### clearField + +Clears a `