codeceptjs 4.0.0-rc.2 → 4.0.0-rc.20
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 +39 -27
- package/bin/codecept.js +15 -2
- package/bin/codeceptq.js +49 -0
- package/bin/mcp-server.js +1187 -0
- package/docs/advanced.md +201 -0
- package/docs/agents.md +159 -0
- package/docs/ai.md +537 -0
- package/docs/aitrace.md +266 -0
- package/docs/api.md +332 -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 +230 -0
- package/docs/continuous-integration.md +497 -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 +136 -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/examples.md +161 -0
- package/docs/heal.md +213 -0
- package/docs/helpers/ApiDataFactory.md +267 -0
- package/docs/helpers/Appium.md +1405 -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/Mochawesome.md +8 -0
- package/docs/helpers/MockRequest.md +377 -0
- package/docs/helpers/MockServer.md +212 -0
- package/docs/helpers/Playwright.md +2969 -0
- package/docs/helpers/Polly.md +44 -0
- package/docs/helpers/Protractor.md +1769 -0
- package/docs/helpers/Puppeteer-firefox.md +86 -0
- package/docs/helpers/Puppeteer.md +2690 -0
- package/docs/helpers/REST.md +289 -0
- package/docs/helpers/SoftExpectHelper.md +352 -0
- package/docs/helpers/WebDriver.md +2682 -0
- package/docs/hooks.md +339 -0
- package/docs/index.md +111 -0
- package/docs/installation.md +83 -0
- package/docs/internal-api.md +265 -0
- package/docs/internal-test-server.md +89 -0
- package/docs/locators.md +355 -0
- package/docs/mcp.md +485 -0
- package/docs/migration-4.md +556 -0
- package/docs/mobile.md +338 -0
- package/docs/pageobjects.md +399 -0
- package/docs/parallel.md +585 -0
- package/docs/playwright.md +714 -0
- package/docs/plugins.md +866 -0
- package/docs/puppeteer.md +314 -0
- package/docs/quickstart.md +120 -0
- package/docs/react.md +70 -0
- package/docs/reports.md +483 -0
- package/docs/retry.md +274 -0
- package/docs/secrets.md +150 -0
- package/docs/sessions.md +80 -0
- package/docs/shadow.md +68 -0
- package/docs/test-structure.md +275 -0
- package/docs/timeouts.md +183 -0
- package/docs/translation.md +247 -0
- package/docs/tutorial.md +271 -0
- package/docs/typescript.md +374 -0
- package/docs/web-element.md +251 -0
- package/docs/webdriver.md +708 -0
- package/docs/within.md +55 -0
- package/lib/ai.js +3 -2
- package/lib/aria.js +260 -0
- package/lib/assertions.js +18 -0
- package/lib/codecept.js +26 -23
- 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 -269
- package/lib/command/list.js +150 -10
- package/lib/command/query.js +218 -0
- package/lib/command/run-multiple.js +2 -0
- package/lib/command/run-workers.js +2 -0
- package/lib/command/run.js +1 -1
- package/lib/command/workers/runTests.js +10 -10
- package/lib/config.js +77 -4
- package/lib/container.js +114 -17
- package/lib/effects.js +17 -0
- package/lib/element/WebElement.js +246 -2
- package/lib/els.js +12 -6
- package/lib/globals.js +32 -19
- package/lib/heal.js +4 -3
- package/lib/helper/ApiDataFactory.js +2 -1
- package/lib/helper/Appium.js +8 -8
- package/lib/helper/FileSystem.js +3 -2
- package/lib/helper/GraphQLDataFactory.js +2 -1
- package/lib/helper/Playwright.js +228 -162
- package/lib/helper/Puppeteer.js +208 -76
- package/lib/helper/WebDriver.js +173 -68
- package/lib/helper/errors/MultipleElementsFound.js +27 -110
- package/lib/helper/errors/NonFocusedType.js +8 -0
- package/lib/helper/extras/Download.js +45 -0
- package/lib/helper/extras/PlaywrightReactVueLocator.js +45 -36
- package/lib/helper/extras/elementSelection.js +58 -0
- package/lib/helper/extras/focusCheck.js +43 -0
- package/lib/helper/extras/richTextEditor.js +178 -0
- package/lib/helper/scripts/dropFile.js +11 -0
- package/lib/history.js +3 -2
- package/lib/html.js +103 -16
- package/lib/index.js +9 -1
- package/lib/listener/config.js +6 -4
- package/lib/listener/emptyRun.js +2 -1
- package/lib/listener/globalRetry.js +32 -6
- 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 -3
- package/lib/mocha/cli.js +14 -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 +453 -0
- package/lib/plugin/analyze.js +1 -1
- 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 +44 -1
- package/lib/plugin/pageInfo.js +53 -49
- package/lib/plugin/pause.js +131 -0
- package/lib/plugin/pauseOnFail.js +10 -34
- package/lib/plugin/retryFailedStep.js +28 -19
- package/lib/plugin/screencast.js +287 -0
- package/lib/plugin/screenshot.js +563 -0
- package/lib/plugin/screenshotOnFail.js +8 -171
- package/lib/rerun.js +2 -1
- package/lib/result.js +2 -1
- package/lib/step/base.js +3 -2
- package/lib/step/config.js +15 -2
- package/lib/step/record.js +2 -2
- 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 +77 -3
- package/lib/workers.js +52 -22
- package/package.json +19 -13
- package/typings/index.d.ts +19 -5
- package/docs/webapi/amOnPage.mustache +0 -11
- package/docs/webapi/appendField.mustache +0 -11
- package/docs/webapi/attachFile.mustache +0 -12
- 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 -9
- 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 -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/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 -16
- 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 -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/seeCurrentPathEquals.mustache +0 -10
- 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/seeTraffic.mustache +0 -36
- package/docs/webapi/selectOption.mustache +0 -21
- 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/listener/enhancedGlobalRetry.js +0 -110
- package/lib/plugin/enhancedRetryFailedStep.js +0 -99
- package/lib/plugin/htmlReporter.js +0 -3648
- package/lib/plugin/stepByStepReport.js +0 -427
- package/lib/plugin/subtitles.js +0 -89
- package/lib/retryCoordinator.js +0 -207
- package/typings/promiseBasedTypes.d.ts +0 -9469
- package/typings/types.d.ts +0 -11402
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'
|
|
@@ -26,17 +27,25 @@ import {
|
|
|
26
27
|
isModifierKey,
|
|
27
28
|
requireWithFallback,
|
|
28
29
|
normalizeSpacesInString,
|
|
30
|
+
normalizePath,
|
|
31
|
+
resolveUrl,
|
|
32
|
+
getMimeType,
|
|
33
|
+
base64EncodeFile,
|
|
29
34
|
} from '../utils.js'
|
|
30
35
|
import { isColorProperty, convertColorToRGBA } from '../colorUtils.js'
|
|
31
36
|
import ElementNotFound from './errors/ElementNotFound.js'
|
|
37
|
+
import MultipleElementsFound from './errors/MultipleElementsFound.js'
|
|
32
38
|
import RemoteBrowserConnectionRefused from './errors/RemoteBrowserConnectionRefused.js'
|
|
33
39
|
import Popup from './extras/Popup.js'
|
|
34
40
|
import Console from './extras/Console.js'
|
|
35
41
|
import { highlightElement } from './scripts/highlightElement.js'
|
|
36
42
|
import { blurElement } from './scripts/blurElement.js'
|
|
43
|
+
import { dropFile } from './scripts/dropFile.js'
|
|
37
44
|
import { dontSeeElementError, seeElementError, dontSeeElementInDOMError, seeElementInDOMError } from './errors/ElementAssertion.js'
|
|
38
45
|
import { dontSeeTraffic, seeTraffic, grabRecordedNetworkTraffics, stopRecordingTraffic, flushNetworkTraffics } from './network/actions.js'
|
|
39
46
|
import WebElement from '../element/WebElement.js'
|
|
47
|
+
import { selectElement } from './extras/elementSelection.js'
|
|
48
|
+
import { fillRichEditor } from './extras/richTextEditor.js'
|
|
40
49
|
|
|
41
50
|
let puppeteer
|
|
42
51
|
|
|
@@ -266,6 +275,7 @@ class Puppeteer extends Helper {
|
|
|
266
275
|
show: false,
|
|
267
276
|
defaultPopupAction: 'accept',
|
|
268
277
|
highlightElement: false,
|
|
278
|
+
strict: false,
|
|
269
279
|
}
|
|
270
280
|
|
|
271
281
|
return Object.assign(defaults, config)
|
|
@@ -743,7 +753,7 @@ class Puppeteer extends Helper {
|
|
|
743
753
|
}
|
|
744
754
|
|
|
745
755
|
if (this.options.trace) {
|
|
746
|
-
const fileName = `${`${
|
|
756
|
+
const fileName = `${`${store.outputDir}${path.sep}trace${path.sep}${uuidv4()}_${clearString(this.currentRunningTest.title)}`.slice(0, 245)}.json`
|
|
747
757
|
const dir = path.dirname(fileName)
|
|
748
758
|
if (!fileExists(dir)) fs.mkdirSync(dir)
|
|
749
759
|
await this.page.tracing.start({ screenshots: true, path: fileName })
|
|
@@ -814,9 +824,26 @@ class Puppeteer extends Helper {
|
|
|
814
824
|
* {{ react }}
|
|
815
825
|
*/
|
|
816
826
|
async moveCursorTo(locator, offsetX = 0, offsetY = 0) {
|
|
817
|
-
|
|
818
|
-
if (
|
|
819
|
-
|
|
827
|
+
let context = null
|
|
828
|
+
if (typeof offsetX !== 'number') {
|
|
829
|
+
context = offsetX
|
|
830
|
+
offsetX = 0
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
let el
|
|
834
|
+
if (context) {
|
|
835
|
+
const contextEls = await findElements.call(this, this.page, context)
|
|
836
|
+
assertElementExists(contextEls, context, 'Context element')
|
|
837
|
+
const els = await findElements.call(this, contextEls[0], locator)
|
|
838
|
+
if (!els || els.length === 0) {
|
|
839
|
+
throw new ElementNotFound(locator, 'Element to move cursor to')
|
|
840
|
+
}
|
|
841
|
+
el = els[0]
|
|
842
|
+
} else {
|
|
843
|
+
el = await this._locateElement(locator)
|
|
844
|
+
if (!el) {
|
|
845
|
+
throw new ElementNotFound(locator, 'Element to move cursor to')
|
|
846
|
+
}
|
|
820
847
|
}
|
|
821
848
|
|
|
822
849
|
// Use manual mouse.move instead of .hover() so the offset can be added to the coordinates
|
|
@@ -984,6 +1011,14 @@ class Puppeteer extends Helper {
|
|
|
984
1011
|
*/
|
|
985
1012
|
async _locateElement(locator) {
|
|
986
1013
|
const context = await this.context
|
|
1014
|
+
const elementIndex = store.currentStep?.opts?.elementIndex
|
|
1015
|
+
if (this.options.strict || elementIndex) {
|
|
1016
|
+
const elements = await findElements.call(this, context, locator)
|
|
1017
|
+
if (elements.length === 0) {
|
|
1018
|
+
throw new ElementNotFound(locator, 'Element', 'was not found')
|
|
1019
|
+
}
|
|
1020
|
+
return selectElement(elements, locator, this)
|
|
1021
|
+
}
|
|
987
1022
|
return findElement.call(this, context, locator)
|
|
988
1023
|
}
|
|
989
1024
|
|
|
@@ -1001,7 +1036,7 @@ class Puppeteer extends Helper {
|
|
|
1001
1036
|
if (!els || els.length === 0) {
|
|
1002
1037
|
throw new ElementNotFound(locator, 'Checkbox or radio')
|
|
1003
1038
|
}
|
|
1004
|
-
return els
|
|
1039
|
+
return selectElement(els, locator, this)
|
|
1005
1040
|
}
|
|
1006
1041
|
|
|
1007
1042
|
/**
|
|
@@ -1158,8 +1193,16 @@ class Puppeteer extends Helper {
|
|
|
1158
1193
|
* {{> seeElement }}
|
|
1159
1194
|
* {{ react }}
|
|
1160
1195
|
*/
|
|
1161
|
-
async seeElement(locator) {
|
|
1162
|
-
let els
|
|
1196
|
+
async seeElement(locator, context = null) {
|
|
1197
|
+
let els
|
|
1198
|
+
if (context) {
|
|
1199
|
+
const contextPage = await this.context
|
|
1200
|
+
const contextEls = await findElements.call(this, contextPage, context)
|
|
1201
|
+
assertElementExists(contextEls, context, 'Context element')
|
|
1202
|
+
els = await findElements.call(this, contextEls[0], locator)
|
|
1203
|
+
} else {
|
|
1204
|
+
els = await this._locate(locator)
|
|
1205
|
+
}
|
|
1163
1206
|
els = (await Promise.all(els.map(el => el.boundingBox() && el))).filter(v => v)
|
|
1164
1207
|
// Puppeteer visibility was ignored? | Remove when Puppeteer is fixed
|
|
1165
1208
|
els = await Promise.all(els.map(async el => (await el.evaluate(node => window.getComputedStyle(node).visibility !== 'hidden' && window.getComputedStyle(node).display !== 'none')) && el))
|
|
@@ -1174,8 +1217,16 @@ class Puppeteer extends Helper {
|
|
|
1174
1217
|
* {{> dontSeeElement }}
|
|
1175
1218
|
* {{ react }}
|
|
1176
1219
|
*/
|
|
1177
|
-
async dontSeeElement(locator) {
|
|
1178
|
-
let els
|
|
1220
|
+
async dontSeeElement(locator, context = null) {
|
|
1221
|
+
let els
|
|
1222
|
+
if (context) {
|
|
1223
|
+
const contextPage = await this.context
|
|
1224
|
+
const contextEls = await findElements.call(this, contextPage, context)
|
|
1225
|
+
assertElementExists(contextEls, context, 'Context element')
|
|
1226
|
+
els = await findElements.call(this, contextEls[0], locator)
|
|
1227
|
+
} else {
|
|
1228
|
+
els = await this._locate(locator)
|
|
1229
|
+
}
|
|
1179
1230
|
els = (await Promise.all(els.map(el => el.boundingBox() && el))).filter(v => v)
|
|
1180
1231
|
// Puppeteer visibility was ignored? | Remove when Puppeteer is fixed
|
|
1181
1232
|
els = await Promise.all(els.map(async el => (await el.evaluate(node => window.getComputedStyle(node).visibility !== 'hidden' && window.getComputedStyle(node).display !== 'none')) && el))
|
|
@@ -1276,7 +1327,7 @@ class Puppeteer extends Helper {
|
|
|
1276
1327
|
* @param {string} [downloadPath='downloads'] change this parameter to set another directory for saving
|
|
1277
1328
|
*/
|
|
1278
1329
|
async handleDownloads(downloadPath = 'downloads') {
|
|
1279
|
-
downloadPath = path.join(
|
|
1330
|
+
downloadPath = path.join(store.outputDir, downloadPath)
|
|
1280
1331
|
if (!fs.existsSync(downloadPath)) {
|
|
1281
1332
|
fs.mkdirSync(downloadPath, '0777')
|
|
1282
1333
|
}
|
|
@@ -1338,7 +1389,7 @@ class Puppeteer extends Helper {
|
|
|
1338
1389
|
},
|
|
1339
1390
|
})
|
|
1340
1391
|
|
|
1341
|
-
const outputFile = path.join(`${
|
|
1392
|
+
const outputFile = path.join(`${store.outputDir}/${fileName}`)
|
|
1342
1393
|
|
|
1343
1394
|
try {
|
|
1344
1395
|
await new Promise((resolve, reject) => {
|
|
@@ -1498,6 +1549,7 @@ class Puppeteer extends Helper {
|
|
|
1498
1549
|
* {{> pressKeyWithKeyNormalization }}
|
|
1499
1550
|
*/
|
|
1500
1551
|
async pressKey(key) {
|
|
1552
|
+
await checkFocusBeforePressKey(this, key)
|
|
1501
1553
|
const modifiers = []
|
|
1502
1554
|
if (Array.isArray(key)) {
|
|
1503
1555
|
for (let k of key) {
|
|
@@ -1526,6 +1578,8 @@ class Puppeteer extends Helper {
|
|
|
1526
1578
|
* {{> type }}
|
|
1527
1579
|
*/
|
|
1528
1580
|
async type(keys, delay = null) {
|
|
1581
|
+
await checkFocusBeforeType(this)
|
|
1582
|
+
|
|
1529
1583
|
if (!Array.isArray(keys)) {
|
|
1530
1584
|
keys = keys.toString()
|
|
1531
1585
|
keys = keys.split('')
|
|
@@ -1541,10 +1595,19 @@ class Puppeteer extends Helper {
|
|
|
1541
1595
|
* {{> fillField }}
|
|
1542
1596
|
* {{ react }}
|
|
1543
1597
|
*/
|
|
1544
|
-
async fillField(field, value) {
|
|
1545
|
-
|
|
1598
|
+
async fillField(field, value, context = null) {
|
|
1599
|
+
let els = await findVisibleFields.call(this, field, context)
|
|
1600
|
+
if (!els.length) {
|
|
1601
|
+
els = await findFields.call(this, field, context)
|
|
1602
|
+
}
|
|
1546
1603
|
assertElementExists(els, field, 'Field')
|
|
1547
|
-
const el = els
|
|
1604
|
+
const el = selectElement(els, field, this)
|
|
1605
|
+
|
|
1606
|
+
if (await fillRichEditor(this, el, value)) {
|
|
1607
|
+
highlightActiveElement.call(this, el, await this._getContext())
|
|
1608
|
+
return this._waitForAction()
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1548
1611
|
const tag = await el.getProperty('tagName').then(el => el.jsonValue())
|
|
1549
1612
|
const editable = await el.getProperty('contenteditable').then(el => el.jsonValue())
|
|
1550
1613
|
if (tag === 'INPUT' || tag === 'TEXTAREA') {
|
|
@@ -1562,8 +1625,8 @@ class Puppeteer extends Helper {
|
|
|
1562
1625
|
/**
|
|
1563
1626
|
* {{> clearField }}
|
|
1564
1627
|
*/
|
|
1565
|
-
async clearField(field) {
|
|
1566
|
-
return this.fillField(field, '')
|
|
1628
|
+
async clearField(field, context = null) {
|
|
1629
|
+
return this.fillField(field, '', context)
|
|
1567
1630
|
}
|
|
1568
1631
|
|
|
1569
1632
|
/**
|
|
@@ -1571,29 +1634,30 @@ class Puppeteer extends Helper {
|
|
|
1571
1634
|
*
|
|
1572
1635
|
* {{ react }}
|
|
1573
1636
|
*/
|
|
1574
|
-
async appendField(field, value) {
|
|
1575
|
-
const els = await findVisibleFields.call(this, field)
|
|
1637
|
+
async appendField(field, value, context = null) {
|
|
1638
|
+
const els = await findVisibleFields.call(this, field, context)
|
|
1576
1639
|
assertElementExists(els, field, 'Field')
|
|
1577
|
-
|
|
1578
|
-
await
|
|
1579
|
-
await
|
|
1640
|
+
const el = selectElement(els, field, this)
|
|
1641
|
+
highlightActiveElement.call(this, el, await this._getContext())
|
|
1642
|
+
await el.press('End')
|
|
1643
|
+
await el.type(value.toString(), { delay: this.options.pressKeyDelay })
|
|
1580
1644
|
return this._waitForAction()
|
|
1581
1645
|
}
|
|
1582
1646
|
|
|
1583
1647
|
/**
|
|
1584
1648
|
* {{> seeInField }}
|
|
1585
1649
|
*/
|
|
1586
|
-
async seeInField(field, value) {
|
|
1650
|
+
async seeInField(field, value, context = null) {
|
|
1587
1651
|
const _value = typeof value === 'boolean' ? value : value.toString()
|
|
1588
|
-
return proceedSeeInField.call(this, 'assert', field, _value)
|
|
1652
|
+
return proceedSeeInField.call(this, 'assert', field, _value, context)
|
|
1589
1653
|
}
|
|
1590
1654
|
|
|
1591
1655
|
/**
|
|
1592
1656
|
* {{> dontSeeInField }}
|
|
1593
1657
|
*/
|
|
1594
|
-
async dontSeeInField(field, value) {
|
|
1658
|
+
async dontSeeInField(field, value, context = null) {
|
|
1595
1659
|
const _value = typeof value === 'boolean' ? value : value.toString()
|
|
1596
|
-
return proceedSeeInField.call(this, 'negate', field, _value)
|
|
1660
|
+
return proceedSeeInField.call(this, 'negate', field, _value, context)
|
|
1597
1661
|
}
|
|
1598
1662
|
|
|
1599
1663
|
/**
|
|
@@ -1601,46 +1665,71 @@ class Puppeteer extends Helper {
|
|
|
1601
1665
|
*
|
|
1602
1666
|
* {{> attachFile }}
|
|
1603
1667
|
*/
|
|
1604
|
-
async attachFile(locator, pathToFile) {
|
|
1605
|
-
const file = path.join(
|
|
1668
|
+
async attachFile(locator, pathToFile, context = null) {
|
|
1669
|
+
const file = path.join(store.codeceptDir, pathToFile)
|
|
1606
1670
|
|
|
1607
1671
|
if (!fileExists(file)) {
|
|
1608
1672
|
throw new Error(`File at ${file} can not be found on local system`)
|
|
1609
1673
|
}
|
|
1610
|
-
const els = await findFields.call(this, locator)
|
|
1611
|
-
|
|
1612
|
-
|
|
1674
|
+
const els = await findFields.call(this, locator, context)
|
|
1675
|
+
if (els.length) {
|
|
1676
|
+
const el = selectElement(els, locator, this)
|
|
1677
|
+
const tag = await el.evaluate(el => el.tagName)
|
|
1678
|
+
const type = await el.evaluate(el => el.type)
|
|
1679
|
+
if (tag === 'INPUT' && type === 'file') {
|
|
1680
|
+
await el.uploadFile(file)
|
|
1681
|
+
return this._waitForAction()
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
const targetEls = els.length ? els : await this._locate(locator)
|
|
1686
|
+
assertElementExists(targetEls, locator, 'Element')
|
|
1687
|
+
const el = selectElement(targetEls, locator, this)
|
|
1688
|
+
const fileData = {
|
|
1689
|
+
base64Content: base64EncodeFile(file),
|
|
1690
|
+
fileName: path.basename(file),
|
|
1691
|
+
mimeType: getMimeType(path.basename(file)),
|
|
1692
|
+
}
|
|
1693
|
+
await el.evaluate(dropFile, fileData)
|
|
1613
1694
|
return this._waitForAction()
|
|
1614
1695
|
}
|
|
1615
1696
|
|
|
1616
1697
|
/**
|
|
1617
1698
|
* {{> selectOption }}
|
|
1618
1699
|
*/
|
|
1619
|
-
async selectOption(select, option) {
|
|
1620
|
-
const
|
|
1700
|
+
async selectOption(select, option, context = null) {
|
|
1701
|
+
const pageContext = await this._getContext()
|
|
1621
1702
|
const matchedLocator = new Locator(select)
|
|
1622
1703
|
|
|
1704
|
+
let contextEl
|
|
1705
|
+
if (context) {
|
|
1706
|
+
const contextEls = await findElements.call(this, pageContext, context)
|
|
1707
|
+
assertElementExists(contextEls, context, 'Context element')
|
|
1708
|
+
contextEl = contextEls[0]
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1623
1711
|
// Strict locator
|
|
1624
1712
|
if (!matchedLocator.isFuzzy()) {
|
|
1625
1713
|
this.debugSection('SelectOption', `Strict: ${JSON.stringify(select)}`)
|
|
1626
|
-
const els = await this._locate(select)
|
|
1714
|
+
const els = contextEl ? await findElements.call(this, contextEl, select) : await this._locate(select)
|
|
1627
1715
|
assertElementExists(els, select, 'Selectable element')
|
|
1628
|
-
return proceedSelect.call(this,
|
|
1716
|
+
return proceedSelect.call(this, pageContext, selectElement(els, select, this), option)
|
|
1629
1717
|
}
|
|
1630
1718
|
|
|
1631
1719
|
// Fuzzy: try combobox
|
|
1632
1720
|
this.debugSection('SelectOption', `Fuzzy: "${matchedLocator.value}"`)
|
|
1633
|
-
|
|
1634
|
-
|
|
1721
|
+
const comboboxSearchCtx = contextEl || pageContext
|
|
1722
|
+
let els = await findByRole(comboboxSearchCtx, { role: 'combobox', name: matchedLocator.value })
|
|
1723
|
+
if (els?.length) return proceedSelect.call(this, pageContext, selectElement(els, select, this), option)
|
|
1635
1724
|
|
|
1636
1725
|
// Fuzzy: try listbox
|
|
1637
|
-
els = await findByRole(
|
|
1638
|
-
if (els?.length) return proceedSelect.call(this,
|
|
1726
|
+
els = await findByRole(comboboxSearchCtx, { role: 'listbox', name: matchedLocator.value })
|
|
1727
|
+
if (els?.length) return proceedSelect.call(this, pageContext, selectElement(els, select, this), option)
|
|
1639
1728
|
|
|
1640
1729
|
// Fuzzy: try native select
|
|
1641
|
-
const visibleEls = await findVisibleFields.call(this, select)
|
|
1730
|
+
const visibleEls = await findVisibleFields.call(this, select, context)
|
|
1642
1731
|
assertElementExists(visibleEls, select, 'Selectable field')
|
|
1643
|
-
return proceedSelect.call(this,
|
|
1732
|
+
return proceedSelect.call(this, pageContext, selectElement(visibleEls, select, this), option)
|
|
1644
1733
|
}
|
|
1645
1734
|
|
|
1646
1735
|
/**
|
|
@@ -1691,7 +1780,7 @@ class Puppeteer extends Helper {
|
|
|
1691
1780
|
const currentUrl = await this._getPageUrl()
|
|
1692
1781
|
const baseUrl = this.options.url || 'http://localhost'
|
|
1693
1782
|
const actualPath = new URL(currentUrl, baseUrl).pathname
|
|
1694
|
-
return equals('url path').assert(path, actualPath)
|
|
1783
|
+
return equals('url path').assert(normalizePath(path), normalizePath(actualPath))
|
|
1695
1784
|
}
|
|
1696
1785
|
|
|
1697
1786
|
/**
|
|
@@ -1701,7 +1790,7 @@ class Puppeteer extends Helper {
|
|
|
1701
1790
|
const currentUrl = await this._getPageUrl()
|
|
1702
1791
|
const baseUrl = this.options.url || 'http://localhost'
|
|
1703
1792
|
const actualPath = new URL(currentUrl, baseUrl).pathname
|
|
1704
|
-
return equals('url path').negate(path, actualPath)
|
|
1793
|
+
return equals('url path').negate(normalizePath(path), normalizePath(actualPath))
|
|
1705
1794
|
}
|
|
1706
1795
|
|
|
1707
1796
|
/**
|
|
@@ -2441,6 +2530,7 @@ class Puppeteer extends Helper {
|
|
|
2441
2530
|
*/
|
|
2442
2531
|
async waitInUrl(urlPart, sec = null) {
|
|
2443
2532
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
2533
|
+
const expectedUrl = resolveUrl(urlPart, this.options.url)
|
|
2444
2534
|
|
|
2445
2535
|
return this.page
|
|
2446
2536
|
.waitForFunction(
|
|
@@ -2449,12 +2539,12 @@ class Puppeteer extends Helper {
|
|
|
2449
2539
|
return currUrl.indexOf(urlPart) > -1
|
|
2450
2540
|
},
|
|
2451
2541
|
{ timeout: waitTimeout },
|
|
2452
|
-
|
|
2542
|
+
expectedUrl,
|
|
2453
2543
|
)
|
|
2454
2544
|
.catch(async e => {
|
|
2455
|
-
const currUrl = await this._getPageUrl()
|
|
2545
|
+
const currUrl = await this._getPageUrl()
|
|
2456
2546
|
if (/Waiting failed:/i.test(e.message) || /failed: timeout/i.test(e.message)) {
|
|
2457
|
-
throw new Error(`expected url to include ${
|
|
2547
|
+
throw new Error(`expected url to include ${expectedUrl}, but found ${currUrl}`)
|
|
2458
2548
|
} else {
|
|
2459
2549
|
throw e
|
|
2460
2550
|
}
|
|
@@ -2466,18 +2556,13 @@ class Puppeteer extends Helper {
|
|
|
2466
2556
|
*/
|
|
2467
2557
|
async waitUrlEquals(urlPart, sec = null) {
|
|
2468
2558
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
2469
|
-
|
|
2470
|
-
const baseUrl = this.options.url
|
|
2471
|
-
let expectedUrl = urlPart
|
|
2472
|
-
if (urlPart.indexOf('http') < 0) {
|
|
2473
|
-
expectedUrl = baseUrl + urlPart
|
|
2474
|
-
}
|
|
2559
|
+
const expectedUrl = resolveUrl(urlPart, this.options.url)
|
|
2475
2560
|
|
|
2476
2561
|
return this.page
|
|
2477
2562
|
.waitForFunction(
|
|
2478
2563
|
url => {
|
|
2479
2564
|
const currUrl = decodeURIComponent(window.location.href)
|
|
2480
|
-
return currUrl
|
|
2565
|
+
return currUrl === url
|
|
2481
2566
|
},
|
|
2482
2567
|
{ timeout: waitTimeout },
|
|
2483
2568
|
expectedUrl,
|
|
@@ -2485,11 +2570,36 @@ class Puppeteer extends Helper {
|
|
|
2485
2570
|
.catch(async e => {
|
|
2486
2571
|
const currUrl = await this._getPageUrl()
|
|
2487
2572
|
if (/Waiting failed/i.test(e.message) || /failed: timeout/i.test(e.message)) {
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2573
|
+
throw new Error(`expected url to be ${expectedUrl}, but found ${currUrl}`)
|
|
2574
|
+
} else {
|
|
2575
|
+
throw e
|
|
2576
|
+
}
|
|
2577
|
+
})
|
|
2578
|
+
}
|
|
2579
|
+
|
|
2580
|
+
/**
|
|
2581
|
+
* {{> waitCurrentPathEquals }}
|
|
2582
|
+
*/
|
|
2583
|
+
async waitCurrentPathEquals(path, sec = null) {
|
|
2584
|
+
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
2585
|
+
const normalizedPath = normalizePath(path)
|
|
2586
|
+
|
|
2587
|
+
return this.page
|
|
2588
|
+
.waitForFunction(
|
|
2589
|
+
expectedPath => {
|
|
2590
|
+
const actualPath = window.location.pathname
|
|
2591
|
+
const normalizePath = p => (p === '' || p === '/' ? '/' : p.replace(/\/+/g, '/').replace(/\/$/, '') || '/')
|
|
2592
|
+
return normalizePath(actualPath) === expectedPath
|
|
2593
|
+
},
|
|
2594
|
+
{ timeout: waitTimeout },
|
|
2595
|
+
normalizedPath,
|
|
2596
|
+
)
|
|
2597
|
+
.catch(async e => {
|
|
2598
|
+
const currUrl = await this._getPageUrl()
|
|
2599
|
+
const baseUrl = this.options.url || 'http://localhost'
|
|
2600
|
+
const actualPath = new URL(currUrl, baseUrl).pathname
|
|
2601
|
+
if (/Waiting failed/i.test(e.message) || /failed: timeout/i.test(e.message)) {
|
|
2602
|
+
throw new Error(`expected path to be ${normalizedPath}, but found ${normalizePath(actualPath)}`)
|
|
2493
2603
|
} else {
|
|
2494
2604
|
throw e
|
|
2495
2605
|
}
|
|
@@ -3026,10 +3136,11 @@ async function proceedClick(locator, context = null, options = {}) {
|
|
|
3026
3136
|
} else {
|
|
3027
3137
|
assertElementExists(els, locator, 'Clickable element')
|
|
3028
3138
|
}
|
|
3139
|
+
const el = selectElement(els, locator, this)
|
|
3029
3140
|
|
|
3030
|
-
highlightActiveElement.call(this,
|
|
3141
|
+
highlightActiveElement.call(this, el, await this._getContext())
|
|
3031
3142
|
|
|
3032
|
-
await
|
|
3143
|
+
await el.click(options)
|
|
3033
3144
|
const promises = []
|
|
3034
3145
|
if (options.waitForNavigation) {
|
|
3035
3146
|
promises.push(this.waitForNavigation())
|
|
@@ -3160,43 +3271,57 @@ async function proceedIsChecked(assertType, option) {
|
|
|
3160
3271
|
return truth(`checkable ${option}`, 'to be checked')[assertType](selected)
|
|
3161
3272
|
}
|
|
3162
3273
|
|
|
3163
|
-
async function findVisibleFields(locator) {
|
|
3164
|
-
const els = await findFields.call(this, locator)
|
|
3274
|
+
async function findVisibleFields(locator, context = null) {
|
|
3275
|
+
const els = await findFields.call(this, locator, context)
|
|
3165
3276
|
const visible = await Promise.all(els.map(el => el.boundingBox()))
|
|
3166
3277
|
return els.filter((el, index) => visible[index])
|
|
3167
3278
|
}
|
|
3168
3279
|
|
|
3169
|
-
async function findFields(locator) {
|
|
3280
|
+
async function findFields(locator, context = null) {
|
|
3281
|
+
let contextEl
|
|
3282
|
+
if (context) {
|
|
3283
|
+
const contextPage = await this.context
|
|
3284
|
+
const contextEls = await findElements.call(this, contextPage, context)
|
|
3285
|
+
assertElementExists(contextEls, context, 'Context element')
|
|
3286
|
+
contextEl = contextEls[0]
|
|
3287
|
+
}
|
|
3288
|
+
|
|
3289
|
+
const locateFn = contextEl
|
|
3290
|
+
? loc => findElements.call(this, contextEl, loc)
|
|
3291
|
+
: loc => this._locate(loc)
|
|
3292
|
+
|
|
3170
3293
|
const matchedLocator = new Locator(locator)
|
|
3171
3294
|
if (!matchedLocator.isFuzzy()) {
|
|
3172
|
-
return
|
|
3295
|
+
return locateFn(matchedLocator)
|
|
3173
3296
|
}
|
|
3174
3297
|
const literal = xpathLocator.literal(matchedLocator.value)
|
|
3175
3298
|
|
|
3176
|
-
let els = await
|
|
3299
|
+
let els = await locateFn({ xpath: Locator.field.labelEquals(literal) })
|
|
3177
3300
|
if (els.length) {
|
|
3178
3301
|
return els
|
|
3179
3302
|
}
|
|
3180
3303
|
|
|
3181
|
-
els = await
|
|
3304
|
+
els = await locateFn({ xpath: Locator.field.labelContains(literal) })
|
|
3182
3305
|
if (els.length) {
|
|
3183
3306
|
return els
|
|
3184
3307
|
}
|
|
3185
|
-
els = await
|
|
3308
|
+
els = await locateFn({ xpath: Locator.field.byName(literal) })
|
|
3186
3309
|
if (els.length) {
|
|
3187
3310
|
return els
|
|
3188
3311
|
}
|
|
3189
3312
|
|
|
3190
3313
|
// Try ARIA selector for accessible name
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3314
|
+
if (!contextEl) {
|
|
3315
|
+
try {
|
|
3316
|
+
const page = await this.context
|
|
3317
|
+
els = await page.$$(`::-p-aria(${matchedLocator.value})`)
|
|
3318
|
+
if (els.length) return els
|
|
3319
|
+
} catch (err) {
|
|
3320
|
+
// ARIA selector not supported or failed
|
|
3321
|
+
}
|
|
3197
3322
|
}
|
|
3198
3323
|
|
|
3199
|
-
return
|
|
3324
|
+
return locateFn({ css: matchedLocator.value })
|
|
3200
3325
|
}
|
|
3201
3326
|
|
|
3202
3327
|
async function proceedDragAndDrop(sourceLocator, destinationLocator) {
|
|
@@ -3225,8 +3350,8 @@ async function proceedDragAndDrop(sourceLocator, destinationLocator) {
|
|
|
3225
3350
|
await this._waitForAction()
|
|
3226
3351
|
}
|
|
3227
3352
|
|
|
3228
|
-
async function proceedSeeInField(assertType, field, value) {
|
|
3229
|
-
const els = await findVisibleFields.call(this, field)
|
|
3353
|
+
async function proceedSeeInField(assertType, field, value, context) {
|
|
3354
|
+
const els = await findVisibleFields.call(this, field, context)
|
|
3230
3355
|
assertElementExists(els, field, 'Field')
|
|
3231
3356
|
const el = els[0]
|
|
3232
3357
|
const tag = await el.getProperty('tagName').then(el => el.jsonValue())
|
|
@@ -3339,6 +3464,13 @@ function assertElementExists(res, locator, prefix, suffix) {
|
|
|
3339
3464
|
}
|
|
3340
3465
|
}
|
|
3341
3466
|
|
|
3467
|
+
function assertOnlyOneElement(elements, locator, helper) {
|
|
3468
|
+
if (elements.length > 1) {
|
|
3469
|
+
const webElements = elements.map(el => new WebElement(el, helper))
|
|
3470
|
+
throw new MultipleElementsFound(locator, webElements)
|
|
3471
|
+
}
|
|
3472
|
+
}
|
|
3473
|
+
|
|
3342
3474
|
function $XPath(element, selector) {
|
|
3343
3475
|
const found = document.evaluate(selector, element || document.body, null, 5, null)
|
|
3344
3476
|
const res = []
|
|
@@ -3446,7 +3578,7 @@ function getNormalizedKey(key) {
|
|
|
3446
3578
|
}
|
|
3447
3579
|
|
|
3448
3580
|
function highlightActiveElement(element, context) {
|
|
3449
|
-
if (this.options.highlightElement &&
|
|
3581
|
+
if (this.options.highlightElement && store.debugMode) {
|
|
3450
3582
|
highlightElement(element, context)
|
|
3451
3583
|
}
|
|
3452
3584
|
}
|