codeceptjs 3.3.7-beta.1 → 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 -41
- 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
|
|
|
@@ -477,8 +482,6 @@ class Playwright extends Helper {
|
|
|
477
482
|
|
|
478
483
|
// close other sessions
|
|
479
484
|
try {
|
|
480
|
-
if (!this.browser.contexts) return this.browser;
|
|
481
|
-
|
|
482
485
|
const contexts = await this.browser.contexts();
|
|
483
486
|
const currentContext = contexts[0];
|
|
484
487
|
if (currentContext && (this.options.keepCookies || this.options.keepBrowserState)) {
|
|
@@ -515,12 +518,13 @@ class Playwright extends Helper {
|
|
|
515
518
|
browserContext = browser.context();
|
|
516
519
|
page = await browser.firstWindow();
|
|
517
520
|
} else {
|
|
518
|
-
browserContext = await this.browser.newContext(config);
|
|
521
|
+
browserContext = await this.browser.newContext(Object.assign(this.options, config));
|
|
519
522
|
page = await browserContext.newPage();
|
|
520
523
|
}
|
|
521
524
|
|
|
522
|
-
|
|
523
|
-
|
|
525
|
+
if (this.options.trace) await browserContext.tracing.start({ screenshots: true, snapshots: true });
|
|
526
|
+
await targetCreatedHandler.call(this, page);
|
|
527
|
+
await this._setPage(page);
|
|
524
528
|
// Create a new page inside context.
|
|
525
529
|
return browserContext;
|
|
526
530
|
},
|
|
@@ -734,6 +738,19 @@ class Playwright extends Helper {
|
|
|
734
738
|
});
|
|
735
739
|
|
|
736
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);
|
|
737
754
|
}
|
|
738
755
|
|
|
739
756
|
_getType() {
|
|
@@ -802,8 +819,8 @@ class Playwright extends Helper {
|
|
|
802
819
|
if (this.isElectron) {
|
|
803
820
|
throw new Error('Cannot open pages inside an Electron container');
|
|
804
821
|
}
|
|
805
|
-
if (!(/^\w
|
|
806
|
-
url = this.options.url + url;
|
|
822
|
+
if (!(/^\w+\:(\/\/|.+)/.test(url))) {
|
|
823
|
+
url = this.options.url + (url.startsWith('/') ? url : `/${url}`);
|
|
807
824
|
}
|
|
808
825
|
|
|
809
826
|
if (this.options.basicAuth && (this.isAuthenticated !== true)) {
|
|
@@ -876,7 +893,7 @@ class Playwright extends Helper {
|
|
|
876
893
|
*/
|
|
877
894
|
async moveCursorTo(locator, offsetX = 0, offsetY = 0) {
|
|
878
895
|
const els = await this._locate(locator);
|
|
879
|
-
assertElementExists(els);
|
|
896
|
+
assertElementExists(els, locator);
|
|
880
897
|
|
|
881
898
|
// Use manual mouse.move instead of .hover() so the offset can be added to the coordinates
|
|
882
899
|
const { x, y } = await clickablePoint(els[0]);
|
|
@@ -903,6 +920,26 @@ class Playwright extends Helper {
|
|
|
903
920
|
return this.page.dragAndDrop(buildLocatorString(src), buildLocatorString(dst), options);
|
|
904
921
|
}
|
|
905
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
|
+
|
|
906
943
|
/**
|
|
907
944
|
* {{> refreshPage }}
|
|
908
945
|
*/
|
|
@@ -1075,7 +1112,7 @@ class Playwright extends Helper {
|
|
|
1075
1112
|
if (!page) {
|
|
1076
1113
|
throw new Error(`There is no ability to switch to next tab with offset ${num}`);
|
|
1077
1114
|
}
|
|
1078
|
-
targetCreatedHandler.call(this, page);
|
|
1115
|
+
await targetCreatedHandler.call(this, page);
|
|
1079
1116
|
await this._setPage(page);
|
|
1080
1117
|
return this._waitForAction();
|
|
1081
1118
|
}
|
|
@@ -1159,7 +1196,7 @@ class Playwright extends Helper {
|
|
|
1159
1196
|
throw new Error('Cannot open new tabs inside an Electron container');
|
|
1160
1197
|
}
|
|
1161
1198
|
const page = await this.browserContext.newPage(options);
|
|
1162
|
-
targetCreatedHandler.call(this, page);
|
|
1199
|
+
await targetCreatedHandler.call(this, page);
|
|
1163
1200
|
await this._setPage(page);
|
|
1164
1201
|
return this._waitForAction();
|
|
1165
1202
|
}
|
|
@@ -1209,7 +1246,7 @@ class Playwright extends Helper {
|
|
|
1209
1246
|
}
|
|
1210
1247
|
|
|
1211
1248
|
/**
|
|
1212
|
-
* Handles a file download.
|
|
1249
|
+
* Handles a file download. A file name is required to save the file on disk.
|
|
1213
1250
|
* Files are saved to "output" directory.
|
|
1214
1251
|
*
|
|
1215
1252
|
* Should be used with [FileSystem helper](https://codecept.io/helpers/FileSystem) to check that file were downloaded correctly.
|
|
@@ -1218,17 +1255,19 @@ class Playwright extends Helper {
|
|
|
1218
1255
|
* I.handleDownloads('downloads/avatar.jpg');
|
|
1219
1256
|
* I.click('Download Avatar');
|
|
1220
1257
|
* I.amInPath('output/downloads');
|
|
1221
|
-
* I.waitForFile('
|
|
1258
|
+
* I.waitForFile('avatar.jpg', 5);
|
|
1222
1259
|
*
|
|
1223
1260
|
* ```
|
|
1224
1261
|
*
|
|
1225
1262
|
* @param {string} [fileName] set filename for downloaded file
|
|
1226
1263
|
* @return {Promise<void>}
|
|
1227
1264
|
*/
|
|
1228
|
-
async handleDownloads(fileName
|
|
1265
|
+
async handleDownloads(fileName) {
|
|
1229
1266
|
this.page.waitForEvent('download').then(async (download) => {
|
|
1230
1267
|
const filePath = await download.path();
|
|
1231
|
-
|
|
1268
|
+
fileName = fileName || `downloads/${path.basename(filePath)}`;
|
|
1269
|
+
|
|
1270
|
+
const downloadPath = path.join(global.output_dir, fileName);
|
|
1232
1271
|
if (!fs.existsSync(path.dirname(downloadPath))) {
|
|
1233
1272
|
fs.mkdirSync(path.dirname(downloadPath), '0777');
|
|
1234
1273
|
}
|
|
@@ -1471,7 +1510,7 @@ class Playwright extends Helper {
|
|
|
1471
1510
|
throw new Error(`File at ${file} can not be found on local system`);
|
|
1472
1511
|
}
|
|
1473
1512
|
const els = await findFields.call(this, locator);
|
|
1474
|
-
assertElementExists(els, 'Field');
|
|
1513
|
+
assertElementExists(els, locator, 'Field');
|
|
1475
1514
|
await els[0].setInputFiles(file);
|
|
1476
1515
|
return this._waitForAction();
|
|
1477
1516
|
}
|
|
@@ -1625,7 +1664,7 @@ class Playwright extends Helper {
|
|
|
1625
1664
|
*/
|
|
1626
1665
|
async seeNumberOfElements(locator, num) {
|
|
1627
1666
|
const elements = await this._locate(locator);
|
|
1628
|
-
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);
|
|
1629
1668
|
}
|
|
1630
1669
|
|
|
1631
1670
|
/**
|
|
@@ -1635,7 +1674,7 @@ class Playwright extends Helper {
|
|
|
1635
1674
|
*/
|
|
1636
1675
|
async seeNumberOfVisibleElements(locator, num) {
|
|
1637
1676
|
const res = await this.grabNumberOfVisibleElements(locator);
|
|
1638
|
-
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);
|
|
1639
1678
|
}
|
|
1640
1679
|
|
|
1641
1680
|
/**
|
|
@@ -1709,6 +1748,7 @@ class Playwright extends Helper {
|
|
|
1709
1748
|
*
|
|
1710
1749
|
* @param {string|function} fn function to be executed in browser context.
|
|
1711
1750
|
* @param {any} [arg] optional argument to pass to the function
|
|
1751
|
+
* @returns {Promise<any>}
|
|
1712
1752
|
*/
|
|
1713
1753
|
async executeScript(fn, arg) {
|
|
1714
1754
|
let context = this.page;
|
|
@@ -1856,7 +1896,7 @@ class Playwright extends Helper {
|
|
|
1856
1896
|
}
|
|
1857
1897
|
return true;
|
|
1858
1898
|
});
|
|
1859
|
-
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);
|
|
1860
1900
|
}
|
|
1861
1901
|
|
|
1862
1902
|
/**
|
|
@@ -1885,7 +1925,7 @@ class Playwright extends Helper {
|
|
|
1885
1925
|
}
|
|
1886
1926
|
return true;
|
|
1887
1927
|
});
|
|
1888
|
-
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);
|
|
1889
1929
|
}
|
|
1890
1930
|
|
|
1891
1931
|
/**
|
|
@@ -1949,7 +1989,7 @@ class Playwright extends Helper {
|
|
|
1949
1989
|
assertElementExists(res, locator);
|
|
1950
1990
|
if (res.length > 1) this.debug(`[Elements] Using first element out of ${res.length}`);
|
|
1951
1991
|
const elem = res[0];
|
|
1952
|
-
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}`);
|
|
1953
1993
|
return elem.screenshot({ path: outputFile, type: 'png' });
|
|
1954
1994
|
}
|
|
1955
1995
|
|
|
@@ -2032,29 +2072,28 @@ class Playwright extends Helper {
|
|
|
2032
2072
|
}
|
|
2033
2073
|
|
|
2034
2074
|
if (this.options.recordVideo && this.page && this.page.video()) {
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
}));
|
|
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
|
+
}
|
|
2040
2079
|
}
|
|
2041
2080
|
|
|
2042
2081
|
if (this.options.trace) {
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
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
|
+
}
|
|
2046
2087
|
}
|
|
2047
2088
|
}
|
|
2048
2089
|
|
|
2049
2090
|
async _passed(test) {
|
|
2050
2091
|
if (this.options.recordVideo && this.page && this.page.video()) {
|
|
2051
|
-
const videoPath = `${global.output_dir}/videos/${clearString(test.title)}.passed.webm`;
|
|
2052
|
-
|
|
2053
2092
|
if (this.options.keepVideoForPassedTests) {
|
|
2054
|
-
test.artifacts.video = await this.page.
|
|
2055
|
-
|
|
2056
|
-
test.artifacts
|
|
2057
|
-
}
|
|
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
|
+
}
|
|
2058
2097
|
} else {
|
|
2059
2098
|
this.page.video().delete().catch(e => {});
|
|
2060
2099
|
}
|
|
@@ -2062,9 +2101,13 @@ class Playwright extends Helper {
|
|
|
2062
2101
|
|
|
2063
2102
|
if (this.options.trace) {
|
|
2064
2103
|
if (this.options.keepTraceForPassedTests) {
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
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
|
+
}
|
|
2068
2111
|
} else {
|
|
2069
2112
|
await this.browserContext.tracing.stop();
|
|
2070
2113
|
}
|
|
@@ -2785,7 +2828,7 @@ async function targetCreatedHandler(page) {
|
|
|
2785
2828
|
page.on('load', () => {
|
|
2786
2829
|
page.$('body')
|
|
2787
2830
|
.catch(() => null)
|
|
2788
|
-
.then(async
|
|
2831
|
+
.then(async () => {
|
|
2789
2832
|
if (this.context && this.context._type === 'Frame') {
|
|
2790
2833
|
// we are inside iframe?
|
|
2791
2834
|
const frameEl = await this.context.frameElement();
|
|
@@ -2810,7 +2853,7 @@ async function targetCreatedHandler(page) {
|
|
|
2810
2853
|
try {
|
|
2811
2854
|
await page.setViewportSize(parseWindowSize(this.options.windowSize));
|
|
2812
2855
|
} catch (err) {
|
|
2813
|
-
|
|
2856
|
+
this.debug('Target can be already closed, ignoring...');
|
|
2814
2857
|
}
|
|
2815
2858
|
}
|
|
2816
2859
|
}
|
|
@@ -2935,3 +2978,21 @@ async function refreshContextSession() {
|
|
|
2935
2978
|
});
|
|
2936
2979
|
}
|
|
2937
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
|
|