diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a426f7c56..2f6dcfbdd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -110,6 +110,7 @@ mocha test/runner Please try to add corresponding testcase to runner or unit. ## 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 @@ -117,12 +118,14 @@ from this directory. Currently we provide following commands to run tests with respective dependencies: ### Run unit tests -``` shell + +```sh docker-compose run --rm test-unit ``` ### Run helper tests -``` shell + +```sh docker-compose run --rm test-helpers # or pass path to helper test to run specific helper, @@ -134,21 +137,25 @@ docker-compose run --rm test-helpers test/rest ``` ### Run acceptance tests + To that we provide two separate services respectively for WebDriverIO and Nightmare tests: -``` shell + +```sh docker-compose run --rm test-acceptance.webdriverio docker-compose run --rm test-acceptance.nightmare ``` ### Running against specific Node version + By default dockerized tests are run against node 6.9.5, 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 8.7.0: -``` shell + +```sh docker-compose build --build-arg NODE_VERSION=8.7.0 test-helpers ``` diff --git a/docs/acceptance.md b/docs/acceptance.md index c1374b3b3..54089c15d 100644 --- a/docs/acceptance.md +++ b/docs/acceptance.md @@ -256,9 +256,9 @@ within({frame: [".content", "#editor"]}, () => { I.see('Page'); }); ``` + --- ### 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/api/helper.md b/docs/api/helper.md index 3f62fe724..33fa46003 100644 --- a/docs/api/helper.md +++ b/docs/api/helper.md @@ -2,31 +2,39 @@ **Parameters** -- `config` +- `config` ## _after Hook executed after each test +## _afterStep + +Hook executed after each step + +**Parameters** + +- `step` + ## _afterSuite Hook executed after each suite **Parameters** -- `suite` +- `suite` ## _before Hook executed before each test. -## _beforeSuite +## _beforeStep Hook executed before each step **Parameters** -- `step` +- `step` ## _beforeSuite @@ -34,15 +42,7 @@ Hook executed before each suite **Parameters** -- `suite` - -## _beforeSuite - -Hook executed after each step - -**Parameters** - -- `step` +- `suite` ## _failed @@ -50,7 +50,7 @@ Hook executed after each failed test **Parameters** -- `test` +- `test` ## _finishTest @@ -58,7 +58,7 @@ Hook executed after all tests are executed **Parameters** -- `suite` +- `suite` ## _init @@ -71,7 +71,7 @@ Executed in the very beginning of a test **Parameters** -- `test` +- `test` ## debug @@ -79,7 +79,7 @@ Print debug message to console (outputs only in debug mode) **Parameters** -- `msg` +- `msg` ## helpers diff --git a/docs/configuration.md b/docs/configuration.md index f23d4e3d8..271994766 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -7,7 +7,7 @@ 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 page objects to be registered in DI container and included in tests. Accepts objects and module `require ` paths +* **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 diff --git a/docs/docker.md b/docs/docker.md index 1a8b476da..02285935a 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -80,6 +80,7 @@ docker build -t codeception/codeceptjs . ``` ### Debugging + To pass arguments to `codecept run` command inside docker image you can set `CODECEPT_ARGS` environment variable. For example to run your tests with debug and steps output: diff --git a/docs/installation.md b/docs/installation.md index 270da97ae..1522eb60a 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,6 +1,6 @@ # Installation -### Local +## Local Use NPM install CodeceptJS: @@ -38,7 +38,6 @@ To use it with Puppeteer install puppeteer package: npm install puppeteer --save-dev ``` - ## Meta Packages By default it doesn't install any backends like Webdriverio, Protractor, or Nightmare, so you need to install corresponding packages manually, or install one of the provided meta-packages: diff --git a/docs/pageobjects.md b/docs/pageobjects.md index 090b4de43..8464cac72 100644 --- a/docs/pageobjects.md +++ b/docs/pageobjects.md @@ -68,6 +68,7 @@ Scenario('login', (I, loginPage) => { ``` Also you can use `async/await` inside PageObject: + ```js 'use strict'; let I; @@ -109,7 +110,6 @@ Scenario('login2', async (I, loginPage, basePage) => { }); ``` - Also you can use generators inside a PageObject: ```js diff --git a/docs/puppeteer.md b/docs/puppeteer.md index 9be1895f4..6d0ee5290 100644 --- a/docs/puppeteer.md +++ b/docs/puppeteer.md @@ -5,8 +5,8 @@ It operates over Google Chrome directly without requireing additional tools like CodeceptJS uses Puppeteer to improve end to end testing experience. -1. No need to learn the syntax of a new tool, all drivers in CodeceptJS share the same API. -2. CodeceptJS can locate elements by XPath. +1. No need to learn the syntax of a new tool, all drivers in CodeceptJS share the same API. +2. CodeceptJS can locate elements by XPath. Take a look at a sample test: @@ -33,7 +33,6 @@ npm install -g codeceptjs-puppeteer Or see [alternative installation options](http://codecept.io/installation/) If you already have CodeceptJS project, just install `puppeteer` package and enable it in config. - And a basic project initialized ```sh @@ -68,7 +67,7 @@ Sometimes test may run faster than application gets rendered. In this case it is CodeceptJS test should be created with `gt` command: -``` +```sh codeceptjs gt ``` @@ -160,9 +159,10 @@ Puppeteer has a very [rich and flexible API](https://github.com/GoogleChrome/pup Start with creating an `MyPuppeteer` helper using `generate:helper` or `gh` command: -``` +```sh codeceptjs gh ``` + Then inside a Helper you can access `Puppeteer` helper of CodeceptJS. Let's say you want to create `I.renderPageToPdf` action. In this case you need to call `pdf` method of `page` object diff --git a/lib/codecept.js b/lib/codecept.js index 4b58591db..b5433f460 100644 --- a/lib/codecept.js +++ b/lib/codecept.js @@ -20,7 +20,7 @@ class Codecept { constructor(config, opts) { this.config = Config.create(config); this.opts = opts; - this.testFiles = []; + this.testFiles = new Array(0); } /** diff --git a/lib/data/table.js b/lib/data/table.js index 9b22873e8..e72bd014b 100644 --- a/lib/data/table.js +++ b/lib/data/table.js @@ -4,7 +4,7 @@ class DataTable { constructor(array) { this.array = array; - this.rows = []; + this.rows = new Array(0); } add(array) { diff --git a/lib/helper.js b/lib/helper.js index 6b6f6b96a..0eb45c709 100644 --- a/lib/helper.js +++ b/lib/helper.js @@ -51,63 +51,65 @@ class Helper { * Hook provides a test details * Executed in the very beginning of a test * - * @param test + * @param {*} test */ - _test() { + _test(test) { } /** * Hook executed after each failed test * - * @param test + * @param {*} test */ - _failed() { + _failed(test) { } /** * Hook executed before each step * - * @param step + * @param {*} step * @override - * - * _beforeStep() */ + _beforeStep(step) { + + } /** * Hook executed after each step * - * @param step + * @param {*} step * @override - * - * _afterStep() */ + _afterStep(step) { + + } /** * Hook executed before each suite * - * @param suite + * @param {*} suite */ - _beforeSuite() { + _beforeSuite(suite) { } /** * Hook executed after each suite * - * @param suite + * @param {*} suite */ - _afterSuite() { + _afterSuite(suite) { } /** * Hook executed after all tests are executed * - * @param suite + * @param {*} suite */ - _finishTest() { + _finishTest(suite) { } diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index 60a4dc296..d5e3f9064 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -516,7 +516,7 @@ class Puppeteer extends Helper { * {{> ../webapi/dontSeeCurrentUrlEquals }} */ async dontSeeCurrentUrlEquals(url) { - const currentUrl = this.page.url(); + const currentUrl = await this.page.url(); urlEquals(this.options.url).negate(url, currentUrl); } @@ -530,7 +530,7 @@ class Puppeteer extends Helper { /** * {{> ../webapi/dontSee }} */ - dontSee(text, context = null) { + async dontSee(text, context = null) { return proceedSee.call(this, 'negate', text, context); } @@ -706,7 +706,7 @@ class Puppeteer extends Helper { waiter = this.page.waitForFunction($XPath, { timeout: waitTimeout }, null, locator.value); } return waiter.catch((err) => { - throw new Error(`element (${locator.toString()}) still not present on page after ${sec} sec\n${err.message}`); + throw new Error(`element (${locator.toString()}) still not present on page after ${waitTimeout / 1000} sec\n${err.message}`); }); } @@ -729,7 +729,7 @@ class Puppeteer extends Helper { waiter = this.page.waitForFunction(visibleFn, { timeout: waitTimeout }, locator.value, $XPath.toString()); } return waiter.catch((err) => { - throw new Error(`element (${locator.toString()}) still not visible on page after ${sec} sec\n${err.message}`); + throw new Error(`element (${locator.toString()}) still not visible on page after ${waitTimeout / 1000} sec\n${err.message}`); }); } @@ -751,7 +751,7 @@ class Puppeteer extends Helper { waiter = this.page.waitForFunction(visibleFn, { timeout: waitTimeout }, locator.value, $XPath.toString()); } return waiter.catch((err) => { - throw new Error(`element (${locator.toString()}) still not hidden after ${sec} sec\n${err.message}`); + throw new Error(`element (${locator.toString()}) still not hidden after ${waitTimeout / 1000} sec\n${err.message}`); }); } @@ -760,7 +760,8 @@ class Puppeteer extends Helper { * {{> ../webapi/waitForText }} */ async waitForText(text, sec = null, context = null) { - const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; + const aSec = sec || this.options.waitForTimeout; + const waitTimeout = aSec * 1000; if (this.withinLocator) this.debug('waitForVisible ignores `within` block'); let waiter; @@ -786,7 +787,7 @@ class Puppeteer extends Helper { } return waiter.catch((err) => { - throw new Error(`Text "${text}" was not found on page after ${sec} sec`); + throw new Error(`Text "${text}" was not found on page after ${waitTimeout / 1000} sec\n${err.message}`); }); } @@ -794,7 +795,8 @@ class Puppeteer extends Helper { * {{> ../webapi/waitUntil }} */ async waitUntil(fn, sec = null) { - const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; + const aSec = sec || this.options.waitForTimeout; + const waitTimeout = aSec * 1000; return this.page.waitForFunction(fn, { timeout: waitTimeout }); } @@ -820,7 +822,7 @@ class Puppeteer extends Helper { waiter = this.page.waitForFunction(visibleFn, { timeout: waitTimeout }, locator.value, $XPath.toString()); } return waiter.catch((err) => { - throw new Error(`element (${locator.toString()}) still on page after ${sec} sec\n${err.message}`); + throw new Error(`element (${locator.toString()}) still on page after ${waitTimeout / 1000} sec\n${err.message}`); }); } diff --git a/lib/helper/REST.js b/lib/helper/REST.js index 9c35b4eb4..deea94790 100644 --- a/lib/helper/REST.js +++ b/lib/helper/REST.js @@ -82,7 +82,7 @@ class REST extends Helper { * ``` * * @param {*} url - * @param object headers + * @param {object} headers */ sendGetRequest(url, headers = {}) { request = unirest.get(this._url(url)).headers(headers); @@ -98,7 +98,7 @@ class REST extends Helper { * * @param {*} url * @param {*} payload - * @param object headers + * @param {object} headers */ sendPostRequest(url, payload = {}, headers = {}) { request = unirest.post(this._url(url)).headers(headers).send(payload); @@ -112,9 +112,9 @@ class REST extends Helper { * I.sendPatchRequest('/api/users.json', { "email": "user@user.com" }); * ``` * - * @param string url - * @param object payload - * @param object headers + * @param {string} url + * @param {object} payload + * @param {object} headers */ sendPatchRequest(url, payload = {}, headers = {}) { request = unirest.patch(this._url(url)).headers(headers).send(payload); @@ -128,9 +128,9 @@ class REST extends Helper { * I.sendPutRequest('/api/users.json', { "email": "user@user.com" }); * ``` * - * @param string url - * @param object payload - * @param object headers + * @param {string} url + * @param {object} payload + * @param {object} headers */ sendPutRequest(url, payload = {}, headers = {}) { request = unirest.put(this._url(url)).headers(headers).send(payload); @@ -145,7 +145,7 @@ class REST extends Helper { * ``` * * @param {*} url - * @param {*} payload + * @param {object} headers */ sendDeleteRequest(url, headers = {}) { request = unirest.delete(this._url(url)).headers(headers); diff --git a/lib/mocha_factory.js b/lib/mocha_factory.js index efa5cf23e..274704e2a 100644 --- a/lib/mocha_factory.js +++ b/lib/mocha_factory.js @@ -34,10 +34,11 @@ class MochaFactory { }); } - if (reporterOptions['codeceptjs-cli-reporter']) { + const attributes = Object.getOwnPropertyDescriptor(reporterOptions, 'codeceptjs-cli-reporter'); + if (reporterOptions['codeceptjs-cli-reporter'] && attributes) { Object.defineProperty( reporterOptions, 'codeceptjs/lib/reporter/cli', - Object.getOwnPropertyDescriptor(reporterOptions, 'codeceptjs-cli-reporter'), + attributes, ); delete reporterOptions['codeceptjs-cli-reporter']; } diff --git a/package.json b/package.json index 53ea63a78..9fa189b3d 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ }, "repository": "Codeception/codeceptjs", "scripts": { + "build": "tsc -p ./", "json-server": "./node_modules/json-server/bin/index.js test/data/rest/db.json -p 8010 --watch -m test/data/rest/headers.js", "lint": "eslint bin/ examples/ lib/ test/ translations/", "lint-fix": "eslint bin/ examples/ lib/ test/ translations/ --fix", @@ -46,7 +47,6 @@ "requireg": "^0.1.5" }, "devDependencies": { - "@types/commander": "^2.12.2", "@types/inquirer": "^0.0.35", "@types/node": "^8.5.1", "chai": "^3.4.1", diff --git a/test/docker-compose.yml b/test/docker-compose.yml index ccb343309..6f78fd1b9 100644 --- a/test/docker-compose.yml +++ b/test/docker-compose.yml @@ -2,7 +2,7 @@ version: '3' services: test-unit: build: .. - entrypoint: node_modules/.bin/gulp + entrypoint: docker/entrypoint node_modules/.bin/mocha command: test working_dir: /codecept volumes: diff --git a/test/runner/interface_test.js b/test/runner/interface_test.js index 994839468..b9dd9e471 100644 --- a/test/runner/interface_test.js +++ b/test/runner/interface_test.js @@ -55,11 +55,15 @@ describe('CodeceptJS Interface', () => { '[1] Starting recording promises', '[1] Queued | hook FileSystem._beforeSuite()', '[1] Queued | hook FileSystem._before()', + '[1] Queued | hook FileSystem._beforeStep()', '[1] Queued | amInPath: "."', + '[1] Queued | hook FileSystem._afterStep()', '[1] Queued | step passed', '[1] Queued | return result', '[1] Queued | say hello world', + '[1] Queued | hook FileSystem._beforeStep()', '[1] Queued | seeFile: "codecept.json"', + '[1] Queued | hook FileSystem._afterStep()', '[1] Queued | step passed', '[1] Queued | return result', '[1] Queued | fire test.passed', diff --git a/test/unit/steps_test.js b/test/unit/steps_test.js index c5a460c0b..abadbe864 100644 --- a/test/unit/steps_test.js +++ b/test/unit/steps_test.js @@ -25,7 +25,7 @@ describe('Step', () => { step.humanizeArgs().should.eql('"word", 1'); step.args = [['some', 'data'], 1]; - step.humanizeArgs().should.eql('[some,data], 1'); + step.humanizeArgs().should.eql('["some","data"], 1'); step.args = [{ css: '.class' }]; step.humanizeArgs().should.eql('{"css":".class"}');