Skip to content

Commit b1cf16d

Browse files
committed
Merge branch '3.x' of github.com:codeceptjs/CodeceptJS into 3.x
2 parents bb1ff81 + bf75294 commit b1cf16d

35 files changed

+457
-389
lines changed

docs/locators.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ CodeceptJS provides flexible strategies for locating elements:
1717

1818
Most methods in CodeceptJS use locators which can be either a string or an object.
1919

20-
If the locator is an object, it should have a single element, with the key signifying the locator type (`id`, `name`, `css`, `xpath`, `link`, `react`, or `class`) and the value being the locator itself. This is called a "strict" locator.
20+
If the locator is an object, it should have a single element, with the key signifying the locator type (`id`, `name`, `css`, `xpath`, `link`, `react`, `class` or `shadow`) and the value being the locator itself. This is called a "strict" locator.
2121

2222
Examples:
2323

docs/plugins.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -788,18 +788,22 @@ Adds global `tryTo` function inside of which all failed steps won't fail a test
788788
789789
Enable this plugin in `codecept.conf.js` (enabled by default for new setups):
790790
791-
````js
791+
```js
792792
plugins: {
793793
tryTo: {
794794
enabled: true
795795
}
796796
}
797+
```
798+
799+
Use it in your tests:
800+
797801
```js
798802
const result = await tryTo(() => I.see('Welcome'));
799803

800804
// if text "Welcome" is on page, result => true
801805
// if text "Welcome" is not on page, result => false
802-
````
806+
```
803807
804808
Disables retryFailedStep plugin for steps inside a block;
805809

