codeceptjs 3.4.1 → 3.5.1-2.beta.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/README.md +31 -30
- package/bin/codecept.js +1 -1
- package/lib/actor.js +6 -3
- package/lib/ai.js +180 -0
- package/lib/cli.js +13 -3
- package/lib/codecept.js +8 -0
- package/lib/colorUtils.js +10 -0
- package/lib/command/definitions.js +2 -7
- package/lib/command/dryRun.js +11 -2
- package/lib/command/generate.js +46 -3
- package/lib/command/info.js +24 -0
- package/lib/command/init.js +64 -6
- package/lib/command/interactive.js +15 -1
- package/lib/command/run-multiple/collection.js +17 -5
- package/lib/command/run-multiple.js +4 -2
- package/lib/command/run-workers.js +68 -5
- package/lib/command/run.js +7 -0
- package/lib/command/workers/runTests.js +39 -0
- package/lib/container.js +13 -3
- package/lib/data/context.js +14 -6
- package/lib/event.js +4 -0
- package/lib/helper/ApiDataFactory.js +2 -1
- package/lib/helper/Appium.js +116 -29
- package/lib/helper/Expect.js +422 -0
- package/lib/helper/FileSystem.js +1 -1
- package/lib/helper/GraphQL.js +25 -0
- package/lib/helper/JSONResponse.js +4 -4
- package/lib/helper/Nightmare.js +10 -5
- package/lib/helper/OpenAI.js +126 -0
- package/lib/helper/Playwright.js +1298 -229
- package/lib/helper/Protractor.js +12 -7
- package/lib/helper/Puppeteer.js +204 -64
- package/lib/helper/REST.js +15 -5
- package/lib/helper/TestCafe.js +45 -10
- package/lib/helper/WebDriver.js +252 -83
- package/lib/helper/errors/ElementNotFound.js +2 -1
- package/lib/helper/extras/PlaywrightReactVueLocator.js +38 -0
- package/lib/helper/scripts/blurElement.js +17 -0
- package/lib/helper/scripts/focusElement.js +17 -0
- package/lib/helper/scripts/highlightElement.js +20 -0
- package/lib/html.js +258 -0
- package/lib/interfaces/bdd.js +1 -1
- package/lib/interfaces/gherkin.js +37 -3
- package/lib/interfaces/scenarioConfig.js +1 -0
- package/lib/listener/retry.js +2 -1
- package/lib/locator.js +17 -4
- package/lib/mochaFactory.js +2 -1
- package/lib/output.js +1 -1
- package/lib/pause.js +78 -19
- package/lib/plugin/autoLogin.js +45 -10
- package/lib/plugin/debugErrors.js +67 -0
- package/lib/plugin/fakerTransform.js +4 -6
- package/lib/plugin/heal.js +209 -0
- package/lib/plugin/retryFailedStep.js +10 -1
- package/lib/plugin/retryTo.js +2 -4
- package/lib/plugin/screenshotOnFail.js +11 -2
- package/lib/plugin/selenoid.js +6 -1
- package/lib/plugin/standardActingHelpers.js +0 -2
- package/lib/plugin/stepByStepReport.js +2 -2
- package/lib/plugin/tryTo.js +5 -7
- package/lib/plugin/wdio.js +0 -1
- package/lib/recorder.js +22 -11
- package/lib/secret.js +5 -4
- package/lib/session.js +1 -1
- package/lib/step.js +36 -12
- package/lib/ui.js +5 -3
- package/lib/utils.js +22 -1
- package/lib/workers.js +83 -10
- package/package.json +117 -95
- package/translations/de-DE.js +5 -0
- package/translations/fr-FR.js +14 -1
- package/translations/it-IT.js +1 -0
- package/translations/ja-JP.js +14 -9
- package/translations/pl-PL.js +5 -0
- package/translations/pt-BR.js +1 -0
- package/translations/ru-RU.js +1 -0
- package/translations/zh-CN.js +5 -0
- package/translations/zh-TW.js +5 -0
- package/typings/index.d.ts +51 -15
- package/typings/promiseBasedTypes.d.ts +864 -802
- package/typings/types.d.ts +1339 -744
- package/CHANGELOG.md +0 -2427
- package/docs/advanced.md +0 -351
- package/docs/api.md +0 -323
- package/docs/basics.md +0 -980
- package/docs/bdd.md +0 -535
- package/docs/best.md +0 -237
- package/docs/books.md +0 -37
- package/docs/bootstrap.md +0 -135
- package/docs/build/ApiDataFactory.js +0 -409
- package/docs/build/Appium.js +0 -1938
- package/docs/build/FileSystem.js +0 -228
- package/docs/build/GraphQL.js +0 -204
- package/docs/build/GraphQLDataFactory.js +0 -309
- package/docs/build/JSONResponse.js +0 -338
- package/docs/build/Mochawesome.js +0 -71
- package/docs/build/Nightmare.js +0 -2145
- package/docs/build/Playwright.js +0 -3986
- package/docs/build/Polly.js +0 -42
- package/docs/build/Protractor.js +0 -2699
- package/docs/build/Puppeteer.js +0 -3710
- package/docs/build/REST.js +0 -334
- package/docs/build/SeleniumWebdriver.js +0 -76
- package/docs/build/TestCafe.js +0 -2057
- package/docs/build/WebDriver.js +0 -4017
- package/docs/changelog.md +0 -2436
- package/docs/commands.md +0 -254
- package/docs/community-helpers.md +0 -58
- package/docs/configuration.md +0 -157
- package/docs/continuous-integration.md +0 -22
- package/docs/custom-helpers.md +0 -306
- package/docs/data.md +0 -375
- package/docs/detox.md +0 -235
- package/docs/docker.md +0 -137
- package/docs/email.md +0 -183
- package/docs/examples.md +0 -149
- package/docs/helpers/ApiDataFactory.md +0 -266
- package/docs/helpers/Appium.md +0 -1312
- package/docs/helpers/Detox.md +0 -586
- package/docs/helpers/FileSystem.md +0 -152
- package/docs/helpers/GraphQL.md +0 -130
- package/docs/helpers/GraphQLDataFactory.md +0 -226
- package/docs/helpers/JSONResponse.md +0 -254
- package/docs/helpers/Mochawesome.md +0 -8
- package/docs/helpers/MockRequest.md +0 -377
- package/docs/helpers/Nightmare.md +0 -1256
- package/docs/helpers/Playwright.md +0 -2208
- package/docs/helpers/Polly.md +0 -44
- package/docs/helpers/Puppeteer-firefox.md +0 -86
- package/docs/helpers/Puppeteer.md +0 -2141
- package/docs/helpers/REST.md +0 -217
- package/docs/helpers/TestCafe.md +0 -1222
- package/docs/helpers/WebDriver.md +0 -2319
- package/docs/hooks.md +0 -340
- package/docs/index.md +0 -111
- package/docs/installation.md +0 -75
- package/docs/internal-api.md +0 -265
- package/docs/locators.md +0 -331
- package/docs/mobile-react-native-locators.md +0 -67
- package/docs/mobile.md +0 -297
- package/docs/nightmare.md +0 -223
- package/docs/pageobjects.md +0 -291
- package/docs/parallel.md +0 -232
- package/docs/playwright.md +0 -609
- package/docs/plugins.md +0 -1171
- package/docs/puppeteer.md +0 -316
- package/docs/quickstart.md +0 -163
- package/docs/react.md +0 -69
- package/docs/reports.md +0 -392
- package/docs/secrets.md +0 -30
- package/docs/shadow.md +0 -68
- package/docs/shared/keys.mustache +0 -31
- package/docs/shared/react.mustache +0 -1
- package/docs/testcafe.md +0 -174
- package/docs/translation.md +0 -247
- package/docs/tutorial.md +0 -271
- package/docs/typescript.md +0 -180
- package/docs/ui.md +0 -59
- package/docs/videos.md +0 -28
- package/docs/visual.md +0 -202
- package/docs/vue.md +0 -121
- package/docs/webapi/amOnPage.mustache +0 -11
- package/docs/webapi/appendField.mustache +0 -9
- package/docs/webapi/attachFile.mustache +0 -12
- package/docs/webapi/checkOption.mustache +0 -13
- package/docs/webapi/clearCookie.mustache +0 -10
- package/docs/webapi/clearField.mustache +0 -9
- package/docs/webapi/click.mustache +0 -25
- package/docs/webapi/clickLink.mustache +0 -8
- package/docs/webapi/closeCurrentTab.mustache +0 -7
- package/docs/webapi/closeOtherTabs.mustache +0 -8
- package/docs/webapi/dontSee.mustache +0 -11
- package/docs/webapi/dontSeeCheckboxIsChecked.mustache +0 -10
- package/docs/webapi/dontSeeCookie.mustache +0 -8
- package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
- package/docs/webapi/dontSeeElement.mustache +0 -8
- package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
- package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
- package/docs/webapi/dontSeeInField.mustache +0 -11
- package/docs/webapi/dontSeeInSource.mustache +0 -8
- package/docs/webapi/dontSeeInTitle.mustache +0 -8
- package/docs/webapi/doubleClick.mustache +0 -13
- package/docs/webapi/downloadFile.mustache +0 -12
- package/docs/webapi/dragAndDrop.mustache +0 -9
- package/docs/webapi/dragSlider.mustache +0 -11
- package/docs/webapi/executeAsyncScript.mustache +0 -24
- package/docs/webapi/executeScript.mustache +0 -26
- package/docs/webapi/fillField.mustache +0 -16
- package/docs/webapi/forceClick.mustache +0 -28
- package/docs/webapi/forceRightClick.mustache +0 -18
- package/docs/webapi/grabAllWindowHandles.mustache +0 -7
- package/docs/webapi/grabAttributeFrom.mustache +0 -10
- package/docs/webapi/grabAttributeFromAll.mustache +0 -9
- package/docs/webapi/grabBrowserLogs.mustache +0 -9
- package/docs/webapi/grabCookie.mustache +0 -11
- package/docs/webapi/grabCssPropertyFrom.mustache +0 -11
- package/docs/webapi/grabCssPropertyFromAll.mustache +0 -10
- package/docs/webapi/grabCurrentUrl.mustache +0 -9
- package/docs/webapi/grabCurrentWindowHandle.mustache +0 -6
- package/docs/webapi/grabDataFromPerformanceTiming.mustache +0 -20
- package/docs/webapi/grabElementBoundingRect.mustache +0 -20
- package/docs/webapi/grabGeoLocation.mustache +0 -8
- package/docs/webapi/grabHTMLFrom.mustache +0 -10
- package/docs/webapi/grabHTMLFromAll.mustache +0 -9
- package/docs/webapi/grabNumberOfOpenTabs.mustache +0 -8
- package/docs/webapi/grabNumberOfVisibleElements.mustache +0 -9
- package/docs/webapi/grabPageScrollPosition.mustache +0 -8
- package/docs/webapi/grabPopupText.mustache +0 -5
- package/docs/webapi/grabSource.mustache +0 -8
- package/docs/webapi/grabTextFrom.mustache +0 -10
- package/docs/webapi/grabTextFromAll.mustache +0 -9
- package/docs/webapi/grabTitle.mustache +0 -8
- package/docs/webapi/grabValueFrom.mustache +0 -9
- package/docs/webapi/grabValueFromAll.mustache +0 -8
- package/docs/webapi/moveCursorTo.mustache +0 -12
- package/docs/webapi/openNewTab.mustache +0 -7
- package/docs/webapi/pressKey.mustache +0 -12
- package/docs/webapi/pressKeyDown.mustache +0 -12
- package/docs/webapi/pressKeyUp.mustache +0 -12
- package/docs/webapi/pressKeyWithKeyNormalization.mustache +0 -60
- package/docs/webapi/refreshPage.mustache +0 -6
- package/docs/webapi/resizeWindow.mustache +0 -6
- package/docs/webapi/rightClick.mustache +0 -14
- package/docs/webapi/saveElementScreenshot.mustache +0 -10
- package/docs/webapi/saveScreenshot.mustache +0 -12
- package/docs/webapi/say.mustache +0 -10
- package/docs/webapi/scrollIntoView.mustache +0 -11
- package/docs/webapi/scrollPageToBottom.mustache +0 -6
- package/docs/webapi/scrollPageToTop.mustache +0 -6
- package/docs/webapi/scrollTo.mustache +0 -12
- package/docs/webapi/see.mustache +0 -11
- package/docs/webapi/seeAttributesOnElements.mustache +0 -9
- package/docs/webapi/seeCheckboxIsChecked.mustache +0 -10
- package/docs/webapi/seeCookie.mustache +0 -8
- package/docs/webapi/seeCssPropertiesOnElements.mustache +0 -9
- package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
- package/docs/webapi/seeElement.mustache +0 -8
- package/docs/webapi/seeElementInDOM.mustache +0 -8
- package/docs/webapi/seeInCurrentUrl.mustache +0 -8
- package/docs/webapi/seeInField.mustache +0 -12
- package/docs/webapi/seeInPopup.mustache +0 -8
- package/docs/webapi/seeInSource.mustache +0 -7
- package/docs/webapi/seeInTitle.mustache +0 -8
- package/docs/webapi/seeNumberOfElements.mustache +0 -11
- package/docs/webapi/seeNumberOfVisibleElements.mustache +0 -10
- package/docs/webapi/seeTextEquals.mustache +0 -9
- package/docs/webapi/seeTitleEquals.mustache +0 -8
- package/docs/webapi/selectOption.mustache +0 -21
- package/docs/webapi/setCookie.mustache +0 -16
- package/docs/webapi/setGeoLocation.mustache +0 -12
- package/docs/webapi/switchTo.mustache +0 -9
- package/docs/webapi/switchToNextTab.mustache +0 -10
- package/docs/webapi/switchToPreviousTab.mustache +0 -10
- package/docs/webapi/type.mustache +0 -18
- package/docs/webapi/uncheckOption.mustache +0 -13
- package/docs/webapi/wait.mustache +0 -8
- package/docs/webapi/waitForClickable.mustache +0 -11
- package/docs/webapi/waitForDetached.mustache +0 -10
- package/docs/webapi/waitForElement.mustache +0 -11
- package/docs/webapi/waitForEnabled.mustache +0 -6
- package/docs/webapi/waitForFunction.mustache +0 -17
- package/docs/webapi/waitForInvisible.mustache +0 -10
- package/docs/webapi/waitForText.mustache +0 -13
- package/docs/webapi/waitForValue.mustache +0 -10
- package/docs/webapi/waitForVisible.mustache +0 -10
- package/docs/webapi/waitInUrl.mustache +0 -9
- package/docs/webapi/waitNumberOfVisibleElements.mustache +0 -10
- package/docs/webapi/waitToHide.mustache +0 -10
- package/docs/webapi/waitUrlEquals.mustache +0 -10
- package/docs/webdriver.md +0 -657
- package/docs/wiki/Books-&-Posts.md +0 -27
- package/docs/wiki/Community-Helpers-&-Plugins.md +0 -49
- package/docs/wiki/Converting-Playwright-to-Istanbul-Coverage.md +0 -29
- package/docs/wiki/Examples.md +0 -139
- package/docs/wiki/Google-Summer-of-Code-(GSoC)-2020.md +0 -68
- package/docs/wiki/Home.md +0 -16
- package/docs/wiki/Release-Process.md +0 -24
- package/docs/wiki/Roadmap.md +0 -23
- package/docs/wiki/Tests.md +0 -1393
- package/docs/wiki/Upgrading-to-CodeceptJS-3.md +0 -153
- package/docs/wiki/Videos.md +0 -19
package/lib/helper/Protractor.js
CHANGED
|
@@ -631,14 +631,16 @@ class Protractor extends Helper {
|
|
|
631
631
|
* {{> seeInField }}
|
|
632
632
|
*/
|
|
633
633
|
async seeInField(field, value) {
|
|
634
|
-
|
|
634
|
+
const _value = (typeof value === 'boolean') ? value : value.toString();
|
|
635
|
+
return proceedSeeInField.call(this, 'assert', field, _value);
|
|
635
636
|
}
|
|
636
637
|
|
|
637
638
|
/**
|
|
638
639
|
* {{> dontSeeInField }}
|
|
639
640
|
*/
|
|
640
641
|
async dontSeeInField(field, value) {
|
|
641
|
-
|
|
642
|
+
const _value = (typeof value === 'boolean') ? value : value.toString();
|
|
643
|
+
return proceedSeeInField.call(this, 'negate', field, _value);
|
|
642
644
|
}
|
|
643
645
|
|
|
644
646
|
/**
|
|
@@ -647,7 +649,7 @@ class Protractor extends Helper {
|
|
|
647
649
|
async appendField(field, value) {
|
|
648
650
|
const els = await findFields(this.browser, field);
|
|
649
651
|
assertElementExists(els, field, 'Field');
|
|
650
|
-
return els[0].sendKeys(value);
|
|
652
|
+
return els[0].sendKeys(value.toString());
|
|
651
653
|
}
|
|
652
654
|
|
|
653
655
|
/**
|
|
@@ -1053,7 +1055,7 @@ class Protractor extends Helper {
|
|
|
1053
1055
|
const stream = fs.createWriteStream(outputFile);
|
|
1054
1056
|
stream.write(Buffer.from(png, 'base64'));
|
|
1055
1057
|
stream.end();
|
|
1056
|
-
return new Promise(resolve => stream.on('finish', resolve));
|
|
1058
|
+
return new Promise(resolve => stream.on('finish', resolve)); // eslint-disable-line no-promise-executor-return
|
|
1057
1059
|
};
|
|
1058
1060
|
|
|
1059
1061
|
const res = await this._locate(locator);
|
|
@@ -1076,7 +1078,7 @@ class Protractor extends Helper {
|
|
|
1076
1078
|
const stream = fs.createWriteStream(outputFile);
|
|
1077
1079
|
stream.write(Buffer.from(png, 'base64'));
|
|
1078
1080
|
stream.end();
|
|
1079
|
-
return new Promise(resolve => stream.on('finish', resolve));
|
|
1081
|
+
return new Promise(resolve => stream.on('finish', resolve)); // eslint-disable-line no-promise-executor-return
|
|
1080
1082
|
};
|
|
1081
1083
|
|
|
1082
1084
|
if (!fullPage) {
|
|
@@ -1613,8 +1615,11 @@ class Protractor extends Helper {
|
|
|
1613
1615
|
const body = document.body;
|
|
1614
1616
|
const html = document.documentElement;
|
|
1615
1617
|
window.scrollTo(0, Math.max(
|
|
1616
|
-
body.scrollHeight,
|
|
1617
|
-
|
|
1618
|
+
body.scrollHeight,
|
|
1619
|
+
body.offsetHeight,
|
|
1620
|
+
html.clientHeight,
|
|
1621
|
+
html.scrollHeight,
|
|
1622
|
+
html.offsetHeight
|
|
1618
1623
|
));
|
|
1619
1624
|
});
|
|
1620
1625
|
/* eslint-enable */
|
package/lib/helper/Puppeteer.js
CHANGED
|
@@ -4,8 +4,10 @@ const fsExtra = require('fs-extra');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
|
|
6
6
|
const Helper = require('@codeceptjs/helper');
|
|
7
|
+
const { v4: uuidv4 } = require('uuid');
|
|
7
8
|
const Locator = require('../locator');
|
|
8
9
|
const recorder = require('../recorder');
|
|
10
|
+
const store = require('../store');
|
|
9
11
|
const stringIncludes = require('../assert/include').includes;
|
|
10
12
|
const { urlEquals } = require('../assert/equal');
|
|
11
13
|
const { equals } = require('../assert/equal');
|
|
@@ -18,11 +20,12 @@ const {
|
|
|
18
20
|
fileExists,
|
|
19
21
|
chunkArray,
|
|
20
22
|
toCamelCase,
|
|
23
|
+
clearString,
|
|
21
24
|
convertCssPropertiesToCamelCase,
|
|
22
25
|
screenshotOutputFolder,
|
|
23
26
|
getNormalizedKeyAttributeValue,
|
|
24
27
|
isModifierKey,
|
|
25
|
-
requireWithFallback,
|
|
28
|
+
requireWithFallback, normalizeSpacesInString,
|
|
26
29
|
} = require('../utils');
|
|
27
30
|
const {
|
|
28
31
|
isColorProperty,
|
|
@@ -33,6 +36,9 @@ const RemoteBrowserConnectionRefused = require('./errors/RemoteBrowserConnection
|
|
|
33
36
|
const Popup = require('./extras/Popup');
|
|
34
37
|
const Console = require('./extras/Console');
|
|
35
38
|
const findReact = require('./extras/React');
|
|
39
|
+
const { highlightElement } = require('./scripts/highlightElement');
|
|
40
|
+
const { blurElement } = require('./scripts/blurElement');
|
|
41
|
+
const { focusElement } = require('./scripts/focusElement');
|
|
36
42
|
|
|
37
43
|
let puppeteer;
|
|
38
44
|
let perfTiming;
|
|
@@ -53,6 +59,8 @@ const consoleLogStore = new Console();
|
|
|
53
59
|
* @prop {boolean} [disableScreenshots=false] - don't save screenshot on failure.
|
|
54
60
|
* @prop {boolean} [fullPageScreenshots=false] - make full page screenshots on failure.
|
|
55
61
|
* @prop {boolean} [uniqueScreenshotNames=false] - option to prevent screenshot override if you have scenarios with the same name in different suites.
|
|
62
|
+
* @prop {boolean} [trace=false] - record [tracing information](https://pptr.dev/api/puppeteer.tracing) with screenshots.
|
|
63
|
+
* @prop {boolean} [keepTraceForPassedTests=false] - save trace for passed tests.
|
|
56
64
|
* @prop {boolean} [keepBrowserState=false] - keep browser state between tests when `restart` is set to false.
|
|
57
65
|
* @prop {boolean} [keepCookies=false] - keep cookies between tests when `restart` is set to false.
|
|
58
66
|
* @prop {number} [waitForAction=100] - how long to wait after click, doubleClick or PressKey actions in ms. Default: 100.
|
|
@@ -65,6 +73,7 @@ const consoleLogStore = new Console();
|
|
|
65
73
|
* @prop {boolean} [manualStart=false] - do not start browser before a test, start it manually inside a helper with `this.helpers["Puppeteer"]._startBrowser()`.
|
|
66
74
|
* @prop {string} [browser=chrome] - can be changed to `firefox` when using [puppeteer-firefox](https://codecept.io/helpers/Puppeteer-firefox).
|
|
67
75
|
* @prop {object} [chrome] - pass additional [Puppeteer run options](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions).
|
|
76
|
+
* @prop {boolean} [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
|
|
68
77
|
*/
|
|
69
78
|
const config = {};
|
|
70
79
|
|
|
@@ -87,6 +96,14 @@ const config = {};
|
|
|
87
96
|
*
|
|
88
97
|
* <!-- configuration -->
|
|
89
98
|
*
|
|
99
|
+
* #### Trace Recording Customization
|
|
100
|
+
*
|
|
101
|
+
* Trace recording provides complete information on test execution and includes screenshots, and network requests logged during run.
|
|
102
|
+
* Traces will be saved to `output/trace`
|
|
103
|
+
*
|
|
104
|
+
* * `trace`: enables trace recording for failed tests; trace are saved into `output/trace` folder
|
|
105
|
+
* * `keepTraceForPassedTests`: - save trace for passed tests
|
|
106
|
+
*
|
|
90
107
|
* #### Example #1: Wait for 0 network connections.
|
|
91
108
|
*
|
|
92
109
|
* ```js
|
|
@@ -226,6 +243,7 @@ class Puppeteer extends Helper {
|
|
|
226
243
|
keepBrowserState: false,
|
|
227
244
|
show: false,
|
|
228
245
|
defaultPopupAction: 'accept',
|
|
246
|
+
highlightElement: false,
|
|
229
247
|
};
|
|
230
248
|
|
|
231
249
|
return Object.assign(defaults, config);
|
|
@@ -241,6 +259,7 @@ class Puppeteer extends Helper {
|
|
|
241
259
|
headless: !this.options.show,
|
|
242
260
|
...this._getOptions(config),
|
|
243
261
|
};
|
|
262
|
+
if (this.puppeteerOptions.headless) this.puppeteerOptions.headless = 'new';
|
|
244
263
|
this.isRemoteBrowser = !!this.puppeteerOptions.browserWSEndpoint;
|
|
245
264
|
popupStore.defaultAction = this.options.defaultPopupAction;
|
|
246
265
|
}
|
|
@@ -275,10 +294,11 @@ class Puppeteer extends Helper {
|
|
|
275
294
|
}
|
|
276
295
|
}
|
|
277
296
|
|
|
278
|
-
async _before() {
|
|
297
|
+
async _before(test) {
|
|
279
298
|
this.sessionPages = {};
|
|
299
|
+
this.currentRunningTest = test;
|
|
280
300
|
recorder.retry({
|
|
281
|
-
retries: 3,
|
|
301
|
+
retries: process.env.FAILED_STEP_RETRIES || 3,
|
|
282
302
|
when: err => {
|
|
283
303
|
if (!err || typeof (err.message) !== 'string') {
|
|
284
304
|
return false;
|
|
@@ -598,8 +618,8 @@ class Puppeteer extends Helper {
|
|
|
598
618
|
return this.switchTo(null)
|
|
599
619
|
.then(() => frame.reduce((p, frameLocator) => p.then(() => this.switchTo(frameLocator)), Promise.resolve()));
|
|
600
620
|
}
|
|
601
|
-
await this.switchTo(
|
|
602
|
-
this.withinLocator = new Locator(
|
|
621
|
+
await this.switchTo(frame);
|
|
622
|
+
this.withinLocator = new Locator(frame);
|
|
603
623
|
return;
|
|
604
624
|
}
|
|
605
625
|
|
|
@@ -641,6 +661,14 @@ class Puppeteer extends Helper {
|
|
|
641
661
|
}
|
|
642
662
|
}
|
|
643
663
|
|
|
664
|
+
if (this.options.trace) {
|
|
665
|
+
const fileName = `${`${global.output_dir}${path.sep}trace${path.sep}${uuidv4()}_${clearString(this.currentRunningTest.title)}`.slice(0, 245)}.json`;
|
|
666
|
+
const dir = path.dirname(fileName);
|
|
667
|
+
if (!fileExists(dir)) fs.mkdirSync(dir);
|
|
668
|
+
await this.page.tracing.start({ screenshots: true, path: fileName });
|
|
669
|
+
this.currentRunningTest.artifacts.trace = fileName;
|
|
670
|
+
}
|
|
671
|
+
|
|
644
672
|
await this.page.goto(url, { waitUntil: this.options.waitForNavigation });
|
|
645
673
|
|
|
646
674
|
const performanceTiming = JSON.parse(await this.page.evaluate(() => JSON.stringify(window.performance.timing)));
|
|
@@ -657,11 +685,13 @@ class Puppeteer extends Helper {
|
|
|
657
685
|
}
|
|
658
686
|
|
|
659
687
|
/**
|
|
660
|
-
* {{> resizeWindow }}
|
|
661
688
|
*
|
|
662
689
|
* Unlike other drivers Puppeteer changes the size of a viewport, not the window!
|
|
663
|
-
* Puppeteer does not control the window of a browser so it can't adjust its real size.
|
|
690
|
+
* Puppeteer does not control the window of a browser, so it can't adjust its real size.
|
|
664
691
|
* It also can't maximize a window.
|
|
692
|
+
*
|
|
693
|
+
* {{> resizeWindow }}
|
|
694
|
+
*
|
|
665
695
|
*/
|
|
666
696
|
async resizeWindow(width, height) {
|
|
667
697
|
if (width === 'maximize') {
|
|
@@ -676,14 +706,14 @@ class Puppeteer extends Helper {
|
|
|
676
706
|
* Set headers for all next requests
|
|
677
707
|
*
|
|
678
708
|
* ```js
|
|
679
|
-
* I.
|
|
709
|
+
* I.setPuppeteerRequestHeaders({
|
|
680
710
|
* 'X-Sent-By': 'CodeceptJS',
|
|
681
711
|
* });
|
|
682
712
|
* ```
|
|
683
713
|
*
|
|
684
714
|
* @param {object} customHeaders headers to set
|
|
685
715
|
*/
|
|
686
|
-
async
|
|
716
|
+
async setPuppeteerRequestHeaders(customHeaders) {
|
|
687
717
|
if (!customHeaders) {
|
|
688
718
|
throw new Error('Cannot send empty headers.');
|
|
689
719
|
}
|
|
@@ -704,6 +734,32 @@ class Puppeteer extends Helper {
|
|
|
704
734
|
return this._waitForAction();
|
|
705
735
|
}
|
|
706
736
|
|
|
737
|
+
/**
|
|
738
|
+
* {{> focus }}
|
|
739
|
+
*
|
|
740
|
+
*/
|
|
741
|
+
async focus(locator) {
|
|
742
|
+
const els = await this._locate(locator);
|
|
743
|
+
assertElementExists(els, locator, 'Element to focus');
|
|
744
|
+
const el = els[0];
|
|
745
|
+
|
|
746
|
+
await el.click();
|
|
747
|
+
await el.focus();
|
|
748
|
+
return this._waitForAction();
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* {{> blur }}
|
|
753
|
+
*
|
|
754
|
+
*/
|
|
755
|
+
async blur(locator) {
|
|
756
|
+
const els = await this._locate(locator);
|
|
757
|
+
assertElementExists(els, locator, 'Element to blur');
|
|
758
|
+
|
|
759
|
+
await blurElement(els[0], this.page);
|
|
760
|
+
return this._waitForAction();
|
|
761
|
+
}
|
|
762
|
+
|
|
707
763
|
/**
|
|
708
764
|
* {{> dragAndDrop }}
|
|
709
765
|
*/
|
|
@@ -735,8 +791,11 @@ class Puppeteer extends Helper {
|
|
|
735
791
|
const body = document.body;
|
|
736
792
|
const html = document.documentElement;
|
|
737
793
|
window.scrollTo(0, Math.max(
|
|
738
|
-
body.scrollHeight,
|
|
739
|
-
|
|
794
|
+
body.scrollHeight,
|
|
795
|
+
body.offsetHeight,
|
|
796
|
+
html.clientHeight,
|
|
797
|
+
html.scrollHeight,
|
|
798
|
+
html.offsetHeight,
|
|
740
799
|
));
|
|
741
800
|
});
|
|
742
801
|
}
|
|
@@ -825,7 +884,7 @@ class Puppeteer extends Helper {
|
|
|
825
884
|
}
|
|
826
885
|
|
|
827
886
|
/**
|
|
828
|
-
* Find a checkbox by providing human
|
|
887
|
+
* Find a checkbox by providing human-readable text:
|
|
829
888
|
* NOTE: Assumes the checkable element exists
|
|
830
889
|
*
|
|
831
890
|
* ```js
|
|
@@ -840,7 +899,7 @@ class Puppeteer extends Helper {
|
|
|
840
899
|
}
|
|
841
900
|
|
|
842
901
|
/**
|
|
843
|
-
* Find a clickable element by providing human
|
|
902
|
+
* Find a clickable element by providing human-readable text:
|
|
844
903
|
*
|
|
845
904
|
* ```js
|
|
846
905
|
* this.helpers['Puppeteer']._locateClickable('Next page').then // ...
|
|
@@ -852,7 +911,7 @@ class Puppeteer extends Helper {
|
|
|
852
911
|
}
|
|
853
912
|
|
|
854
913
|
/**
|
|
855
|
-
* Find field elements by providing human
|
|
914
|
+
* Find field elements by providing human-readable text:
|
|
856
915
|
*
|
|
857
916
|
* ```js
|
|
858
917
|
* this.helpers['Puppeteer']._locateFields('Your email').then // ...
|
|
@@ -862,6 +921,14 @@ class Puppeteer extends Helper {
|
|
|
862
921
|
return findFields.call(this, locator);
|
|
863
922
|
}
|
|
864
923
|
|
|
924
|
+
/**
|
|
925
|
+
* {{> grabWebElements }}
|
|
926
|
+
*
|
|
927
|
+
*/
|
|
928
|
+
async grabWebElements(locator) {
|
|
929
|
+
return this._locate(locator);
|
|
930
|
+
}
|
|
931
|
+
|
|
865
932
|
/**
|
|
866
933
|
* Switch focus to a particular tab by its number. It waits tabs loading and then switch tab
|
|
867
934
|
*
|
|
@@ -1056,7 +1123,7 @@ class Puppeteer extends Helper {
|
|
|
1056
1123
|
* Sets a directory to where save files. Allows to test file downloads.
|
|
1057
1124
|
* Should be used with [FileSystem helper](https://codecept.io/helpers/FileSystem) to check that file were downloaded correctly.
|
|
1058
1125
|
*
|
|
1059
|
-
* By default files are saved to `output/downloads`.
|
|
1126
|
+
* By default, files are saved to `output/downloads`.
|
|
1060
1127
|
* This directory is cleaned on every `handleDownloads` call, to ensure no old files are kept.
|
|
1061
1128
|
*
|
|
1062
1129
|
* ```js
|
|
@@ -1228,9 +1295,9 @@ class Puppeteer extends Helper {
|
|
|
1228
1295
|
}
|
|
1229
1296
|
|
|
1230
1297
|
/**
|
|
1231
|
-
* {{> pressKeyWithKeyNormalization }}
|
|
1232
|
-
*
|
|
1233
1298
|
* _Note:_ Shortcuts like `'Meta'` + `'A'` do not work on macOS ([GoogleChrome/puppeteer#1313](https://github.com/GoogleChrome/puppeteer/issues/1313)).
|
|
1299
|
+
*
|
|
1300
|
+
* {{> pressKeyWithKeyNormalization }}
|
|
1234
1301
|
*/
|
|
1235
1302
|
async pressKey(key) {
|
|
1236
1303
|
const modifiers = [];
|
|
@@ -1262,6 +1329,7 @@ class Puppeteer extends Helper {
|
|
|
1262
1329
|
*/
|
|
1263
1330
|
async type(keys, delay = null) {
|
|
1264
1331
|
if (!Array.isArray(keys)) {
|
|
1332
|
+
keys = keys.toString();
|
|
1265
1333
|
keys = keys.split('');
|
|
1266
1334
|
}
|
|
1267
1335
|
|
|
@@ -1286,7 +1354,10 @@ class Puppeteer extends Helper {
|
|
|
1286
1354
|
} else if (editable) {
|
|
1287
1355
|
await this._evaluateHandeInContext(el => el.innerHTML = '', el);
|
|
1288
1356
|
}
|
|
1357
|
+
|
|
1358
|
+
highlightActiveElement.call(this, el, await this._getContext());
|
|
1289
1359
|
await el.type(value.toString(), { delay: this.options.pressKeyDelay });
|
|
1360
|
+
|
|
1290
1361
|
return this._waitForAction();
|
|
1291
1362
|
}
|
|
1292
1363
|
|
|
@@ -1305,8 +1376,9 @@ class Puppeteer extends Helper {
|
|
|
1305
1376
|
async appendField(field, value) {
|
|
1306
1377
|
const els = await findVisibleFields.call(this, field);
|
|
1307
1378
|
assertElementExists(els, field, 'Field');
|
|
1379
|
+
highlightActiveElement.call(this, els[0], await this._getContext());
|
|
1308
1380
|
await els[0].press('End');
|
|
1309
|
-
await els[0].type(value, { delay: this.options.pressKeyDelay });
|
|
1381
|
+
await els[0].type(value.toString(), { delay: this.options.pressKeyDelay });
|
|
1310
1382
|
return this._waitForAction();
|
|
1311
1383
|
}
|
|
1312
1384
|
|
|
@@ -1314,20 +1386,22 @@ class Puppeteer extends Helper {
|
|
|
1314
1386
|
* {{> seeInField }}
|
|
1315
1387
|
*/
|
|
1316
1388
|
async seeInField(field, value) {
|
|
1317
|
-
|
|
1389
|
+
const _value = (typeof value === 'boolean') ? value : value.toString();
|
|
1390
|
+
return proceedSeeInField.call(this, 'assert', field, _value);
|
|
1318
1391
|
}
|
|
1319
1392
|
|
|
1320
1393
|
/**
|
|
1321
1394
|
* {{> dontSeeInField }}
|
|
1322
1395
|
*/
|
|
1323
1396
|
async dontSeeInField(field, value) {
|
|
1324
|
-
|
|
1397
|
+
const _value = (typeof value === 'boolean') ? value : value.toString();
|
|
1398
|
+
return proceedSeeInField.call(this, 'negate', field, _value);
|
|
1325
1399
|
}
|
|
1326
1400
|
|
|
1327
1401
|
/**
|
|
1328
|
-
* {{> attachFile }}
|
|
1329
|
-
*
|
|
1330
1402
|
* > ⚠ There is an [issue with file upload in Puppeteer 2.1.0 & 2.1.1](https://github.com/puppeteer/puppeteer/issues/5420), downgrade to 2.0.0 if you face it.
|
|
1403
|
+
*
|
|
1404
|
+
* {{> attachFile }}
|
|
1331
1405
|
*/
|
|
1332
1406
|
async attachFile(locator, pathToFile) {
|
|
1333
1407
|
const file = path.join(global.codecept_dir, pathToFile);
|
|
@@ -1351,6 +1425,7 @@ class Puppeteer extends Helper {
|
|
|
1351
1425
|
if (await el.getProperty('tagName').then(t => t.jsonValue()) !== 'SELECT') {
|
|
1352
1426
|
throw new Error('Element is not <select>');
|
|
1353
1427
|
}
|
|
1428
|
+
highlightActiveElement.call(this, els[0], await this._getContext());
|
|
1354
1429
|
if (!Array.isArray(option)) option = [option];
|
|
1355
1430
|
|
|
1356
1431
|
for (const key in option) {
|
|
@@ -1557,9 +1632,9 @@ class Puppeteer extends Helper {
|
|
|
1557
1632
|
}
|
|
1558
1633
|
|
|
1559
1634
|
/**
|
|
1560
|
-
*
|
|
1635
|
+
* If a function returns a Promise, tt will wait for its resolution.
|
|
1561
1636
|
*
|
|
1562
|
-
*
|
|
1637
|
+
* {{> executeScript }}
|
|
1563
1638
|
*/
|
|
1564
1639
|
async executeScript(...args) {
|
|
1565
1640
|
let context = this.page;
|
|
@@ -1570,9 +1645,8 @@ class Puppeteer extends Helper {
|
|
|
1570
1645
|
}
|
|
1571
1646
|
|
|
1572
1647
|
/**
|
|
1573
|
-
* {{> executeAsyncScript }}
|
|
1574
|
-
*
|
|
1575
1648
|
* Asynchronous scripts can also be executed with `executeScript` if a function returns a Promise.
|
|
1649
|
+
* {{> executeAsyncScript }}
|
|
1576
1650
|
*/
|
|
1577
1651
|
async executeAsyncScript(...args) {
|
|
1578
1652
|
const asyncFn = function () {
|
|
@@ -1699,29 +1773,26 @@ class Puppeteer extends Helper {
|
|
|
1699
1773
|
|
|
1700
1774
|
const cssPropertiesCamelCase = convertCssPropertiesToCamelCase(cssProperties);
|
|
1701
1775
|
const elemAmount = res.length;
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
.
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
}));
|
|
1716
|
-
});
|
|
1717
|
-
});
|
|
1718
|
-
let props = await Promise.all(commands);
|
|
1776
|
+
let props = [];
|
|
1777
|
+
|
|
1778
|
+
for (const element of res) {
|
|
1779
|
+
for (const prop of Object.keys(cssProperties)) {
|
|
1780
|
+
const cssProp = await this.grabCssPropertyFrom(locator, prop);
|
|
1781
|
+
if (isColorProperty(prop)) {
|
|
1782
|
+
props.push(convertColorToRGBA(cssProp));
|
|
1783
|
+
} else {
|
|
1784
|
+
props.push(cssProp);
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1719
1789
|
const values = Object.keys(cssPropertiesCamelCase).map(key => cssPropertiesCamelCase[key]);
|
|
1720
1790
|
if (!Array.isArray(props)) props = [props];
|
|
1721
1791
|
let chunked = chunkArray(props, values.length);
|
|
1722
1792
|
chunked = chunked.filter((val) => {
|
|
1723
1793
|
for (let i = 0; i < val.length; ++i) {
|
|
1724
|
-
|
|
1794
|
+
// eslint-disable-next-line eqeqeq
|
|
1795
|
+
if (val[i] != values[i]) return false;
|
|
1725
1796
|
}
|
|
1726
1797
|
return true;
|
|
1727
1798
|
});
|
|
@@ -1752,7 +1823,10 @@ class Puppeteer extends Helper {
|
|
|
1752
1823
|
let chunked = chunkArray(attrs, values.length);
|
|
1753
1824
|
chunked = chunked.filter((val) => {
|
|
1754
1825
|
for (let i = 0; i < val.length; ++i) {
|
|
1755
|
-
|
|
1826
|
+
const _actual = Number.isNaN(val[i]) || (typeof values[i]) === 'string' ? val[i] : Number.parseInt(values[i], 10);
|
|
1827
|
+
const _expected = Number.isNaN(values[i]) || (typeof values[i]) === 'string' ? values[i] : Number.parseInt(values[i], 10);
|
|
1828
|
+
// if the attribute doesn't exist, returns false as well
|
|
1829
|
+
if (!_actual || !_actual.includes(_expected)) return false;
|
|
1756
1830
|
}
|
|
1757
1831
|
return true;
|
|
1758
1832
|
});
|
|
@@ -1828,27 +1902,58 @@ class Puppeteer extends Helper {
|
|
|
1828
1902
|
*/
|
|
1829
1903
|
async saveScreenshot(fileName, fullPage) {
|
|
1830
1904
|
const fullPageOption = fullPage || this.options.fullPageScreenshots;
|
|
1831
|
-
|
|
1905
|
+
let outputFile = screenshotOutputFolder(fileName);
|
|
1832
1906
|
|
|
1833
1907
|
this.debug(`Screenshot is saving to ${outputFile}`);
|
|
1834
1908
|
|
|
1909
|
+
await this.page.screenshot({
|
|
1910
|
+
path: outputFile,
|
|
1911
|
+
fullPage: fullPageOption,
|
|
1912
|
+
type: 'png',
|
|
1913
|
+
});
|
|
1914
|
+
|
|
1835
1915
|
if (this.activeSessionName) {
|
|
1836
|
-
const
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1916
|
+
for (const sessionName in this.sessionPages) {
|
|
1917
|
+
const activeSessionPage = this.sessionPages[sessionName];
|
|
1918
|
+
outputFile = screenshotOutputFolder(`${sessionName}_${fileName}`);
|
|
1919
|
+
|
|
1920
|
+
this.debug(`${sessionName} - Screenshot is saving to ${outputFile}`);
|
|
1921
|
+
|
|
1922
|
+
if (activeSessionPage) {
|
|
1923
|
+
await activeSessionPage.screenshot({
|
|
1924
|
+
path: outputFile,
|
|
1925
|
+
fullPage: fullPageOption,
|
|
1926
|
+
type: 'png',
|
|
1927
|
+
});
|
|
1928
|
+
}
|
|
1844
1929
|
}
|
|
1845
1930
|
}
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
async _failed(test) {
|
|
1934
|
+
await this._withinEnd();
|
|
1846
1935
|
|
|
1847
|
-
|
|
1936
|
+
if (this.options.trace) {
|
|
1937
|
+
await this.page.tracing.stop();
|
|
1938
|
+
const _traceName = this.currentRunningTest.artifacts.trace.replace('.json', '.failed.json');
|
|
1939
|
+
fs.renameSync(this.currentRunningTest.artifacts.trace, _traceName);
|
|
1940
|
+
test.artifacts.trace = _traceName;
|
|
1941
|
+
}
|
|
1848
1942
|
}
|
|
1849
1943
|
|
|
1850
|
-
async
|
|
1944
|
+
async _passed(test) {
|
|
1851
1945
|
await this._withinEnd();
|
|
1946
|
+
|
|
1947
|
+
if (this.options.trace) {
|
|
1948
|
+
await this.page.tracing.stop();
|
|
1949
|
+
if (this.options.keepTraceForPassedTests) {
|
|
1950
|
+
const _traceName = this.currentRunningTest.artifacts.trace.replace('.json', '.passed.json');
|
|
1951
|
+
fs.renameSync(this.currentRunningTest.artifacts.trace, _traceName);
|
|
1952
|
+
test.artifacts.trace = _traceName;
|
|
1953
|
+
} else {
|
|
1954
|
+
fs.unlinkSync(this.currentRunningTest.artifacts.trace);
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1852
1957
|
}
|
|
1853
1958
|
|
|
1854
1959
|
/**
|
|
@@ -1960,7 +2065,7 @@ class Puppeteer extends Helper {
|
|
|
1960
2065
|
assertElementExists(els, locator);
|
|
1961
2066
|
|
|
1962
2067
|
return this.waitForFunction(isElementClickable, [els[0]], waitTimeout).catch(async (e) => {
|
|
1963
|
-
if (/failed: timeout/i.test(e.message)) {
|
|
2068
|
+
if (/Waiting failed/i.test(e.message) || /failed: timeout/i.test(e.message)) {
|
|
1964
2069
|
throw new Error(`element ${new Locator(locator).toString()} still not clickable after ${waitTimeout || this.options.waitForTimeout / 1000} sec`);
|
|
1965
2070
|
} else {
|
|
1966
2071
|
throw e;
|
|
@@ -1991,7 +2096,7 @@ class Puppeteer extends Helper {
|
|
|
1991
2096
|
/**
|
|
1992
2097
|
* {{> waitForVisible }}
|
|
1993
2098
|
*
|
|
1994
|
-
*
|
|
2099
|
+
* {{ react }}
|
|
1995
2100
|
*/
|
|
1996
2101
|
async waitForVisible(locator, sec) {
|
|
1997
2102
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -2046,6 +2151,24 @@ class Puppeteer extends Helper {
|
|
|
2046
2151
|
});
|
|
2047
2152
|
}
|
|
2048
2153
|
|
|
2154
|
+
/**
|
|
2155
|
+
* {{> waitForNumberOfTabs }}
|
|
2156
|
+
*/
|
|
2157
|
+
async waitForNumberOfTabs(expectedTabs, sec) {
|
|
2158
|
+
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
2159
|
+
let currentTabs;
|
|
2160
|
+
let count = 0;
|
|
2161
|
+
|
|
2162
|
+
do {
|
|
2163
|
+
currentTabs = await this.grabNumberOfOpenTabs();
|
|
2164
|
+
await this.wait(1);
|
|
2165
|
+
count += 1000;
|
|
2166
|
+
if (currentTabs >= expectedTabs) return;
|
|
2167
|
+
} while (count <= waitTimeout);
|
|
2168
|
+
|
|
2169
|
+
throw new Error(`Expected ${expectedTabs} tabs are not met after ${waitTimeout / 1000} sec.`);
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2049
2172
|
async _getContext() {
|
|
2050
2173
|
if (this.context && this.context.constructor.name === 'Frame') {
|
|
2051
2174
|
return this.context;
|
|
@@ -2064,7 +2187,7 @@ class Puppeteer extends Helper {
|
|
|
2064
2187
|
return currUrl.indexOf(urlPart) > -1;
|
|
2065
2188
|
}, { timeout: waitTimeout }, urlPart).catch(async (e) => {
|
|
2066
2189
|
const currUrl = await this._getPageUrl(); // Required because the waitForFunction can't return data.
|
|
2067
|
-
if (/failed: timeout/i.test(e.message)) {
|
|
2190
|
+
if (/Waiting failed:/i.test(e.message) || /failed: timeout/i.test(e.message)) {
|
|
2068
2191
|
throw new Error(`expected url to include ${urlPart}, but found ${currUrl}`);
|
|
2069
2192
|
} else {
|
|
2070
2193
|
throw e;
|
|
@@ -2088,7 +2211,7 @@ class Puppeteer extends Helper {
|
|
|
2088
2211
|
return currUrl.indexOf(urlPart) > -1;
|
|
2089
2212
|
}, { timeout: waitTimeout }, urlPart).catch(async (e) => {
|
|
2090
2213
|
const currUrl = await this._getPageUrl(); // Required because the waitForFunction can't return data.
|
|
2091
|
-
if (/failed: timeout/i.test(e.message)) {
|
|
2214
|
+
if (/Waiting failed/i.test(e.message) || /failed: timeout/i.test(e.message)) {
|
|
2092
2215
|
throw new Error(`expected url to be ${urlPart}, but found ${currUrl}`);
|
|
2093
2216
|
} else {
|
|
2094
2217
|
throw e;
|
|
@@ -2220,9 +2343,9 @@ class Puppeteer extends Helper {
|
|
|
2220
2343
|
}
|
|
2221
2344
|
|
|
2222
2345
|
/**
|
|
2223
|
-
* Waits for navigation to finish. By default takes configured `waitForNavigation` option.
|
|
2346
|
+
* Waits for navigation to finish. By default, takes configured `waitForNavigation` option.
|
|
2224
2347
|
*
|
|
2225
|
-
* See [
|
|
2348
|
+
* See [Puppeteer's reference](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitfornavigationoptions)
|
|
2226
2349
|
*
|
|
2227
2350
|
* @param {*} opts
|
|
2228
2351
|
*/
|
|
@@ -2297,6 +2420,10 @@ async function findElements(matcher, locator) {
|
|
|
2297
2420
|
if (locator.react) return findReact(matcher.executionContext(), locator);
|
|
2298
2421
|
locator = new Locator(locator, 'css');
|
|
2299
2422
|
if (!locator.isXPath()) return matcher.$$(locator.simplify());
|
|
2423
|
+
// puppeteer version < 19.4.0 is no longer supported. This one is backward support.
|
|
2424
|
+
if (puppeteer.default?.defaultBrowserRevision) {
|
|
2425
|
+
return matcher.$$(`xpath/${locator.value}`);
|
|
2426
|
+
}
|
|
2300
2427
|
return matcher.$x(locator.value);
|
|
2301
2428
|
}
|
|
2302
2429
|
|
|
@@ -2313,12 +2440,16 @@ async function proceedClick(locator, context = null, options = {}) {
|
|
|
2313
2440
|
} else {
|
|
2314
2441
|
assertElementExists(els, locator, 'Clickable element');
|
|
2315
2442
|
}
|
|
2443
|
+
|
|
2444
|
+
highlightActiveElement.call(this, els[0], await this._getContext());
|
|
2445
|
+
|
|
2316
2446
|
await els[0].click(options);
|
|
2317
2447
|
const promises = [];
|
|
2318
2448
|
if (options.waitForNavigation) {
|
|
2319
2449
|
promises.push(this.waitForNavigation());
|
|
2320
2450
|
}
|
|
2321
2451
|
promises.push(this._waitForAction());
|
|
2452
|
+
|
|
2322
2453
|
return Promise.all(promises);
|
|
2323
2454
|
}
|
|
2324
2455
|
|
|
@@ -2370,7 +2501,7 @@ async function proceedSee(assertType, text, context, strict = false) {
|
|
|
2370
2501
|
if (strict) {
|
|
2371
2502
|
return allText.map(elText => equals(description)[assertType](text, elText));
|
|
2372
2503
|
}
|
|
2373
|
-
return stringIncludes(description)[assertType](text, allText.join(' | '));
|
|
2504
|
+
return stringIncludes(description)[assertType](normalizeSpacesInString(text), normalizeSpacesInString(allText.join(' | ')));
|
|
2374
2505
|
}
|
|
2375
2506
|
|
|
2376
2507
|
async function findCheckable(locator, context) {
|
|
@@ -2547,7 +2678,10 @@ async function elementSelected(element) {
|
|
|
2547
2678
|
|
|
2548
2679
|
function isFrameLocator(locator) {
|
|
2549
2680
|
locator = new Locator(locator);
|
|
2550
|
-
if (locator.isFrame())
|
|
2681
|
+
if (locator.isFrame()) {
|
|
2682
|
+
const _locator = new Locator(locator);
|
|
2683
|
+
return _locator.value;
|
|
2684
|
+
}
|
|
2551
2685
|
return false;
|
|
2552
2686
|
}
|
|
2553
2687
|
|
|
@@ -2663,3 +2797,9 @@ function getNormalizedKey(key) {
|
|
|
2663
2797
|
}
|
|
2664
2798
|
return normalizedKey;
|
|
2665
2799
|
}
|
|
2800
|
+
|
|
2801
|
+
function highlightActiveElement(element, context) {
|
|
2802
|
+
if (this.options.highlightElement && global.debugMode) {
|
|
2803
|
+
highlightElement(element, context);
|
|
2804
|
+
}
|
|
2805
|
+
}
|