codeceptjs 4.0.0-rc.9 → 4.0.0
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 +9 -10
- package/bin/codecept.js +15 -2
- package/bin/codeceptq.js +49 -0
- package/bin/mcp-server.js +751 -172
- package/docs/advanced.md +201 -0
- package/docs/agents.md +181 -0
- package/docs/ai.md +489 -0
- package/docs/aitrace.md +266 -0
- package/docs/api.md +332 -0
- package/docs/architecture.md +235 -0
- package/docs/assertions.md +415 -0
- package/docs/auth.md +318 -0
- package/docs/basics.md +424 -0
- package/docs/bdd.md +539 -0
- package/docs/best.md +240 -0
- package/docs/bootstrap.md +132 -0
- package/docs/commands.md +352 -0
- package/docs/community-helpers.md +63 -0
- package/docs/configuration.md +185 -0
- package/docs/continuous-integration.md +431 -0
- package/docs/custom-helpers.md +297 -0
- package/docs/data.md +448 -0
- package/docs/debugging.md +332 -0
- package/docs/detox.md +235 -0
- package/docs/docker.md +107 -0
- package/docs/effects.md +179 -0
- package/docs/element-based-testing.md +295 -0
- package/docs/element-selection.md +125 -0
- package/docs/els.md +328 -0
- package/docs/environment-variables.md +131 -0
- package/docs/examples.md +160 -0
- package/docs/heal.md +213 -0
- package/docs/helpers/ApiDataFactory.md +267 -0
- package/docs/helpers/Appium.md +1419 -0
- package/docs/helpers/Detox.md +665 -0
- package/docs/helpers/ExpectHelper.md +275 -0
- package/docs/helpers/FileSystem.md +152 -0
- package/docs/helpers/GraphQL.md +152 -0
- package/docs/helpers/GraphQLDataFactory.md +226 -0
- package/docs/helpers/JSONResponse.md +255 -0
- package/docs/helpers/MockRequest.md +377 -0
- package/docs/helpers/Playwright.md +2970 -0
- package/docs/helpers/Puppeteer-firefox.md +86 -0
- package/docs/helpers/Puppeteer.md +2583 -0
- package/docs/helpers/REST.md +289 -0
- package/docs/helpers/WebDriver.md +2639 -0
- package/docs/hooks.md +148 -0
- package/docs/index.md +111 -0
- package/docs/installation.md +121 -0
- package/docs/internal-test-server.md +89 -0
- package/docs/locators.md +355 -0
- package/docs/mcp.md +485 -0
- package/docs/migrate-from-cypress.md +98 -0
- package/docs/migrate-from-java.md +108 -0
- package/docs/migrate-from-protractor.md +101 -0
- package/docs/migrate-from-testcafe.md +99 -0
- package/docs/migration-4.md +743 -0
- package/docs/mobile.md +338 -0
- package/docs/pageobjects.md +399 -0
- package/docs/parallel.md +187 -0
- package/docs/playwright.md +714 -0
- package/docs/plugins/aiTrace.md +49 -0
- package/docs/plugins/analyze.md +66 -0
- package/docs/plugins/auth.md +241 -0
- package/docs/plugins/autoDelay.md +48 -0
- package/docs/plugins/browser.md +41 -0
- package/docs/plugins/coverage.md +39 -0
- package/docs/plugins/customLocator.md +119 -0
- package/docs/plugins/customReporter.md +16 -0
- package/docs/plugins/expose.md +75 -0
- package/docs/plugins/heal.md +44 -0
- package/docs/plugins/junitReporter.md +51 -0
- package/docs/plugins/pageInfo.md +34 -0
- package/docs/plugins/pause.md +43 -0
- package/docs/plugins/pauseOnFail.md +18 -0
- package/docs/plugins/retryFailedStep.md +75 -0
- package/docs/plugins/screencast.md +55 -0
- package/docs/plugins/screenshot.md +58 -0
- package/docs/plugins/screenshotOnFail.md +18 -0
- package/docs/plugins/stepTimeout.md +65 -0
- package/docs/plugins.md +87 -0
- package/docs/puppeteer.md +314 -0
- package/docs/quickstart.md +120 -0
- package/docs/reports.md +198 -0
- package/docs/retry.md +311 -0
- package/docs/secrets.md +150 -0
- package/docs/sessions.md +80 -0
- package/docs/shadow.md +68 -0
- package/docs/store.md +94 -0
- package/docs/test-structure.md +275 -0
- package/docs/timeouts.md +183 -0
- package/docs/translation.md +247 -0
- package/docs/tutorial.md +323 -0
- package/docs/typescript.md +159 -0
- package/docs/web-element.md +251 -0
- package/docs/webdriver.md +641 -0
- package/docs/within.md +55 -0
- package/lib/actor.js +1 -36
- package/lib/ai.js +3 -2
- package/lib/aria.js +260 -0
- package/lib/assertions.js +18 -0
- package/lib/codecept.js +7 -7
- package/lib/command/check.js +2 -1
- package/lib/command/dryRun.js +24 -5
- package/lib/command/generate.js +2 -0
- package/lib/command/gherkin/snippets.js +5 -4
- package/lib/command/init.js +248 -266
- package/lib/command/list.js +150 -10
- package/lib/command/query.js +218 -0
- package/lib/command/run-multiple.js +3 -2
- package/lib/command/run-workers.js +1 -14
- package/lib/command/run.js +3 -17
- package/lib/command/utils.js +14 -0
- package/lib/command/workers/runTests.js +11 -15
- package/lib/config.js +77 -4
- package/lib/container.js +97 -15
- package/lib/effects.js +17 -0
- package/lib/element/WebElement.js +194 -2
- package/lib/els.js +12 -6
- package/lib/globals.js +32 -19
- package/lib/heal.js +7 -4
- package/lib/helper/ApiDataFactory.js +2 -1
- package/lib/helper/FileSystem.js +3 -2
- package/lib/helper/GraphQLDataFactory.js +2 -1
- package/lib/helper/Playwright.js +63 -70
- package/lib/helper/Puppeteer.js +20 -109
- package/lib/helper/WebDriver.js +13 -30
- package/lib/helper/errors/NonFocusedType.js +8 -0
- package/lib/helper/extras/Download.js +45 -0
- package/lib/helper/extras/PlaywrightLocator.js +10 -0
- package/lib/helper/extras/elementSelection.js +10 -3
- package/lib/helper/extras/focusCheck.js +43 -0
- package/lib/helper/extras/richTextEditor.js +178 -0
- package/lib/history.js +3 -2
- package/lib/html.js +90 -16
- package/lib/index.js +9 -1
- package/lib/listener/config.js +6 -4
- package/lib/listener/emptyRun.js +2 -1
- package/lib/listener/helpers.js +4 -1
- package/lib/listener/mocha.js +2 -1
- package/lib/listener/pageobjects.js +43 -0
- package/lib/listener/result.js +3 -2
- package/lib/locator.js +126 -16
- package/lib/mocha/cli.js +4 -2
- package/lib/mocha/factory.js +7 -2
- package/lib/mocha/inject.js +1 -1
- package/lib/mocha/scenarioConfig.js +2 -1
- package/lib/mocha/ui.js +5 -6
- package/lib/parser.js +2 -2
- package/lib/pause.js +38 -4
- package/lib/plugin/aiTrace.js +96 -103
- package/lib/plugin/analyze.js +9 -9
- package/lib/plugin/auth.js +3 -3
- package/lib/plugin/browser.js +77 -0
- package/lib/plugin/expose.js +159 -0
- package/lib/plugin/heal.js +47 -3
- package/lib/plugin/junitReporter.js +303 -0
- package/lib/plugin/pageInfo.js +54 -52
- package/lib/plugin/pause.js +131 -0
- package/lib/plugin/pauseOnFail.js +11 -33
- package/lib/plugin/retryFailedStep.js +15 -13
- package/lib/plugin/screencast.js +289 -0
- package/lib/plugin/screenshot.js +558 -0
- package/lib/plugin/screenshotOnFail.js +9 -170
- package/lib/plugin/stepTimeout.js +3 -2
- package/lib/recorder.js +1 -1
- package/lib/rerun.js +2 -1
- package/lib/result.js +2 -1
- package/lib/step/base.js +10 -9
- package/lib/step/comment.js +2 -2
- package/lib/step/config.js +7 -0
- package/lib/step/helper.js +4 -4
- package/lib/step/meta.js +3 -3
- package/lib/step/record.js +5 -5
- package/lib/store.js +72 -3
- package/lib/translation.js +2 -1
- package/lib/utils/mask_data.js +2 -1
- package/lib/utils/pluginParser.js +151 -0
- package/lib/utils/trace.js +297 -0
- package/lib/utils.js +29 -3
- package/lib/workers.js +14 -22
- package/package.json +17 -14
- package/typings/index.d.ts +0 -5
- package/docs/webapi/amOnPage.mustache +0 -11
- package/docs/webapi/appendField.mustache +0 -16
- package/docs/webapi/attachFile.mustache +0 -24
- package/docs/webapi/blur.mustache +0 -18
- package/docs/webapi/checkOption.mustache +0 -13
- package/docs/webapi/clearCookie.mustache +0 -9
- package/docs/webapi/clearField.mustache +0 -14
- package/docs/webapi/click.mustache +0 -29
- 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/dontSeeCurrentPathEquals.mustache +0 -10
- package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
- package/docs/webapi/dontSeeElement.mustache +0 -12
- package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
- package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
- package/docs/webapi/dontSeeInField.mustache +0 -16
- package/docs/webapi/dontSeeInSource.mustache +0 -8
- package/docs/webapi/dontSeeInTitle.mustache +0 -8
- package/docs/webapi/dontSeeTraffic.mustache +0 -13
- 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 -21
- package/docs/webapi/flushNetworkTraffics.mustache +0 -5
- package/docs/webapi/focus.mustache +0 -13
- 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/grabRecordedNetworkTraffics.mustache +0 -10
- 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/grabWebElement.mustache +0 -9
- package/docs/webapi/grabWebElements.mustache +0 -9
- package/docs/webapi/moveCursorTo.mustache +0 -16
- 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/seeCurrentPathEquals.mustache +0 -10
- package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
- package/docs/webapi/seeElement.mustache +0 -12
- package/docs/webapi/seeElementInDOM.mustache +0 -8
- package/docs/webapi/seeInCurrentUrl.mustache +0 -8
- package/docs/webapi/seeInField.mustache +0 -17
- 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/seeTraffic.mustache +0 -36
- package/docs/webapi/selectOption.mustache +0 -26
- package/docs/webapi/setCookie.mustache +0 -16
- package/docs/webapi/setGeoLocation.mustache +0 -12
- package/docs/webapi/startRecordingTraffic.mustache +0 -8
- package/docs/webapi/startRecordingWebSocketMessages.mustache +0 -8
- package/docs/webapi/stopRecordingTraffic.mustache +0 -5
- package/docs/webapi/stopRecordingWebSocketMessages.mustache +0 -7
- 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 -21
- package/docs/webapi/uncheckOption.mustache +0 -13
- package/docs/webapi/wait.mustache +0 -8
- package/docs/webapi/waitForClickable.mustache +0 -11
- package/docs/webapi/waitForCookie.mustache +0 -9
- package/docs/webapi/waitForDetached.mustache +0 -10
- package/docs/webapi/waitForDisabled.mustache +0 -6
- 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/waitForNumberOfTabs.mustache +0 -9
- 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/lib/helper/AI.js +0 -214
- package/lib/helper/Mochawesome.js +0 -96
- package/lib/helper/extras/PlaywrightReactVueLocator.js +0 -52
- package/lib/helper/extras/React.js +0 -65
- package/lib/plugin/stepByStepReport.js +0 -431
- package/lib/plugin/subtitles.js +0 -89
package/lib/helper/Puppeteer.js
CHANGED
|
@@ -8,6 +8,7 @@ import promiseRetry from 'promise-retry'
|
|
|
8
8
|
import Locator from '../locator.js'
|
|
9
9
|
import recorder from '../recorder.js'
|
|
10
10
|
import store from '../store.js'
|
|
11
|
+
import { checkFocusBeforeType, checkFocusBeforePressKey } from './extras/focusCheck.js'
|
|
11
12
|
import { includes as stringIncludes } from '../assert/include.js'
|
|
12
13
|
import { urlEquals, equals } from '../assert/equal.js'
|
|
13
14
|
import { empty } from '../assert/empty.js'
|
|
@@ -44,6 +45,7 @@ import { dontSeeElementError, seeElementError, dontSeeElementInDOMError, seeElem
|
|
|
44
45
|
import { dontSeeTraffic, seeTraffic, grabRecordedNetworkTraffics, stopRecordingTraffic, flushNetworkTraffics } from './network/actions.js'
|
|
45
46
|
import WebElement from '../element/WebElement.js'
|
|
46
47
|
import { selectElement } from './extras/elementSelection.js'
|
|
48
|
+
import { fillRichEditor } from './extras/richTextEditor.js'
|
|
47
49
|
|
|
48
50
|
let puppeteer
|
|
49
51
|
|
|
@@ -751,7 +753,7 @@ class Puppeteer extends Helper {
|
|
|
751
753
|
}
|
|
752
754
|
|
|
753
755
|
if (this.options.trace) {
|
|
754
|
-
const fileName = `${`${
|
|
756
|
+
const fileName = `${`${store.outputDir}${path.sep}trace${path.sep}${uuidv4()}_${clearString(this.currentRunningTest.title)}`.slice(0, 245)}.json`
|
|
755
757
|
const dir = path.dirname(fileName)
|
|
756
758
|
if (!fileExists(dir)) fs.mkdirSync(dir)
|
|
757
759
|
await this.page.tracing.start({ screenshots: true, path: fileName })
|
|
@@ -819,7 +821,6 @@ class Puppeteer extends Helper {
|
|
|
819
821
|
|
|
820
822
|
/**
|
|
821
823
|
* {{> moveCursorTo }}
|
|
822
|
-
* {{ react }}
|
|
823
824
|
*/
|
|
824
825
|
async moveCursorTo(locator, offsetX = 0, offsetY = 0) {
|
|
825
826
|
let context = null
|
|
@@ -990,7 +991,6 @@ class Puppeteer extends Helper {
|
|
|
990
991
|
* const elements = await this.helpers['Puppeteer']._locate({name: 'password'});
|
|
991
992
|
* ```
|
|
992
993
|
*
|
|
993
|
-
* {{ react }}
|
|
994
994
|
*/
|
|
995
995
|
async _locate(locator) {
|
|
996
996
|
const context = await this.context
|
|
@@ -1005,7 +1005,6 @@ class Puppeteer extends Helper {
|
|
|
1005
1005
|
* const element = await this.helpers['Puppeteer']._locateElement({name: 'password'});
|
|
1006
1006
|
* ```
|
|
1007
1007
|
*
|
|
1008
|
-
* {{ react }}
|
|
1009
1008
|
*/
|
|
1010
1009
|
async _locateElement(locator) {
|
|
1011
1010
|
const context = await this.context
|
|
@@ -1189,7 +1188,6 @@ class Puppeteer extends Helper {
|
|
|
1189
1188
|
|
|
1190
1189
|
/**
|
|
1191
1190
|
* {{> seeElement }}
|
|
1192
|
-
* {{ react }}
|
|
1193
1191
|
*/
|
|
1194
1192
|
async seeElement(locator, context = null) {
|
|
1195
1193
|
let els
|
|
@@ -1213,7 +1211,6 @@ class Puppeteer extends Helper {
|
|
|
1213
1211
|
|
|
1214
1212
|
/**
|
|
1215
1213
|
* {{> dontSeeElement }}
|
|
1216
|
-
* {{ react }}
|
|
1217
1214
|
*/
|
|
1218
1215
|
async dontSeeElement(locator, context = null) {
|
|
1219
1216
|
let els
|
|
@@ -1262,7 +1259,6 @@ class Puppeteer extends Helper {
|
|
|
1262
1259
|
/**
|
|
1263
1260
|
* {{> click }}
|
|
1264
1261
|
*
|
|
1265
|
-
* {{ react }}
|
|
1266
1262
|
*/
|
|
1267
1263
|
async click(locator = '//body', context = null) {
|
|
1268
1264
|
return proceedClick.call(this, locator, context)
|
|
@@ -1271,7 +1267,6 @@ class Puppeteer extends Helper {
|
|
|
1271
1267
|
/**
|
|
1272
1268
|
* {{> forceClick }}
|
|
1273
1269
|
*
|
|
1274
|
-
* {{ react }}
|
|
1275
1270
|
*/
|
|
1276
1271
|
async forceClick(locator, context = null) {
|
|
1277
1272
|
let matcher = await this.context
|
|
@@ -1301,7 +1296,6 @@ class Puppeteer extends Helper {
|
|
|
1301
1296
|
/**
|
|
1302
1297
|
* {{> clickLink }}
|
|
1303
1298
|
*
|
|
1304
|
-
* {{ react }}
|
|
1305
1299
|
*/
|
|
1306
1300
|
async clickLink(locator, context = null) {
|
|
1307
1301
|
return proceedClick.call(this, locator, context, { waitForNavigation: true })
|
|
@@ -1325,7 +1319,7 @@ class Puppeteer extends Helper {
|
|
|
1325
1319
|
* @param {string} [downloadPath='downloads'] change this parameter to set another directory for saving
|
|
1326
1320
|
*/
|
|
1327
1321
|
async handleDownloads(downloadPath = 'downloads') {
|
|
1328
|
-
downloadPath = path.join(
|
|
1322
|
+
downloadPath = path.join(store.outputDir, downloadPath)
|
|
1329
1323
|
if (!fs.existsSync(downloadPath)) {
|
|
1330
1324
|
fs.mkdirSync(downloadPath, '0777')
|
|
1331
1325
|
}
|
|
@@ -1387,7 +1381,7 @@ class Puppeteer extends Helper {
|
|
|
1387
1381
|
},
|
|
1388
1382
|
})
|
|
1389
1383
|
|
|
1390
|
-
const outputFile = path.join(`${
|
|
1384
|
+
const outputFile = path.join(`${store.outputDir}/${fileName}`)
|
|
1391
1385
|
|
|
1392
1386
|
try {
|
|
1393
1387
|
await new Promise((resolve, reject) => {
|
|
@@ -1409,7 +1403,6 @@ class Puppeteer extends Helper {
|
|
|
1409
1403
|
/**
|
|
1410
1404
|
* {{> doubleClick }}
|
|
1411
1405
|
*
|
|
1412
|
-
* {{ react }}
|
|
1413
1406
|
*/
|
|
1414
1407
|
async doubleClick(locator, context = null) {
|
|
1415
1408
|
return proceedClick.call(this, locator, context, { clickCount: 2 })
|
|
@@ -1418,7 +1411,6 @@ class Puppeteer extends Helper {
|
|
|
1418
1411
|
/**
|
|
1419
1412
|
* {{> rightClick }}
|
|
1420
1413
|
*
|
|
1421
|
-
* {{ react }}
|
|
1422
1414
|
*/
|
|
1423
1415
|
async rightClick(locator, context = null) {
|
|
1424
1416
|
return proceedClick.call(this, locator, context, { button: 'right' })
|
|
@@ -1547,6 +1539,7 @@ class Puppeteer extends Helper {
|
|
|
1547
1539
|
* {{> pressKeyWithKeyNormalization }}
|
|
1548
1540
|
*/
|
|
1549
1541
|
async pressKey(key) {
|
|
1542
|
+
await checkFocusBeforePressKey(this, key)
|
|
1550
1543
|
const modifiers = []
|
|
1551
1544
|
if (Array.isArray(key)) {
|
|
1552
1545
|
for (let k of key) {
|
|
@@ -1575,6 +1568,8 @@ class Puppeteer extends Helper {
|
|
|
1575
1568
|
* {{> type }}
|
|
1576
1569
|
*/
|
|
1577
1570
|
async type(keys, delay = null) {
|
|
1571
|
+
await checkFocusBeforeType(this)
|
|
1572
|
+
|
|
1578
1573
|
if (!Array.isArray(keys)) {
|
|
1579
1574
|
keys = keys.toString()
|
|
1580
1575
|
keys = keys.split('')
|
|
@@ -1588,12 +1583,20 @@ class Puppeteer extends Helper {
|
|
|
1588
1583
|
|
|
1589
1584
|
/**
|
|
1590
1585
|
* {{> fillField }}
|
|
1591
|
-
* {{ react }}
|
|
1592
1586
|
*/
|
|
1593
1587
|
async fillField(field, value, context = null) {
|
|
1594
|
-
|
|
1588
|
+
let els = await findVisibleFields.call(this, field, context)
|
|
1589
|
+
if (!els.length) {
|
|
1590
|
+
els = await findFields.call(this, field, context)
|
|
1591
|
+
}
|
|
1595
1592
|
assertElementExists(els, field, 'Field')
|
|
1596
1593
|
const el = selectElement(els, field, this)
|
|
1594
|
+
|
|
1595
|
+
if (await fillRichEditor(this, el, value)) {
|
|
1596
|
+
highlightActiveElement.call(this, el, await this._getContext())
|
|
1597
|
+
return this._waitForAction()
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1597
1600
|
const tag = await el.getProperty('tagName').then(el => el.jsonValue())
|
|
1598
1601
|
const editable = await el.getProperty('contenteditable').then(el => el.jsonValue())
|
|
1599
1602
|
if (tag === 'INPUT' || tag === 'TEXTAREA') {
|
|
@@ -1618,7 +1621,6 @@ class Puppeteer extends Helper {
|
|
|
1618
1621
|
/**
|
|
1619
1622
|
* {{> appendField }}
|
|
1620
1623
|
*
|
|
1621
|
-
* {{ react }}
|
|
1622
1624
|
*/
|
|
1623
1625
|
async appendField(field, value, context = null) {
|
|
1624
1626
|
const els = await findVisibleFields.call(this, field, context)
|
|
@@ -1652,7 +1654,7 @@ class Puppeteer extends Helper {
|
|
|
1652
1654
|
* {{> attachFile }}
|
|
1653
1655
|
*/
|
|
1654
1656
|
async attachFile(locator, pathToFile, context = null) {
|
|
1655
|
-
const file = path.join(
|
|
1657
|
+
const file = path.join(store.codeceptDir, pathToFile)
|
|
1656
1658
|
|
|
1657
1659
|
if (!fileExists(file)) {
|
|
1658
1660
|
throw new Error(`File at ${file} can not be found on local system`)
|
|
@@ -1720,7 +1722,6 @@ class Puppeteer extends Helper {
|
|
|
1720
1722
|
|
|
1721
1723
|
/**
|
|
1722
1724
|
* {{> grabNumberOfVisibleElements }}
|
|
1723
|
-
* {{ react }}
|
|
1724
1725
|
*/
|
|
1725
1726
|
async grabNumberOfVisibleElements(locator) {
|
|
1726
1727
|
let els = await this._locate(locator)
|
|
@@ -1782,7 +1783,6 @@ class Puppeteer extends Helper {
|
|
|
1782
1783
|
/**
|
|
1783
1784
|
* {{> see }}
|
|
1784
1785
|
*
|
|
1785
|
-
* {{ react }}
|
|
1786
1786
|
*/
|
|
1787
1787
|
async see(text, context = null) {
|
|
1788
1788
|
return proceedSee.call(this, 'assert', text, context)
|
|
@@ -1798,7 +1798,6 @@ class Puppeteer extends Helper {
|
|
|
1798
1798
|
/**
|
|
1799
1799
|
* {{> dontSee }}
|
|
1800
1800
|
*
|
|
1801
|
-
* {{ react }}
|
|
1802
1801
|
*/
|
|
1803
1802
|
async dontSee(text, context = null) {
|
|
1804
1803
|
return proceedSee.call(this, 'negate', text, context)
|
|
@@ -1852,7 +1851,6 @@ class Puppeteer extends Helper {
|
|
|
1852
1851
|
/**
|
|
1853
1852
|
* {{> seeNumberOfElements }}
|
|
1854
1853
|
*
|
|
1855
|
-
* {{ react }}
|
|
1856
1854
|
*/
|
|
1857
1855
|
async seeNumberOfElements(locator, num) {
|
|
1858
1856
|
const elements = await this._locate(locator)
|
|
@@ -1862,7 +1860,6 @@ class Puppeteer extends Helper {
|
|
|
1862
1860
|
/**
|
|
1863
1861
|
* {{> seeNumberOfVisibleElements }}
|
|
1864
1862
|
*
|
|
1865
|
-
* {{ react }}
|
|
1866
1863
|
*/
|
|
1867
1864
|
async seeNumberOfVisibleElements(locator, num) {
|
|
1868
1865
|
const res = await this.grabNumberOfVisibleElements(locator)
|
|
@@ -1989,7 +1986,6 @@ class Puppeteer extends Helper {
|
|
|
1989
1986
|
|
|
1990
1987
|
/**
|
|
1991
1988
|
* {{> grabTextFromAll }}
|
|
1992
|
-
* {{ react }}
|
|
1993
1989
|
*/
|
|
1994
1990
|
async grabTextFromAll(locator) {
|
|
1995
1991
|
const els = await this._locate(locator)
|
|
@@ -2002,7 +1998,6 @@ class Puppeteer extends Helper {
|
|
|
2002
1998
|
|
|
2003
1999
|
/**
|
|
2004
2000
|
* {{> grabTextFrom }}
|
|
2005
|
-
* {{ react }}
|
|
2006
2001
|
*/
|
|
2007
2002
|
async grabTextFrom(locator) {
|
|
2008
2003
|
const texts = await this.grabTextFromAll(locator)
|
|
@@ -2063,7 +2058,6 @@ class Puppeteer extends Helper {
|
|
|
2063
2058
|
|
|
2064
2059
|
/**
|
|
2065
2060
|
* {{> grabCssPropertyFromAll }}
|
|
2066
|
-
* {{ react }}
|
|
2067
2061
|
*/
|
|
2068
2062
|
async grabCssPropertyFromAll(locator, cssProperty) {
|
|
2069
2063
|
const els = await this._locate(locator)
|
|
@@ -2075,7 +2069,6 @@ class Puppeteer extends Helper {
|
|
|
2075
2069
|
|
|
2076
2070
|
/**
|
|
2077
2071
|
* {{> grabCssPropertyFrom }}
|
|
2078
|
-
* {{ react }}
|
|
2079
2072
|
*/
|
|
2080
2073
|
async grabCssPropertyFrom(locator, cssProperty) {
|
|
2081
2074
|
const cssValues = await this.grabCssPropertyFromAll(locator, cssProperty)
|
|
@@ -2090,7 +2083,6 @@ class Puppeteer extends Helper {
|
|
|
2090
2083
|
|
|
2091
2084
|
/**
|
|
2092
2085
|
* {{> seeCssPropertiesOnElements }}
|
|
2093
|
-
* {{ react }}
|
|
2094
2086
|
*/
|
|
2095
2087
|
async seeCssPropertiesOnElements(locator, cssProperties) {
|
|
2096
2088
|
const res = await this._locate(locator)
|
|
@@ -2125,7 +2117,6 @@ class Puppeteer extends Helper {
|
|
|
2125
2117
|
|
|
2126
2118
|
/**
|
|
2127
2119
|
* {{> seeAttributesOnElements }}
|
|
2128
|
-
* {{ react }}
|
|
2129
2120
|
*/
|
|
2130
2121
|
async seeAttributesOnElements(locator, attributes) {
|
|
2131
2122
|
const elements = await this._locate(locator)
|
|
@@ -2163,7 +2154,6 @@ class Puppeteer extends Helper {
|
|
|
2163
2154
|
|
|
2164
2155
|
/**
|
|
2165
2156
|
* {{> dragSlider }}
|
|
2166
|
-
* {{ react }}
|
|
2167
2157
|
*/
|
|
2168
2158
|
async dragSlider(locator, offsetX = 0) {
|
|
2169
2159
|
const src = await this._locate(locator)
|
|
@@ -2185,7 +2175,6 @@ class Puppeteer extends Helper {
|
|
|
2185
2175
|
|
|
2186
2176
|
/**
|
|
2187
2177
|
* {{> grabAttributeFromAll }}
|
|
2188
|
-
* {{ react }}
|
|
2189
2178
|
*/
|
|
2190
2179
|
async grabAttributeFromAll(locator, attr) {
|
|
2191
2180
|
const els = await this._locate(locator)
|
|
@@ -2199,7 +2188,6 @@ class Puppeteer extends Helper {
|
|
|
2199
2188
|
|
|
2200
2189
|
/**
|
|
2201
2190
|
* {{> grabAttributeFrom }}
|
|
2202
|
-
* {{ react }}
|
|
2203
2191
|
*/
|
|
2204
2192
|
async grabAttributeFrom(locator, attr) {
|
|
2205
2193
|
const attrs = await this.grabAttributeFromAll(locator, attr)
|
|
@@ -2362,7 +2350,6 @@ class Puppeteer extends Helper {
|
|
|
2362
2350
|
|
|
2363
2351
|
/**
|
|
2364
2352
|
* {{> waitNumberOfVisibleElements }}
|
|
2365
|
-
* {{ react }}
|
|
2366
2353
|
*/
|
|
2367
2354
|
async waitNumberOfVisibleElements(locator, num, sec) {
|
|
2368
2355
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
@@ -2410,7 +2397,6 @@ class Puppeteer extends Helper {
|
|
|
2410
2397
|
|
|
2411
2398
|
/**
|
|
2412
2399
|
* {{> waitForElement }}
|
|
2413
|
-
* {{ react }}
|
|
2414
2400
|
*/
|
|
2415
2401
|
async waitForElement(locator, sec) {
|
|
2416
2402
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
@@ -2431,7 +2417,6 @@ class Puppeteer extends Helper {
|
|
|
2431
2417
|
/**
|
|
2432
2418
|
* {{> waitForVisible }}
|
|
2433
2419
|
*
|
|
2434
|
-
* {{ react }}
|
|
2435
2420
|
*/
|
|
2436
2421
|
async waitForVisible(locator, sec) {
|
|
2437
2422
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
@@ -3008,10 +2993,6 @@ export default Puppeteer
|
|
|
3008
2993
|
* @returns {Promise<Array>} Array of ElementHandle objects
|
|
3009
2994
|
*/
|
|
3010
2995
|
async function findElements(matcher, locator) {
|
|
3011
|
-
// Check if locator is a Locator object with react type, or a raw object with react property
|
|
3012
|
-
const isReactLocator = locator.type === 'react' || (locator.locator && locator.locator.react) || locator.react
|
|
3013
|
-
if (isReactLocator) return findReactElements.call(this, locator)
|
|
3014
|
-
|
|
3015
2996
|
locator = new Locator(locator, 'css')
|
|
3016
2997
|
|
|
3017
2998
|
// Check if locator is a role locator and call findByRole
|
|
@@ -3078,7 +3059,6 @@ async function findElements(matcher, locator) {
|
|
|
3078
3059
|
* @returns {Promise<Object>} Single ElementHandle object
|
|
3079
3060
|
*/
|
|
3080
3061
|
async function findElement(matcher, locator) {
|
|
3081
|
-
if (locator.react) return findReactElements.call(this, locator)
|
|
3082
3062
|
locator = new Locator(locator, 'css')
|
|
3083
3063
|
|
|
3084
3064
|
// Check if locator is a role locator and call findByRole
|
|
@@ -3564,7 +3544,7 @@ function getNormalizedKey(key) {
|
|
|
3564
3544
|
}
|
|
3565
3545
|
|
|
3566
3546
|
function highlightActiveElement(element, context) {
|
|
3567
|
-
if (this.options.highlightElement &&
|
|
3547
|
+
if (this.options.highlightElement && store.debugMode) {
|
|
3568
3548
|
highlightElement(element, context)
|
|
3569
3549
|
}
|
|
3570
3550
|
}
|
|
@@ -3577,75 +3557,6 @@ function _waitForElement(locator, options) {
|
|
|
3577
3557
|
}
|
|
3578
3558
|
}
|
|
3579
3559
|
|
|
3580
|
-
async function findReactElements(locator) {
|
|
3581
|
-
// Handle both Locator objects and raw locator objects
|
|
3582
|
-
const resolved = locator.locator ? locator.locator : toLocatorConfig(locator, 'react')
|
|
3583
|
-
this.debug(`Finding React elements: ${JSON.stringify(resolved)}`)
|
|
3584
|
-
|
|
3585
|
-
// Use createRequire to access require.resolve in ESM
|
|
3586
|
-
const { createRequire } = await import('module')
|
|
3587
|
-
const require = createRequire(import.meta.url)
|
|
3588
|
-
const resqScript = await fs.promises.readFile(require.resolve('resq'), 'utf-8')
|
|
3589
|
-
await this.page.evaluate(resqScript.toString())
|
|
3590
|
-
|
|
3591
|
-
await this.page.evaluate(() => window.resq.waitToLoadReact())
|
|
3592
|
-
const arrayHandle = await this.page.evaluateHandle(
|
|
3593
|
-
obj => {
|
|
3594
|
-
const { selector, props, state } = obj
|
|
3595
|
-
let elements = window.resq.resq$$(selector)
|
|
3596
|
-
if (Object.keys(props).length) {
|
|
3597
|
-
elements = elements.byProps(props)
|
|
3598
|
-
}
|
|
3599
|
-
if (Object.keys(state).length) {
|
|
3600
|
-
elements = elements.byState(state)
|
|
3601
|
-
}
|
|
3602
|
-
|
|
3603
|
-
if (!elements.length) {
|
|
3604
|
-
return []
|
|
3605
|
-
}
|
|
3606
|
-
|
|
3607
|
-
// resq returns an array of HTMLElements if the React component is a fragment
|
|
3608
|
-
// this avoids having nested arrays of nodes which the driver does not understand
|
|
3609
|
-
// [[div, div], [div, div]] => [div, div, div, div]
|
|
3610
|
-
let nodes = []
|
|
3611
|
-
|
|
3612
|
-
elements.forEach(element => {
|
|
3613
|
-
let { node, isFragment } = element
|
|
3614
|
-
|
|
3615
|
-
if (!node) {
|
|
3616
|
-
isFragment = true
|
|
3617
|
-
node = element.children
|
|
3618
|
-
}
|
|
3619
|
-
|
|
3620
|
-
if (isFragment) {
|
|
3621
|
-
nodes = nodes.concat(node)
|
|
3622
|
-
} else {
|
|
3623
|
-
nodes.push(node)
|
|
3624
|
-
}
|
|
3625
|
-
})
|
|
3626
|
-
|
|
3627
|
-
return [...nodes]
|
|
3628
|
-
},
|
|
3629
|
-
{
|
|
3630
|
-
selector: resolved.react,
|
|
3631
|
-
props: resolved.props || {},
|
|
3632
|
-
state: resolved.state || {},
|
|
3633
|
-
},
|
|
3634
|
-
)
|
|
3635
|
-
|
|
3636
|
-
const properties = await arrayHandle.getProperties()
|
|
3637
|
-
const result = []
|
|
3638
|
-
for (const property of properties.values()) {
|
|
3639
|
-
const elementHandle = property.asElement()
|
|
3640
|
-
if (elementHandle) {
|
|
3641
|
-
result.push(elementHandle)
|
|
3642
|
-
}
|
|
3643
|
-
}
|
|
3644
|
-
|
|
3645
|
-
await arrayHandle.dispose()
|
|
3646
|
-
return result
|
|
3647
|
-
}
|
|
3648
|
-
|
|
3649
3560
|
async function findByRole(matcher, locator) {
|
|
3650
3561
|
const resolved = toLocatorConfig(locator, 'role')
|
|
3651
3562
|
const roleSelector = buildRoleSelector(resolved)
|
package/lib/helper/WebDriver.js
CHANGED
|
@@ -10,6 +10,7 @@ import promiseRetry from 'promise-retry'
|
|
|
10
10
|
import { includes as stringIncludes } from '../assert/include.js'
|
|
11
11
|
import { urlEquals, equals } from '../assert/equal.js'
|
|
12
12
|
import store from '../store.js'
|
|
13
|
+
import { checkFocusBeforeType, checkFocusBeforePressKey } from './extras/focusCheck.js'
|
|
13
14
|
import output from '../output.js'
|
|
14
15
|
const { debug } = output
|
|
15
16
|
import { empty } from '../assert/empty.js'
|
|
@@ -41,6 +42,7 @@ import { dropFile } from './scripts/dropFile.js'
|
|
|
41
42
|
import { dontSeeTraffic, seeTraffic, grabRecordedNetworkTraffics, stopRecordingTraffic, flushNetworkTraffics } from './network/actions.js'
|
|
42
43
|
import WebElement from '../element/WebElement.js'
|
|
43
44
|
import { selectElement } from './extras/elementSelection.js'
|
|
45
|
+
import { fillRichEditor } from './extras/richTextEditor.js'
|
|
44
46
|
|
|
45
47
|
const SHADOW = 'shadow'
|
|
46
48
|
const webRoot = 'body'
|
|
@@ -95,11 +97,7 @@ const config = {}
|
|
|
95
97
|
* WebDriver helper which wraps [webdriverio](http://webdriver.io/) library to
|
|
96
98
|
* manipulate browser using Selenium WebDriver or PhantomJS.
|
|
97
99
|
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
* With the release of WebdriverIO version v8.14.0, and onwards, all driver management hassles are now a thing of the past 🙌. Read more [here](https://webdriver.io/blog/2023/07/31/driver-management/).
|
|
101
|
-
* One of the significant advantages of this update is that you can now get rid of any driver services you previously had to manage, such as
|
|
102
|
-
* `wdio-chromedriver-service`, `wdio-geckodriver-service`, `wdio-edgedriver-service`, `wdio-safaridriver-service`, and even `@wdio/selenium-standalone-service`.
|
|
100
|
+
* No Selenium Server, ChromeDriver, or GeckoDriver to install or start. Since WebdriverIO 9, driver management is fully automatic — WebdriverIO downloads and starts the matching driver for you. Read more [here](https://webdriver.io/blog/2023/07/31/driver-management/). Please check [Testing with WebDriver](https://codecept.io/webdriver/#testing-with-webdriver) for more details.
|
|
103
101
|
*
|
|
104
102
|
* For those who require custom driver options, fear not; WebDriver Helper allows you to pass in driver options through custom WebDriver configuration.
|
|
105
103
|
* If you have a custom grid, use a cloud service, or prefer to run your own driver, there's no need to worry since WebDriver Helper will only start a driver when there are no other connection information settings like hostname or port specified.
|
|
@@ -906,13 +904,6 @@ class WebDriver extends Helper {
|
|
|
906
904
|
return els
|
|
907
905
|
}
|
|
908
906
|
|
|
909
|
-
// special locator type for React
|
|
910
|
-
if (locator.react) {
|
|
911
|
-
const els = await this.browser.react$$(locator.react, locator.props || undefined, locator.state || undefined)
|
|
912
|
-
this.debugSection('Elements', `Found ${els.length} react components`)
|
|
913
|
-
return els
|
|
914
|
-
}
|
|
915
|
-
|
|
916
907
|
// special locator type for ARIA roles
|
|
917
908
|
if (locator.role) {
|
|
918
909
|
return this._locateByRole(locator)
|
|
@@ -1082,7 +1073,6 @@ class WebDriver extends Helper {
|
|
|
1082
1073
|
/**
|
|
1083
1074
|
* {{> click }}
|
|
1084
1075
|
*
|
|
1085
|
-
* {{ react }}
|
|
1086
1076
|
*/
|
|
1087
1077
|
async click(locator, context = null) {
|
|
1088
1078
|
const clickMethod = this.browser.isMobile && this.browser.capabilities.platformName !== 'android' ? 'touchClick' : 'elementClick'
|
|
@@ -1102,7 +1092,6 @@ class WebDriver extends Helper {
|
|
|
1102
1092
|
/**
|
|
1103
1093
|
* {{> forceClick }}
|
|
1104
1094
|
*
|
|
1105
|
-
* {{ react }}
|
|
1106
1095
|
*/
|
|
1107
1096
|
async forceClick(locator, context = null) {
|
|
1108
1097
|
const locateFn = prepareLocateFn.call(this, context)
|
|
@@ -1129,7 +1118,6 @@ class WebDriver extends Helper {
|
|
|
1129
1118
|
/**
|
|
1130
1119
|
* {{> doubleClick }}
|
|
1131
1120
|
*
|
|
1132
|
-
* {{ react }}
|
|
1133
1121
|
*/
|
|
1134
1122
|
async doubleClick(locator, context = null) {
|
|
1135
1123
|
const locateFn = prepareLocateFn.call(this, context)
|
|
@@ -1149,7 +1137,6 @@ class WebDriver extends Helper {
|
|
|
1149
1137
|
/**
|
|
1150
1138
|
* {{> rightClick }}
|
|
1151
1139
|
*
|
|
1152
|
-
* {{ react }}
|
|
1153
1140
|
*/
|
|
1154
1141
|
async rightClick(locator, context) {
|
|
1155
1142
|
const locateFn = prepareLocateFn.call(this, context)
|
|
@@ -1244,7 +1231,6 @@ class WebDriver extends Helper {
|
|
|
1244
1231
|
/**
|
|
1245
1232
|
* {{> forceRightClick }}
|
|
1246
1233
|
*
|
|
1247
|
-
* {{ react }}
|
|
1248
1234
|
*/
|
|
1249
1235
|
async forceRightClick(locator, context = null) {
|
|
1250
1236
|
const locateFn = prepareLocateFn.call(this, context)
|
|
@@ -1269,7 +1255,6 @@ class WebDriver extends Helper {
|
|
|
1269
1255
|
|
|
1270
1256
|
/**
|
|
1271
1257
|
* {{> fillField }}
|
|
1272
|
-
* {{ react }}
|
|
1273
1258
|
* {{ custom }}
|
|
1274
1259
|
*
|
|
1275
1260
|
*/
|
|
@@ -1278,6 +1263,11 @@ class WebDriver extends Helper {
|
|
|
1278
1263
|
assertElementExists(res, field, 'Field')
|
|
1279
1264
|
const elem = selectElement(res, field, this)
|
|
1280
1265
|
highlightActiveElement.call(this, elem)
|
|
1266
|
+
|
|
1267
|
+
if (await fillRichEditor(this, elem, value)) {
|
|
1268
|
+
return
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1281
1271
|
try {
|
|
1282
1272
|
await elem.clearValue()
|
|
1283
1273
|
} catch (err) {
|
|
@@ -1294,7 +1284,6 @@ class WebDriver extends Helper {
|
|
|
1294
1284
|
|
|
1295
1285
|
/**
|
|
1296
1286
|
* {{> appendField }}
|
|
1297
|
-
* {{ react }}
|
|
1298
1287
|
*/
|
|
1299
1288
|
async appendField(field, value, context = null) {
|
|
1300
1289
|
const res = await findFields.call(this, field, context)
|
|
@@ -1352,7 +1341,7 @@ class WebDriver extends Helper {
|
|
|
1352
1341
|
* {{> attachFile }}
|
|
1353
1342
|
*/
|
|
1354
1343
|
async attachFile(locator, pathToFile, context = null) {
|
|
1355
|
-
let file = path.join(
|
|
1344
|
+
let file = path.join(store.codeceptDir, pathToFile)
|
|
1356
1345
|
if (!fileExists(file)) {
|
|
1357
1346
|
throw new Error(`File at ${file} can not be found on local system`)
|
|
1358
1347
|
}
|
|
@@ -1592,7 +1581,6 @@ class WebDriver extends Helper {
|
|
|
1592
1581
|
/**
|
|
1593
1582
|
* {{> see }}
|
|
1594
1583
|
*
|
|
1595
|
-
* {{ react }}
|
|
1596
1584
|
*/
|
|
1597
1585
|
async see(text, context = null) {
|
|
1598
1586
|
return proceedSee.call(this, 'assert', text, context)
|
|
@@ -1608,7 +1596,6 @@ class WebDriver extends Helper {
|
|
|
1608
1596
|
/**
|
|
1609
1597
|
* {{> dontSee }}
|
|
1610
1598
|
*
|
|
1611
|
-
* {{ react }}
|
|
1612
1599
|
*/
|
|
1613
1600
|
async dontSee(text, context = null) {
|
|
1614
1601
|
return proceedSee.call(this, 'negate', text, context)
|
|
@@ -1650,7 +1637,6 @@ class WebDriver extends Helper {
|
|
|
1650
1637
|
|
|
1651
1638
|
/**
|
|
1652
1639
|
* {{> seeElement }}
|
|
1653
|
-
* {{ react }}
|
|
1654
1640
|
*
|
|
1655
1641
|
*/
|
|
1656
1642
|
async seeElement(locator, context = null) {
|
|
@@ -1667,7 +1653,6 @@ class WebDriver extends Helper {
|
|
|
1667
1653
|
|
|
1668
1654
|
/**
|
|
1669
1655
|
* {{> dontSeeElement }}
|
|
1670
|
-
* {{ react }}
|
|
1671
1656
|
*/
|
|
1672
1657
|
async dontSeeElement(locator, context = null) {
|
|
1673
1658
|
const locateFn = prepareLocateFn.call(this, context)
|
|
@@ -1752,7 +1737,6 @@ class WebDriver extends Helper {
|
|
|
1752
1737
|
|
|
1753
1738
|
/**
|
|
1754
1739
|
* {{> seeNumberOfElements }}
|
|
1755
|
-
* {{ react }}
|
|
1756
1740
|
*/
|
|
1757
1741
|
async seeNumberOfElements(locator, num) {
|
|
1758
1742
|
const res = await this._locate(locator)
|
|
@@ -1761,7 +1745,6 @@ class WebDriver extends Helper {
|
|
|
1761
1745
|
|
|
1762
1746
|
/**
|
|
1763
1747
|
* {{> seeNumberOfVisibleElements }}
|
|
1764
|
-
* {{ react }}
|
|
1765
1748
|
*/
|
|
1766
1749
|
async seeNumberOfVisibleElements(locator, num) {
|
|
1767
1750
|
const res = await this.grabNumberOfVisibleElements(locator)
|
|
@@ -2237,6 +2220,7 @@ class WebDriver extends Helper {
|
|
|
2237
2220
|
* {{> pressKeyWithKeyNormalization }}
|
|
2238
2221
|
*/
|
|
2239
2222
|
async pressKey(key) {
|
|
2223
|
+
await checkFocusBeforePressKey(this, key)
|
|
2240
2224
|
const modifiers = []
|
|
2241
2225
|
if (Array.isArray(key)) {
|
|
2242
2226
|
for (let k of key) {
|
|
@@ -2283,6 +2267,8 @@ class WebDriver extends Helper {
|
|
|
2283
2267
|
* {{> type }}
|
|
2284
2268
|
*/
|
|
2285
2269
|
async type(keys, delay = null) {
|
|
2270
|
+
await checkFocusBeforeType(this)
|
|
2271
|
+
|
|
2286
2272
|
if (!Array.isArray(keys)) {
|
|
2287
2273
|
keys = keys.toString()
|
|
2288
2274
|
keys = keys.split('')
|
|
@@ -3480,7 +3466,7 @@ function isModifierKey(key) {
|
|
|
3480
3466
|
}
|
|
3481
3467
|
|
|
3482
3468
|
function highlightActiveElement(element) {
|
|
3483
|
-
if (this.options.highlightElement &&
|
|
3469
|
+
if (this.options.highlightElement && store.debugMode) {
|
|
3484
3470
|
highlightElement(element, this.browser)
|
|
3485
3471
|
}
|
|
3486
3472
|
}
|
|
@@ -3491,9 +3477,6 @@ function prepareLocateFn(context) {
|
|
|
3491
3477
|
l = new Locator(l, 'css')
|
|
3492
3478
|
return this._locate(context, true).then(async res => {
|
|
3493
3479
|
assertElementExists(res, context, 'Context element')
|
|
3494
|
-
if (l.react) {
|
|
3495
|
-
return res[0].react$$(l.react, l.props || undefined)
|
|
3496
|
-
}
|
|
3497
3480
|
return res[0].$$(l.simplify())
|
|
3498
3481
|
})
|
|
3499
3482
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import minimatch from 'minimatch'
|
|
4
|
+
import store from '../../store.js'
|
|
5
|
+
import assert from 'assert'
|
|
6
|
+
|
|
7
|
+
function getDownloadDir() {
|
|
8
|
+
return path.join(store.outputDir, 'downloads')
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function getNewFiles(downloadDir, sinceTimestamp) {
|
|
12
|
+
if (!fs.existsSync(downloadDir)) return []
|
|
13
|
+
return fs.readdirSync(downloadDir).filter(name => {
|
|
14
|
+
const stat = fs.statSync(path.join(downloadDir, name))
|
|
15
|
+
return stat.isFile() && stat.mtimeMs >= sinceTimestamp
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function seeFileDownloaded(arg) {
|
|
20
|
+
const downloadDir = getDownloadDir()
|
|
21
|
+
const files = getNewFiles(downloadDir, this._downloadStartTimestamp)
|
|
22
|
+
|
|
23
|
+
if (arg === undefined || arg === null) {
|
|
24
|
+
assert.ok(files.length > 0, `No files downloaded to ${downloadDir}`)
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
if (typeof arg === 'number') {
|
|
28
|
+
assert.strictEqual(files.length, arg, `Expected ${arg} downloaded file(s), found ${files.length}: [${files.join(', ')}]`)
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
const regexMatch = arg.match(/^\/(.+)\/$/)
|
|
32
|
+
if (regexMatch) {
|
|
33
|
+
const re = new RegExp(regexMatch[1])
|
|
34
|
+
assert.ok(files.some(f => re.test(f)), `No file matches ${arg}. Downloaded: [${files.join(', ')}]`)
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
if (/[*?[\]]/.test(arg)) {
|
|
38
|
+
const matched = minimatch.match(files, arg)
|
|
39
|
+
assert.ok(matched.length > 0, `No file matches glob "${arg}". Downloaded: [${files.join(', ')}]`)
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
assert.ok(files.includes(arg), `File "${arg}" not downloaded. Downloaded: [${files.join(', ')}]`)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { seeFileDownloaded, getDownloadDir }
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
async function findByPlaywrightLocator(matcher, locator) {
|
|
2
|
+
const pwLocator = locator.locator || locator
|
|
3
|
+
if (pwLocator && pwLocator.toString && pwLocator.toString().includes(process.env.testIdAttribute)) {
|
|
4
|
+
return matcher.getByTestId(pwLocator.pw.value.split('=')[1])
|
|
5
|
+
}
|
|
6
|
+
const pwValue = typeof pwLocator.pw === 'string' ? pwLocator.pw : pwLocator.pw
|
|
7
|
+
return matcher.locator(pwValue).all()
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export { findByPlaywrightLocator }
|
|
@@ -9,8 +9,15 @@ function resolveElementIndex(value) {
|
|
|
9
9
|
return value
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
function isStrictStep(opts, helper) {
|
|
13
|
+
if (opts?.exact === true || opts?.strictMode === true) return true
|
|
14
|
+
if (opts?.exact === false || opts?.strictMode === false) return false
|
|
15
|
+
return helper.options.strict
|
|
16
|
+
}
|
|
17
|
+
|
|
12
18
|
function selectElement(els, locator, helper) {
|
|
13
|
-
const
|
|
19
|
+
const opts = store.currentStep?.opts
|
|
20
|
+
const rawIndex = opts?.elementIndex
|
|
14
21
|
const elementIndex = resolveElementIndex(rawIndex)
|
|
15
22
|
|
|
16
23
|
if (elementIndex != null) {
|
|
@@ -37,9 +44,9 @@ function selectElement(els, locator, helper) {
|
|
|
37
44
|
return els[idx]
|
|
38
45
|
}
|
|
39
46
|
|
|
40
|
-
if (helper
|
|
47
|
+
if (isStrictStep(opts, helper)) {
|
|
41
48
|
if (els.length > 1) {
|
|
42
|
-
const webElements = els.map(el => new WebElement(el, helper))
|
|
49
|
+
const webElements = Array.from(els).map(el => new WebElement(el, helper))
|
|
43
50
|
throw new MultipleElementsFound(locator, webElements)
|
|
44
51
|
}
|
|
45
52
|
}
|