lib/actor.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ class Actor {
3535
retry(opts) {
3636
if (opts === undefined) opts = 1;
3737
recorder.retry(opts);
38-
// adding an empty promise to clear retries
39-
recorder.add(() => null);
4038
// remove retry once the step passed
4139
recorder.add(() => event.dispatcher.once(event.step.finished, () => recorder.retries.pop()));
4240
return this;

lib/helper/Playwright.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2152,7 +2152,7 @@ async function findElements(matcher, locator) {
21522152
}
21532153

21542154
async function proceedClick(locator, context = null, options = {}) {
2155-
let matcher = await this.context;
2155+
let matcher = await this._getContext();
21562156
if (context) {
21572157
const els = await this._locate(context);
21582158
assertElementExists(els, context);

lib/helper/WebDriver.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2188,7 +2188,9 @@ class WebDriver extends Helper {
21882188
}, aSec * 1000, `element (${new Locator(locator)}) still not visible after ${aSec} sec`);
21892189
}
21902190
return this.browser.waitUntil(async () => {
2191-
const res = await this.$$(withStrictLocator(locator));
2191+
const res = (this._isShadowLocator(locator))
2192+
? await this._locate(withStrictLocator(locator))
2193+
: await this.$$(withStrictLocator(locator));
21922194
if (!res || res.length === 0) return false;
21932195
const selected = await forEachAsync(res, async el => el.isDisplayed());
21942196
if (Array.isArray(selected)) {

lib/listener/helpers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ module.exports = function () {
2323
if (store.dryRun) return;
2424
Object.keys(helpers).forEach((key) => {
2525
if (!helpers[key][hook]) return;
26-
recorder.add(`hook ${key}.${hook}()`, () => helpers[key][hook](param), force);
26+
recorder.add(`hook ${key}.${hook}()`, () => helpers[key][hook](param), force, false);
2727
});
2828
};
2929

lib/locator.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const { sprintf } = require('sprintf-js');
33

44
const { xpathLocator } = require('./utils');
55

6-
const locatorTypes = ['css', 'by', 'xpath', 'id', 'name', 'fuzzy', 'frame'];
6+
const locatorTypes = ['css', 'by', 'xpath', 'id', 'name', 'fuzzy', 'frame', 'shadow'];
77
/** @class */
88
class Locator {
99
/**
@@ -43,6 +43,9 @@ class Locator {
4343
if (isXPath(locator)) {
4444
this.type = 'xpath';
4545
}
46+
if (isShadow(locator)) {
47+
this.type = 'shadow';
48+
}
4649

4750
Locator.filters.forEach(f => f(locator, this));
4851
}
@@ -61,6 +64,8 @@ class Locator {
6164
return `[name="${this.value}"]`;
6265
case 'fuzzy':
6366
return this.value;
67+
case 'shadow':
68+
return { shadow: this.value };
6469
}
6570
return this.value;
6671
}
@@ -81,6 +86,10 @@ class Locator {
8186
return this.type === 'fuzzy';
8287
}
8388

89+
isShadow() {
90+
return this.type === 'shadow';
91+
}
92+
8493
isFrame() {
8594
return this.type === 'frame';
8695
}
@@ -165,6 +174,7 @@ class Locator {
165174
at(position) {
166175
if (position < 0) {
167176
position++; // -1 points to the last element
177+
// @ts-ignore
168178
position = `last()-${Math.abs(position)}`;
169179
}
170180
if (position === 0) {
@@ -338,6 +348,11 @@ function isXPath(locator) {
338348
return trimmed === '//' || trimmed === './';
339349
}
340350

351+
function isShadow(locator) {
352+
const hasShadowProperty = (locator.shadow !== undefined) && (Object.keys(locator).length === 1);
353+
return hasShadowProperty;
354+
}
355+
341356
function isXPathStartingWithRoundBrackets(locator) {
342357
return isXPath(locator) && locator[0] === '(';
343358
}

lib/plugin/tryTo.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,16 @@ const defaultConfig = {
1212
* Adds global `tryTo` function inside of which all failed steps won't fail a test but will return true/false.
1313
*
1414
* Enable this plugin in `codecept.conf.js` (enabled by default for new setups):
15+
*
1516
* ```js
1617
* plugins: {
1718
* tryTo: {
1819
* enabled: true
1920
* }
2021
* }
22+
* ```
23+
* Use it in your tests:
24+
*
2125
* ```js
2226
* const result = await tryTo(() => I.see('Welcome'));
2327
*

lib/recorder.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,17 +154,20 @@ module.exports = {
154154
* @param {string|function} taskName
155155
* @param {function} [fn]
156156
* @param {boolean} [force=false]
157-
* @param {boolean} [retry=true] -
157+
* @param {boolean} [retry]
158+
* undefined: `add(fn)` -> `false` and `add('step',fn)` -> `true`
158159
* true: it will retries if `retryOpts` set.
159160
* false: ignore `retryOpts` and won't retry.
160161
* @return {Promise<*> | undefined}
161162
* @inner
162163
*/
163-
add(taskName, fn = undefined, force = false, retry = true) {
164+
add(taskName, fn = undefined, force = false, retry = undefined) {
164165
if (typeof taskName === 'function') {
165166
fn = taskName;
166167
taskName = fn.toString();
168+
if (retry === undefined) retry = false;
167169
}
170+
if (retry === undefined) retry = true;
168171
if (!running && !force) {
169172
return;
170173
}
@@ -178,11 +181,9 @@ module.exports = {
178181
return Promise.resolve(res).then(fn);
179182
}
180183

184+
const retryRules = this.retries.slice().reverse();
181185
return promiseRetry(Object.assign(defaultRetryOptions, retryOpts), (retry, number) => {
182186
if (number > 1) log(`${currentQueue()}Retrying... Attempt #${number}`);
183-
184-
const retryRules = this.retries.reverse();
185-
186187
return Promise.resolve(res).then(fn).catch((err) => {
187188
for (const retryObj of retryRules) {
188189
if (!retryObj.when) return retry(err);

package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,17 @@
3939
"build": "tsc -p ./",
4040
"json-server": "./node_modules/json-server/bin/index.js test/data/rest/db.json -p 8010 --watch -m test/data/rest/headers.js",
4141
"json-server:graphql": "node test/data/graphql/index.js",
42-
"lint": "eslint bin/ examples/ lib/ test/ translations/ runio.js",
43-
"lint-fix": "eslint bin/ examples/ lib/ test/ translations/ runio.js --fix",
44-
"docs": "./runio.js docs",
42+
"lint": "eslint bin/ examples/ lib/ test/ translations/ runok.js",
43+
"lint-fix": "eslint bin/ examples/ lib/ test/ translations/ runok.js --fix",
44+
"docs": "./runok.js docs",
4545
"test:unit": "mocha test/unit --recursive",
4646
"test:runner": "mocha test/runner --recursive",
4747
"test": "npm run test:unit && npm run test:runner",
4848
"test:appium-quick": "mocha test/helper/Appium_test.js --grep 'quick'",
4949
"test:appium-other": "mocha test/helper/Appium_test.js --grep 'second'",
50-
"def": "./runio.js def",
50+
"def": "./runok.js def",
5151
"dev:graphql": "nodemon test/data/graphql/index.js",
52-
"publish:site": "./runio.js publish:site",
52+
"publish:site": "./runok.js publish:site",
5353
"update-contributor-faces": "contributor-faces .",
5454
"dtslint": "dtslint typings --localTs './node_modules/typescript/lib'"
5555
},
@@ -124,7 +124,7 @@
124124
"puppeteer": "^4.0.0",
125125
"qrcode-terminal": "^0.12.0",
126126
"rosie": "^1.6.0",
127-
"runio.js": "^1.0.20",
127+
"runok": "^0.9.2",
128128
"sinon": "^9.0.2",
129129
"sinon-chai": "^3.5.0",
130130
"testcafe": "^1.8.6",

0 commit comments

Comments
 (0)