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/Playwright.js
CHANGED
|
@@ -44,6 +44,8 @@ const {
|
|
|
44
44
|
} = require('./extras/PlaywrightRestartOpts');
|
|
45
45
|
const { createValueEngine, createDisabledEngine } = require('./extras/PlaywrightPropEngine');
|
|
46
46
|
|
|
47
|
+
const pathSeparator = path.sep;
|
|
48
|
+
|
|
47
49
|
/**
|
|
48
50
|
* ## Configuration
|
|
49
51
|
*
|
|
@@ -52,7 +54,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
|
|
|
52
54
|
* @typedef PlaywrightConfig
|
|
53
55
|
* @type {object}
|
|
54
56
|
* @prop {string} url - base url of website to be tested
|
|
55
|
-
* @prop {string} browser - a browser to test on, either: `chromium`, `firefox`, `webkit`, `electron`. Default: chromium.
|
|
57
|
+
* @prop {string} [browser] - a browser to test on, either: `chromium`, `firefox`, `webkit`, `electron`. Default: chromium.
|
|
56
58
|
* @prop {boolean} [show=false] - show browser window.
|
|
57
59
|
* @prop {string|boolean} [restart=false] - restart strategy between tests. Possible values:
|
|
58
60
|
* * 'context' or **false** - restarts [browser context](https://playwright.dev/docs/api/class-browsercontext) but keeps running browser. Recommended by Playwright team to keep tests isolated.
|
|
@@ -80,8 +82,11 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
|
|
|
80
82
|
* @prop {string} [locale] - locale string. Example: 'en-GB', 'de-DE', 'fr-FR', ...
|
|
81
83
|
* @prop {boolean} [manualStart] - do not start browser before a test, start it manually inside a helper with `this.helpers["Playwright"]._startBrowser()`.
|
|
82
84
|
* @prop {object} [chromium] - pass additional chromium options
|
|
85
|
+
* @prop {object} [firefox] - pass additional firefox options
|
|
83
86
|
* @prop {object} [electron] - (pass additional electron options
|
|
84
87
|
* @prop {any} [channel] - (While Playwright can operate against the stock Google Chrome and Microsoft Edge browsers available on the machine. In particular, current Playwright version will support Stable and Beta channels of these browsers. See [Google Chrome & Microsoft Edge](https://playwright.dev/docs/browsers/#google-chrome--microsoft-edge).
|
|
88
|
+
* @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).
|
|
89
|
+
* @prop {boolean} [ignoreHTTPSErrors] - Allows access to untrustworthy pages, e.g. to a page with an expired certificate. Default value is `false`
|
|
85
90
|
*/
|
|
86
91
|
const config = {};
|
|
87
92
|
|
|
@@ -448,7 +453,7 @@ class Playwright extends Helper {
|
|
|
448
453
|
const existingPages = await this.browserContext.pages();
|
|
449
454
|
mainPage = existingPages[0] || await this.browserContext.newPage();
|
|
450
455
|
}
|
|
451
|
-
targetCreatedHandler.call(this, mainPage);
|
|
456
|
+
await targetCreatedHandler.call(this, mainPage);
|
|
452
457
|
|
|
453
458
|
await this._setPage(mainPage);
|
|
454
459
|
|
|
@@ -513,12 +518,13 @@ class Playwright extends Helper {
|
|
|
513
518
|
browserContext = browser.context();
|
|
514
519
|
page = await browser.firstWindow();
|
|
515
520
|
} else {
|
|
516
|
-
browserContext = await this.browser.newContext(config);
|
|
521
|
+
browserContext = await this.browser.newContext(Object.assign(this.options, config));
|
|
517
522
|
page = await browserContext.newPage();
|
|
518
523
|
}
|
|
519
524
|
|
|
520
|
-
|
|
521
|
-
|
|
525
|
+
if (this.options.trace) await browserContext.tracing.start({ screenshots: true, snapshots: true });
|
|
526
|
+
await targetCreatedHandler.call(this, page);
|
|
527
|
+
await this._setPage(page);
|
|
522
528
|
// Create a new page inside context.
|
|
523
529
|
return browserContext;
|
|
524
530
|
},
|
|
@@ -732,6 +738,19 @@ class Playwright extends Helper {
|
|
|
732
738
|
});
|
|
733
739
|
|
|
734
740
|
this.isRunning = true;
|
|
741
|
+
return this.browser;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
/**
|
|
745
|
+
* Create a new browser context with a page. \
|
|
746
|
+
* Usually it should be run from a custom helper after call of `_startBrowser()`
|
|
747
|
+
* @param {object} [contextOptions] See https://playwright.dev/docs/api/class-browser#browser-new-context
|
|
748
|
+
*/
|
|
749
|
+
async _createContextPage(contextOptions) {
|
|
750
|
+
this.browserContext = await this.browser.newContext(contextOptions);
|
|
751
|
+
const page = await this.browserContext.newPage();
|
|
752
|
+
targetCreatedHandler.call(this, page);
|
|
753
|
+
await this._setPage(page);
|
|
735
754
|
}
|
|
736
755
|
|
|
737
756
|
_getType() {
|
|
@@ -800,8 +819,8 @@ class Playwright extends Helper {
|
|
|
800
819
|
if (this.isElectron) {
|
|
801
820
|
throw new Error('Cannot open pages inside an Electron container');
|
|
802
821
|
}
|
|
803
|
-
if (!(/^\w
|
|
804
|
-
url = this.options.url + url;
|
|
822
|
+
if (!(/^\w+\:(\/\/|.+)/.test(url))) {
|
|
823
|
+
url = this.options.url + (url.startsWith('/') ? url : `/${url}`);
|
|
805
824
|
}
|
|
806
825
|
|
|
807
826
|
if (this.options.basicAuth && (this.isAuthenticated !== true)) {
|
|
@@ -874,7 +893,7 @@ class Playwright extends Helper {
|
|
|
874
893
|
*/
|
|
875
894
|
async moveCursorTo(locator, offsetX = 0, offsetY = 0) {
|
|
876
895
|
const els = await this._locate(locator);
|
|
877
|
-
assertElementExists(els);
|
|
896
|
+
assertElementExists(els, locator);
|
|
878
897
|
|
|
879
898
|
// Use manual mouse.move instead of .hover() so the offset can be added to the coordinates
|
|
880
899
|
const { x, y } = await clickablePoint(els[0]);
|
|
@@ -901,6 +920,26 @@ class Playwright extends Helper {
|
|
|
901
920
|
return this.page.dragAndDrop(buildLocatorString(src), buildLocatorString(dst), options);
|
|
902
921
|
}
|
|
903
922
|
|
|
923
|
+
/**
|
|
924
|
+
* Restart browser with a new context and a new page
|
|
925
|
+
*
|
|
926
|
+
* ```js
|
|
927
|
+
* // Restart browser and use a new timezone
|
|
928
|
+
* I.restartBrowser({ timezoneId: 'America/Phoenix' });
|
|
929
|
+
* // Open URL in a new page in changed timezone
|
|
930
|
+
* I.amOnPage('/');
|
|
931
|
+
* // Restart browser, allow reading/copying of text from/into clipboard in Chrome
|
|
932
|
+
* I.restartBrowser({ permissions: ['clipboard-read', 'clipboard-write'] });
|
|
933
|
+
* ```
|
|
934
|
+
*
|
|
935
|
+
* @param {object} [contextOptions] [Options for browser context](https://playwright.dev/docs/api/class-browser#browser-new-context) when starting new browser
|
|
936
|
+
*/
|
|
937
|
+
async restartBrowser(contextOptions) {
|
|
938
|
+
await this._stopBrowser();
|
|
939
|
+
await this._startBrowser();
|
|
940
|
+
await this._createContextPage(contextOptions);
|
|
941
|
+
}
|
|
942
|
+
|
|
904
943
|
/**
|
|
905
944
|
* {{> refreshPage }}
|
|
906
945
|
*/
|
|
@@ -1073,7 +1112,7 @@ class Playwright extends Helper {
|
|
|
1073
1112
|
if (!page) {
|
|
1074
1113
|
throw new Error(`There is no ability to switch to next tab with offset ${num}`);
|
|
1075
1114
|
}
|
|
1076
|
-
targetCreatedHandler.call(this, page);
|
|
1115
|
+
await targetCreatedHandler.call(this, page);
|
|
1077
1116
|
await this._setPage(page);
|
|
1078
1117
|
return this._waitForAction();
|
|
1079
1118
|
}
|
|
@@ -1157,7 +1196,7 @@ class Playwright extends Helper {
|
|
|
1157
1196
|
throw new Error('Cannot open new tabs inside an Electron container');
|
|
1158
1197
|
}
|
|
1159
1198
|
const page = await this.browserContext.newPage(options);
|
|
1160
|
-
targetCreatedHandler.call(this, page);
|
|
1199
|
+
await targetCreatedHandler.call(this, page);
|
|
1161
1200
|
await this._setPage(page);
|
|
1162
1201
|
return this._waitForAction();
|
|
1163
1202
|
}
|
|
@@ -1207,7 +1246,7 @@ class Playwright extends Helper {
|
|
|
1207
1246
|
}
|
|
1208
1247
|
|
|
1209
1248
|
/**
|
|
1210
|
-
* Handles a file download.
|
|
1249
|
+
* Handles a file download. A file name is required to save the file on disk.
|
|
1211
1250
|
* Files are saved to "output" directory.
|
|
1212
1251
|
*
|
|
1213
1252
|
* Should be used with [FileSystem helper](https://codecept.io/helpers/FileSystem) to check that file were downloaded correctly.
|
|
@@ -1216,17 +1255,19 @@ class Playwright extends Helper {
|
|
|
1216
1255
|
* I.handleDownloads('downloads/avatar.jpg');
|
|
1217
1256
|
* I.click('Download Avatar');
|
|
1218
1257
|
* I.amInPath('output/downloads');
|
|
1219
|
-
* I.waitForFile('
|
|
1258
|
+
* I.waitForFile('avatar.jpg', 5);
|
|
1220
1259
|
*
|
|
1221
1260
|
* ```
|
|
1222
1261
|
*
|
|
1223
1262
|
* @param {string} [fileName] set filename for downloaded file
|
|
1224
1263
|
* @return {Promise<void>}
|
|
1225
1264
|
*/
|
|
1226
|
-
async handleDownloads(fileName
|
|
1265
|
+
async handleDownloads(fileName) {
|
|
1227
1266
|
this.page.waitForEvent('download').then(async (download) => {
|
|
1228
1267
|
const filePath = await download.path();
|
|
1229
|
-
|
|
1268
|
+
fileName = fileName || `downloads/${path.basename(filePath)}`;
|
|
1269
|
+
|
|
1270
|
+
const downloadPath = path.join(global.output_dir, fileName);
|
|
1230
1271
|
if (!fs.existsSync(path.dirname(downloadPath))) {
|
|
1231
1272
|
fs.mkdirSync(path.dirname(downloadPath), '0777');
|
|
1232
1273
|
}
|
|
@@ -1469,7 +1510,7 @@ class Playwright extends Helper {
|
|
|
1469
1510
|
throw new Error(`File at ${file} can not be found on local system`);
|
|
1470
1511
|
}
|
|
1471
1512
|
const els = await findFields.call(this, locator);
|
|
1472
|
-
assertElementExists(els, 'Field');
|
|
1513
|
+
assertElementExists(els, locator, 'Field');
|
|
1473
1514
|
await els[0].setInputFiles(file);
|
|
1474
1515
|
return this._waitForAction();
|
|
1475
1516
|
}
|
|
@@ -1623,7 +1664,7 @@ class Playwright extends Helper {
|
|
|
1623
1664
|
*/
|
|
1624
1665
|
async seeNumberOfElements(locator, num) {
|
|
1625
1666
|
const elements = await this._locate(locator);
|
|
1626
|
-
return equals(`expected number of elements (${locator}) is ${num}, but found ${elements.length}`).assert(elements.length, num);
|
|
1667
|
+
return equals(`expected number of elements (${(new Locator(locator))}) is ${num}, but found ${elements.length}`).assert(elements.length, num);
|
|
1627
1668
|
}
|
|
1628
1669
|
|
|
1629
1670
|
/**
|
|
@@ -1633,7 +1674,7 @@ class Playwright extends Helper {
|
|
|
1633
1674
|
*/
|
|
1634
1675
|
async seeNumberOfVisibleElements(locator, num) {
|
|
1635
1676
|
const res = await this.grabNumberOfVisibleElements(locator);
|
|
1636
|
-
return equals(`expected number of visible elements (${locator}) is ${num}, but found ${res}`).assert(res, num);
|
|
1677
|
+
return equals(`expected number of visible elements (${(new Locator(locator))}) is ${num}, but found ${res}`).assert(res, num);
|
|
1637
1678
|
}
|
|
1638
1679
|
|
|
1639
1680
|
/**
|
|
@@ -1707,6 +1748,7 @@ class Playwright extends Helper {
|
|
|
1707
1748
|
*
|
|
1708
1749
|
* @param {string|function} fn function to be executed in browser context.
|
|
1709
1750
|
* @param {any} [arg] optional argument to pass to the function
|
|
1751
|
+
* @returns {Promise<any>}
|
|
1710
1752
|
*/
|
|
1711
1753
|
async executeScript(fn, arg) {
|
|
1712
1754
|
let context = this.page;
|
|
@@ -1854,7 +1896,7 @@ class Playwright extends Helper {
|
|
|
1854
1896
|
}
|
|
1855
1897
|
return true;
|
|
1856
1898
|
});
|
|
1857
|
-
return equals(`all elements (${locator}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(chunked.length, elemAmount);
|
|
1899
|
+
return equals(`all elements (${(new Locator(locator))}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(chunked.length, elemAmount);
|
|
1858
1900
|
}
|
|
1859
1901
|
|
|
1860
1902
|
/**
|
|
@@ -1883,7 +1925,7 @@ class Playwright extends Helper {
|
|
|
1883
1925
|
}
|
|
1884
1926
|
return true;
|
|
1885
1927
|
});
|
|
1886
|
-
return equals(`all elements (${locator}) to have attributes ${JSON.stringify(attributes)}`).assert(chunked.length, elemAmount);
|
|
1928
|
+
return equals(`all elements (${(new Locator(locator))}) to have attributes ${JSON.stringify(attributes)}`).assert(chunked.length, elemAmount);
|
|
1887
1929
|
}
|
|
1888
1930
|
|
|
1889
1931
|
/**
|
|
@@ -1947,7 +1989,7 @@ class Playwright extends Helper {
|
|
|
1947
1989
|
assertElementExists(res, locator);
|
|
1948
1990
|
if (res.length > 1) this.debug(`[Elements] Using first element out of ${res.length}`);
|
|
1949
1991
|
const elem = res[0];
|
|
1950
|
-
this.debug(`Screenshot of ${locator} element has been saved to ${outputFile}`);
|
|
1992
|
+
this.debug(`Screenshot of ${(new Locator(locator))} element has been saved to ${outputFile}`);
|
|
1951
1993
|
return elem.screenshot({ path: outputFile, type: 'png' });
|
|
1952
1994
|
}
|
|
1953
1995
|
|
|
@@ -2030,29 +2072,28 @@ class Playwright extends Helper {
|
|
|
2030
2072
|
}
|
|
2031
2073
|
|
|
2032
2074
|
if (this.options.recordVideo && this.page && this.page.video()) {
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
}));
|
|
2075
|
+
test.artifacts.video = await saveVideoForPage(this.page, `${test.title}.failed`);
|
|
2076
|
+
for (const sessionName in this.sessionPages) {
|
|
2077
|
+
test.artifacts[`video_${sessionName}`] = await saveVideoForPage(this.sessionPages[sessionName], `${test.title}_${sessionName}.failed`);
|
|
2078
|
+
}
|
|
2038
2079
|
}
|
|
2039
2080
|
|
|
2040
2081
|
if (this.options.trace) {
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2082
|
+
test.artifacts.trace = await saveTraceForContext(this.browserContext, `${test.title}.failed`);
|
|
2083
|
+
for (const sessionName in this.sessionPages) {
|
|
2084
|
+
if (!this.sessionPages[sessionName].context) continue;
|
|
2085
|
+
test.artifacts[`trace_${sessionName}`] = await saveTraceForContext(this.sessionPages[sessionName].context(), `${test.title}_${sessionName}.failed`);
|
|
2086
|
+
}
|
|
2044
2087
|
}
|
|
2045
2088
|
}
|
|
2046
2089
|
|
|
2047
2090
|
async _passed(test) {
|
|
2048
2091
|
if (this.options.recordVideo && this.page && this.page.video()) {
|
|
2049
|
-
const videoPath = `${global.output_dir}/videos/${clearString(test.title)}.passed.webm`;
|
|
2050
|
-
|
|
2051
2092
|
if (this.options.keepVideoForPassedTests) {
|
|
2052
|
-
test.artifacts.video = await this.page.
|
|
2053
|
-
|
|
2054
|
-
test.artifacts
|
|
2055
|
-
}
|
|
2093
|
+
test.artifacts.video = await saveVideoForPage(this.page, `${test.title}.passed`);
|
|
2094
|
+
for (const sessionName of Object.keys(this.sessionPages)) {
|
|
2095
|
+
test.artifacts[`video_${sessionName}`] = await saveVideoForPage(this.sessionPages[sessionName], `${test.title}_${sessionName}.passed`);
|
|
2096
|
+
}
|
|
2056
2097
|
} else {
|
|
2057
2098
|
this.page.video().delete().catch(e => {});
|
|
2058
2099
|
}
|
|
@@ -2060,9 +2101,13 @@ class Playwright extends Helper {
|
|
|
2060
2101
|
|
|
2061
2102
|
if (this.options.trace) {
|
|
2062
2103
|
if (this.options.keepTraceForPassedTests) {
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2104
|
+
if (this.options.trace) {
|
|
2105
|
+
test.artifacts.trace = await saveTraceForContext(this.browserContext, `${test.title}.passed`);
|
|
2106
|
+
for (const sessionName in this.sessionPages) {
|
|
2107
|
+
if (!this.sessionPages[sessionName].context) continue;
|
|
2108
|
+
test.artifacts[`trace_${sessionName}`] = await saveTraceForContext(this.sessionPages[sessionName].context(), `${test.title}_${sessionName}.passed`);
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2066
2111
|
} else {
|
|
2067
2112
|
await this.browserContext.tracing.stop();
|
|
2068
2113
|
}
|
|
@@ -2783,7 +2828,7 @@ async function targetCreatedHandler(page) {
|
|
|
2783
2828
|
page.on('load', () => {
|
|
2784
2829
|
page.$('body')
|
|
2785
2830
|
.catch(() => null)
|
|
2786
|
-
.then(async
|
|
2831
|
+
.then(async () => {
|
|
2787
2832
|
if (this.context && this.context._type === 'Frame') {
|
|
2788
2833
|
// we are inside iframe?
|
|
2789
2834
|
const frameEl = await this.context.frameElement();
|
|
@@ -2808,7 +2853,7 @@ async function targetCreatedHandler(page) {
|
|
|
2808
2853
|
try {
|
|
2809
2854
|
await page.setViewportSize(parseWindowSize(this.options.windowSize));
|
|
2810
2855
|
} catch (err) {
|
|
2811
|
-
|
|
2856
|
+
this.debug('Target can be already closed, ignoring...');
|
|
2812
2857
|
}
|
|
2813
2858
|
}
|
|
2814
2859
|
}
|
|
@@ -2933,3 +2978,21 @@ async function refreshContextSession() {
|
|
|
2933
2978
|
});
|
|
2934
2979
|
}
|
|
2935
2980
|
}
|
|
2981
|
+
|
|
2982
|
+
async function saveVideoForPage(page, name) {
|
|
2983
|
+
if (!page.video()) return null;
|
|
2984
|
+
const fileName = `${global.output_dir}${pathSeparator}videos${pathSeparator}${Date.now()}_${clearString(name).slice(0, 245)}.webm`;
|
|
2985
|
+
page.video().saveAs(fileName).then(() => {
|
|
2986
|
+
if (!page) return;
|
|
2987
|
+
page.video().delete().catch(e => {});
|
|
2988
|
+
});
|
|
2989
|
+
return fileName;
|
|
2990
|
+
}
|
|
2991
|
+
|
|
2992
|
+
async function saveTraceForContext(context, name) {
|
|
2993
|
+
if (!context) return;
|
|
2994
|
+
if (!context.tracing) return;
|
|
2995
|
+
const fileName = `${`${global.output_dir}${pathSeparator}trace${pathSeparator}${Date.now()}_${clearString(name)}`.slice(0, 245)}.zip`;
|
|
2996
|
+
await context.tracing.stop({ path: fileName });
|
|
2997
|
+
return fileName;
|
|
2998
|
+
}
|
package/lib/helper/Protractor.js
CHANGED
|
@@ -153,7 +153,7 @@ class Protractor extends Helper {
|
|
|
153
153
|
if (config.proxy) config.capabilities.proxy = config.proxy;
|
|
154
154
|
if (config.browser) config.capabilities.browserName = config.browser;
|
|
155
155
|
|
|
156
|
-
config.waitForTimeout
|
|
156
|
+
config.waitForTimeoutInSeconds = config.waitForTimeout / 1000; // convert to seconds
|
|
157
157
|
return config;
|
|
158
158
|
}
|
|
159
159
|
|
|
@@ -722,7 +722,7 @@ class Protractor extends Helper {
|
|
|
722
722
|
*/
|
|
723
723
|
async grabTextFrom(locator) {
|
|
724
724
|
const texts = await this.grabTextFromAll(locator);
|
|
725
|
-
assertElementExists(texts);
|
|
725
|
+
assertElementExists(texts, locator);
|
|
726
726
|
if (texts.length > 1) {
|
|
727
727
|
this.debugSection('GrabText', `Using first element out of ${texts.length}`);
|
|
728
728
|
}
|
|
@@ -748,7 +748,7 @@ class Protractor extends Helper {
|
|
|
748
748
|
*/
|
|
749
749
|
async grabHTMLFrom(locator) {
|
|
750
750
|
const html = await this.grabHTMLFromAll(locator);
|
|
751
|
-
assertElementExists(html);
|
|
751
|
+
assertElementExists(html, locator);
|
|
752
752
|
if (html.length > 1) {
|
|
753
753
|
this.debugSection('GrabHTMl', `Using first element out of ${html.length}`);
|
|
754
754
|
}
|
|
@@ -920,7 +920,7 @@ class Protractor extends Helper {
|
|
|
920
920
|
*/
|
|
921
921
|
async seeNumberOfElements(locator, num) {
|
|
922
922
|
const elements = await this._locate(locator);
|
|
923
|
-
return equals(`expected number of elements (${locator}) is ${num}, but found ${elements.length}`).assert(elements.length, num);
|
|
923
|
+
return equals(`expected number of elements (${(new Locator(locator))}) is ${num}, but found ${elements.length}`).assert(elements.length, num);
|
|
924
924
|
}
|
|
925
925
|
|
|
926
926
|
/**
|
|
@@ -928,7 +928,7 @@ class Protractor extends Helper {
|
|
|
928
928
|
*/
|
|
929
929
|
async seeNumberOfVisibleElements(locator, num) {
|
|
930
930
|
const res = await this.grabNumberOfVisibleElements(locator);
|
|
931
|
-
return equals(`expected number of visible elements (${locator}) is ${num}, but found ${res}`).assert(res, num);
|
|
931
|
+
return equals(`expected number of visible elements (${(new Locator(locator))}) is ${num}, but found ${res}`).assert(res, num);
|
|
932
932
|
}
|
|
933
933
|
|
|
934
934
|
/**
|
|
@@ -968,7 +968,7 @@ class Protractor extends Helper {
|
|
|
968
968
|
missingAttributes.push(...missing);
|
|
969
969
|
}
|
|
970
970
|
}
|
|
971
|
-
return equals(`all elements (${locator}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(missingAttributes.length, 0);
|
|
971
|
+
return equals(`all elements (${(new Locator(locator))}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(missingAttributes.length, 0);
|
|
972
972
|
}
|
|
973
973
|
|
|
974
974
|
/**
|
|
@@ -995,7 +995,7 @@ class Protractor extends Helper {
|
|
|
995
995
|
}
|
|
996
996
|
}
|
|
997
997
|
|
|
998
|
-
return equals(`all elements (${locator}) to have attributes ${JSON.stringify(attributes)}`).assert(missingAttributes.length, 0);
|
|
998
|
+
return equals(`all elements (${(new Locator(locator))}) to have attributes ${JSON.stringify(attributes)}`).assert(missingAttributes.length, 0);
|
|
999
999
|
}
|
|
1000
1000
|
|
|
1001
1001
|
/**
|
|
@@ -1060,7 +1060,7 @@ class Protractor extends Helper {
|
|
|
1060
1060
|
assertElementExists(res, locator);
|
|
1061
1061
|
if (res.length > 1) this.debug(`[Elements] Using first element out of ${res.length}`);
|
|
1062
1062
|
const elem = res[0];
|
|
1063
|
-
this.debug(`Screenshot of ${locator} element has been saved to ${outputFile}`);
|
|
1063
|
+
this.debug(`Screenshot of ${(new Locator(locator))} element has been saved to ${outputFile}`);
|
|
1064
1064
|
const png = await elem.takeScreenshot();
|
|
1065
1065
|
return writeFile(png, outputFile);
|
|
1066
1066
|
}
|
|
@@ -1200,8 +1200,8 @@ class Protractor extends Helper {
|
|
|
1200
1200
|
async dragAndDrop(srcElement, destElement) {
|
|
1201
1201
|
const srcEl = await this._locate(srcElement, true);
|
|
1202
1202
|
const destEl = await this._locate(destElement, true);
|
|
1203
|
-
assertElementExists(srcEl);
|
|
1204
|
-
assertElementExists(destEl);
|
|
1203
|
+
assertElementExists(srcEl, srcElement);
|
|
1204
|
+
assertElementExists(destEl, destElement);
|
|
1205
1205
|
return this.browser
|
|
1206
1206
|
.actions()
|
|
1207
1207
|
.dragAndDrop(srcEl[0], destEl[0])
|
|
@@ -1348,7 +1348,7 @@ class Protractor extends Helper {
|
|
|
1348
1348
|
* {{> waitForElement }}
|
|
1349
1349
|
*/
|
|
1350
1350
|
async waitForElement(locator, sec = null) {
|
|
1351
|
-
const aSec = sec || this.options.
|
|
1351
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
1352
1352
|
const el = global.element(guessLocator(locator) || global.by.css(locator));
|
|
1353
1353
|
return this.browser.wait(EC.presenceOf(el), aSec * 1000);
|
|
1354
1354
|
}
|
|
@@ -1364,7 +1364,7 @@ class Protractor extends Helper {
|
|
|
1364
1364
|
* {{> waitForDetached }}
|
|
1365
1365
|
*/
|
|
1366
1366
|
async waitForDetached(locator, sec = null) {
|
|
1367
|
-
const aSec = sec || this.options.
|
|
1367
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
1368
1368
|
const el = global.element(guessLocator(locator) || global.by.css(locator));
|
|
1369
1369
|
return this.browser.wait(EC.not(EC.presenceOf(el)), aSec * 1000).catch((err) => {
|
|
1370
1370
|
if (err.message && err.message.indexOf('Wait timed out after') > -1) {
|
|
@@ -1381,7 +1381,7 @@ class Protractor extends Helper {
|
|
|
1381
1381
|
* ```
|
|
1382
1382
|
*/
|
|
1383
1383
|
async waitForClickable(locator, sec = null) {
|
|
1384
|
-
const aSec = sec || this.options.
|
|
1384
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
1385
1385
|
const el = global.element(guessLocator(locator) || global.by.css(locator));
|
|
1386
1386
|
return this.browser.wait(EC.elementToBeClickable(el), aSec * 1000);
|
|
1387
1387
|
}
|
|
@@ -1390,7 +1390,7 @@ class Protractor extends Helper {
|
|
|
1390
1390
|
* {{> waitForVisible }}
|
|
1391
1391
|
*/
|
|
1392
1392
|
async waitForVisible(locator, sec = null) {
|
|
1393
|
-
const aSec = sec || this.options.
|
|
1393
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
1394
1394
|
const el = global.element(guessLocator(locator) || global.by.css(locator));
|
|
1395
1395
|
return this.browser.wait(EC.visibilityOf(el), aSec * 1000);
|
|
1396
1396
|
}
|
|
@@ -1406,7 +1406,7 @@ class Protractor extends Helper {
|
|
|
1406
1406
|
* {{> waitForInvisible }}
|
|
1407
1407
|
*/
|
|
1408
1408
|
async waitForInvisible(locator, sec = null) {
|
|
1409
|
-
const aSec = sec || this.options.
|
|
1409
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
1410
1410
|
const el = global.element(guessLocator(locator) || global.by.css(locator));
|
|
1411
1411
|
return this.browser.wait(EC.invisibilityOf(el), aSec * 1000);
|
|
1412
1412
|
}
|
|
@@ -1431,12 +1431,12 @@ class Protractor extends Helper {
|
|
|
1431
1431
|
};
|
|
1432
1432
|
}
|
|
1433
1433
|
|
|
1434
|
-
const aSec = sec || this.options.
|
|
1434
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
1435
1435
|
const guessLoc = guessLocator(locator) || global.by.css(locator);
|
|
1436
1436
|
|
|
1437
1437
|
return this.browser.wait(visibilityCountOf(guessLoc, num), aSec * 1000)
|
|
1438
1438
|
.catch(() => {
|
|
1439
|
-
throw Error(`The number of elements (${locator}) is not ${num} after ${aSec} sec`);
|
|
1439
|
+
throw Error(`The number of elements (${(new Locator(locator))}) is not ${num} after ${aSec} sec`);
|
|
1440
1440
|
});
|
|
1441
1441
|
}
|
|
1442
1442
|
|
|
@@ -1444,12 +1444,12 @@ class Protractor extends Helper {
|
|
|
1444
1444
|
* {{> waitForEnabled }}
|
|
1445
1445
|
*/
|
|
1446
1446
|
async waitForEnabled(locator, sec = null) {
|
|
1447
|
-
const aSec = sec || this.options.
|
|
1447
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
1448
1448
|
const el = global.element(guessLocator(locator) || global.by.css(locator));
|
|
1449
1449
|
|
|
1450
1450
|
return this.browser.wait(EC.elementToBeClickable(el), aSec * 1000)
|
|
1451
1451
|
.catch(() => {
|
|
1452
|
-
throw Error(`element (${locator}) still not enabled after ${aSec} sec`);
|
|
1452
|
+
throw Error(`element (${(new Locator(locator))}) still not enabled after ${aSec} sec`);
|
|
1453
1453
|
});
|
|
1454
1454
|
}
|
|
1455
1455
|
|
|
@@ -1457,7 +1457,7 @@ class Protractor extends Helper {
|
|
|
1457
1457
|
* {{> waitForValue }}
|
|
1458
1458
|
*/
|
|
1459
1459
|
async waitForValue(field, value, sec = null) {
|
|
1460
|
-
const aSec = sec || this.options.
|
|
1460
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
1461
1461
|
|
|
1462
1462
|
const valueToBeInElementValue = (loc) => {
|
|
1463
1463
|
return async () => {
|
|
@@ -1490,7 +1490,7 @@ class Protractor extends Helper {
|
|
|
1490
1490
|
}
|
|
1491
1491
|
}
|
|
1492
1492
|
|
|
1493
|
-
const aSec = sec || this.options.
|
|
1493
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
1494
1494
|
return this.browser.wait(() => this.browser.executeScript.call(this.browser, fn, ...args), aSec * 1000);
|
|
1495
1495
|
}
|
|
1496
1496
|
|
|
@@ -1498,7 +1498,7 @@ class Protractor extends Helper {
|
|
|
1498
1498
|
* {{> waitInUrl }}
|
|
1499
1499
|
*/
|
|
1500
1500
|
async waitInUrl(urlPart, sec = null) {
|
|
1501
|
-
const aSec = sec || this.options.
|
|
1501
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
1502
1502
|
const waitTimeout = aSec * 1000;
|
|
1503
1503
|
|
|
1504
1504
|
return this.browser.wait(EC.urlContains(urlPart), waitTimeout)
|
|
@@ -1516,7 +1516,7 @@ class Protractor extends Helper {
|
|
|
1516
1516
|
* {{> waitUrlEquals }}
|
|
1517
1517
|
*/
|
|
1518
1518
|
async waitUrlEquals(urlPart, sec = null) {
|
|
1519
|
-
const aSec = sec || this.options.
|
|
1519
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
1520
1520
|
const waitTimeout = aSec * 1000;
|
|
1521
1521
|
const baseUrl = this.options.url;
|
|
1522
1522
|
if (urlPart.indexOf('http') < 0) {
|
|
@@ -1542,7 +1542,7 @@ class Protractor extends Helper {
|
|
|
1542
1542
|
context = this.context;
|
|
1543
1543
|
}
|
|
1544
1544
|
const el = global.element(guessLocator(context) || global.by.css(context));
|
|
1545
|
-
const aSec = sec || this.options.
|
|
1545
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
1546
1546
|
return this.browser.wait(EC.textToBePresentInElement(el, text), aSec * 1000);
|
|
1547
1547
|
}
|
|
1548
1548
|
|
|
@@ -1583,7 +1583,7 @@ class Protractor extends Helper {
|
|
|
1583
1583
|
if (locator) {
|
|
1584
1584
|
const res = await this._locate(locator, true);
|
|
1585
1585
|
if (!res || res.length === 0) {
|
|
1586
|
-
return truth(`elements of ${locator}`, 'to be seen').assert(false);
|
|
1586
|
+
return truth(`elements of ${(new Locator(locator))}`, 'to be seen').assert(false);
|
|
1587
1587
|
}
|
|
1588
1588
|
const elem = res[0];
|
|
1589
1589
|
const location = await elem.getLocation();
|
package/lib/helper/Puppeteer.js
CHANGED
|
@@ -696,7 +696,7 @@ class Puppeteer extends Helper {
|
|
|
696
696
|
*/
|
|
697
697
|
async moveCursorTo(locator, offsetX = 0, offsetY = 0) {
|
|
698
698
|
const els = await this._locate(locator);
|
|
699
|
-
assertElementExists(els);
|
|
699
|
+
assertElementExists(els, locator);
|
|
700
700
|
|
|
701
701
|
// Use manual mouse.move instead of .hover() so the offset can be added to the coordinates
|
|
702
702
|
const { x, y } = await getClickablePoint(els[0]);
|
|
@@ -1336,7 +1336,7 @@ class Puppeteer extends Helper {
|
|
|
1336
1336
|
throw new Error(`File at ${file} can not be found on local system`);
|
|
1337
1337
|
}
|
|
1338
1338
|
const els = await findFields.call(this, locator);
|
|
1339
|
-
assertElementExists(els, 'Field');
|
|
1339
|
+
assertElementExists(els, locator, 'Field');
|
|
1340
1340
|
await els[0].uploadFile(file);
|
|
1341
1341
|
return this._waitForAction();
|
|
1342
1342
|
}
|
|
@@ -1491,7 +1491,7 @@ class Puppeteer extends Helper {
|
|
|
1491
1491
|
*/
|
|
1492
1492
|
async seeNumberOfElements(locator, num) {
|
|
1493
1493
|
const elements = await this._locate(locator);
|
|
1494
|
-
return equals(`expected number of elements (${locator}) is ${num}, but found ${elements.length}`).assert(elements.length, num);
|
|
1494
|
+
return equals(`expected number of elements (${(new Locator(locator))}) is ${num}, but found ${elements.length}`).assert(elements.length, num);
|
|
1495
1495
|
}
|
|
1496
1496
|
|
|
1497
1497
|
/**
|
|
@@ -1501,7 +1501,7 @@ class Puppeteer extends Helper {
|
|
|
1501
1501
|
*/
|
|
1502
1502
|
async seeNumberOfVisibleElements(locator, num) {
|
|
1503
1503
|
const res = await this.grabNumberOfVisibleElements(locator);
|
|
1504
|
-
return equals(`expected number of visible elements (${locator}) is ${num}, but found ${res}`).assert(res, num);
|
|
1504
|
+
return equals(`expected number of visible elements (${(new Locator(locator))}) is ${num}, but found ${res}`).assert(res, num);
|
|
1505
1505
|
}
|
|
1506
1506
|
|
|
1507
1507
|
/**
|
|
@@ -1725,7 +1725,7 @@ class Puppeteer extends Helper {
|
|
|
1725
1725
|
}
|
|
1726
1726
|
return true;
|
|
1727
1727
|
});
|
|
1728
|
-
return equals(`all elements (${locator}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(chunked.length, elemAmount);
|
|
1728
|
+
return equals(`all elements (${(new Locator(locator))}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(chunked.length, elemAmount);
|
|
1729
1729
|
}
|
|
1730
1730
|
|
|
1731
1731
|
/**
|
|
@@ -1756,7 +1756,7 @@ class Puppeteer extends Helper {
|
|
|
1756
1756
|
}
|
|
1757
1757
|
return true;
|
|
1758
1758
|
});
|
|
1759
|
-
return equals(`all elements (${locator}) to have attributes ${JSON.stringify(attributes)}`).assert(chunked.length, elemAmount);
|
|
1759
|
+
return equals(`all elements (${(new Locator(locator))}) to have attributes ${JSON.stringify(attributes)}`).assert(chunked.length, elemAmount);
|
|
1760
1760
|
}
|
|
1761
1761
|
|
|
1762
1762
|
/**
|
|
@@ -1819,7 +1819,7 @@ class Puppeteer extends Helper {
|
|
|
1819
1819
|
assertElementExists(res, locator);
|
|
1820
1820
|
if (res.length > 1) this.debug(`[Elements] Using first element out of ${res.length}`);
|
|
1821
1821
|
const elem = res[0];
|
|
1822
|
-
this.debug(`Screenshot of ${locator} element has been saved to ${outputFile}`);
|
|
1822
|
+
this.debug(`Screenshot of ${(new Locator(locator))} element has been saved to ${outputFile}`);
|
|
1823
1823
|
return elem.screenshot({ path: outputFile, type: 'png' });
|
|
1824
1824
|
}
|
|
1825
1825
|
|