Skip to content

Commit 12009e0

Browse files
authored
implemented eachElement plugin (#3221)
1 parent c10666c commit 12009e0

File tree

8 files changed

+441
-61
lines changed

8 files changed

+441
-61
lines changed

docs/playwright.md

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,10 @@ If you need to get element's value inside a test you can use `grab*` methods. Th
175175
```js
176176
const assert = require('assert');
177177
Scenario('get value of current tasks', async ({ I }) => {
178-
I.createTodo('do 1');
179-
I.createTodo('do 2');
178+
I.fillField('.todo', 'my first item');
179+
I.pressKey('Enter')
180+
I.fillField('.todo', 'my second item');
181+
I.pressKey('Enter')
180182
let numTodos = await I.grabTextFrom('.todo-count strong');
181183
assert.equal(2, numTodos);
182184
});
@@ -188,17 +190,35 @@ In case some actions should be taken inside one element (a container or modal wi
188190
Please take a note that you can't use within inside another within in Playwright helper:
189191

190192
```js
191-
within('.todoapp', () => {
192-
I.createTodo('my new item');
193+
await within('.todoapp', () => {
194+
I.fillField('.todo', 'my new item');
195+
I.pressKey('Enter')
193196
I.see('1 item left', '.todo-count');
194197
I.click('.todo-list input.toggle');
195198
});
196199
I.see('0 items left', '.todo-count');
197200
```
198201

199-
> [▶ Learn more about basic commands](/basics#writing-tests)
202+
### Each Element <Badge text="Since 3.3" type="warning"/>
200203

201-
CodeceptJS allows you to implement custom actions like `I.createTodo` or use **PageObjects**. Learn how to improve your tests in [PageObjects](https://codecept.io/pageobjects/) guide.
204+
Usually, CodeceptJS performs an action on the first matched element.
205+
In case you want to do an action on each element found, use the special function `eachElement` which comes from [eachElement](https://codecept.io/plugins/#eachelement) plugin.
206+
207+
`eachElement` function matches all elements by locator and performs a callback on each of those element. A callback function receives [ElementHandle instance](https://playwright.dev/docs/api/class-elementhandle) from Playwright API. `eachElement` may perform arbitrary actions on a page, so the first argument should by a description of the actions performed. This description will be used for logging purposes.
208+
209+
Usage example
210+
211+
```js
212+
await eachElement(
213+
'tick all checkboxes',
214+
'input.custom-checkbox',
215+
async (el, index) => {
216+
await el.check();
217+
});
218+
);
219+
```
220+
221+
> ℹ Learn more about [eachElement plugin](/plugins/#eachelement)
202222
203223
## Multi Session Testing
204224

@@ -307,19 +327,6 @@ Scenario('website looks nice on iPhone', () => {
307327
});
308328
```
309329

310-
## Configuring CI
311-
312-
### GitHub Actions
313-
314-
Playwright can be added to GitHub Actions using [official action](https://github.com/microsoft/playwright-github-action). Use it before starting CodeceptJS tests to install all dependencies. It is important to run tests in headless mode ([otherwise you will need to enable xvfb to emulate desktop](https://github.com/microsoft/playwright-github-action#run-in-headful-mode)).
315-
316-
```yml
317-
# from workflows/tests.yml
318-
- uses: microsoft/playwright-github-action@v1
319-
- name: run CodeceptJS tests
320-
run: npx codeceptjs run
321-
```
322-
323330
## Accessing Playwright API
324331

325332
To get [Playwright API](https://playwright.dev/docs/api/class-playwright) inside a test use `I.usePlaywrightTo` method with a callback.
@@ -496,6 +503,7 @@ Open `index.html` in your browser to view the full interactive coverage report.
496503
![](https://user-images.githubusercontent.com/16587779/131858993-87d1aafc-8ef1-4a82-867d-e64a13e36106.png)
497504

498505
![](https://user-images.githubusercontent.com/16587779/131859006-c6f17d18-c603-44a5-9d59-0670177276cf.png)
506+
499507
## Extending Helper
500508

501509
To create custom `I.*` commands using Playwright API you need to create a custom helper.
@@ -538,3 +546,17 @@ async setPermissions() {
538546
> [▶ Learn more about BrowserContext](https://github.com/microsoft/playwright/blob/master/docs/src/api/class-browsercontext.md)
539547
540548
> [▶ Learn more about Helpers](https://codecept.io/helpers/)
549+
550+
551+
## Configuring CI
552+
553+
### GitHub Actions
554+
555+
Playwright can be added to GitHub Actions using [official action](https://github.com/microsoft/playwright-github-action). Use it before starting CodeceptJS tests to install all dependencies. It is important to run tests in headless mode ([otherwise you will need to enable xvfb to emulate desktop](https://github.com/microsoft/playwright-github-action#run-in-headful-mode)).
556+
557+
```yml
558+
# from workflows/tests.yml
559+
- uses: microsoft/playwright-github-action@v1
560+
- name: run CodeceptJS tests
561+
run: npx codeceptjs run
562+
```

docs/plugins.md

Lines changed: 106 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -501,11 +501,76 @@ I.click('=sign-up'); // matches => [data-qa=sign-up]
501501
502502
- `config`
503503
504+
## eachElement
505+
506+
Provides `eachElement` global function to iterate over found elements to perform actions on them.
507+
508+
`eachElement` takes following args:
509+
510+
- `purpose` - the goal of an action. A comment text that will be displayed in output.
511+
- `locator` - a CSS/XPath locator to match elements
512+
- `fn(element, index)` - **asynchronous** function which will be executed for each matched element.
513+
514+
Example of usage:
515+
516+
```js
517+
// this example works with Playwright and Puppeteer helper
518+
await eachElement('click all checkboxes', 'form input[type=checkbox]', async (el) => {
519+
await el.click();
520+
});
521+
```
522+
523+
Click odd elements:
524+
525+
```js
526+
// this example works with Playwright and Puppeteer helper
527+
await eachElement('click odd buttons', '.button-select', async (el, index) => {
528+
if (index % 2) await el.click();
529+
});
530+
```
531+
532+
Check all elements for visibility:
533+
534+
```js
535+
// this example works with Playwright and Puppeteer helper
536+
const assert = require('assert');
537+
await eachElement('check all items are visible', '.item', async (el) => {
538+
assert(await el.isVisible());
539+
});
540+
```
541+
542+
This method works with WebDriver, Playwright, Puppeteer, Appium helpers.
543+
544+
Function parameter `el` represents a matched element.
545+
Depending on a helper API of `el` can be different. Refer to API of corresponding browser testing engine for a complete API list:
546+
547+
- [Playwright ElementHandle][4]
548+
- [Puppeteer][5]
549+
- [webdriverio element][6]
550+
551+
#### Configuration
552+
553+
- `registerGlobal` - to register `eachElement` function globally, true by default
554+
555+
If `registerGlobal` is false you can use eachElement from the plugin:
556+
557+
```js
558+
const eachElement = codeceptjs.container.plugins('eachElement');
559+
```
560+
561+
### Parameters
562+
563+
- `purpose` **[string][7]**
564+
- `locator` **CodeceptJS.LocatorOrString**
565+
- `fn` **[Function][8]**
566+
567+
Returns **([Promise][9]&lt;any> | [undefined][10])**
568+
504569
## fakerTransform
505570
506-
Use the [faker.js][4] package to generate fake data inside examples on your gherkin tests
571+
Use the [faker.js][11] package to generate fake data inside examples on your gherkin tests
507572
508-
![Faker.js][5]
573+
![Faker.js][12]
509574
510575
#### Usage
511576
@@ -543,7 +608,7 @@ Scenario Outline: ...
543608
544609
## pauseOnFail
545610
546-
Automatically launches [interactive pause][6] when a test fails.
611+
Automatically launches [interactive pause][13] when a test fails.
547612
548613
Useful for debugging flaky tests on local environment.
549614
Add this plugin to config file:
@@ -726,14 +791,14 @@ Possible config options:
726791
727792
## selenoid
728793
729-
[Selenoid][7] plugin automatically starts browsers and video recording.
794+
[Selenoid][14] plugin automatically starts browsers and video recording.
730795
Works with WebDriver helper.
731796
732797
### Prerequisite
733798
734799
This plugin **requires Docker** to be installed.
735800
736-
> If you have issues starting Selenoid with this plugin consider using the official [Configuration Manager][8] tool from Selenoid
801+
> If you have issues starting Selenoid with this plugin consider using the official [Configuration Manager][15] tool from Selenoid
737802
738803
### Usage
739804
@@ -762,7 +827,7 @@ plugins: {
762827
}
763828
```
764829
765-
When `autoCreate` is enabled it will pull the [latest Selenoid from DockerHub][9] and start Selenoid automatically.
830+
When `autoCreate` is enabled it will pull the [latest Selenoid from DockerHub][16] and start Selenoid automatically.
766831
It will also create `browsers.json` file required by Selenoid.
767832
768833
In automatic mode the latest version of browser will be used for tests. It is recommended to specify exact version of each browser inside `browsers.json` file.
@@ -774,10 +839,10 @@ In automatic mode the latest version of browser will be used for tests. It is re
774839
While this plugin can create containers for you for better control it is recommended to create and launch containers manually.
775840
This is especially useful for Continous Integration server as you can configure scaling for Selenoid containers.
776841
777-
> Use [Selenoid Configuration Manager][8] to create and start containers semi-automatically.
842+
> Use [Selenoid Configuration Manager][15] to create and start containers semi-automatically.
778843
779844
1. Create `browsers.json` file in the same directory `codecept.conf.js` is located
780-
[Refer to Selenoid documentation][10] to know more about browsers.json.
845+
[Refer to Selenoid documentation][17] to know more about browsers.json.
781846
782847
_Sample browsers.json_
783848
@@ -802,7 +867,7 @@ _Sample browsers.json_
802867
803868
2. Create Selenoid container
804869
805-
Run the following command to create a container. To know more [refer here][11]
870+
Run the following command to create a container. To know more [refer here][18]
806871
807872
```bash
808873
docker create \
@@ -835,15 +900,15 @@ When `allure` plugin is enabled a video is attached to report automatically.
835900
| enableVideo | Enable video recording and use `video` folder of output (default: false) |
836901
| enableLog | Enable log recording and use `logs` folder of output (default: false) |
837902
| deletePassed | Delete video and logs of passed tests (default : true) |
838-
| additionalParams | example: `additionalParams: '--env TEST=test'` [Refer here][12] to know more |
903+
| additionalParams | example: `additionalParams: '--env TEST=test'` [Refer here][19] to know more |
839904
840905
### Parameters
841906
842907
- `config`
843908
844909
## stepByStepReport
845910
846-
![step-by-step-report][13]
911+
![step-by-step-report][20]
847912
848913
Generates step by step report for a test.
849914
After each step in a test a screenshot is created. After test executed screenshots are combined into slideshow.
@@ -1024,7 +1089,7 @@ This plugin allows to run webdriverio services like:
10241089
- browserstack
10251090
- appium
10261091
1027-
A complete list of all available services can be found on [webdriverio website][14].
1092+
A complete list of all available services can be found on [webdriverio website][21].
10281093
10291094
#### Setup
10301095
@@ -1036,7 +1101,7 @@ See examples below:
10361101
10371102
#### Selenium Standalone Service
10381103
1039-
Install `@wdio/selenium-standalone-service` package, as [described here][15].
1104+
Install `@wdio/selenium-standalone-service` package, as [described here][22].
10401105
It is important to make sure it is compatible with current webdriverio version.
10411106
10421107
Enable `wdio` plugin in plugins list and add `selenium-standalone` service:
@@ -1055,7 +1120,7 @@ Please note, this service can be used with Protractor helper as well!
10551120
10561121
#### Sauce Service
10571122
1058-
Install `@wdio/sauce-service` package, as [described here][16].
1123+
Install `@wdio/sauce-service` package, as [described here][23].
10591124
It is important to make sure it is compatible with current webdriverio version.
10601125
10611126
Enable `wdio` plugin in plugins list and add `sauce` service:
@@ -1091,28 +1156,42 @@ In the same manner additional services from webdriverio can be installed, enable
10911156
10921157
[3]: https://codecept.io/locators#custom-locators
10931158
1094-
[4]: https://www.npmjs.com/package/faker
1159+
[4]: https://playwright.dev/docs/api/class-elementhandle
1160+
1161+
[5]: https://pptr.dev/#?product=Puppeteer&show=api-class-elementhandle
1162+
1163+
[6]: https://webdriver.io/docs/api
1164+
1165+
[7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
1166+
1167+
[8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function
1168+
1169+
[9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise
1170+
1171+
[10]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined
1172+
1173+
[11]: https://www.npmjs.com/package/faker
10951174
1096-
[5]: https://raw.githubusercontent.com/Marak/faker.js/master/logo.png
1175+
[12]: https://raw.githubusercontent.com/Marak/faker.js/master/logo.png
10971176
1098-
[6]: /basics/#pause
1177+
[13]: /basics/#pause
10991178
1100-
[7]: https://aerokube.com/selenoid/
1179+
[14]: https://aerokube.com/selenoid/
11011180
1102-
[8]: https://aerokube.com/cm/latest/
1181+
[15]: https://aerokube.com/cm/latest/
11031182
1104-
[9]: https://hub.docker.com/u/selenoid
1183+
[16]: https://hub.docker.com/u/selenoid
11051184
1106-
[10]: https://aerokube.com/selenoid/latest/#_prepare_configuration
1185+
[17]: https://aerokube.com/selenoid/latest/#_prepare_configuration
11071186
1108-
[11]: https://aerokube.com/selenoid/latest/#_option_2_start_selenoid_container
1187+
[18]: https://aerokube.com/selenoid/latest/#_option_2_start_selenoid_container
11091188
1110-
[12]: https://docs.docker.com/engine/reference/commandline/create/
1189+
[19]: https://docs.docker.com/engine/reference/commandline/create/
11111190
1112-
[13]: https://codecept.io/img/codeceptjs-slideshow.gif
1191+
[20]: https://codecept.io/img/codeceptjs-slideshow.gif
11131192
1114-
[14]: https://webdriver.io
1193+
[21]: https://webdriver.io
11151194
1116-
[15]: https://webdriver.io/docs/selenium-standalone-service.html
1195+
[22]: https://webdriver.io/docs/selenium-standalone-service.html
11171196
1118-
[16]: https://webdriver.io/docs/sauce-service.html
1197+
[23]: https://webdriver.io/docs/sauce-service.html

docs/puppeteer.md

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ Tests consist with a scenario of user's action taken on a page. The most widely
110110
All actions which interact with elements **support CSS and XPath locators**. Actions like `click` or `fillField` by locate elements by their name or value on a page:
111111

112112
```js
113-
114113
// search for link or button
115114
I.click('Login');
116115
// locate field by its label
@@ -172,8 +171,10 @@ If you need to get element's value inside a test you can use `grab*` methods. Th
172171
```js
173172
const assert = require('assert');
174173
Scenario('get value of current tasks', async ({ I }) => {
175-
I.createTodo('do 1');
176-
I.createTodo('do 2');
174+
I.fillField('.todo', 'my first item');
175+
I.pressKey('Enter')
176+
I.fillField('.todo', 'my second item');
177+
I.pressKey('Enter')
177178
let numTodos = await I.grabTextFrom('.todo-count strong');
178179
assert.equal(2, numTodos);
179180
});
@@ -185,20 +186,35 @@ In case some actions should be taken inside one element (a container or modal wi
185186
Please take a note that you can't use within inside another within in Puppeteer helper:
186187

187188
```js
188-
within('.todoapp', () => {
189-
I.createTodo('my new item');
189+
await within('.todoapp', () => {
190+
I.fillField('.todo', 'my new item');
191+
I.pressKey('Enter')
190192
I.see('1 item left', '.todo-count');
191193
I.click('.todo-list input.toggle');
192194
});
193195
I.see('0 items left', '.todo-count');
194196
```
195197

196-
> [▶ Learn more about basic commands](/basics#writing-tests)
198+
### Each Element <Badge text="Since 3.3" type="warning"/>
199+
200+
Usually, CodeceptJS performs an action on the first matched element.
201+
In case you want to do an action on each element found, use the special function `eachElement` which comes from [eachElement](https://codecept.io/plugins/#eachelement) plugin.
202+
203+
`eachElement` function matches all elements by locator and performs a callback on each of those element. A callback function receives [ElementHandle instance](https://pptr.dev/#?product=Puppeteer&show=api-class-elementhandle) from Puppeteer API. `eachElement` may perform arbitrary actions on a page, so the first argument should by a description of the actions performed. This description will be used for logging purposes.
197204

198-
CodeceptJS allows you to implement custom actions like `I.createTodo` or use **PageObjects**. Learn how to improve your tests in [PageObjects](https://codecept.io/pageobjects/) guide.
205+
Usage example
199206

200-
> [▶ Demo project is available on GitHub](https://github.com/DavertMik/codeceptjs-todomvc-puppeteer)
207+
```js
208+
await eachElement(
209+
'click all checkboxes',
210+
'input.custom-checkbox',
211+
async (el, index) => {
212+
await el.click();
213+
});
214+
);
215+
```
201216

217+
> ℹ Learn more about [eachElement plugin](/plugins/#eachelement)
202218
203219
## Mocking Requests
204220

0 commit comments

Comments
 (0)