Skip to content

Commit 51556a7

Browse files
authored
feat: highlight the interacting elements (#3672)
* feat: highlight the interacting elements * fix: puppeteer and support wdio
1 parent 5ee921d commit 51556a7

File tree

11 files changed

+114
-9
lines changed

11 files changed

+114
-9
lines changed

Diff for: docs/helpers/Appium.md

+2
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,8 @@ Field is located by name, label, CSS or XPath
841841

842842
```js
843843
I.appendField('#myTextField', 'appended');
844+
// typing secret
845+
I.appendField('password', secret('123456'));
844846
```
845847

846848
#### Parameters

Diff for: docs/helpers/Nightmare.md

+2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ Field is located by name, label, CSS or XPath
9191

9292
```js
9393
I.appendField('#myTextField', 'appended');
94+
// typing secret
95+
I.appendField('password', secret('123456'));
9496
```
9597

9698
#### Parameters

Diff for: docs/helpers/Playwright.md

+6
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ Type: [object][5]
7474
- `ignoreLog` **[Array][15]<[string][8]>?** An array with console message types that are not logged to debug log. Default value is `['warning', 'log']`. E.g. you can set `[]` to log all messages. See all possible [values][38].
7575
- `ignoreHTTPSErrors` **[boolean][26]?** Allows access to untrustworthy pages, e.g. to a page with an expired certificate. Default value is `false`
7676
- `bypassCSP` **[boolean][26]?** bypass Content Security Policy or CSP
77+
- `highlightElement` **[boolean][26]?** highlight the interacting elements
7778

7879

7980

@@ -378,6 +379,8 @@ Field is located by name, label, CSS or XPath
378379

379380
```js
380381
I.appendField('#myTextField', 'appended');
382+
// typing secret
383+
I.appendField('password', secret('123456'));
381384
```
382385

383386
#### Parameters
@@ -1826,6 +1829,9 @@ I.type('4141555311111111', 100);
18261829

18271830
// passing in an array
18281831
I.type(['T', 'E', 'X', 'T']);
1832+
1833+
// passing a secret
1834+
I.type(secret('123456'));
18291835
```
18301836

18311837
#### Parameters

Diff for: docs/helpers/Puppeteer.md

+6
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Type: [object][4]
5656
- `manualStart` **[boolean][17]?** do not start browser before a test, start it manually inside a helper with `this.helpers["Puppeteer"]._startBrowser()`.
5757
- `browser` **[string][6]?** can be changed to `firefox` when using [puppeteer-firefox][2].
5858
- `chrome` **[object][4]?** pass additional [Puppeteer run options][22].
59+
- `highlightElement` **[boolean][17]?** highlight the interacting elements
5960

6061

6162

@@ -296,6 +297,8 @@ Field is located by name, label, CSS or XPath
296297

297298
```js
298299
I.appendField('#myTextField', 'appended');
300+
// typing secret
301+
I.appendField('password', secret('123456'));
299302
```
300303

301304
#### Parameters
@@ -1786,6 +1789,9 @@ I.type('4141555311111111', 100);
17861789

17871790
// passing in an array
17881791
I.type(['T', 'E', 'X', 'T']);
1792+
1793+
// passing a secret
1794+
I.type(secret('123456'));
17891795
```
17901796
17911797
#### Parameters

Diff for: docs/helpers/TestCafe.md

+2
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ Field is located by name, label, CSS or XPath
116116

117117
```js
118118
I.appendField('#myTextField', 'appended');
119+
// typing secret
120+
I.appendField('password', secret('123456'));
119121
```
120122

121123
#### Parameters

Diff for: docs/helpers/WebDriver.md

+10-4
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Type: [object][16]
2727
### Properties
2828

2929
- `url` **[string][17]** base url of website to be tested.
30-
- `browser` **[string][17]** browser in which to perform testing.
30+
- `browser` **[string][17]** Browser in which to perform testing.
3131
- `basicAuth` **[string][17]?** (optional) the basic authentication to pass to base url. Example: {username: 'username', password: 'password'}
3232
- `host` **[string][17]?** WebDriver host to connect.
3333
- `port` **[number][20]?** WebDriver port to connect.
@@ -45,6 +45,7 @@ Type: [object][16]
4545
- `desiredCapabilities` **[object][16]?** Selenium's [desired capabilities][6].
4646
- `manualStart` **[boolean][29]?** do not start browser before a test, start it manually inside a helper with `this.helpers["WebDriver"]._startBrowser()`.
4747
- `timeouts` **[object][16]?** [WebDriver timeouts][34] defined as hash.
48+
- `highlightElement` **[boolean][29]?** highlight the interacting elements
4849

4950

5051

@@ -382,7 +383,7 @@ this.helpers['WebDriver']._locate({name: 'password'}).then //...
382383

383384
### _locateCheckable
384385

385-
Find a checkbox by providing human readable text:
386+
Find a checkbox by providing human-readable text:
386387

387388
```js
388389
this.helpers['WebDriver']._locateCheckable('I agree with terms and conditions').then // ...
@@ -394,7 +395,7 @@ this.helpers['WebDriver']._locateCheckable('I agree with terms and conditions').
394395

395396
### _locateClickable
396397

397-
Find a clickable element by providing human readable text:
398+
Find a clickable element by providing human-readable text:
398399

399400
```js
400401
const els = await this.helpers.WebDriver._locateClickable('Next page');
@@ -408,7 +409,7 @@ const els = await this.helpers.WebDriver._locateClickable('Next page', '.pages')
408409

409410
### _locateFields
410411

411-
Find field elements by providing human readable text:
412+
Find field elements by providing human-readable text:
412413

413414
```js
414415
this.helpers['WebDriver']._locateFields('Your email').then // ...
@@ -464,6 +465,8 @@ Field is located by name, label, CSS or XPath
464465

465466
```js
466467
I.appendField('#myTextField', 'appended');
468+
// typing secret
469+
I.appendField('password', secret('123456'));
467470
```
468471

469472
#### Parameters
@@ -1985,6 +1988,9 @@ I.type('4141555311111111', 100);
19851988

19861989
// passing in an array
19871990
I.type(['T', 'E', 'X', 'T']);
1991+
1992+
// passing a secret
1993+
I.type(secret('123456'));
19881994
```
19891995
19901996
#### Parameters

Diff for: lib/helper/Playwright.js

+20
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const {
4343
setRestartStrategy, restartsSession, restartsContext, restartsBrowser,
4444
} = require('./extras/PlaywrightRestartOpts');
4545
const { createValueEngine, createDisabledEngine } = require('./extras/PlaywrightPropEngine');
46+
const { highlightElement, unhighlightElement } = require('./scripts/highlightElement');
4647

4748
const pathSeparator = path.sep;
4849

@@ -89,6 +90,7 @@ const pathSeparator = path.sep;
8990
* @prop {string[]} [ignoreLog] - An array with console message types that are not logged to debug log. Default value is `['warning', 'log']`. E.g. you can set `[]` to log all messages. See all possible [values](https://playwright.dev/docs/api/class-consolemessage#console-message-type).
9091
* @prop {boolean} [ignoreHTTPSErrors] - Allows access to untrustworthy pages, e.g. to a page with an expired certificate. Default value is `false`
9192
* @prop {boolean} [bypassCSP] - bypass Content Security Policy or CSP
93+
* @prop {boolean} [highlightElement] - highlight the interacting elements
9294
*/
9395
const config = {};
9496

@@ -1464,7 +1466,16 @@ class Playwright extends Helper {
14641466
} else if (editable) {
14651467
await this._evaluateHandeInContext(el => el.innerHTML = '', el);
14661468
}
1469+
1470+
if (this.options.highlightElement) {
1471+
highlightElement(el, this.page);
1472+
}
1473+
14671474
await el.type(value.toString(), { delay: this.options.pressKeyDelay });
1475+
1476+
if (this.options.highlightElement) {
1477+
unhighlightElement(el, this.page);
1478+
}
14681479
return this._waitForAction();
14691480
}
14701481

@@ -2589,6 +2600,11 @@ async function proceedClick(locator, context = null, options = {}) {
25892600
} else {
25902601
assertElementExists(els, locator, 'Clickable element');
25912602
}
2603+
2604+
const element = els[0];
2605+
if (this.options.highlightElement) {
2606+
highlightElement(element, this.page);
2607+
}
25922608
/*
25932609
using the force true options itself but instead dispatching a click
25942610
*/
@@ -2603,6 +2619,10 @@ async function proceedClick(locator, context = null, options = {}) {
26032619
promises.push(this.waitForNavigation());
26042620
}
26052621
promises.push(this._waitForAction());
2622+
2623+
if (this.options.highlightElement) {
2624+
unhighlightElement(element, this.page);
2625+
}
26062626
return Promise.all(promises);
26072627
}
26082628

