Skip to content

Commit

Permalink
feat: highlight the interacting elements (#3672)
Browse files Browse the repository at this point in the history
* feat: highlight the interacting elements

* fix: puppeteer and support wdio
  • Loading branch information
kobenguyent committed Jun 4, 2023
1 parent 5ee921d commit 51556a7
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 9 deletions.
2 changes: 2 additions & 0 deletions docs/helpers/Appium.md
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,8 @@ Field is located by name, label, CSS or XPath

```js
I.appendField('#myTextField', 'appended');
// typing secret
I.appendField('password', secret('123456'));
```

#### Parameters
Expand Down
2 changes: 2 additions & 0 deletions docs/helpers/Nightmare.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ Field is located by name, label, CSS or XPath

```js
I.appendField('#myTextField', 'appended');
// typing secret
I.appendField('password', secret('123456'));
```

#### Parameters
Expand Down
6 changes: 6 additions & 0 deletions docs/helpers/Playwright.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ Type: [object][5]
- `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].
- `ignoreHTTPSErrors` **[boolean][26]?** Allows access to untrustworthy pages, e.g. to a page with an expired certificate. Default value is `false`
- `bypassCSP` **[boolean][26]?** bypass Content Security Policy or CSP
- `highlightElement` **[boolean][26]?** highlight the interacting elements



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

```js
I.appendField('#myTextField', 'appended');
// typing secret
I.appendField('password', secret('123456'));
```

#### Parameters
Expand Down Expand Up @@ -1826,6 +1829,9 @@ I.type('4141555311111111', 100);

// passing in an array
I.type(['T', 'E', 'X', 'T']);

// passing a secret
I.type(secret('123456'));
```

#### Parameters
Expand Down
6 changes: 6 additions & 0 deletions docs/helpers/Puppeteer.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ Type: [object][4]
- `manualStart` **[boolean][17]?** do not start browser before a test, start it manually inside a helper with `this.helpers["Puppeteer"]._startBrowser()`.
- `browser` **[string][6]?** can be changed to `firefox` when using [puppeteer-firefox][2].
- `chrome` **[object][4]?** pass additional [Puppeteer run options][22].
- `highlightElement` **[boolean][17]?** highlight the interacting elements



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

```js
I.appendField('#myTextField', 'appended');
// typing secret
I.appendField('password', secret('123456'));
```

#### Parameters
Expand Down Expand Up @@ -1786,6 +1789,9 @@ I.type('4141555311111111', 100);

// passing in an array
I.type(['T', 'E', 'X', 'T']);

// passing a secret
I.type(secret('123456'));
```
#### Parameters
Expand Down
2 changes: 2 additions & 0 deletions docs/helpers/TestCafe.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ Field is located by name, label, CSS or XPath

```js
I.appendField('#myTextField', 'appended');
// typing secret
I.appendField('password', secret('123456'));
```

#### Parameters
Expand Down
14 changes: 10 additions & 4 deletions docs/helpers/WebDriver.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Type: [object][16]
### Properties

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



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

### _locateCheckable

Find a checkbox by providing human readable text:
Find a checkbox by providing human-readable text:

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

### _locateClickable

Find a clickable element by providing human readable text:
Find a clickable element by providing human-readable text:

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

### _locateFields

Find field elements by providing human readable text:
Find field elements by providing human-readable text:

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

```js
I.appendField('#myTextField', 'appended');
// typing secret
I.appendField('password', secret('123456'));
```

#### Parameters
Expand Down Expand Up @@ -1985,6 +1988,9 @@ I.type('4141555311111111', 100);

// passing in an array
I.type(['T', 'E', 'X', 'T']);

// passing a secret
I.type(secret('123456'));
```
#### Parameters
Expand Down
20 changes: 20 additions & 0 deletions lib/helper/Playwright.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const {
setRestartStrategy, restartsSession, restartsContext, restartsBrowser,
} = require('./extras/PlaywrightRestartOpts');
const { createValueEngine, createDisabledEngine } = require('./extras/PlaywrightPropEngine');
const { highlightElement, unhighlightElement } = require('./scripts/highlightElement');

const pathSeparator = path.sep;

Expand Down Expand Up @@ -89,6 +90,7 @@ const pathSeparator = path.sep;
* @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).
* @prop {boolean} [ignoreHTTPSErrors] - Allows access to untrustworthy pages, e.g. to a page with an expired certificate. Default value is `false`
* @prop {boolean} [bypassCSP] - bypass Content Security Policy or CSP
* @prop {boolean} [highlightElement] - highlight the interacting elements
*/
const config = {};

Expand Down Expand Up @@ -1464,7 +1466,16 @@ class Playwright extends Helper {
} else if (editable) {
await this._evaluateHandeInContext(el => el.innerHTML = '', el);
}

if (this.options.highlightElement) {
highlightElement(el, this.page);
}

await el.type(value.toString(), { delay: this.options.pressKeyDelay });

if (this.options.highlightElement) {
unhighlightElement(el, this.page);
}
return this._waitForAction();
}

Expand Down Expand Up @@ -2589,6 +2600,11 @@ async function proceedClick(locator, context = null, options = {}) {
} else {
assertElementExists(els, locator, 'Clickable element');
}

