Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: highlight the interacting elements #3672

Merged
merged 2 commits into from
Jun 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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