Diff for: lib/helper/Puppeteer.js

+19
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const RemoteBrowserConnectionRefused = require('./errors/RemoteBrowserConnection
3333
const Popup = require('./extras/Popup');
3434
const Console = require('./extras/Console');
3535
const findReact = require('./extras/React');
36+
const { highlightElement, unhighlightElement } = require('./scripts/highlightElement');
3637

3738
let puppeteer;
3839
let perfTiming;
@@ -65,6 +66,7 @@ const consoleLogStore = new Console();
6566
* @prop {boolean} [manualStart=false] - do not start browser before a test, start it manually inside a helper with `this.helpers["Puppeteer"]._startBrowser()`.
6667
* @prop {string} [browser=chrome] - can be changed to `firefox` when using [puppeteer-firefox](https://codecept.io/helpers/Puppeteer-firefox).
6768
* @prop {object} [chrome] - pass additional [Puppeteer run options](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions).
69+
* @prop {boolean} [highlightElement] - highlight the interacting elements
6870
*/
6971
const config = {};
7072

@@ -1287,7 +1289,14 @@ class Puppeteer extends Helper {
12871289
} else if (editable) {
12881290
await this._evaluateHandeInContext(el => el.innerHTML = '', el);
12891291
}
1292+
1293+
if (this.options.highlightElement) {
1294+
highlightElement(el, this.page);
1295+
}
12901296
await el.type(value.toString(), { delay: this.options.pressKeyDelay });
1297+
if (this.options.highlightElement) {
1298+
unhighlightElement(el, this.page);
1299+
}
12911300
return this._waitForAction();
12921301
}
12931302

@@ -2314,12 +2323,22 @@ async function proceedClick(locator, context = null, options = {}) {
23142323
} else {
23152324
assertElementExists(els, locator, 'Clickable element');
23162325
}
2326+
2327+
if (this.options.highlightElement) {
2328+
highlightElement(els[0], this.page);
2329+
}
2330+
23172331
await els[0].click(options);
23182332
const promises = [];
23192333
if (options.waitForNavigation) {
23202334
promises.push(this.waitForNavigation());
23212335
}
23222336
promises.push(this._waitForAction());
2337+
2338+
if (this.options.highlightElement) {
2339+
unhighlightElement(els[0], this.page);
2340+
}
2341+
23232342
return Promise.all(promises);
23242343
}
23252344

