Skip to content

Commit 26a552b

Browse files
committed
preparing 2.2.1 release
1 parent 02bdbb6 commit 26a552b

File tree

10 files changed

+279
-20
lines changed

10 files changed

+279
-20
lines changed

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,27 @@
1+
## 2.2.1
2+
3+
* [WebDriver] Use filename for `uploadFile` by @VikalpP. See #1797
4+
* [Polly] Take configuration values from Puppeteer. Fix #1766 by @VikalpP
5+
* [Polly] Add preconditions to check for puppeteer page availability by @VikalpP. Fixes #1767
6+
* [Puppeteer] Configure speed of input with `pressKeyDelay` option. By @hubidu
7+
* Fixed support object definitions in steps.d.ts by @johnyb. Fixes #1795
8+
* Fixed `Data().Scenario().injectDependencies()` is not a function by @andrerleao
9+
* Fixed crash when using xScenario & Scenario.skip with tag by @VikalpP. Fixes #1751
10+
* Dynamic configuration of helpers can be performed with async function. See #1786 by @cviejo
11+
* Added TS definitions for internal objects by @Vorobeyko
12+
* [TestCafe] Actions implemented by @hubidu
13+
* `grabPageScrollPosition`
14+
* `scrollPageToTop`
15+
* `scrollPageToBottom`
16+
* `scrollTo`
17+
* `switchTo`
18+
* BDD improvements:
19+
* Fix for snippets command with a .feature file that has special characters by @asselin
20+
* Fix `--path` option on `gherkin:snippets` command by @asselin. See #1790
21+
* Added `--feature` option to `gherkin:snippets` to enable creating snippets for a subset of .feature files. See #1803 by @asselin.
22+
* Fixed: dynamic configs not reset after test. Fixes #1776 by @cviejo.
23+
24+
125
## 2.2.0
226

327
* **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.