const element = els[0];
if (this.options.highlightElement) {
highlightElement(element, this.page);
}
/*
using the force true options itself but instead dispatching a click
*/
Expand All @@ -2603,6 +2619,10 @@ async function proceedClick(locator, context = null, options = {}) {
promises.push(this.waitForNavigation());
}
promises.push(this._waitForAction());

if (this.options.highlightElement) {
unhighlightElement(element, this.page);
}
return Promise.all(promises);
}

Expand Down
19 changes: 19 additions & 0 deletions lib/helper/Puppeteer.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const RemoteBrowserConnectionRefused = require('./errors/RemoteBrowserConnection
const Popup = require('./extras/Popup');
const Console = require('./extras/Console');
const findReact = require('./extras/React');
const { highlightElement, unhighlightElement } = require('./scripts/highlightElement');

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

Expand Down Expand Up @@ -1287,7 +1289,14 @@ class Puppeteer extends Helper {
} else if (editable) {
await this._evaluateHandeInContext(el => el.innerHTML = '', el);
}

if (this.options.highlightElement) {
highlightElement(el, this.page);
}
await el.type(value.toString(), { delay: this.options.pressKeyDelay });
if (this.options.highlightElement) {
unhighlightElement(el, this.page);
}
return this._waitForAction();
}

Expand Down Expand Up @@ -2314,12 +2323,22 @@ async function proceedClick(locator, context = null, options = {}) {
} else {
assertElementExists(els, locator, 'Clickable element');
}

if (this.options.highlightElement) {
highlightElement(els[0], this.page);
}

await els[0].click(options);
const promises = [];
if (options.waitForNavigation) {
promises.push(this.waitForNavigation());
}
promises.push(this._waitForAction());

if (this.options.highlightElement) {
unhighlightElement(els[0], this.page);
}

return Promise.all(promises);
}

Expand Down
34 changes: 30 additions & 4 deletions lib/helper/WebDriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const path = require('path');
const fs = require('fs');

const Helper = require('@codeceptjs/helper');
const crypto = require('crypto');
const stringIncludes = require('../assert/include').includes;
const { urlEquals, equals } = require('../assert/equal');
const { debug } = require('../output');
Expand All @@ -27,6 +28,7 @@ const {
const ElementNotFound = require('./errors/ElementNotFound');
const ConnectionRefused = require('./errors/ConnectionRefused');
const Locator = require('../locator');
const { highlightElement, unhighlightElement } = require('./scripts/highlightElement');

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

Expand Down Expand Up @@ -822,7 +825,7 @@ class WebDriver extends Helper {
}

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

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

/**
* Find field elements by providing human readable text:
* Find field elements by providing human-readable text:
*
* ```js
* this.helpers['WebDriver']._locateFields('Your email').then // ...
Expand Down Expand Up @@ -914,6 +917,10 @@ class WebDriver extends Helper {
assertElementExists(res, locator, 'Clickable element');
}
const elem = usingFirstElement(res);

if (this.options.highlightElement) {
highlightElement(elem, this.browser);
}
return this.browser[clickMethod](getElementId(elem));
}

Expand Down Expand Up @@ -1024,6 +1031,13 @@ class WebDriver extends Helper {
const res = await findFields.call(this, field);
assertElementExists(res, field, 'Field');
const elem = usingFirstElement(res);
if (this.options.highlightElement) {
highlightElement(elem, this.browser);
}

if (this.options.highlightElement) {
unhighlightElement(elem, this.browser);
}
return elem.setValue(value.toString());
}

Expand All @@ -1035,6 +1049,12 @@ class WebDriver extends Helper {
const res = await findFields.call(this, field);
assertElementExists(res, field, 'Field');
const elem = usingFirstElement(res);
if (this.options.highlightElement) {
highlightElement(elem, this.browser);
}
if (this.options.highlightElement) {
unhighlightElement(elem, this.browser);
}
return elem.addValue(value.toString());
}

Expand All @@ -1046,6 +1066,12 @@ class WebDriver extends Helper {
const res = await findFields.call(this, field);
assertElementExists(res, field, 'Field');
const elem = usingFirstElement(res);
if (this.options.highlightElement) {
highlightElement(elem, this.browser);
}
if (this.options.highlightElement) {
unhighlightElement(elem, this.browser);
}
return elem.clearValue(getElementId(elem));
}

Expand Down
15 changes: 15 additions & 0 deletions lib/helper/scripts/highlightElement.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module.exports.highlightElement = (element, context) => {
try {
context.evaluate(el => el.style.border = '2px solid red', element);
} catch (e) {
context.execute(el => el.style.border = '2px solid red', element);
}
};

module.exports.unhighlightElement = (element, context) => {
try {
context.evaluate(el => el.style.border = '', element);
} catch (e) {
context.execute(el => el.style.border = '', element);
}
};
3 changes: 2 additions & 1 deletion typings/tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"array-type": false,
"trim-file": false,
"no-consecutive-blank-lines": false,
"no-redundant-jsdoc": false
"no-redundant-jsdoc": false,
"adjacent-overload-signatures": false
},
"linterOptions": {
"exclude": [
Expand Down

0 comments on commit 51556a7

Please sign in to comment.