codeceptjs 3.3.6 → 3.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/basics.md +2 -3
- package/docs/bdd.md +33 -0
- package/docs/best.md +8 -8
- package/docs/build/Appium.js +60 -22
- package/docs/build/GraphQL.js +6 -6
- package/docs/build/Nightmare.js +4 -4
- package/docs/build/Playwright.js +102 -39
- package/docs/build/Polly.js +0 -0
- package/docs/build/Protractor.js +25 -25
- package/docs/build/Puppeteer.js +7 -7
- package/docs/build/SeleniumWebdriver.js +0 -0
- package/docs/build/TestCafe.js +12 -12
- package/docs/build/WebDriver.js +32 -32
- package/docs/changelog.md +36 -1
- package/docs/helpers/Appium.md +103 -79
- package/docs/helpers/GraphQL.md +6 -6
- package/docs/helpers/Playwright.md +280 -245
- package/docs/helpers/Puppeteer.md +1 -1
- package/docs/helpers/REST.md +1 -1
- package/docs/helpers/WebDriver.md +2 -2
- package/docs/playwright.md +14 -0
- package/docs/quickstart.md +40 -13
- package/docs/translation.md +83 -56
- package/docs/typescript.md +49 -3
- package/docs/wiki/Books-&-Posts.md +0 -0
- package/docs/wiki/Community-Helpers-&-Plugins.md +0 -0
- package/docs/wiki/Converting-Playwright-to-Istanbul-Coverage.md +0 -0
- package/docs/wiki/Examples.md +0 -0
- package/docs/wiki/Google-Summer-of-Code-(GSoC)-2020.md +0 -0
- package/docs/wiki/Home.md +0 -0
- package/docs/wiki/Release-Process.md +0 -0
- package/docs/wiki/Roadmap.md +0 -0
- package/docs/wiki/Tests.md +0 -0
- package/docs/wiki/Upgrading-to-CodeceptJS-3.md +0 -0
- package/docs/wiki/Videos.md +0 -0
- package/lib/codecept.js +3 -1
- package/lib/command/definitions.js +26 -2
- package/lib/command/generate.js +23 -9
- package/lib/command/init.js +32 -7
- package/lib/command/run.js +5 -1
- package/lib/container.js +15 -15
- package/lib/helper/Appium.js +60 -22
- package/lib/helper/GraphQL.js +6 -6
- package/lib/helper/Nightmare.js +4 -4
- package/lib/helper/Playwright.js +102 -39
- package/lib/helper/Protractor.js +25 -25
- package/lib/helper/Puppeteer.js +7 -7
- package/lib/helper/TestCafe.js +12 -12
- package/lib/helper/WebDriver.js +32 -32
- package/lib/helper/errors/ElementNotFound.js +1 -1
- package/lib/helper/extras/PlaywrightRestartOpts.js +0 -2
- package/lib/interfaces/bdd.js +26 -1
- package/lib/listener/artifacts.js +19 -0
- package/lib/rerun.js +12 -13
- package/lib/step.js +5 -5
- package/lib/translation.js +32 -0
- package/package.json +11 -17
- package/translations/ru-RU.js +1 -0
- package/typings/index.d.ts +29 -1
- package/typings/promiseBasedTypes.d.ts +10466 -0
- package/typings/types.d.ts +62 -12
- package/CHANGELOG.md +0 -2340
package/lib/helper/TestCafe.js
CHANGED
|
@@ -448,7 +448,7 @@ class TestCafe extends Helper {
|
|
|
448
448
|
*/
|
|
449
449
|
async moveCursorTo(locator, offsetX = 0, offsetY = 0) {
|
|
450
450
|
const els = (await findElements.call(this, this.context, locator)).filterVisible();
|
|
451
|
-
await assertElementExists(els);
|
|
451
|
+
await assertElementExists(els, locator);
|
|
452
452
|
|
|
453
453
|
return this.t
|
|
454
454
|
.hover(els.nth(0), { offsetX, offsetY })
|
|
@@ -485,7 +485,7 @@ class TestCafe extends Helper {
|
|
|
485
485
|
matcher = await els.nth(0);
|
|
486
486
|
}
|
|
487
487
|
const els = (await findClickable.call(this, matcher, locator)).filterVisible();
|
|
488
|
-
assertElementExists(els);
|
|
488
|
+
assertElementExists(els, locator);
|
|
489
489
|
return this.t
|
|
490
490
|
.rightClick(els.nth(0))
|
|
491
491
|
.catch(mapError);
|
|
@@ -642,7 +642,7 @@ class TestCafe extends Helper {
|
|
|
642
642
|
async seeElement(locator) {
|
|
643
643
|
const exists = (await findElements.call(this, this.context, locator)).filterVisible().exists;
|
|
644
644
|
return this.t
|
|
645
|
-
.expect(exists).ok(`No element "${locator}" found`)
|
|
645
|
+
.expect(exists).ok(`No element "${(new Locator(locator))}" found`)
|
|
646
646
|
.catch(mapError);
|
|
647
647
|
}
|
|
648
648
|
|
|
@@ -652,7 +652,7 @@ class TestCafe extends Helper {
|
|
|
652
652
|
async dontSeeElement(locator) {
|
|
653
653
|
const exists = (await findElements.call(this, this.context, locator)).filterVisible().exists;
|
|
654
654
|
return this.t
|
|
655
|
-
.expect(exists).notOk(`Element "${locator}" is still visible`)
|
|
655
|
+
.expect(exists).notOk(`Element "${(new Locator(locator))}" is still visible`)
|
|
656
656
|
.catch(mapError);
|
|
657
657
|
}
|
|
658
658
|
|
|
@@ -662,7 +662,7 @@ class TestCafe extends Helper {
|
|
|
662
662
|
async seeElementInDOM(locator) {
|
|
663
663
|
const exists = (await findElements.call(this, this.context, locator)).exists;
|
|
664
664
|
return this.t
|
|
665
|
-
.expect(exists).ok(`No element "${locator}" found in DOM`)
|
|
665
|
+
.expect(exists).ok(`No element "${(new Locator(locator))}" found in DOM`)
|
|
666
666
|
.catch(mapError);
|
|
667
667
|
}
|
|
668
668
|
|
|
@@ -672,7 +672,7 @@ class TestCafe extends Helper {
|
|
|
672
672
|
async dontSeeElementInDOM(locator) {
|
|
673
673
|
const exists = (await findElements.call(this, this.context, locator)).exists;
|
|
674
674
|
return this.t
|
|
675
|
-
.expect(exists).notOk(`Element "${locator}" is still in DOM`)
|
|
675
|
+
.expect(exists).notOk(`Element "${(new Locator(locator))}" is still in DOM`)
|
|
676
676
|
.catch(mapError);
|
|
677
677
|
}
|
|
678
678
|
|
|
@@ -761,10 +761,10 @@ class TestCafe extends Helper {
|
|
|
761
761
|
const outputFile = path.join(global.output_dir, fileName);
|
|
762
762
|
|
|
763
763
|
const sel = await findElements.call(this, this.context, locator);
|
|
764
|
-
assertElementExists(sel);
|
|
764
|
+
assertElementExists(sel, locator);
|
|
765
765
|
const firstElement = await sel.filterVisible().nth(0);
|
|
766
766
|
|
|
767
|
-
this.debug(`Screenshot of ${locator} element has been saved to ${outputFile}`);
|
|
767
|
+
this.debug(`Screenshot of ${(new Locator(locator))} element has been saved to ${outputFile}`);
|
|
768
768
|
return this.t.takeElementScreenshot(firstElement, fileName);
|
|
769
769
|
}
|
|
770
770
|
|
|
@@ -818,7 +818,7 @@ class TestCafe extends Helper {
|
|
|
818
818
|
*/
|
|
819
819
|
async grabTextFrom(locator) {
|
|
820
820
|
const sel = await findElements.call(this, this.context, locator);
|
|
821
|
-
assertElementExists(sel);
|
|
821
|
+
assertElementExists(sel, locator);
|
|
822
822
|
const texts = await this.grabTextFromAll(locator);
|
|
823
823
|
if (texts.length > 1) {
|
|
824
824
|
this.debugSection('GrabText', `Using first element out of ${texts.length}`);
|
|
@@ -846,7 +846,7 @@ class TestCafe extends Helper {
|
|
|
846
846
|
*/
|
|
847
847
|
async grabAttributeFrom(locator, attr) {
|
|
848
848
|
const sel = await findElements.call(this, this.context, locator);
|
|
849
|
-
assertElementExists(sel);
|
|
849
|
+
assertElementExists(sel, locator);
|
|
850
850
|
const attrs = await this.grabAttributeFromAll(locator, attr);
|
|
851
851
|
if (attrs.length > 1) {
|
|
852
852
|
this.debugSection('GrabAttribute', `Using first element out of ${attrs.length}`);
|
|
@@ -874,7 +874,7 @@ class TestCafe extends Helper {
|
|
|
874
874
|
*/
|
|
875
875
|
async grabValueFrom(locator) {
|
|
876
876
|
const sel = await findElements.call(this, this.context, locator);
|
|
877
|
-
assertElementExists(sel);
|
|
877
|
+
assertElementExists(sel, locator);
|
|
878
878
|
const values = await this.grabValueFromAll(locator);
|
|
879
879
|
if (values.length > 1) {
|
|
880
880
|
this.debugSection('GrabValue', `Using first element out of ${values.length}`);
|
|
@@ -1130,7 +1130,7 @@ class TestCafe extends Helper {
|
|
|
1130
1130
|
|
|
1131
1131
|
return this.t
|
|
1132
1132
|
.expect(createSelector(locator).with({ boundTestRun: this.t }).filterVisible().count)
|
|
1133
|
-
.eql(num, `The number of elements (${locator}) is not ${num} after ${sec} sec`, { timeout: waitTimeout })
|
|
1133
|
+
.eql(num, `The number of elements (${(new Locator(locator))}) is not ${num} after ${sec} sec`, { timeout: waitTimeout })
|
|
1134
1134
|
.catch(mapError);
|
|
1135
1135
|
}
|
|
1136
1136
|
|
package/lib/helper/WebDriver.js
CHANGED
|
@@ -46,7 +46,7 @@ let version;
|
|
|
46
46
|
* @prop {string} [host=localhost] - WebDriver host to connect.
|
|
47
47
|
* @prop {number} [port=4444] - WebDriver port to connect.
|
|
48
48
|
* @prop {string} [protocol=http] - protocol for WebDriver server.
|
|
49
|
-
* @prop {string} [path=/wd/hub] - path to WebDriver server
|
|
49
|
+
* @prop {string} [path=/wd/hub] - path to WebDriver server.
|
|
50
50
|
* @prop {boolean} [restart=true] - restart browser between tests.
|
|
51
51
|
* @prop {boolean|number} [smartWait=false] - **enables [SmartWait](http://codecept.io/acceptance/#smartwait)**; wait for additional milliseconds for element to appear. Enable for 5 secs: "smartWait": 5000.
|
|
52
52
|
* @prop {boolean} [disableScreenshots=false] - don't save screenshots on failure.
|
|
@@ -463,7 +463,7 @@ class WebDriver extends Helper {
|
|
|
463
463
|
delete config.capabilities.selenoidOptions;
|
|
464
464
|
}
|
|
465
465
|
|
|
466
|
-
config.waitForTimeout
|
|
466
|
+
config.waitForTimeoutInSeconds = config.waitForTimeout / 1000; // convert to seconds
|
|
467
467
|
|
|
468
468
|
if (!config.capabilities.platformName && (!config.url || !config.browser)) {
|
|
469
469
|
throw new Error(`
|
|
@@ -1201,7 +1201,7 @@ class WebDriver extends Helper {
|
|
|
1201
1201
|
*/
|
|
1202
1202
|
async grabHTMLFrom(locator) {
|
|
1203
1203
|
const html = await this.grabHTMLFromAll(locator);
|
|
1204
|
-
assertElementExists(html);
|
|
1204
|
+
assertElementExists(html, locator);
|
|
1205
1205
|
if (html.length > 1) {
|
|
1206
1206
|
this.debugSection('GrabHTML', `Using first element out of ${html.length}`);
|
|
1207
1207
|
}
|
|
@@ -1380,7 +1380,7 @@ class WebDriver extends Helper {
|
|
|
1380
1380
|
const res = await this._locate(locator, true);
|
|
1381
1381
|
assertElementExists(res, locator);
|
|
1382
1382
|
const selected = await forEachAsync(res, async el => el.isDisplayed());
|
|
1383
|
-
return truth(`elements of ${locator}`, 'to be seen').assert(selected);
|
|
1383
|
+
return truth(`elements of ${(new Locator(locator))}`, 'to be seen').assert(selected);
|
|
1384
1384
|
}
|
|
1385
1385
|
|
|
1386
1386
|
/**
|
|
@@ -1390,10 +1390,10 @@ class WebDriver extends Helper {
|
|
|
1390
1390
|
async dontSeeElement(locator) {
|
|
1391
1391
|
const res = await this._locate(locator, false);
|
|
1392
1392
|
if (!res || res.length === 0) {
|
|
1393
|
-
return truth(`elements of ${locator}`, 'to be seen').negate(false);
|
|
1393
|
+
return truth(`elements of ${(new Locator(locator))}`, 'to be seen').negate(false);
|
|
1394
1394
|
}
|
|
1395
1395
|
const selected = await forEachAsync(res, async el => el.isDisplayed());
|
|
1396
|
-
return truth(`elements of ${locator}`, 'to be seen').negate(selected);
|
|
1396
|
+
return truth(`elements of ${(new Locator(locator))}`, 'to be seen').negate(selected);
|
|
1397
1397
|
}
|
|
1398
1398
|
|
|
1399
1399
|
/**
|
|
@@ -1465,7 +1465,7 @@ class WebDriver extends Helper {
|
|
|
1465
1465
|
*/
|
|
1466
1466
|
async seeNumberOfElements(locator, num) {
|
|
1467
1467
|
const res = await this._locate(locator);
|
|
1468
|
-
return assert.equal(res.length, num, `expected number of elements (${locator}) is ${num}, but found ${res.length}`);
|
|
1468
|
+
return assert.equal(res.length, num, `expected number of elements (${(new Locator(locator))}) is ${num}, but found ${res.length}`);
|
|
1469
1469
|
}
|
|
1470
1470
|
|
|
1471
1471
|
/**
|
|
@@ -1474,7 +1474,7 @@ class WebDriver extends Helper {
|
|
|
1474
1474
|
*/
|
|
1475
1475
|
async seeNumberOfVisibleElements(locator, num) {
|
|
1476
1476
|
const res = await this.grabNumberOfVisibleElements(locator);
|
|
1477
|
-
return assert.equal(res, num, `expected number of visible elements (${locator}) is ${num}, but found ${res}`);
|
|
1477
|
+
return assert.equal(res, num, `expected number of visible elements (${(new Locator(locator))}) is ${num}, but found ${res}`);
|
|
1478
1478
|
}
|
|
1479
1479
|
|
|
1480
1480
|
/**
|
|
@@ -1508,7 +1508,7 @@ class WebDriver extends Helper {
|
|
|
1508
1508
|
});
|
|
1509
1509
|
return assert.ok(
|
|
1510
1510
|
chunked.length === elemAmount,
|
|
1511
|
-
`expected all elements (${locator}) to have CSS property ${JSON.stringify(cssProperties)}`,
|
|
1511
|
+
`expected all elements (${(new Locator(locator))}) to have CSS property ${JSON.stringify(cssProperties)}`,
|
|
1512
1512
|
);
|
|
1513
1513
|
}
|
|
1514
1514
|
|
|
@@ -1535,7 +1535,7 @@ class WebDriver extends Helper {
|
|
|
1535
1535
|
});
|
|
1536
1536
|
return assert.ok(
|
|
1537
1537
|
chunked.length === elemAmount,
|
|
1538
|
-
`expected all elements (${locator}) to have attributes ${JSON.stringify(attributes)}`,
|
|
1538
|
+
`expected all elements (${(new Locator(locator))}) to have attributes ${JSON.stringify(attributes)}`,
|
|
1539
1539
|
);
|
|
1540
1540
|
}
|
|
1541
1541
|
|
|
@@ -1611,7 +1611,7 @@ class WebDriver extends Helper {
|
|
|
1611
1611
|
*/
|
|
1612
1612
|
async scrollIntoView(locator, scrollIntoViewOptions) {
|
|
1613
1613
|
const res = await this._locate(withStrictLocator(locator), true);
|
|
1614
|
-
assertElementExists(res);
|
|
1614
|
+
assertElementExists(res, locator);
|
|
1615
1615
|
const elem = usingFirstElement(res);
|
|
1616
1616
|
return elem.scrollIntoView(scrollIntoViewOptions);
|
|
1617
1617
|
}
|
|
@@ -1629,12 +1629,12 @@ class WebDriver extends Helper {
|
|
|
1629
1629
|
|
|
1630
1630
|
if (locator) {
|
|
1631
1631
|
const res = await this._locate(withStrictLocator(locator), true);
|
|
1632
|
-
assertElementExists(res);
|
|
1632
|
+
assertElementExists(res, locator);
|
|
1633
1633
|
const elem = usingFirstElement(res);
|
|
1634
1634
|
const elementId = getElementId(elem);
|
|
1635
1635
|
if (this.browser.isMobile && !this.browser.isW3C) return this.browser.touchScroll(offsetX, offsetY, elementId);
|
|
1636
1636
|
const location = await elem.getLocation();
|
|
1637
|
-
assertElementExists(location, 'Failed to receive', 'location');
|
|
1637
|
+
assertElementExists(location, locator, 'Failed to receive', 'location');
|
|
1638
1638
|
/* eslint-disable prefer-arrow-callback */
|
|
1639
1639
|
return this.browser.execute(function (x, y) { return window.scrollTo(x, y); }, location.x + offsetX, location.y + offsetY);
|
|
1640
1640
|
/* eslint-enable */
|
|
@@ -1669,7 +1669,7 @@ class WebDriver extends Helper {
|
|
|
1669
1669
|
assertElementExists(res, locator);
|
|
1670
1670
|
const elem = usingFirstElement(res);
|
|
1671
1671
|
|
|
1672
|
-
this.debug(`Screenshot of ${locator} element has been saved to ${outputFile}`);
|
|
1672
|
+
this.debug(`Screenshot of ${(new Locator(locator))} element has been saved to ${outputFile}`);
|
|
1673
1673
|
return elem.saveScreenshot(outputFile);
|
|
1674
1674
|
}
|
|
1675
1675
|
|
|
@@ -1939,11 +1939,11 @@ class WebDriver extends Helper {
|
|
|
1939
1939
|
*/
|
|
1940
1940
|
async dragAndDrop(srcElement, destElement) {
|
|
1941
1941
|
let sourceEl = await this._locate(srcElement);
|
|
1942
|
-
assertElementExists(sourceEl);
|
|
1942
|
+
assertElementExists(sourceEl, srcElement);
|
|
1943
1943
|
sourceEl = usingFirstElement(sourceEl);
|
|
1944
1944
|
|
|
1945
1945
|
let destEl = await this._locate(destElement);
|
|
1946
|
-
assertElementExists(destEl);
|
|
1946
|
+
assertElementExists(destEl, destElement);
|
|
1947
1947
|
destEl = usingFirstElement(destEl);
|
|
1948
1948
|
|
|
1949
1949
|
return sourceEl.dragAndDrop(destEl);
|
|
@@ -2042,7 +2042,7 @@ class WebDriver extends Helper {
|
|
|
2042
2042
|
* {{> waitForEnabled }}
|
|
2043
2043
|
*/
|
|
2044
2044
|
async waitForEnabled(locator, sec = null) {
|
|
2045
|
-
const aSec = sec || this.options.
|
|
2045
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
2046
2046
|
if (isWebDriver5()) {
|
|
2047
2047
|
return this.browser.waitUntil(async () => {
|
|
2048
2048
|
const res = await this.$$(withStrictLocator(locator));
|
|
@@ -2076,24 +2076,24 @@ class WebDriver extends Helper {
|
|
|
2076
2076
|
* {{> waitForElement }}
|
|
2077
2077
|
*/
|
|
2078
2078
|
async waitForElement(locator, sec = null) {
|
|
2079
|
-
const aSec = sec || this.options.
|
|
2079
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
2080
2080
|
if (isWebDriver5()) {
|
|
2081
2081
|
return this.browser.waitUntil(async () => {
|
|
2082
2082
|
const res = await this.$$(withStrictLocator(locator));
|
|
2083
2083
|
return res && res.length;
|
|
2084
|
-
}, aSec * 1000, `element (${locator}) still not present on page after ${aSec} sec`);
|
|
2084
|
+
}, aSec * 1000, `element (${(new Locator(locator))}) still not present on page after ${aSec} sec`);
|
|
2085
2085
|
}
|
|
2086
2086
|
return this.browser.waitUntil(async () => {
|
|
2087
2087
|
const res = await this._res(locator);
|
|
2088
2088
|
return res && res.length;
|
|
2089
|
-
}, { timeout: aSec * 1000, timeoutMsg: `element (${locator}) still not present on page after ${aSec} sec` });
|
|
2089
|
+
}, { timeout: aSec * 1000, timeoutMsg: `element (${(new Locator(locator))}) still not present on page after ${aSec} sec` });
|
|
2090
2090
|
}
|
|
2091
2091
|
|
|
2092
2092
|
/**
|
|
2093
2093
|
* {{> waitForClickable }}
|
|
2094
2094
|
*/
|
|
2095
2095
|
async waitForClickable(locator, waitTimeout) {
|
|
2096
|
-
waitTimeout = waitTimeout || this.options.
|
|
2096
|
+
waitTimeout = waitTimeout || this.options.waitForTimeoutInSeconds;
|
|
2097
2097
|
let res = await this._locate(locator);
|
|
2098
2098
|
res = usingFirstElement(res);
|
|
2099
2099
|
assertElementExists(res, locator);
|
|
@@ -2109,7 +2109,7 @@ class WebDriver extends Helper {
|
|
|
2109
2109
|
*/
|
|
2110
2110
|
async waitInUrl(urlPart, sec = null) {
|
|
2111
2111
|
const client = this.browser;
|
|
2112
|
-
const aSec = sec || this.options.
|
|
2112
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
2113
2113
|
let currUrl = '';
|
|
2114
2114
|
if (isWebDriver5()) {
|
|
2115
2115
|
return client
|
|
@@ -2143,7 +2143,7 @@ class WebDriver extends Helper {
|
|
|
2143
2143
|
* {{> waitUrlEquals }}
|
|
2144
2144
|
*/
|
|
2145
2145
|
async waitUrlEquals(urlPart, sec = null) {
|
|
2146
|
-
const aSec = sec || this.options.
|
|
2146
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
2147
2147
|
const baseUrl = this.options.url;
|
|
2148
2148
|
if (urlPart.indexOf('http') < 0) {
|
|
2149
2149
|
urlPart = baseUrl + urlPart;
|
|
@@ -2167,7 +2167,7 @@ class WebDriver extends Helper {
|
|
|
2167
2167
|
*
|
|
2168
2168
|
*/
|
|
2169
2169
|
async waitForText(text, sec = null, context = null) {
|
|
2170
|
-
const aSec = sec || this.options.
|
|
2170
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
2171
2171
|
const _context = context || this.root;
|
|
2172
2172
|
if (isWebDriver5()) {
|
|
2173
2173
|
return this.browser.waitUntil(
|
|
@@ -2205,7 +2205,7 @@ class WebDriver extends Helper {
|
|
|
2205
2205
|
*/
|
|
2206
2206
|
async waitForValue(field, value, sec = null) {
|
|
2207
2207
|
const client = this.browser;
|
|
2208
|
-
const aSec = sec || this.options.
|
|
2208
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
2209
2209
|
if (isWebDriver5()) {
|
|
2210
2210
|
return client.waitUntil(
|
|
2211
2211
|
async () => {
|
|
@@ -2241,7 +2241,7 @@ class WebDriver extends Helper {
|
|
|
2241
2241
|
*
|
|
2242
2242
|
*/
|
|
2243
2243
|
async waitForVisible(locator, sec = null) {
|
|
2244
|
-
const aSec = sec || this.options.
|
|
2244
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
2245
2245
|
if (isWebDriver5()) {
|
|
2246
2246
|
return this.browser.waitUntil(async () => {
|
|
2247
2247
|
const res = await this.$$(withStrictLocator(locator));
|
|
@@ -2268,7 +2268,7 @@ class WebDriver extends Helper {
|
|
|
2268
2268
|
* {{> waitNumberOfVisibleElements }}
|
|
2269
2269
|
*/
|
|
2270
2270
|
async waitNumberOfVisibleElements(locator, num, sec = null) {
|
|
2271
|
-
const aSec = sec || this.options.
|
|
2271
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
2272
2272
|
if (isWebDriver5()) {
|
|
2273
2273
|
return this.browser.waitUntil(async () => {
|
|
2274
2274
|
const res = await this.$$(withStrictLocator(locator));
|
|
@@ -2295,7 +2295,7 @@ class WebDriver extends Helper {
|
|
|
2295
2295
|
* {{> waitForInvisible }}
|
|
2296
2296
|
*/
|
|
2297
2297
|
async waitForInvisible(locator, sec = null) {
|
|
2298
|
-
const aSec = sec || this.options.
|
|
2298
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
2299
2299
|
if (isWebDriver5()) {
|
|
2300
2300
|
return this.browser.waitUntil(async () => {
|
|
2301
2301
|
const res = await this.$$(withStrictLocator(locator));
|
|
@@ -2323,7 +2323,7 @@ class WebDriver extends Helper {
|
|
|
2323
2323
|
* {{> waitForDetached }}
|
|
2324
2324
|
*/
|
|
2325
2325
|
async waitForDetached(locator, sec = null) {
|
|
2326
|
-
const aSec = sec || this.options.
|
|
2326
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
2327
2327
|
if (isWebDriver5()) {
|
|
2328
2328
|
return this.browser.waitUntil(async () => {
|
|
2329
2329
|
const res = await this._res(locator);
|
|
@@ -2355,7 +2355,7 @@ class WebDriver extends Helper {
|
|
|
2355
2355
|
}
|
|
2356
2356
|
}
|
|
2357
2357
|
|
|
2358
|
-
const aSec = sec || this.options.
|
|
2358
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
2359
2359
|
if (isWebDriver5()) {
|
|
2360
2360
|
return this.browser.waitUntil(async () => this.browser.execute(fn, ...args), aSec * 1000, '');
|
|
2361
2361
|
}
|
|
@@ -2384,7 +2384,7 @@ class WebDriver extends Helper {
|
|
|
2384
2384
|
* {{> switchToNextTab }}
|
|
2385
2385
|
*/
|
|
2386
2386
|
async switchToNextTab(num = 1, sec = null) {
|
|
2387
|
-
const aSec = sec || this.options.
|
|
2387
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
2388
2388
|
let target;
|
|
2389
2389
|
const current = await this.browser.getWindowHandle();
|
|
2390
2390
|
|
|
@@ -2415,7 +2415,7 @@ class WebDriver extends Helper {
|
|
|
2415
2415
|
* {{> switchToPreviousTab }}
|
|
2416
2416
|
*/
|
|
2417
2417
|
async switchToPreviousTab(num = 1, sec = null) {
|
|
2418
|
-
const aSec = sec || this.options.
|
|
2418
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
2419
2419
|
const current = await this.browser.getWindowHandle();
|
|
2420
2420
|
let target;
|
|
2421
2421
|
|
|
@@ -11,7 +11,7 @@ class ElementNotFound {
|
|
|
11
11
|
if (typeof locator === 'object') {
|
|
12
12
|
locator = JSON.stringify(locator);
|
|
13
13
|
}
|
|
14
|
-
throw new Error(`${prefixMessage} "${(new Locator(locator))
|
|
14
|
+
throw new Error(`${prefixMessage} "${(new Locator(locator))}" ${postfixMessage}`);
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -18,8 +18,6 @@ module.exports = {
|
|
|
18
18
|
|
|
19
19
|
restarts = Object.keys(RESTART_OPTS).find(key => RESTART_OPTS[key] === restart);
|
|
20
20
|
|
|
21
|
-
console.log(restarts);
|
|
22
|
-
|
|
23
21
|
if (restarts === null || restarts === undefined) throw new Error('No restart strategy set, use the following values for restart: session, context, browser');
|
|
24
22
|
},
|
|
25
23
|
|
package/lib/interfaces/bdd.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { CucumberExpression, ParameterTypeRegistry } = require('cucumber-expressions');
|
|
1
|
+
const { CucumberExpression, ParameterTypeRegistry, ParameterType } = require('cucumber-expressions');
|
|
2
2
|
const Config = require('../config');
|
|
3
3
|
|
|
4
4
|
let steps = {};
|
|
@@ -58,6 +58,30 @@ const getSteps = () => {
|
|
|
58
58
|
return steps;
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
+
const defineParameterType = (options) => {
|
|
62
|
+
const parameterType = buildParameterType(options);
|
|
63
|
+
parameterTypeRegistry.defineParameterType(parameterType);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const buildParameterType = ({
|
|
67
|
+
name,
|
|
68
|
+
regexp,
|
|
69
|
+
transformer,
|
|
70
|
+
useForSnippets,
|
|
71
|
+
preferForRegexpMatch,
|
|
72
|
+
}) => {
|
|
73
|
+
if (typeof useForSnippets !== 'boolean') useForSnippets = true;
|
|
74
|
+
if (typeof preferForRegexpMatch !== 'boolean') preferForRegexpMatch = false;
|
|
75
|
+
return new ParameterType(
|
|
76
|
+
name,
|
|
77
|
+
regexp,
|
|
78
|
+
null,
|
|
79
|
+
transformer,
|
|
80
|
+
useForSnippets,
|
|
81
|
+
preferForRegexpMatch,
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
|
|
61
85
|
module.exports = {
|
|
62
86
|
Given: addStep,
|
|
63
87
|
When: addStep,
|
|
@@ -66,4 +90,5 @@ module.exports = {
|
|
|
66
90
|
matchStep,
|
|
67
91
|
getSteps,
|
|
68
92
|
clearSteps,
|
|
93
|
+
defineParameterType,
|
|
69
94
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const event = require('../event');
|
|
2
|
+
const recorder = require('../recorder');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Create and clean up empty artifacts
|
|
6
|
+
*/
|
|
7
|
+
module.exports = function () {
|
|
8
|
+
event.dispatcher.on(event.test.before, (test) => {
|
|
9
|
+
test.artifacts = {};
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
event.dispatcher.on(event.test.after, (test) => {
|
|
13
|
+
recorder.add('clean up empty artifacts', () => {
|
|
14
|
+
for (const key in (test.artifacts || {})) {
|
|
15
|
+
if (!test.artifacts[key]) delete test.artifacts[key];
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
};
|
package/lib/rerun.js
CHANGED
|
@@ -38,7 +38,10 @@ class CodeceptRerunner extends BaseCodecept {
|
|
|
38
38
|
const configRerun = this.config.rerun || {};
|
|
39
39
|
const minSuccess = configRerun.minSuccess || 1;
|
|
40
40
|
const maxReruns = configRerun.maxReruns || 1;
|
|
41
|
-
if (minSuccess > maxReruns)
|
|
41
|
+
if (minSuccess > maxReruns) {
|
|
42
|
+
process.exitCode = 1;
|
|
43
|
+
throw new Error(`run-rerun Configuration Error: minSuccess must be less than maxReruns. Current values: minSuccess=${minSuccess} maxReruns=${maxReruns}`);
|
|
44
|
+
}
|
|
42
45
|
if (maxReruns === 1) {
|
|
43
46
|
await this.runOnce(test);
|
|
44
47
|
return;
|
|
@@ -61,20 +64,16 @@ class CodeceptRerunner extends BaseCodecept {
|
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
66
|
|
|
64
|
-
run(test) {
|
|
65
|
-
|
|
67
|
+
async run(test) {
|
|
68
|
+
event.emit(event.all.before, this);
|
|
69
|
+
try {
|
|
70
|
+
await this.runTests(test);
|
|
71
|
+
} catch (e) {
|
|
72
|
+
output.error(e.stack);
|
|
73
|
+
} finally {
|
|
66
74
|
event.emit(event.all.result, this);
|
|
67
75
|
event.emit(event.all.after, this);
|
|
68
|
-
}
|
|
69
|
-
event.emit(event.all.before, this);
|
|
70
|
-
return this.runTests(test)
|
|
71
|
-
.then(() => {
|
|
72
|
-
this.teardown(done);
|
|
73
|
-
})
|
|
74
|
-
.catch((e) => {
|
|
75
|
-
this.teardown(done);
|
|
76
|
-
throw e;
|
|
77
|
-
});
|
|
76
|
+
}
|
|
78
77
|
}
|
|
79
78
|
}
|
|
80
79
|
|
package/lib/step.js
CHANGED
|
@@ -268,13 +268,13 @@ class MetaStep extends Step {
|
|
|
268
268
|
step.metaStep = this;
|
|
269
269
|
};
|
|
270
270
|
event.dispatcher.prependListener(event.step.before, registerStep);
|
|
271
|
-
|
|
271
|
+
// Handle async and sync methods.
|
|
272
272
|
if (fn.constructor.name === 'AsyncFunction') {
|
|
273
273
|
result = fn.apply(this.context, this.args).then((result) => {
|
|
274
274
|
return result;
|
|
275
|
-
}).catch(
|
|
275
|
+
}).catch((error) => {
|
|
276
276
|
this.setStatus('failed');
|
|
277
|
-
|
|
277
|
+
throw error;
|
|
278
278
|
}).finally(() => {
|
|
279
279
|
this.endTime = Date.now();
|
|
280
280
|
event.dispatcher.removeListener(event.step.before, registerStep);
|
|
@@ -285,13 +285,13 @@ class MetaStep extends Step {
|
|
|
285
285
|
result = fn.apply(this.context, this.args);
|
|
286
286
|
} catch (error) {
|
|
287
287
|
this.setStatus('failed');
|
|
288
|
-
|
|
288
|
+
throw error;
|
|
289
289
|
} finally {
|
|
290
290
|
this.endTime = Date.now();
|
|
291
291
|
event.dispatcher.removeListener(event.step.before, registerStep);
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
|
-
|
|
294
|
+
|
|
295
295
|
return result;
|
|
296
296
|
}
|
|
297
297
|
}
|
package/lib/translation.js
CHANGED
|
@@ -1,9 +1,29 @@
|
|
|
1
|
+
const merge = require('lodash.merge');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const defaultVocabulary = {
|
|
5
|
+
I: 'I',
|
|
6
|
+
actions: {},
|
|
7
|
+
};
|
|
8
|
+
|
|
1
9
|
class Translation {
|
|
2
10
|
constructor(vocabulary, loaded) {
|
|
3
11
|
this.vocabulary = vocabulary;
|
|
4
12
|
this.loaded = loaded !== false;
|
|
5
13
|
}
|
|
6
14
|
|
|
15
|
+
loadVocabulary(vocabularyFile) {
|
|
16
|
+
if (!vocabularyFile) return;
|
|
17
|
+
const filePath = path.join(global.codecept_dir, vocabularyFile);
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const vocabulary = require(filePath);
|
|
21
|
+
this.vocabulary = merge(this.vocabulary, vocabulary);
|
|
22
|
+
} catch (err) {
|
|
23
|
+
throw new Error(`Can't load vocabulary from ${filePath}; ${err}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
7
27
|
value(val) {
|
|
8
28
|
return this.vocabulary[val];
|
|
9
29
|
}
|
|
@@ -18,6 +38,18 @@ class Translation {
|
|
|
18
38
|
get I() {
|
|
19
39
|
return this.vocabulary.I;
|
|
20
40
|
}
|
|
41
|
+
|
|
42
|
+
static get langs() {
|
|
43
|
+
return require('../translations');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static createDefault() {
|
|
47
|
+
return new Translation(defaultVocabulary, true);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static createEmpty() {
|
|
51
|
+
return new Translation(defaultVocabulary, false);
|
|
52
|
+
}
|
|
21
53
|
}
|
|
22
54
|
|
|
23
55
|
module.exports = Translation;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeceptjs",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.7",
|
|
4
4
|
"description": "Supercharged End 2 End Testing Framework for NodeJS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"acceptance",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"lint-fix": "eslint bin/ examples/ lib/ test/ translations/ runok.js --fix",
|
|
43
43
|
"docs": "./runok.js docs",
|
|
44
44
|
"test:unit": "mocha test/unit --recursive",
|
|
45
|
-
"test:runner": "mocha test/runner --recursive",
|
|
45
|
+
"test:runner": "mocha test/runner --recursive --timeout 5000",
|
|
46
46
|
"test": "npm run test:unit && npm run test:runner",
|
|
47
47
|
"test:appium-quick": "mocha test/helper/Appium_test.js --grep 'quick'",
|
|
48
48
|
"test:appium-other": "mocha test/helper/Appium_test.js --grep 'second'",
|
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
"dev:graphql": "nodemon test/data/graphql/index.js",
|
|
51
51
|
"publish:site": "./runok.js publish:site",
|
|
52
52
|
"update-contributor-faces": "contributor-faces .",
|
|
53
|
-
"dtslint": "dtslint typings --localTs './node_modules/typescript/lib'"
|
|
53
|
+
"dtslint": "dtslint typings --localTs './node_modules/typescript/lib'",
|
|
54
|
+
"prepare": "husky install"
|
|
54
55
|
},
|
|
55
56
|
"dependencies": {
|
|
56
57
|
"@codeceptjs/configure": "^0.8.0",
|
|
@@ -86,8 +87,8 @@
|
|
|
86
87
|
"promise-retry": "^1.1.1",
|
|
87
88
|
"requireg": "^0.2.2",
|
|
88
89
|
"resq": "^1.10.2",
|
|
89
|
-
"sprintf-js": "^1.1.1",
|
|
90
90
|
"semver": "^6.3.0",
|
|
91
|
+
"sprintf-js": "^1.1.1",
|
|
91
92
|
"uuid": "^8.3.2"
|
|
92
93
|
},
|
|
93
94
|
"devDependencies": {
|
|
@@ -116,7 +117,7 @@
|
|
|
116
117
|
"express": "^4.17.2",
|
|
117
118
|
"form-data": "^3.0.1",
|
|
118
119
|
"graphql": "^14.6.0",
|
|
119
|
-
"husky": "^
|
|
120
|
+
"husky": "^8.0.1",
|
|
120
121
|
"jsdoc": "^3.6.10",
|
|
121
122
|
"jsdoc-typeof-plugin": "^1.0.0",
|
|
122
123
|
"json-server": "^0.10.1",
|
|
@@ -132,28 +133,21 @@
|
|
|
132
133
|
"sinon-chai": "^3.7.0",
|
|
133
134
|
"testcafe": "^1.18.3",
|
|
134
135
|
"ts-morph": "^3.1.3",
|
|
136
|
+
"ts-node": "^10.9.1",
|
|
135
137
|
"tsd-jsdoc": "https://github.com/englercj/tsd-jsdoc.git",
|
|
136
138
|
"typedoc": "^0.23.10",
|
|
137
139
|
"typedoc-plugin-markdown": "^3.13.4",
|
|
138
|
-
"typescript": "^4.4
|
|
140
|
+
"typescript": "^4.8.4",
|
|
139
141
|
"wdio-docker-service": "^1.5.0",
|
|
140
142
|
"webdriverio": "^7.16.14",
|
|
141
143
|
"xml2js": "^0.4.23",
|
|
142
144
|
"xmldom": "^0.1.31",
|
|
143
|
-
"xpath": "0.0.27"
|
|
145
|
+
"xpath": "0.0.27",
|
|
146
|
+
"inquirer-test": "^2.0.1"
|
|
144
147
|
},
|
|
145
148
|
"engines": {
|
|
146
149
|
"node": ">=8.9.1",
|
|
147
150
|
"npm": ">=5.6.0"
|
|
148
151
|
},
|
|
149
|
-
"
|
|
150
|
-
"@faker-js/faker": "^5.5.3"
|
|
151
|
-
},
|
|
152
|
-
"es6": true,
|
|
153
|
-
"husky": {
|
|
154
|
-
"hooks": {
|
|
155
|
-
"pre-commit": "npm run lint",
|
|
156
|
-
"pre-push": "npm run test:unit"
|
|
157
|
-
}
|
|
158
|
-
}
|
|
152
|
+
"es6": true
|
|
159
153
|
}
|