Diff for: lib/helper/WebDriver.js

+30-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const path = require('path');
55
const fs = require('fs');
66

77
const Helper = require('@codeceptjs/helper');
8+
const crypto = require('crypto');
89
const stringIncludes = require('../assert/include').includes;
910
const { urlEquals, equals } = require('../assert/equal');
1011
const { debug } = require('../output');
@@ -27,6 +28,7 @@ const {
2728
const ElementNotFound = require('./errors/ElementNotFound');
2829
const ConnectionRefused = require('./errors/ConnectionRefused');
2930
const Locator = require('../locator');
31+
const { highlightElement, unhighlightElement } = require('./scripts/highlightElement');
3032

3133
const SHADOW = 'shadow';
3234
const webRoot = 'body';
@@ -39,7 +41,7 @@ const webRoot = 'body';
3941
* @typedef WebDriverConfig
4042
* @type {object}
4143
* @prop {string} url - base url of website to be tested.
42-
* @prop {string} browser browser in which to perform testing.
44+
* @prop {string} browser - Browser in which to perform testing.
4345
* @prop {string} [basicAuth] - (optional) the basic authentication to pass to base url. Example: {username: 'username', password: 'password'}
4446
* @prop {string} [host=localhost] - WebDriver host to connect.
4547
* @prop {number} [port=4444] - WebDriver port to connect.
@@ -57,6 +59,7 @@ const webRoot = 'body';
5759
* @prop {object} [desiredCapabilities] Selenium's [desired capabilities](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities).
5860
* @prop {boolean} [manualStart=false] - do not start browser before a test, start it manually inside a helper with `this.helpers["WebDriver"]._startBrowser()`.
5961
* @prop {object} [timeouts] [WebDriver timeouts](http://webdriver.io/docs/timeouts.html) defined as hash.
62+
* @prop {boolean} [highlightElement] - highlight the interacting elements
6063
*/
6164
const config = {};
6265

@@ -822,7 +825,7 @@ class WebDriver extends Helper {
822825
}
823826

824827
/**
825-
* Find a checkbox by providing human readable text:
828+
* Find a checkbox by providing human-readable text:
826829
*
827830
* ```js
828831
* this.helpers['WebDriver']._locateCheckable('I agree with terms and conditions').then // ...
@@ -835,7 +838,7 @@ class WebDriver extends Helper {
835838
}
836839

837840
/**
838-
* Find a clickable element by providing human readable text:
841+
* Find a clickable element by providing human-readable text:
839842
*
840843
* ```js
841844
* const els = await this.helpers.WebDriver._locateClickable('Next page');
@@ -850,7 +853,7 @@ class WebDriver extends Helper {
850853
}
851854

852855
/**
853-
* Find field elements by providing human readable text:
856+
* Find field elements by providing human-readable text:
854857
*
855858
* ```js
856859
* this.helpers['WebDriver']._locateFields('Your email').then // ...
@@ -914,6 +917,10 @@ class WebDriver extends Helper {
914917
assertElementExists(res, locator, 'Clickable element');
915918
}
916919
const elem = usingFirstElement(res);
920+
921+
if (this.options.highlightElement) {
922+
highlightElement(elem, this.browser);
923+
}
917924
return this.browser[clickMethod](getElementId(elem));
918925
}
919926

@@ -1024,6 +1031,13 @@ class WebDriver extends Helper {
10241031
const res = await findFields.call(this, field);
10251032
assertElementExists(res, field, 'Field');
10261033
const elem = usingFirstElement(res);
1034+
if (this.options.highlightElement) {
1035+
highlightElement(elem, this.browser);
1036+
}
1037+
1038+
if (this.options.highlightElement) {
1039+
unhighlightElement(elem, this.browser);
1040+
}
10271041
return elem.setValue(value.toString());
10281042
}
10291043

@@ -1035,6 +1049,12 @@ class WebDriver extends Helper {
10351049
const res = await findFields.call(this, field);
10361050
assertElementExists(res, field, 'Field');
10371051
const elem = usingFirstElement(res);
1052+
if (this.options.highlightElement) {
1053+
highlightElement(elem, this.browser);
1054+
}
1055+
if (this.options.highlightElement) {
1056+
unhighlightElement(elem, this.browser);
1057+
}
10381058
return elem.addValue(value.toString());
10391059
}
10401060

@@ -1046,6 +1066,12 @@ class WebDriver extends Helper {
10461066
const res = await findFields.call(this, field);
10471067
assertElementExists(res, field, 'Field');
10481068
const elem = usingFirstElement(res);
1069+
if (this.options.highlightElement) {
1070+
highlightElement(elem, this.browser);
1071+
}
1072+
if (this.options.highlightElement) {
1073+
unhighlightElement(elem, this.browser);
1074+
}
10491075
return elem.clearValue(getElementId(elem));
10501076
}
10511077

Diff for: lib/helper/scripts/highlightElement.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module.exports.highlightElement = (element, context) => {
2+
try {
3+
context.evaluate(el => el.style.border = '2px solid red', element);
4+
} catch (e) {
5+
context.execute(el => el.style.border = '2px solid red', element);
6+
}
7+
};
8+
9+
module.exports.unhighlightElement = (element, context) => {
10+
try {
11+
context.evaluate(el => el.style.border = '', element);
12+
} catch (e) {
13+
context.execute(el => el.style.border = '', element);
14+
}
15+
};

Diff for: typings/tslint.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"array-type": false,
1515
"trim-file": false,
1616
"no-consecutive-blank-lines": false,
17-
"no-redundant-jsdoc": false
17+
"no-redundant-jsdoc": false,
18+
"adjacent-overload-signatures": false
1819
},
1920
"linterOptions": {
2021
"exclude": [

0 commit comments

Comments
 (0)