docs/puppeteer.md

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@ Make sure `Puppeteer` helper is enabled in `codecept.conf.js` config:
5252
helpers: {
5353
Puppeteer: {
5454
url: "http://localhost",
55-
show: false
55+
show: true
5656
}
5757
}
5858
// ..
5959
}
6060
```
6161

62-
Turn on the `show` option if you want to follow test progress in a window. This is very useful for debugging.
62+
> Turn off the `show` option if you want to run test in headless mode.
6363
6464
Puppeteer uses different strategies to detect if a page is loaded. In configuration use `waitForNavigation` option for that:
6565

@@ -69,6 +69,7 @@ By default it is set to `domcontentloaded` which waits for `DOMContentLoaded` ev
6969
helpers: {
7070
Puppeteer: {
7171
url: "http://localhost",
72+
show: true,
7273
waitForNavigation: "networkidle0"
7374
}
7475
}
@@ -77,7 +78,7 @@ By default it is set to `domcontentloaded` which waits for `DOMContentLoaded` ev
7778
When a test runs faster than application it is recommended to increase `waitForAction` config value.
7879
It will wait for a small amount of time (100ms) by default after each user action is taken.
7980

80-
> More options are listed in [helper reference](http://codecept.io/helpers/Puppeteer/).
81+
> More options are listed in [helper reference](http://codecept.io/helpers/Puppeteer/).
8182
8283
## Writing Tests
8384

@@ -155,7 +156,7 @@ Scenario('get value of current tasks', async (I) => {
155156

156157
### Within
157158

158-
In case some actions should be taken inside one element (a container or modal window) you can use `within` block to narrow the scope.
159+
In case some actions should be taken inside one element (a container or modal window or iframe) you can use `within` block to narrow the scope.
159160
Please take a note that you can't use within inside another within in Puppeteer helper:
160161

161162
```js
@@ -167,15 +168,58 @@ within('.todoapp', () => {
167168
I.see('0 items left', '.todo-count');
168169
```
169170

171+
> [▶ Learn more about basic commands](https://codecept.io/basics#writing-tests)
172+
170173
CodeceptJS allows you to implement custom actions like `I.createTodo` or use **PageObjects**. Learn how to improve your tests in [PageObjects](http://codecept.io/pageobjects/) guide.
171174

172-
`within` can also work with [iframes](/acceptance/#iframes)
175+
> [▶ Demo project is available on GitHub](https://github.com/DavertMik/codeceptjs-todomvc-puppeteer)
176+
177+
## Mocking Requests
178+
179+
Web application sends various requetss to local services (Rest API, GraphQL) or to 3rd party services (CDNS, Google Analytics, etc).
180+
When you run tests with Puppeteer you can control those requests by mocking them. For instance, you can speed up your tests by blocking trackers, Google Analytics, and other services you don't control.
173181

174-
When running steps inside a within block will be shown with a shift.
182+
Also you can replace real request with a one explicitly defined. This is useful when you want to isolate application testing from a backend. For instance, if you don't want to save data to database, and you know the request which performs save, you can mock the request, so application will treat this as valid response, but no data will be actually saved.
175183

176-
![within](https://codecept.io/img/within.png)
184+
To mock requests enable additional helper [Polly](https://codecept.io/helpers/Polly) (which is based on Polly.js).
185+
186+
```js
187+
helpers: {
188+
Puppeteer: {
189+
// regular Puppeteer config here
190+
},
191+
Polly: {}
192+
}
193+
```
194+
195+
And install additional packages:
196+
197+
```
198+
npm i @pollyjs/core @pollyjs/adapter-puppeteer --save-dev
199+
```
177200

178-
> [Demo project is available on GitHub](https://github.com/DavertMik/codeceptjs-todomvc-puppeteer)
201+
After an installation function `mockRequest` will be added to `I` object. You can use it to explicitly define which requests to block and which response they should return instead:
202+
203+
```js
204+
// block all Google Analytics calls
205+
I.mockRequest('/google-analytics/*path', 200);
206+
// return an empty successful response
207+
I.mockRequest('GET', '/api/users', 200);
208+
// block post requests to /api/users and return predefined object
209+
I.mockRequest('POST', '/api/users', { user: 'davert' });
210+
// return error request with body
211+
I.mockRequest('GET', '/api/users/1', 404, { error: 'User not found' });
212+
```
213+
214+
> See [`mockRequest` API](https://codecept.io/helpers/Polly#mockrequest)
215+
216+
To see `mockRequest` method in intellisense auto completion don't forget to run `codeceptjs def` command:
217+
218+
```
219+
npx codeceptjs def
220+
```
221+
222+
Mocking rules will be kept while a test is running. To stop mocking use `I.stopMocking()` command
179223

180224
## Extending
181225

@@ -199,5 +243,7 @@ async renderPageToPdf() {
199243
}
200244
```
201245

202-
The same way you can also access `browser` object to implement more actions or handle events. [Learn more about Helpers](http://codecept.io/helpers/) in the corresponding guide.
246+
The same way you can also access `browser` object to implement more actions or handle events.
247+
248+
> [▶ Learn more about Helpers](http://codecept.io/helpers/)
203249

docs/testcafe.md

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# TestCafe
2+
3+
[TestCafe](https://devexpress.github.io/testcafe/) is another alternative engine for driving browsers. It is driven by unique technology which provides fast and simple cross browser testing for desktop and mobile browsers. Unlike WebDriver or Puppeteer, TestCafe doesn't control a browser at all. It is not a browser itself, like [Nightmare](https://codecept.io/nightmare) or Cypress. **TestCafe core is a proxy server** that runs behind the scene, and transforms all HTML and JS to include code that is needed for test automation.
4+
5+
![](/img/testcafe.png)
6+
7+
This is very smart idea. But to use TestCafe on daily basis you need to clearly understand its benefits and limitations:
8+
9+
### Pros
10+
11+
* **Fast**. Browser is controlled from inside a web page. This makes test run inside a browser as fast as your browser can render page with no extra network requests.
12+
* **Simple Cross-Browser Support.** Because TestCafe only launches browsers, it can **automate browser** on desktop or mobile. Unlike WebDriver, you don't need special version of browser and driver to prepare to run tests. Setup simplified. All you need is just a browser installed, and you are ready to go.
13+
* **Stable to Execution.** Because a test is executed inside a browser, the network latency effects are reduced. Unlike WebDriver you won't hit stale element exceptions, or element not interactable exceptions, as from within a web browser all DOM elements are accessible.
14+
15+
## Cons
16+
17+
* **Magic.** Browsers executed in TestCafe are not aware that they run in test mode. So at some edges automation control can be broken. It's also quite hard to debug possible issues, as you don't know how actually a web page is parsed to inject automation scripts.
18+
* **No Browser Control.** Because TestCafe do not control browser, you can't actually automate all users actions. For instance, TestCafe can't open new tabs or open a new browser window in incognito mode. There can be also some issues running tests on 3rd party servers or inside iframes.
19+
* **Simulated Events.** Events like `click` or `doubleClick` are simulated by JavaScript internally. Inside WebDriver or Puppeteer, where those events are dispatched by a browser, called native events. Native events are closer to real user experience. So in some cases simulated events wouldn't represent actual user experience, which can lead to false positive results. For instance, a button which can't be physically clicked by a user, would be clickable inside TestCafe.
20+
21+
Anyway, TestCafe is a good option to start if you need cross browser testing. And here is the **reason to use TestCafe with CodeceptJS: if you hit an edge case or issue, you can easily switch your tests to WebDriver**. As all helpers in CodeceptJS share the same syntax.
22+
23+
CodeceptJS is a rich testing frameworks which also provides features missing in original TestCafe:
24+
25+
* [Cucumber integration](https://codecept.io/bdd)
26+
* [Real Page Objects](https://codecept.io/pageobjects)
27+
* [Data Management via API](https://codecept.io/data)
28+
* and others
29+
30+
## Writing Tests
31+
32+
To start using TestCafe with CodeceptJS install both via NPM
33+
34+
> If you don't have `package.json` in your project, create it with `npm init -y`.
35+
36+
```
37+
npm i codeceptjs testcafe --save-dev
38+
```
39+
40+
Then you need to initialize a project, selecting TestCafe when asked:
41+
42+
```
43+
npx codeceptjs init
44+
```
45+
46+
A first test should be created with `codeceptjs gt` command
47+
48+
```
49+
npx codeceptjs gt
50+
```
51+
52+
In the next example we will [TodoMVC application](http://todomvc.com/examples/angularjs/#/). So let's create a test which will fill in todo list:
53+
54+
```js
55+
Feature('TodoMVC');
56+
57+
Scenario('create todo item', (I) => {
58+
I.amOnPage('http://todomvc.com/examples/angularjs/#/');
59+
I.fillField('.new-todo', todo)
60+
I.pressKey('Enter');
61+
I.seeNumberOfVisibleElements('.todo-list li', 1);
62+
I.see('1 item left', '.todo-count');
63+
});
64+
```
65+
66+
Same syntax is the same for all helpers in CodeceptJS so to learn more about available commands learn [CodeceptJS Basics](https://codecept.io/basics).
67+
68+
> [▶ Complete list of TestCafe actions](https://codecept.io/helpers/TestCafe)
69+
70+
## Page Objects
71+
72+
Multiple tests can be refactored to share some logic and locators. It is recommended to use PageObjects for this. For instance, in example above, we could create special actions for creating todos and checking them. If we move such methods in a corresponding object a test would look even clearer:
73+
74+
```js
75+
Scenario('Create a new todo item', async (I, TodosPage) => {
76+
I.say('Given I have an empty todo list')
77+
78+
I.say('When I create a todo "foo"')
79+
TodosPage.enterTodo('foo')
80+
81+
I.say('Then I see the new todo on my list')
82+
TodosPage.seeNumberOfTodos(1)
83+
84+
I.saveScreenshot('create-todo-item.png')
85+
})
86+
87+
Scenario('Create multiple todo items', async (I, TodosPage) => {
88+
I.say('Given I have an empty todo list')
89+
90+
I.say('When I create todos "foo", "bar" and "baz"')
91+
TodosPage.enterTodo('foo')
92+
TodosPage.enterTodo('bar')
93+
TodosPage.enterTodo('baz')
94+
95+
I.say('Then I have these 3 todos on my list')
96+
TodosPage.seeNumberOfTodos(3)
97+
98+
I.saveScreenshot('create-multiple-todo-items.png')
99+
})
100+
```
101+
102+
> [Source code of this example](https://github.com/hubidu/codeceptjs-testcafe-todomvc) is available on GitHub.
103+
104+
A PageObject can be injected into a test by its name. Here is how TodosPage looks like:
105+
106+
```js
107+
// inside todos_page.js
108+
const { I } = inject();
109+
110+
module.exports = {
111+
goto() {
112+
I.amOnPage('http://todomvc.com/examples/angularjs/#/')
113+
},
114+
115+
enterTodo(todo) {
116+
I.fillField('.new-todo', todo)
117+
I.pressKey('Enter')
118+
},
119+
120+
seeNumberOfTodos(numberOfTodos) {
121+
I.seeNumberOfVisibleElements('.todo-list li', numberOfTodos)
122+
},
123+
}
124+
```
125+
126+
> [▶ Read more about PageObjects in CodeceptJS](https://codecept.io/pageobjects)
127+
128+
## Extending
129+
130+
If you want to use TestCafe API inside your tests you can put them into actions of `I` object. To do so you can generate a new helper, access TestCafe helper, and get the test controller.
131+
132+
Create a helper using `codecepjs gh` command.
133+
134+
```
135+
npx codeceptjs gh
136+
```
137+
138+
All methods of newly created class will be added to `I` object.
139+
140+
```js
141+
const Helper = codeceptjs.helper;
142+
143+
class MyTestCafe extends Helper {
144+
145+
slowlyFillField(field, text) {
146+
// import test controller from TestCafe helper
147+
const { t } = this.helpers.TestCafe;
148+
// use TestCafe API here
149+
return t.setTestSpeed(0.1)
150+
.typeText(field, text);
151+
}
152+
153+
}
154+
```

docs/webdriver.md

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ Configuration for WebDriver should be provided inside `codecept.conf.js` file un
7979

8080
WebDriver protocol works over HTTP, so you need to have a Selenium Server to be running or other service that will launch a browser for you. That's why you may need to specify `host`, `port`, `protocol`, and `path` parameters.
8181

82-
By default, those parameters are set to connect to local Selenium Server but they should be changed if you want to run tests via [Cloud Services](https://codecept.io/helpers/WebDriver#cloud-providers) (Sauce Labs, etc) or inside Docker container.
82+
By default, those parameters are set to connect to local Selenium Server but they should be changed if you want to run tests via [Cloud Services](https://codecept.io/helpers/WebDriver#cloud-providers). You may also need `user` and `key` parameters to authenticate on cloud service.
8383

8484
If you want to run tests using raw ChromeDriver (which also supports WebDriver protocol) avoiding Selenium Server, you should provide following configuration:
8585

@@ -112,6 +112,31 @@ desiredCapabilities: {
112112

113113
There are also [browser and platform specific capabilities](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities). Services like SauceLabs, BrowserStack or browser vendors can provide their own specific capabilities for more tuning.
114114

115+
Here is a sample BrowserStack config for running tests on iOS mobile browser:
116+
117+
```js
118+
helpers: {
119+
WebDriver: {
120+
host: 'hub.browserstack.com',
121+
path: '/wd/hub',
122+
url: 'http://WEBSITE:8080/renderer',
123+
user: 'xx', // credentials
124+
key: 'xx', // credentials
125+
browser: 'iphone',
126+
desiredCapabilities: {
127+
'os_version' : '11',
128+
'device' : 'iPhone 8', // you can select device
129+
'real_mobile' : 'true', // real or emulated
130+
'browserstack.local' : 'true',
131+
'browserstack.debug' : 'true',
132+
'browserstack.networkLogs' : 'true',
133+
'browserstack.appium_version' : '1.9.1',
134+
'browserstack.user' : 'xx', // credentials
135+
'browserstack.key' : 'xx' // credentials
136+
}
137+
}
138+
```
139+
115140
There are also options specific to CodeceptJS. By default CodeceptJS runs tests in the same browser window but clears cookies and local storage after each test. This behavior can be changed with these options:
116141
117142
```js
@@ -124,7 +149,7 @@ keepCookies: true,
124149
125150
> ▶ More config options available on [WebDriver helper reference](https://codecept.io/helpers/WebDriver#configuration)
126151
127-
### Configuring WebDriver for CI
152+
### Configuring CI
128153
129154
To develop tests it's fine to use local Selenium Server and window mode. Setting up WebDriver on remote CI (Continous Integration) server is different. If there is no desktop and no window mode on CI.
130155

lib/helper/Polly.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,21 @@ class Polly extends Helper {
9191
* I.mockRequest('GET', '/api/users', 200);
9292
* I.mockRequest('ANY', '/secretsRoutes/*', 403);
9393
* I.mockRequest('POST', '/secrets', { secrets: 'fakeSecrets' });
94+
* I.mockRequest('GET', '/api/users/1', 404, 'User not found');
9495
* ```
9596
*
9697
* Multiple requests
9798
*
9899
* ```js
99100
* I.mockRequest('GET', ['/secrets', '/v2/secrets'], 403);
100101
* ```
102+
* @param {string} method request method. Can be `GET`, `POST`, `PUT`, etc or `ANY`.
103+
* @param {string|array} oneOrMoreUrls url(s) to mock. Can be exact URL, a pattern, or an array of URLs.
104+
* @param {number|string|object} dataOrStatusCode status code when number provided. A response body otherwise
105+
* @param {string|object} additionalData response body when a status code is set by previous parameter.
106+
*
101107
*/
102-
async mockRequest(method, oneOrMoreUrls, dataOrStatusCode) {
108+
async mockRequest(method, oneOrMoreUrls, dataOrStatusCode, additionalData = null) {
103109
await this._checkAndStartMocking();
104110
const puppeteerConfigUrl = this.helpers.Puppeteer && this.helpers.Puppeteer.options.url;
105111

@@ -111,6 +117,9 @@ class Polly extends Helper {
111117

112118
if (typeof dataOrStatusCode === 'number') {
113119
const statusCode = dataOrStatusCode;
120+
if (additionalData) {
121+
return handler.intercept((_, res) => res.status(statusCode).send(additionalData));
122+
}
114123
return handler.intercept((_, res) => res.sendStatus(statusCode));
115124
}
116125
const data = dataOrStatusCode;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codeceptjs",
3-
"version": "2.2.0",
3+
"version": "2.2.1",
44
"description": "Modern Era Acceptance Testing Framework for NodeJS",
55
"keywords": [
66
"acceptance",

test/runner/interface_test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ describe('CodeceptJS Interface', () => {
184184
});
185185
});
186186

187-
it.only('should inject page objects via proxy', (done) => {
187+
it('should inject page objects via proxy', (done) => {
188188
exec(`${config_run_config('../inject-fail-example')} --debug`, (err, stdout) => {
189189
stdout.should.include('qw');
190190
stdout.should.include('OK | 1 passed');

0 commit comments

Comments
 (0)