codeceptjs 3.6.10 → 3.7.0-beta.10
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 +89 -119
- package/bin/codecept.js +9 -2
- package/docs/webapi/clearCookie.mustache +1 -1
- package/lib/actor.js +66 -102
- package/lib/ai.js +130 -121
- package/lib/assert/empty.js +3 -5
- package/lib/assert/equal.js +4 -7
- package/lib/assert/include.js +4 -6
- package/lib/assert/throws.js +2 -4
- package/lib/assert/truth.js +2 -2
- package/lib/codecept.js +87 -83
- package/lib/command/check.js +186 -0
- package/lib/command/configMigrate.js +2 -4
- package/lib/command/definitions.js +8 -26
- package/lib/command/generate.js +10 -14
- package/lib/command/gherkin/snippets.js +10 -8
- package/lib/command/gherkin/steps.js +1 -1
- package/lib/command/info.js +1 -3
- package/lib/command/init.js +8 -12
- package/lib/command/interactive.js +2 -2
- package/lib/command/list.js +1 -1
- package/lib/command/run-multiple.js +12 -35
- package/lib/command/run-workers.js +5 -57
- package/lib/command/utils.js +5 -6
- package/lib/command/workers/runTests.js +68 -232
- package/lib/container.js +354 -237
- package/lib/data/context.js +10 -13
- package/lib/data/dataScenarioConfig.js +8 -8
- package/lib/data/dataTableArgument.js +6 -6
- package/lib/data/table.js +5 -11
- package/lib/effects.js +218 -0
- package/lib/els.js +158 -0
- package/lib/event.js +19 -17
- package/lib/heal.js +88 -80
- package/lib/helper/AI.js +2 -1
- package/lib/helper/ApiDataFactory.js +3 -6
- package/lib/helper/Appium.js +45 -51
- package/lib/helper/FileSystem.js +3 -3
- package/lib/helper/GraphQLDataFactory.js +3 -3
- package/lib/helper/JSONResponse.js +57 -37
- package/lib/helper/Nightmare.js +35 -53
- package/lib/helper/Playwright.js +211 -252
- package/lib/helper/Protractor.js +54 -77
- package/lib/helper/Puppeteer.js +139 -232
- package/lib/helper/REST.js +5 -17
- package/lib/helper/TestCafe.js +21 -44
- package/lib/helper/WebDriver.js +131 -169
- package/lib/helper/testcafe/testcafe-utils.js +26 -27
- package/lib/listener/emptyRun.js +55 -0
- package/lib/listener/exit.js +7 -10
- package/lib/listener/{retry.js → globalRetry.js} +5 -5
- package/lib/listener/globalTimeout.js +165 -0
- package/lib/listener/helpers.js +15 -15
- package/lib/listener/mocha.js +1 -1
- package/lib/listener/result.js +12 -0
- package/lib/listener/steps.js +20 -18
- package/lib/listener/store.js +20 -0
- package/lib/mocha/asyncWrapper.js +216 -0
- package/lib/{interfaces → mocha}/bdd.js +3 -3
- package/lib/mocha/cli.js +308 -0
- package/lib/mocha/factory.js +104 -0
- package/lib/{interfaces → mocha}/featureConfig.js +24 -12
- package/lib/{interfaces → mocha}/gherkin.js +26 -28
- package/lib/mocha/hooks.js +112 -0
- package/lib/mocha/index.js +12 -0
- package/lib/mocha/inject.js +29 -0
- package/lib/{interfaces → mocha}/scenarioConfig.js +21 -6
- package/lib/mocha/suite.js +81 -0
- package/lib/mocha/test.js +159 -0
- package/lib/mocha/types.d.ts +42 -0
- package/lib/mocha/ui.js +219 -0
- package/lib/output.js +82 -62
- package/lib/pause.js +155 -138
- package/lib/plugin/analyze.js +349 -0
- package/lib/plugin/autoDelay.js +6 -6
- package/lib/plugin/autoLogin.js +6 -7
- package/lib/plugin/commentStep.js +6 -1
- package/lib/plugin/coverage.js +10 -19
- package/lib/plugin/customLocator.js +3 -3
- package/lib/plugin/customReporter.js +52 -0
- package/lib/plugin/eachElement.js +1 -1
- package/lib/plugin/fakerTransform.js +1 -1
- package/lib/plugin/heal.js +36 -9
- package/lib/plugin/pageInfo.js +140 -0
- package/lib/plugin/retryFailedStep.js +4 -4
- package/lib/plugin/retryTo.js +18 -118
- package/lib/plugin/screenshotOnFail.js +17 -49
- package/lib/plugin/selenoid.js +15 -35
- package/lib/plugin/standardActingHelpers.js +4 -1
- package/lib/plugin/stepByStepReport.js +56 -17
- package/lib/plugin/stepTimeout.js +5 -12
- package/lib/plugin/subtitles.js +4 -4
- package/lib/plugin/tryTo.js +17 -107
- package/lib/plugin/wdio.js +8 -10
- package/lib/recorder.js +146 -125
- package/lib/rerun.js +43 -42
- package/lib/result.js +161 -0
- package/lib/secret.js +1 -1
- package/lib/step/base.js +228 -0
- package/lib/step/config.js +50 -0
- package/lib/step/func.js +46 -0
- package/lib/step/helper.js +50 -0
- package/lib/step/meta.js +99 -0
- package/lib/step/record.js +74 -0
- package/lib/step/retry.js +11 -0
- package/lib/step/section.js +55 -0
- package/lib/step.js +21 -332
- package/lib/steps.js +50 -0
- package/lib/store.js +10 -2
- package/lib/template/heal.js +2 -11
- package/lib/timeout.js +66 -0
- package/lib/utils.js +317 -216
- package/lib/within.js +73 -55
- package/lib/workers.js +259 -275
- package/package.json +56 -54
- package/typings/index.d.ts +175 -186
- package/typings/promiseBasedTypes.d.ts +164 -17
- package/typings/types.d.ts +284 -115
- package/lib/cli.js +0 -256
- package/lib/helper/ExpectHelper.js +0 -391
- package/lib/helper/SoftExpectHelper.js +0 -381
- package/lib/listener/artifacts.js +0 -19
- package/lib/listener/timeout.js +0 -109
- package/lib/mochaFactory.js +0 -113
- package/lib/plugin/debugErrors.js +0 -67
- package/lib/scenario.js +0 -224
- package/lib/ui.js +0 -236
package/lib/helper/Puppeteer.js
CHANGED
|
@@ -36,19 +36,8 @@ const Popup = require('./extras/Popup')
|
|
|
36
36
|
const Console = require('./extras/Console')
|
|
37
37
|
const { highlightElement } = require('./scripts/highlightElement')
|
|
38
38
|
const { blurElement } = require('./scripts/blurElement')
|
|
39
|
-
const {
|
|
40
|
-
|
|
41
|
-
seeElementError,
|
|
42
|
-
dontSeeElementInDOMError,
|
|
43
|
-
seeElementInDOMError,
|
|
44
|
-
} = require('./errors/ElementAssertion')
|
|
45
|
-
const {
|
|
46
|
-
dontSeeTraffic,
|
|
47
|
-
seeTraffic,
|
|
48
|
-
grabRecordedNetworkTraffics,
|
|
49
|
-
stopRecordingTraffic,
|
|
50
|
-
flushNetworkTraffics,
|
|
51
|
-
} = require('./network/actions')
|
|
39
|
+
const { dontSeeElementError, seeElementError, dontSeeElementInDOMError, seeElementInDOMError } = require('./errors/ElementAssertion')
|
|
40
|
+
const { dontSeeTraffic, seeTraffic, grabRecordedNetworkTraffics, stopRecordingTraffic, flushNetworkTraffics } = require('./network/actions')
|
|
52
41
|
|
|
53
42
|
let puppeteer
|
|
54
43
|
let perfTiming
|
|
@@ -271,9 +260,7 @@ class Puppeteer extends Helper {
|
|
|
271
260
|
}
|
|
272
261
|
|
|
273
262
|
_getOptions(config) {
|
|
274
|
-
return config.browser === 'firefox'
|
|
275
|
-
? Object.assign(this.options.firefox, { product: 'firefox' })
|
|
276
|
-
: this.options.chrome
|
|
263
|
+
return config.browser === 'firefox' ? Object.assign(this.options.firefox, { product: 'firefox' }) : this.options.chrome
|
|
277
264
|
}
|
|
278
265
|
|
|
279
266
|
_setConfig(config) {
|
|
@@ -326,7 +313,7 @@ class Puppeteer extends Helper {
|
|
|
326
313
|
this.currentRunningTest = test
|
|
327
314
|
recorder.retry({
|
|
328
315
|
retries: process.env.FAILED_STEP_RETRIES || 3,
|
|
329
|
-
when:
|
|
316
|
+
when: err => {
|
|
330
317
|
if (!err || typeof err.message !== 'string') {
|
|
331
318
|
return false
|
|
332
319
|
}
|
|
@@ -346,7 +333,7 @@ class Puppeteer extends Helper {
|
|
|
346
333
|
const contexts = this.browser.browserContexts()
|
|
347
334
|
const defaultCtx = contexts.shift()
|
|
348
335
|
|
|
349
|
-
await Promise.all(contexts.map(
|
|
336
|
+
await Promise.all(contexts.map(c => c.close()))
|
|
350
337
|
|
|
351
338
|
if (this.options.restart) {
|
|
352
339
|
this.isRunning = false
|
|
@@ -355,7 +342,7 @@ class Puppeteer extends Helper {
|
|
|
355
342
|
|
|
356
343
|
// ensure this.page is from default context
|
|
357
344
|
if (this.page) {
|
|
358
|
-
const existingPages = defaultCtx.targets().filter(
|
|
345
|
+
const existingPages = defaultCtx.targets().filter(t => t.type() === 'page')
|
|
359
346
|
await this._setPage(await existingPages[0].page())
|
|
360
347
|
}
|
|
361
348
|
|
|
@@ -368,10 +355,10 @@ class Puppeteer extends Helper {
|
|
|
368
355
|
const currentUrl = await this.grabCurrentUrl()
|
|
369
356
|
|
|
370
357
|
if (currentUrl.startsWith('http')) {
|
|
371
|
-
await this.executeScript('localStorage.clear();').catch(
|
|
358
|
+
await this.executeScript('localStorage.clear();').catch(err => {
|
|
372
359
|
if (!(err.message.indexOf("Storage is disabled inside 'data:' URLs.") > -1)) throw err
|
|
373
360
|
})
|
|
374
|
-
await this.executeScript('sessionStorage.clear();').catch(
|
|
361
|
+
await this.executeScript('sessionStorage.clear();').catch(err => {
|
|
375
362
|
if (!(err.message.indexOf("Storage is disabled inside 'data:' URLs.") > -1)) throw err
|
|
376
363
|
})
|
|
377
364
|
}
|
|
@@ -400,12 +387,12 @@ class Puppeteer extends Helper {
|
|
|
400
387
|
stop: async () => {
|
|
401
388
|
// is closed by _after
|
|
402
389
|
},
|
|
403
|
-
loadVars: async
|
|
404
|
-
const existingPages = context.targets().filter(
|
|
390
|
+
loadVars: async context => {
|
|
391
|
+
const existingPages = context.targets().filter(t => t.type() === 'page')
|
|
405
392
|
this.sessionPages[this.activeSessionName] = await existingPages[0].page()
|
|
406
393
|
return this._setPage(this.sessionPages[this.activeSessionName])
|
|
407
394
|
},
|
|
408
|
-
restoreVars: async
|
|
395
|
+
restoreVars: async session => {
|
|
409
396
|
this.withinLocator = null
|
|
410
397
|
|
|
411
398
|
if (!session) {
|
|
@@ -414,7 +401,7 @@ class Puppeteer extends Helper {
|
|
|
414
401
|
this.activeSessionName = session
|
|
415
402
|
}
|
|
416
403
|
const defaultCtx = this.browser.defaultBrowserContext()
|
|
417
|
-
const existingPages = defaultCtx.targets().filter(
|
|
404
|
+
const existingPages = defaultCtx.targets().filter(t => t.type() === 'page')
|
|
418
405
|
await this._setPage(await existingPages[0].page())
|
|
419
406
|
|
|
420
407
|
return this._waitForAction()
|
|
@@ -517,7 +504,7 @@ class Puppeteer extends Helper {
|
|
|
517
504
|
if (!page) {
|
|
518
505
|
return
|
|
519
506
|
}
|
|
520
|
-
page.on('error', async
|
|
507
|
+
page.on('error', async error => {
|
|
521
508
|
console.error('Puppeteer page error', error)
|
|
522
509
|
})
|
|
523
510
|
}
|
|
@@ -533,7 +520,7 @@ class Puppeteer extends Helper {
|
|
|
533
520
|
if (!page) {
|
|
534
521
|
return
|
|
535
522
|
}
|
|
536
|
-
page.on('dialog', async
|
|
523
|
+
page.on('dialog', async dialog => {
|
|
537
524
|
popupStore.popup = dialog
|
|
538
525
|
const action = popupStore.actionType || this.options.defaultPopupAction
|
|
539
526
|
await this._waitForAction()
|
|
@@ -588,15 +575,15 @@ class Puppeteer extends Helper {
|
|
|
588
575
|
this.browser = await puppeteer.launch(this.puppeteerOptions)
|
|
589
576
|
}
|
|
590
577
|
|
|
591
|
-
this.browser.on('targetcreated',
|
|
578
|
+
this.browser.on('targetcreated', target =>
|
|
592
579
|
target
|
|
593
580
|
.page()
|
|
594
|
-
.then(
|
|
595
|
-
.catch(
|
|
581
|
+
.then(page => targetCreatedHandler.call(this, page))
|
|
582
|
+
.catch(e => {
|
|
596
583
|
console.error('Puppeteer page error', e)
|
|
597
584
|
}),
|
|
598
585
|
)
|
|
599
|
-
this.browser.on('targetchanged',
|
|
586
|
+
this.browser.on('targetchanged', target => {
|
|
600
587
|
this.debugSection('Url', target.url())
|
|
601
588
|
})
|
|
602
589
|
|
|
@@ -639,9 +626,7 @@ class Puppeteer extends Helper {
|
|
|
639
626
|
|
|
640
627
|
if (frame) {
|
|
641
628
|
if (Array.isArray(frame)) {
|
|
642
|
-
return this.switchTo(null).then(() =>
|
|
643
|
-
frame.reduce((p, frameLocator) => p.then(() => this.switchTo(frameLocator)), Promise.resolve()),
|
|
644
|
-
)
|
|
629
|
+
return this.switchTo(null).then(() => frame.reduce((p, frameLocator) => p.then(() => this.switchTo(frameLocator)), Promise.resolve()))
|
|
645
630
|
}
|
|
646
631
|
await this.switchTo(frame)
|
|
647
632
|
this.withinLocator = new Locator(frame)
|
|
@@ -664,7 +649,7 @@ class Puppeteer extends Helper {
|
|
|
664
649
|
const navigationStart = timing.navigationStart
|
|
665
650
|
|
|
666
651
|
const extractedData = {}
|
|
667
|
-
dataNames.forEach(
|
|
652
|
+
dataNames.forEach(name => {
|
|
668
653
|
extractedData[name] = timing[name] - navigationStart
|
|
669
654
|
})
|
|
670
655
|
|
|
@@ -698,13 +683,7 @@ class Puppeteer extends Helper {
|
|
|
698
683
|
|
|
699
684
|
const performanceTiming = JSON.parse(await this.page.evaluate(() => JSON.stringify(window.performance.timing)))
|
|
700
685
|
|
|
701
|
-
perfTiming = this._extractDataFromPerformanceTiming(
|
|
702
|
-
performanceTiming,
|
|
703
|
-
'responseEnd',
|
|
704
|
-
'domInteractive',
|
|
705
|
-
'domContentLoadedEventEnd',
|
|
706
|
-
'loadEventEnd',
|
|
707
|
-
)
|
|
686
|
+
perfTiming = this._extractDataFromPerformanceTiming(performanceTiming, 'responseEnd', 'domInteractive', 'domContentLoadedEventEnd', 'loadEventEnd')
|
|
708
687
|
|
|
709
688
|
return this._waitForAction()
|
|
710
689
|
}
|
|
@@ -815,10 +794,7 @@ class Puppeteer extends Helper {
|
|
|
815
794
|
return this.executeScript(() => {
|
|
816
795
|
const body = document.body
|
|
817
796
|
const html = document.documentElement
|
|
818
|
-
window.scrollTo(
|
|
819
|
-
0,
|
|
820
|
-
Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),
|
|
821
|
-
)
|
|
797
|
+
window.scrollTo(0, Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight))
|
|
822
798
|
})
|
|
823
799
|
}
|
|
824
800
|
|
|
@@ -836,13 +812,9 @@ class Puppeteer extends Helper {
|
|
|
836
812
|
const els = await this._locate(locator)
|
|
837
813
|
assertElementExists(els, locator, 'Element')
|
|
838
814
|
const el = els[0]
|
|
839
|
-
await el.evaluate(
|
|
815
|
+
await el.evaluate(el => el.scrollIntoView())
|
|
840
816
|
const elementCoordinates = await getClickablePoint(els[0])
|
|
841
|
-
await this.executeScript(
|
|
842
|
-
(x, y) => window.scrollBy(x, y),
|
|
843
|
-
elementCoordinates.x + offsetX,
|
|
844
|
-
elementCoordinates.y + offsetY,
|
|
845
|
-
)
|
|
817
|
+
await this.executeScript((x, y) => window.scrollBy(x, y), elementCoordinates.x + offsetX, elementCoordinates.y + offsetY)
|
|
846
818
|
} else {
|
|
847
819
|
await this.executeScript((x, y) => window.scrollTo(x, y), offsetX, offsetY)
|
|
848
820
|
}
|
|
@@ -1025,10 +997,10 @@ class Puppeteer extends Helper {
|
|
|
1025
997
|
*/
|
|
1026
998
|
async closeOtherTabs() {
|
|
1027
999
|
const pages = await this.browser.pages()
|
|
1028
|
-
const otherPages = pages.filter(
|
|
1000
|
+
const otherPages = pages.filter(page => page !== this.page)
|
|
1029
1001
|
|
|
1030
1002
|
let p = Promise.resolve()
|
|
1031
|
-
otherPages.forEach(
|
|
1003
|
+
otherPages.forEach(page => {
|
|
1032
1004
|
p = p.then(() => page.close())
|
|
1033
1005
|
})
|
|
1034
1006
|
await p
|
|
@@ -1061,19 +1033,11 @@ class Puppeteer extends Helper {
|
|
|
1061
1033
|
*/
|
|
1062
1034
|
async seeElement(locator) {
|
|
1063
1035
|
let els = await this._locate(locator)
|
|
1064
|
-
els = (await Promise.all(els.map(
|
|
1036
|
+
els = (await Promise.all(els.map(el => el.boundingBox() && el))).filter(v => v)
|
|
1065
1037
|
// Puppeteer visibility was ignored? | Remove when Puppeteer is fixed
|
|
1066
|
-
els = await Promise.all(
|
|
1067
|
-
els.map(
|
|
1068
|
-
async (el) =>
|
|
1069
|
-
(await el.evaluate(
|
|
1070
|
-
(node) =>
|
|
1071
|
-
window.getComputedStyle(node).visibility !== 'hidden' && window.getComputedStyle(node).display !== 'none',
|
|
1072
|
-
)) && el,
|
|
1073
|
-
),
|
|
1074
|
-
)
|
|
1038
|
+
els = await Promise.all(els.map(async el => (await el.evaluate(node => window.getComputedStyle(node).visibility !== 'hidden' && window.getComputedStyle(node).display !== 'none')) && el))
|
|
1075
1039
|
try {
|
|
1076
|
-
return empty('visible elements').negate(els.filter(
|
|
1040
|
+
return empty('visible elements').negate(els.filter(v => v).fill('ELEMENT'))
|
|
1077
1041
|
} catch (e) {
|
|
1078
1042
|
dontSeeElementError(locator)
|
|
1079
1043
|
}
|
|
@@ -1085,19 +1049,11 @@ class Puppeteer extends Helper {
|
|
|
1085
1049
|
*/
|
|
1086
1050
|
async dontSeeElement(locator) {
|
|
1087
1051
|
let els = await this._locate(locator)
|
|
1088
|
-
els = (await Promise.all(els.map(
|
|
1052
|
+
els = (await Promise.all(els.map(el => el.boundingBox() && el))).filter(v => v)
|
|
1089
1053
|
// Puppeteer visibility was ignored? | Remove when Puppeteer is fixed
|
|
1090
|
-
els = await Promise.all(
|
|
1091
|
-
els.map(
|
|
1092
|
-
async (el) =>
|
|
1093
|
-
(await el.evaluate(
|
|
1094
|
-
(node) =>
|
|
1095
|
-
window.getComputedStyle(node).visibility !== 'hidden' && window.getComputedStyle(node).display !== 'none',
|
|
1096
|
-
)) && el,
|
|
1097
|
-
),
|
|
1098
|
-
)
|
|
1054
|
+
els = await Promise.all(els.map(async el => (await el.evaluate(node => window.getComputedStyle(node).visibility !== 'hidden' && window.getComputedStyle(node).display !== 'none')) && el))
|
|
1099
1055
|
try {
|
|
1100
|
-
return empty('visible elements').assert(els.filter(
|
|
1056
|
+
return empty('visible elements').assert(els.filter(v => v).fill('ELEMENT'))
|
|
1101
1057
|
} catch (e) {
|
|
1102
1058
|
seeElementError(locator)
|
|
1103
1059
|
}
|
|
@@ -1109,7 +1065,7 @@ class Puppeteer extends Helper {
|
|
|
1109
1065
|
async seeElementInDOM(locator) {
|
|
1110
1066
|
const els = await this._locate(locator)
|
|
1111
1067
|
try {
|
|
1112
|
-
return empty('elements on page').negate(els.filter(
|
|
1068
|
+
return empty('elements on page').negate(els.filter(v => v).fill('ELEMENT'))
|
|
1113
1069
|
} catch (e) {
|
|
1114
1070
|
dontSeeElementInDOMError(locator)
|
|
1115
1071
|
}
|
|
@@ -1121,7 +1077,7 @@ class Puppeteer extends Helper {
|
|
|
1121
1077
|
async dontSeeElementInDOM(locator) {
|
|
1122
1078
|
const els = await this._locate(locator)
|
|
1123
1079
|
try {
|
|
1124
|
-
return empty('elements on a page').assert(els.filter(
|
|
1080
|
+
return empty('elements on a page').assert(els.filter(v => v).fill('ELEMENT'))
|
|
1125
1081
|
} catch (e) {
|
|
1126
1082
|
seeElementInDOMError(locator)
|
|
1127
1083
|
}
|
|
@@ -1151,17 +1107,12 @@ class Puppeteer extends Helper {
|
|
|
1151
1107
|
|
|
1152
1108
|
const els = await findClickable.call(this, matcher, locator)
|
|
1153
1109
|
if (context) {
|
|
1154
|
-
assertElementExists(
|
|
1155
|
-
els,
|
|
1156
|
-
locator,
|
|
1157
|
-
'Clickable element',
|
|
1158
|
-
`was not found inside element ${new Locator(context).toString()}`,
|
|
1159
|
-
)
|
|
1110
|
+
assertElementExists(els, locator, 'Clickable element', `was not found inside element ${new Locator(context).toString()}`)
|
|
1160
1111
|
} else {
|
|
1161
1112
|
assertElementExists(els, locator, 'Clickable element')
|
|
1162
1113
|
}
|
|
1163
1114
|
const elem = els[0]
|
|
1164
|
-
return this.executeScript(
|
|
1115
|
+
return this.executeScript(el => {
|
|
1165
1116
|
if (document.activeElement instanceof HTMLElement) {
|
|
1166
1117
|
document.activeElement.blur()
|
|
1167
1118
|
}
|
|
@@ -1220,8 +1171,8 @@ class Puppeteer extends Helper {
|
|
|
1220
1171
|
let fileName
|
|
1221
1172
|
await this.page.setRequestInterception(true)
|
|
1222
1173
|
|
|
1223
|
-
const xRequest = await new Promise(
|
|
1224
|
-
this.page.on('request',
|
|
1174
|
+
const xRequest = await new Promise(resolve => {
|
|
1175
|
+
this.page.on('request', request => {
|
|
1225
1176
|
console.log('rq', request, customName)
|
|
1226
1177
|
const grabbedFileName = request.url().split('/')[request.url().split('/').length - 1]
|
|
1227
1178
|
const fileExtension = request.url().split('/')[request.url().split('/').length - 1].split('.')[1]
|
|
@@ -1248,7 +1199,7 @@ class Puppeteer extends Helper {
|
|
|
1248
1199
|
}
|
|
1249
1200
|
|
|
1250
1201
|
const cookies = await this.page.cookies()
|
|
1251
|
-
options.headers.Cookie = cookies.map(
|
|
1202
|
+
options.headers.Cookie = cookies.map(ck => `${ck.name}=${ck.value}`).join(';')
|
|
1252
1203
|
|
|
1253
1204
|
const response = await axios({
|
|
1254
1205
|
method: options.method,
|
|
@@ -1302,7 +1253,7 @@ class Puppeteer extends Helper {
|
|
|
1302
1253
|
*/
|
|
1303
1254
|
async checkOption(field, context = null) {
|
|
1304
1255
|
const elm = await this._locateCheckable(field, context)
|
|
1305
|
-
const curentlyChecked = await elm.getProperty('checked').then(
|
|
1256
|
+
const curentlyChecked = await elm.getProperty('checked').then(checkedProperty => checkedProperty.jsonValue())
|
|
1306
1257
|
// Only check if NOT currently checked
|
|
1307
1258
|
if (!curentlyChecked) {
|
|
1308
1259
|
await elm.click()
|
|
@@ -1315,7 +1266,7 @@ class Puppeteer extends Helper {
|
|
|
1315
1266
|
*/
|
|
1316
1267
|
async uncheckOption(field, context = null) {
|
|
1317
1268
|
const elm = await this._locateCheckable(field, context)
|
|
1318
|
-
const curentlyChecked = await elm.getProperty('checked').then(
|
|
1269
|
+
const curentlyChecked = await elm.getProperty('checked').then(checkedProperty => checkedProperty.jsonValue())
|
|
1319
1270
|
// Only uncheck if currently checked
|
|
1320
1271
|
if (curentlyChecked) {
|
|
1321
1272
|
await elm.click()
|
|
@@ -1408,12 +1359,12 @@ class Puppeteer extends Helper {
|
|
|
1408
1359
|
const els = await findVisibleFields.call(this, field)
|
|
1409
1360
|
assertElementExists(els, field, 'Field')
|
|
1410
1361
|
const el = els[0]
|
|
1411
|
-
const tag = await el.getProperty('tagName').then(
|
|
1412
|
-
const editable = await el.getProperty('contenteditable').then(
|
|
1362
|
+
const tag = await el.getProperty('tagName').then(el => el.jsonValue())
|
|
1363
|
+
const editable = await el.getProperty('contenteditable').then(el => el.jsonValue())
|
|
1413
1364
|
if (tag === 'INPUT' || tag === 'TEXTAREA') {
|
|
1414
|
-
await this._evaluateHandeInContext(
|
|
1365
|
+
await this._evaluateHandeInContext(el => (el.value = ''), el)
|
|
1415
1366
|
} else if (editable) {
|
|
1416
|
-
await this._evaluateHandeInContext(
|
|
1367
|
+
await this._evaluateHandeInContext(el => (el.innerHTML = ''), el)
|
|
1417
1368
|
}
|
|
1418
1369
|
|
|
1419
1370
|
highlightActiveElement.call(this, el, await this._getContext())
|
|
@@ -1483,7 +1434,7 @@ class Puppeteer extends Helper {
|
|
|
1483
1434
|
const els = await findVisibleFields.call(this, select)
|
|
1484
1435
|
assertElementExists(els, select, 'Selectable field')
|
|
1485
1436
|
const el = els[0]
|
|
1486
|
-
if ((await el.getProperty('tagName').then(
|
|
1437
|
+
if ((await el.getProperty('tagName').then(t => t.jsonValue())) !== 'SELECT') {
|
|
1487
1438
|
throw new Error('Element is not <select>')
|
|
1488
1439
|
}
|
|
1489
1440
|
highlightActiveElement.call(this, els[0], await this._getContext())
|
|
@@ -1493,15 +1444,15 @@ class Puppeteer extends Helper {
|
|
|
1493
1444
|
const opt = xpathLocator.literal(option[key])
|
|
1494
1445
|
let optEl = await findElements.call(this, el, { xpath: Locator.select.byVisibleText(opt) })
|
|
1495
1446
|
if (optEl.length) {
|
|
1496
|
-
this._evaluateHandeInContext(
|
|
1447
|
+
this._evaluateHandeInContext(el => (el.selected = true), optEl[0])
|
|
1497
1448
|
continue
|
|
1498
1449
|
}
|
|
1499
1450
|
optEl = await findElements.call(this, el, { xpath: Locator.select.byValue(opt) })
|
|
1500
1451
|
if (optEl.length) {
|
|
1501
|
-
this._evaluateHandeInContext(
|
|
1452
|
+
this._evaluateHandeInContext(el => (el.selected = true), optEl[0])
|
|
1502
1453
|
}
|
|
1503
1454
|
}
|
|
1504
|
-
await this._evaluateHandeInContext(
|
|
1455
|
+
await this._evaluateHandeInContext(element => {
|
|
1505
1456
|
element.dispatchEvent(new Event('input', { bubbles: true }))
|
|
1506
1457
|
element.dispatchEvent(new Event('change', { bubbles: true }))
|
|
1507
1458
|
}, el)
|
|
@@ -1515,19 +1466,11 @@ class Puppeteer extends Helper {
|
|
|
1515
1466
|
*/
|
|
1516
1467
|
async grabNumberOfVisibleElements(locator) {
|
|
1517
1468
|
let els = await this._locate(locator)
|
|
1518
|
-
els = (await Promise.all(els.map(
|
|
1469
|
+
els = (await Promise.all(els.map(el => el.boundingBox() && el))).filter(v => v)
|
|
1519
1470
|
// Puppeteer visibility was ignored? | Remove when Puppeteer is fixed
|
|
1520
|
-
els = await Promise.all(
|
|
1521
|
-
els.map(
|
|
1522
|
-
async (el) =>
|
|
1523
|
-
(await el.evaluate(
|
|
1524
|
-
(node) =>
|
|
1525
|
-
window.getComputedStyle(node).visibility !== 'hidden' && window.getComputedStyle(node).display !== 'none',
|
|
1526
|
-
)) && el,
|
|
1527
|
-
),
|
|
1528
|
-
)
|
|
1471
|
+
els = await Promise.all(els.map(async el => (await el.evaluate(node => window.getComputedStyle(node).visibility !== 'hidden' && window.getComputedStyle(node).display !== 'none')) && el))
|
|
1529
1472
|
|
|
1530
|
-
return els.filter(
|
|
1473
|
+
return els.filter(v => v).length
|
|
1531
1474
|
}
|
|
1532
1475
|
|
|
1533
1476
|
/**
|
|
@@ -1635,9 +1578,7 @@ class Puppeteer extends Helper {
|
|
|
1635
1578
|
*/
|
|
1636
1579
|
async seeNumberOfElements(locator, num) {
|
|
1637
1580
|
const elements = await this._locate(locator)
|
|
1638
|
-
return equals(
|
|
1639
|
-
`expected number of elements (${new Locator(locator)}) is ${num}, but found ${elements.length}`,
|
|
1640
|
-
).assert(elements.length, num)
|
|
1581
|
+
return equals(`expected number of elements (${new Locator(locator)}) is ${num}, but found ${elements.length}`).assert(elements.length, num)
|
|
1641
1582
|
}
|
|
1642
1583
|
|
|
1643
1584
|
/**
|
|
@@ -1647,10 +1588,7 @@ class Puppeteer extends Helper {
|
|
|
1647
1588
|
*/
|
|
1648
1589
|
async seeNumberOfVisibleElements(locator, num) {
|
|
1649
1590
|
const res = await this.grabNumberOfVisibleElements(locator)
|
|
1650
|
-
return equals(`expected number of visible elements (${new Locator(locator)}) is ${num}, but found ${res}`).assert(
|
|
1651
|
-
res,
|
|
1652
|
-
num,
|
|
1653
|
-
)
|
|
1591
|
+
return equals(`expected number of visible elements (${new Locator(locator)}) is ${num}, but found ${res}`).assert(res, num)
|
|
1654
1592
|
}
|
|
1655
1593
|
|
|
1656
1594
|
/**
|
|
@@ -1669,7 +1607,7 @@ class Puppeteer extends Helper {
|
|
|
1669
1607
|
*/
|
|
1670
1608
|
async seeCookie(name) {
|
|
1671
1609
|
const cookies = await this.page.cookies()
|
|
1672
|
-
empty(`cookie ${name} to be set`).negate(cookies.filter(
|
|
1610
|
+
empty(`cookie ${name} to be set`).negate(cookies.filter(c => c.name === name))
|
|
1673
1611
|
}
|
|
1674
1612
|
|
|
1675
1613
|
/**
|
|
@@ -1677,7 +1615,7 @@ class Puppeteer extends Helper {
|
|
|
1677
1615
|
*/
|
|
1678
1616
|
async dontSeeCookie(name) {
|
|
1679
1617
|
const cookies = await this.page.cookies()
|
|
1680
|
-
empty(`cookie ${name} not to be set`).assert(cookies.filter(
|
|
1618
|
+
empty(`cookie ${name} not to be set`).assert(cookies.filter(c => c.name === name))
|
|
1681
1619
|
}
|
|
1682
1620
|
|
|
1683
1621
|
/**
|
|
@@ -1688,7 +1626,7 @@ class Puppeteer extends Helper {
|
|
|
1688
1626
|
async grabCookie(name) {
|
|
1689
1627
|
const cookies = await this.page.cookies()
|
|
1690
1628
|
if (!name) return cookies
|
|
1691
|
-
const cookie = cookies.filter(
|
|
1629
|
+
const cookie = cookies.filter(c => c.name === name)
|
|
1692
1630
|
if (cookie[0]) return cookie[0]
|
|
1693
1631
|
}
|
|
1694
1632
|
|
|
@@ -1708,9 +1646,9 @@ class Puppeteer extends Helper {
|
|
|
1708
1646
|
|
|
1709
1647
|
return promiseRetry(
|
|
1710
1648
|
async (retry, number) => {
|
|
1711
|
-
const _grabCookie = async
|
|
1649
|
+
const _grabCookie = async name => {
|
|
1712
1650
|
const cookies = await this.page.cookies()
|
|
1713
|
-
const cookie = cookies.filter(
|
|
1651
|
+
const cookie = cookies.filter(c => c.name === name)
|
|
1714
1652
|
if (cookie.length === 0) throw Error(`Cookie ${name} is not found after ${retries}s`)
|
|
1715
1653
|
}
|
|
1716
1654
|
|
|
@@ -1735,7 +1673,7 @@ class Puppeteer extends Helper {
|
|
|
1735
1673
|
if (!name) {
|
|
1736
1674
|
return this.page.deleteCookie.apply(this.page, cookies)
|
|
1737
1675
|
}
|
|
1738
|
-
const cookie = cookies.filter(
|
|
1676
|
+
const cookie = cookies.filter(c => c.name === name)
|
|
1739
1677
|
if (!cookie[0]) return
|
|
1740
1678
|
return this.page.deleteCookie(cookie[0])
|
|
1741
1679
|
}
|
|
@@ -1760,8 +1698,8 @@ class Puppeteer extends Helper {
|
|
|
1760
1698
|
async executeAsyncScript(...args) {
|
|
1761
1699
|
const asyncFn = function () {
|
|
1762
1700
|
const args = Array.from(arguments)
|
|
1763
|
-
const fn = eval(`(${args.shift()})`)
|
|
1764
|
-
return new Promise(
|
|
1701
|
+
const fn = eval(`(${args.shift()})`)
|
|
1702
|
+
return new Promise(done => {
|
|
1765
1703
|
args.push(done)
|
|
1766
1704
|
fn.apply(null, args)
|
|
1767
1705
|
})
|
|
@@ -1828,7 +1766,7 @@ class Puppeteer extends Helper {
|
|
|
1828
1766
|
*/
|
|
1829
1767
|
async grabHTMLFromAll(locator) {
|
|
1830
1768
|
const els = await this._locate(locator)
|
|
1831
|
-
const values = await Promise.all(els.map(
|
|
1769
|
+
const values = await Promise.all(els.map(el => el.evaluate(element => element.innerHTML, el)))
|
|
1832
1770
|
return values
|
|
1833
1771
|
}
|
|
1834
1772
|
|
|
@@ -1851,10 +1789,8 @@ class Puppeteer extends Helper {
|
|
|
1851
1789
|
*/
|
|
1852
1790
|
async grabCssPropertyFromAll(locator, cssProperty) {
|
|
1853
1791
|
const els = await this._locate(locator)
|
|
1854
|
-
const res = await Promise.all(
|
|
1855
|
-
|
|
1856
|
-
)
|
|
1857
|
-
const cssValues = res.map((props) => props[toCamelCase(cssProperty)])
|
|
1792
|
+
const res = await Promise.all(els.map(el => el.evaluate(el => JSON.parse(JSON.stringify(getComputedStyle(el))), el)))
|
|
1793
|
+
const cssValues = res.map(props => props[toCamelCase(cssProperty)])
|
|
1858
1794
|
|
|
1859
1795
|
return cssValues
|
|
1860
1796
|
}
|
|
@@ -1897,19 +1833,16 @@ class Puppeteer extends Helper {
|
|
|
1897
1833
|
}
|
|
1898
1834
|
}
|
|
1899
1835
|
|
|
1900
|
-
const values = Object.keys(cssPropertiesCamelCase).map(
|
|
1836
|
+
const values = Object.keys(cssPropertiesCamelCase).map(key => cssPropertiesCamelCase[key])
|
|
1901
1837
|
if (!Array.isArray(props)) props = [props]
|
|
1902
1838
|
let chunked = chunkArray(props, values.length)
|
|
1903
|
-
chunked = chunked.filter(
|
|
1839
|
+
chunked = chunked.filter(val => {
|
|
1904
1840
|
for (let i = 0; i < val.length; ++i) {
|
|
1905
|
-
// eslint-disable-next-line eqeqeq
|
|
1906
1841
|
if (val[i] != values[i]) return false
|
|
1907
1842
|
}
|
|
1908
1843
|
return true
|
|
1909
1844
|
})
|
|
1910
|
-
return equals(
|
|
1911
|
-
`all elements (${new Locator(locator)}) to have CSS property ${JSON.stringify(cssProperties)}`,
|
|
1912
|
-
).assert(chunked.length, elemAmount)
|
|
1845
|
+
return equals(`all elements (${new Locator(locator)}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(chunked.length, elemAmount)
|
|
1913
1846
|
}
|
|
1914
1847
|
|
|
1915
1848
|
/**
|
|
@@ -1922,7 +1855,7 @@ class Puppeteer extends Helper {
|
|
|
1922
1855
|
|
|
1923
1856
|
const expectedAttributes = Object.entries(attributes)
|
|
1924
1857
|
|
|
1925
|
-
const valuesPromises = elements.map(async
|
|
1858
|
+
const valuesPromises = elements.map(async element => {
|
|
1926
1859
|
const elementAttributes = {}
|
|
1927
1860
|
await Promise.all(
|
|
1928
1861
|
expectedAttributes.map(async ([attribute, expectedValue]) => {
|
|
@@ -1935,7 +1868,7 @@ class Puppeteer extends Helper {
|
|
|
1935
1868
|
|
|
1936
1869
|
const actualAttributes = await Promise.all(valuesPromises)
|
|
1937
1870
|
|
|
1938
|
-
const matchingElements = actualAttributes.filter(
|
|
1871
|
+
const matchingElements = actualAttributes.filter(attrs =>
|
|
1939
1872
|
expectedAttributes.every(([attribute, expectedValue]) => {
|
|
1940
1873
|
const actualValue = attrs[attribute]
|
|
1941
1874
|
if (!actualValue) return false
|
|
@@ -1947,10 +1880,7 @@ class Puppeteer extends Helper {
|
|
|
1947
1880
|
const elementsCount = elements.length
|
|
1948
1881
|
const matchingCount = matchingElements.length
|
|
1949
1882
|
|
|
1950
|
-
return equals(`all elements (${new Locator(locator)}) to have attributes ${JSON.stringify(attributes)}`).assert(
|
|
1951
|
-
matchingCount,
|
|
1952
|
-
elementsCount,
|
|
1953
|
-
)
|
|
1883
|
+
return equals(`all elements (${new Locator(locator)}) to have attributes ${JSON.stringify(attributes)}`).assert(matchingCount, elementsCount)
|
|
1954
1884
|
}
|
|
1955
1885
|
|
|
1956
1886
|
/**
|
|
@@ -2080,7 +2010,7 @@ class Puppeteer extends Helper {
|
|
|
2080
2010
|
* {{> wait }}
|
|
2081
2011
|
*/
|
|
2082
2012
|
async wait(sec) {
|
|
2083
|
-
return new Promise(
|
|
2013
|
+
return new Promise(done => {
|
|
2084
2014
|
setTimeout(done, sec * 1000)
|
|
2085
2015
|
})
|
|
2086
2016
|
}
|
|
@@ -2100,20 +2030,18 @@ class Puppeteer extends Helper {
|
|
|
2100
2030
|
if (!els || els.length === 0) {
|
|
2101
2031
|
return false
|
|
2102
2032
|
}
|
|
2103
|
-
return Array.prototype.filter.call(els,
|
|
2033
|
+
return Array.prototype.filter.call(els, el => !el.disabled).length > 0
|
|
2104
2034
|
}
|
|
2105
2035
|
waiter = context.waitForFunction(enabledFn, { timeout: waitTimeout }, locator.value)
|
|
2106
2036
|
} else {
|
|
2107
2037
|
const enabledFn = function (locator, $XPath) {
|
|
2108
|
-
eval($XPath)
|
|
2109
|
-
return $XPath(null, locator).filter(
|
|
2038
|
+
eval($XPath)
|
|
2039
|
+
return $XPath(null, locator).filter(el => !el.disabled).length > 0
|
|
2110
2040
|
}
|
|
2111
2041
|
waiter = context.waitForFunction(enabledFn, { timeout: waitTimeout }, locator.value, $XPath.toString())
|
|
2112
2042
|
}
|
|
2113
|
-
return waiter.catch(
|
|
2114
|
-
throw new Error(
|
|
2115
|
-
`element (${locator.toString()}) still not enabled after ${waitTimeout / 1000} sec\n${err.message}`,
|
|
2116
|
-
)
|
|
2043
|
+
return waiter.catch(err => {
|
|
2044
|
+
throw new Error(`element (${locator.toString()}) still not enabled after ${waitTimeout / 1000} sec\n${err.message}`)
|
|
2117
2045
|
})
|
|
2118
2046
|
}
|
|
2119
2047
|
|
|
@@ -2132,21 +2060,19 @@ class Puppeteer extends Helper {
|
|
|
2132
2060
|
if (!els || els.length === 0) {
|
|
2133
2061
|
return false
|
|
2134
2062
|
}
|
|
2135
|
-
return Array.prototype.filter.call(els,
|
|
2063
|
+
return Array.prototype.filter.call(els, el => (el.value.toString() || '').indexOf(value) !== -1).length > 0
|
|
2136
2064
|
}
|
|
2137
2065
|
waiter = context.waitForFunction(valueFn, { timeout: waitTimeout }, locator.value, value)
|
|
2138
2066
|
} else {
|
|
2139
2067
|
const valueFn = function (locator, $XPath, value) {
|
|
2140
|
-
eval($XPath)
|
|
2141
|
-
return $XPath(null, locator).filter(
|
|
2068
|
+
eval($XPath)
|
|
2069
|
+
return $XPath(null, locator).filter(el => (el.value || '').indexOf(value) !== -1).length > 0
|
|
2142
2070
|
}
|
|
2143
2071
|
waiter = context.waitForFunction(valueFn, { timeout: waitTimeout }, locator.value, $XPath.toString(), value)
|
|
2144
2072
|
}
|
|
2145
|
-
return waiter.catch(
|
|
2073
|
+
return waiter.catch(err => {
|
|
2146
2074
|
const loc = locator.toString()
|
|
2147
|
-
throw new Error(
|
|
2148
|
-
`element (${loc}) is not in DOM or there is no element(${loc}) with value "${value}" after ${waitTimeout / 1000} sec\n${err.message}`,
|
|
2149
|
-
)
|
|
2075
|
+
throw new Error(`element (${loc}) is not in DOM or there is no element(${loc}) with value "${value}" after ${waitTimeout / 1000} sec\n${err.message}`)
|
|
2150
2076
|
})
|
|
2151
2077
|
}
|
|
2152
2078
|
|
|
@@ -2165,20 +2091,18 @@ class Puppeteer extends Helper {
|
|
|
2165
2091
|
if (!els || els.length === 0) {
|
|
2166
2092
|
return false
|
|
2167
2093
|
}
|
|
2168
|
-
return Array.prototype.filter.call(els,
|
|
2094
|
+
return Array.prototype.filter.call(els, el => el.offsetParent !== null).length === num
|
|
2169
2095
|
}
|
|
2170
2096
|
waiter = context.waitForFunction(visibleFn, { timeout: waitTimeout }, locator.value, num)
|
|
2171
2097
|
} else {
|
|
2172
2098
|
const visibleFn = function (locator, $XPath, num) {
|
|
2173
|
-
eval($XPath)
|
|
2174
|
-
return $XPath(null, locator).filter(
|
|
2099
|
+
eval($XPath)
|
|
2100
|
+
return $XPath(null, locator).filter(el => el.offsetParent !== null).length === num
|
|
2175
2101
|
}
|
|
2176
2102
|
waiter = context.waitForFunction(visibleFn, { timeout: waitTimeout }, locator.value, $XPath.toString(), num)
|
|
2177
2103
|
}
|
|
2178
|
-
return waiter.catch(
|
|
2179
|
-
throw new Error(
|
|
2180
|
-
`The number of elements (${locator.toString()}) is not ${num} after ${waitTimeout / 1000} sec\n${err.message}`,
|
|
2181
|
-
)
|
|
2104
|
+
return waiter.catch(err => {
|
|
2105
|
+
throw new Error(`The number of elements (${locator.toString()}) is not ${num} after ${waitTimeout / 1000} sec\n${err.message}`)
|
|
2182
2106
|
})
|
|
2183
2107
|
}
|
|
2184
2108
|
|
|
@@ -2189,11 +2113,9 @@ class Puppeteer extends Helper {
|
|
|
2189
2113
|
const els = await this._locate(locator)
|
|
2190
2114
|
assertElementExists(els, locator)
|
|
2191
2115
|
|
|
2192
|
-
return this.waitForFunction(isElementClickable, [els[0]], waitTimeout).catch(async
|
|
2116
|
+
return this.waitForFunction(isElementClickable, [els[0]], waitTimeout).catch(async e => {
|
|
2193
2117
|
if (/Waiting failed/i.test(e.message) || /failed: timeout/i.test(e.message)) {
|
|
2194
|
-
throw new Error(
|
|
2195
|
-
`element ${new Locator(locator).toString()} still not clickable after ${waitTimeout || this.options.waitForTimeout / 1000} sec`,
|
|
2196
|
-
)
|
|
2118
|
+
throw new Error(`element ${new Locator(locator).toString()} still not clickable after ${waitTimeout || this.options.waitForTimeout / 1000} sec`)
|
|
2197
2119
|
} else {
|
|
2198
2120
|
throw e
|
|
2199
2121
|
}
|
|
@@ -2215,10 +2137,8 @@ class Puppeteer extends Helper {
|
|
|
2215
2137
|
} else {
|
|
2216
2138
|
waiter = _waitForElement.call(this, locator, { timeout: waitTimeout })
|
|
2217
2139
|
}
|
|
2218
|
-
return waiter.catch(
|
|
2219
|
-
throw new Error(
|
|
2220
|
-
`element (${locator.toString()}) still not present on page after ${waitTimeout / 1000} sec\n${err.message}`,
|
|
2221
|
-
)
|
|
2140
|
+
return waiter.catch(err => {
|
|
2141
|
+
throw new Error(`element (${locator.toString()}) still not present on page after ${waitTimeout / 1000} sec\n${err.message}`)
|
|
2222
2142
|
})
|
|
2223
2143
|
}
|
|
2224
2144
|
|
|
@@ -2238,10 +2158,8 @@ class Puppeteer extends Helper {
|
|
|
2238
2158
|
} else {
|
|
2239
2159
|
waiter = _waitForElement.call(this, locator, { timeout: waitTimeout, visible: true })
|
|
2240
2160
|
}
|
|
2241
|
-
return waiter.catch(
|
|
2242
|
-
throw new Error(
|
|
2243
|
-
`element (${locator.toString()}) still not visible after ${waitTimeout / 1000} sec\n${err.message}`,
|
|
2244
|
-
)
|
|
2161
|
+
return waiter.catch(err => {
|
|
2162
|
+
throw new Error(`element (${locator.toString()}) still not visible after ${waitTimeout / 1000} sec\n${err.message}`)
|
|
2245
2163
|
})
|
|
2246
2164
|
}
|
|
2247
2165
|
|
|
@@ -2259,7 +2177,7 @@ class Puppeteer extends Helper {
|
|
|
2259
2177
|
} else {
|
|
2260
2178
|
waiter = _waitForElement.call(this, locator, { timeout: waitTimeout, hidden: true })
|
|
2261
2179
|
}
|
|
2262
|
-
return waiter.catch(
|
|
2180
|
+
return waiter.catch(err => {
|
|
2263
2181
|
throw new Error(`element (${locator.toString()}) still visible after ${waitTimeout / 1000} sec\n${err.message}`)
|
|
2264
2182
|
})
|
|
2265
2183
|
}
|
|
@@ -2277,10 +2195,8 @@ class Puppeteer extends Helper {
|
|
|
2277
2195
|
} else {
|
|
2278
2196
|
waiter = _waitForElement.call(this, locator, { timeout: waitTimeout, hidden: true })
|
|
2279
2197
|
}
|
|
2280
|
-
return waiter.catch(
|
|
2281
|
-
throw new Error(
|
|
2282
|
-
`element (${locator.toString()}) still not hidden after ${waitTimeout / 1000} sec\n${err.message}`,
|
|
2283
|
-
)
|
|
2198
|
+
return waiter.catch(err => {
|
|
2199
|
+
throw new Error(`element (${locator.toString()}) still not hidden after ${waitTimeout / 1000} sec\n${err.message}`)
|
|
2284
2200
|
})
|
|
2285
2201
|
}
|
|
2286
2202
|
|
|
@@ -2317,14 +2233,14 @@ class Puppeteer extends Helper {
|
|
|
2317
2233
|
|
|
2318
2234
|
return this.page
|
|
2319
2235
|
.waitForFunction(
|
|
2320
|
-
|
|
2236
|
+
urlPart => {
|
|
2321
2237
|
const currUrl = decodeURIComponent(decodeURIComponent(decodeURIComponent(window.location.href)))
|
|
2322
2238
|
return currUrl.indexOf(urlPart) > -1
|
|
2323
2239
|
},
|
|
2324
2240
|
{ timeout: waitTimeout },
|
|
2325
2241
|
urlPart,
|
|
2326
2242
|
)
|
|
2327
|
-
.catch(async
|
|
2243
|
+
.catch(async e => {
|
|
2328
2244
|
const currUrl = await this._getPageUrl() // Required because the waitForFunction can't return data.
|
|
2329
2245
|
if (/Waiting failed:/i.test(e.message) || /failed: timeout/i.test(e.message)) {
|
|
2330
2246
|
throw new Error(`expected url to include ${urlPart}, but found ${currUrl}`)
|
|
@@ -2347,14 +2263,14 @@ class Puppeteer extends Helper {
|
|
|
2347
2263
|
|
|
2348
2264
|
return this.page
|
|
2349
2265
|
.waitForFunction(
|
|
2350
|
-
|
|
2266
|
+
urlPart => {
|
|
2351
2267
|
const currUrl = decodeURIComponent(decodeURIComponent(decodeURIComponent(window.location.href)))
|
|
2352
2268
|
return currUrl.indexOf(urlPart) > -1
|
|
2353
2269
|
},
|
|
2354
2270
|
{ timeout: waitTimeout },
|
|
2355
2271
|
urlPart,
|
|
2356
2272
|
)
|
|
2357
|
-
.catch(async
|
|
2273
|
+
.catch(async e => {
|
|
2358
2274
|
const currUrl = await this._getPageUrl() // Required because the waitForFunction can't return data.
|
|
2359
2275
|
if (/Waiting failed/i.test(e.message) || /failed: timeout/i.test(e.message)) {
|
|
2360
2276
|
throw new Error(`expected url to be ${urlPart}, but found ${currUrl}`)
|
|
@@ -2391,7 +2307,7 @@ class Puppeteer extends Helper {
|
|
|
2391
2307
|
if (locator.isXPath()) {
|
|
2392
2308
|
waiter = contextObject.waitForFunction(
|
|
2393
2309
|
(locator, text, $XPath) => {
|
|
2394
|
-
eval($XPath)
|
|
2310
|
+
eval($XPath)
|
|
2395
2311
|
const el = $XPath(null, locator)
|
|
2396
2312
|
if (!el.length) return false
|
|
2397
2313
|
return el[0].innerText.indexOf(text) > -1
|
|
@@ -2403,14 +2319,10 @@ class Puppeteer extends Helper {
|
|
|
2403
2319
|
)
|
|
2404
2320
|
}
|
|
2405
2321
|
} else {
|
|
2406
|
-
waiter = contextObject.waitForFunction(
|
|
2407
|
-
(text) => document.body && document.body.innerText.indexOf(text) > -1,
|
|
2408
|
-
{ timeout: waitTimeout },
|
|
2409
|
-
text,
|
|
2410
|
-
)
|
|
2322
|
+
waiter = contextObject.waitForFunction(text => document.body && document.body.innerText.indexOf(text) > -1, { timeout: waitTimeout }, text)
|
|
2411
2323
|
}
|
|
2412
2324
|
|
|
2413
|
-
return waiter.catch(
|
|
2325
|
+
return waiter.catch(err => {
|
|
2414
2326
|
throw new Error(`Text "${text}" was not found on page after ${waitTimeout / 1000} sec\n${err.message}`)
|
|
2415
2327
|
})
|
|
2416
2328
|
}
|
|
@@ -2543,12 +2455,12 @@ class Puppeteer extends Helper {
|
|
|
2543
2455
|
waiter = context.waitForFunction(visibleFn, { timeout: waitTimeout }, locator.value)
|
|
2544
2456
|
} else {
|
|
2545
2457
|
const visibleFn = function (locator, $XPath) {
|
|
2546
|
-
eval($XPath)
|
|
2458
|
+
eval($XPath)
|
|
2547
2459
|
return $XPath(null, locator).length === 0
|
|
2548
2460
|
}
|
|
2549
2461
|
waiter = context.waitForFunction(visibleFn, { timeout: waitTimeout }, locator.value, $XPath.toString())
|
|
2550
2462
|
}
|
|
2551
|
-
return waiter.catch(
|
|
2463
|
+
return waiter.catch(err => {
|
|
2552
2464
|
throw new Error(`element (${locator.toString()}) still on page after ${waitTimeout / 1000} sec\n${err.message}`)
|
|
2553
2465
|
})
|
|
2554
2466
|
}
|
|
@@ -2589,7 +2501,7 @@ class Puppeteer extends Helper {
|
|
|
2589
2501
|
async mockRoute(url, handler) {
|
|
2590
2502
|
await this.page.setRequestInterception(true)
|
|
2591
2503
|
|
|
2592
|
-
this.page.on('request',
|
|
2504
|
+
this.page.on('request', interceptedRequest => {
|
|
2593
2505
|
if (interceptedRequest.url().match(url)) {
|
|
2594
2506
|
// @ts-ignore
|
|
2595
2507
|
handler(interceptedRequest)
|
|
@@ -2614,7 +2526,7 @@ class Puppeteer extends Helper {
|
|
|
2614
2526
|
this.page.off('request')
|
|
2615
2527
|
|
|
2616
2528
|
// Resume normal request handling for the given URL
|
|
2617
|
-
this.page.on('request',
|
|
2529
|
+
this.page.on('request', interceptedRequest => {
|
|
2618
2530
|
if (interceptedRequest.url().includes(url)) {
|
|
2619
2531
|
interceptedRequest.continue()
|
|
2620
2532
|
} else {
|
|
@@ -2650,7 +2562,7 @@ class Puppeteer extends Helper {
|
|
|
2650
2562
|
|
|
2651
2563
|
await this.page.setRequestInterception(true)
|
|
2652
2564
|
|
|
2653
|
-
this.page.on('request',
|
|
2565
|
+
this.page.on('request', request => {
|
|
2654
2566
|
const information = {
|
|
2655
2567
|
url: request.url(),
|
|
2656
2568
|
method: request.method(),
|
|
@@ -2711,15 +2623,15 @@ class Puppeteer extends Helper {
|
|
|
2711
2623
|
await this.cdpSession.send('Network.enable')
|
|
2712
2624
|
await this.cdpSession.send('Page.enable')
|
|
2713
2625
|
|
|
2714
|
-
this.cdpSession.on('Network.webSocketFrameReceived',
|
|
2626
|
+
this.cdpSession.on('Network.webSocketFrameReceived', payload => {
|
|
2715
2627
|
this._logWebsocketMessages(this._getWebSocketLog('RECEIVED', payload))
|
|
2716
2628
|
})
|
|
2717
2629
|
|
|
2718
|
-
this.cdpSession.on('Network.webSocketFrameSent',
|
|
2630
|
+
this.cdpSession.on('Network.webSocketFrameSent', payload => {
|
|
2719
2631
|
this._logWebsocketMessages(this._getWebSocketLog('SENT', payload))
|
|
2720
2632
|
})
|
|
2721
2633
|
|
|
2722
|
-
this.cdpSession.on('Network.webSocketFrameError',
|
|
2634
|
+
this.cdpSession.on('Network.webSocketFrameError', payload => {
|
|
2723
2635
|
this._logWebsocketMessages(this._getWebSocketLog('ERROR', payload))
|
|
2724
2636
|
})
|
|
2725
2637
|
}
|
|
@@ -2743,9 +2655,7 @@ class Puppeteer extends Helper {
|
|
|
2743
2655
|
grabWebSocketMessages() {
|
|
2744
2656
|
if (!this.recordingWebSocketMessages) {
|
|
2745
2657
|
if (!this.recordedWebSocketMessagesAtLeastOnce) {
|
|
2746
|
-
throw new Error(
|
|
2747
|
-
'Failure in test automation. You use "I.grabWebSocketMessages", but "I.startRecordingWebSocketMessages" was never called before.',
|
|
2748
|
-
)
|
|
2658
|
+
throw new Error('Failure in test automation. You use "I.grabWebSocketMessages", but "I.startRecordingWebSocketMessages" was never called before.')
|
|
2749
2659
|
}
|
|
2750
2660
|
}
|
|
2751
2661
|
return this.webSocketMessages
|
|
@@ -2797,12 +2707,7 @@ async function proceedClick(locator, context = null, options = {}) {
|
|
|
2797
2707
|
}
|
|
2798
2708
|
const els = await findClickable.call(this, matcher, locator)
|
|
2799
2709
|
if (context) {
|
|
2800
|
-
assertElementExists(
|
|
2801
|
-
els,
|
|
2802
|
-
locator,
|
|
2803
|
-
'Clickable element',
|
|
2804
|
-
`was not found inside element ${new Locator(context).toString()}`,
|
|
2805
|
-
)
|
|
2710
|
+
assertElementExists(els, locator, 'Clickable element', `was not found inside element ${new Locator(context).toString()}`)
|
|
2806
2711
|
} else {
|
|
2807
2712
|
assertElementExists(els, locator, 'Clickable element')
|
|
2808
2713
|
}
|
|
@@ -2854,23 +2759,25 @@ async function proceedSee(assertType, text, context, strict = false) {
|
|
|
2854
2759
|
el = await this.context.$('body')
|
|
2855
2760
|
}
|
|
2856
2761
|
|
|
2857
|
-
allText = [await el.getProperty('innerText').then(
|
|
2762
|
+
allText = [await el.getProperty('innerText').then(p => p.jsonValue())]
|
|
2858
2763
|
description = 'web application'
|
|
2859
2764
|
} else {
|
|
2860
2765
|
const locator = new Locator(context, 'css')
|
|
2861
2766
|
description = `element ${locator.toString()}`
|
|
2862
2767
|
const els = await this._locate(locator)
|
|
2863
2768
|
assertElementExists(els, locator.toString())
|
|
2864
|
-
allText = await Promise.all(els.map(
|
|
2769
|
+
allText = await Promise.all(els.map(el => el.getProperty('innerText').then(p => p.jsonValue())))
|
|
2770
|
+
}
|
|
2771
|
+
|
|
2772
|
+
if (store?.currentStep?.opts?.ignoreCase === true) {
|
|
2773
|
+
text = text.toLowerCase()
|
|
2774
|
+
allText = allText.map(elText => elText.toLowerCase())
|
|
2865
2775
|
}
|
|
2866
2776
|
|
|
2867
2777
|
if (strict) {
|
|
2868
|
-
return allText.map(
|
|
2778
|
+
return allText.map(elText => equals(description)[assertType](text, elText))
|
|
2869
2779
|
}
|
|
2870
|
-
return stringIncludes(description)[assertType](
|
|
2871
|
-
normalizeSpacesInString(text),
|
|
2872
|
-
normalizeSpacesInString(allText.join(' | ')),
|
|
2873
|
-
)
|
|
2780
|
+
return stringIncludes(description)[assertType](normalizeSpacesInString(text), normalizeSpacesInString(allText.join(' | ')))
|
|
2874
2781
|
}
|
|
2875
2782
|
|
|
2876
2783
|
async function findCheckable(locator, context) {
|
|
@@ -2900,15 +2807,15 @@ async function findCheckable(locator, context) {
|
|
|
2900
2807
|
async function proceedIsChecked(assertType, option) {
|
|
2901
2808
|
let els = await findCheckable.call(this, option)
|
|
2902
2809
|
assertElementExists(els, option, 'Checkable')
|
|
2903
|
-
els = await Promise.all(els.map(
|
|
2904
|
-
els = await Promise.all(els.map(
|
|
2810
|
+
els = await Promise.all(els.map(el => el.getProperty('checked')))
|
|
2811
|
+
els = await Promise.all(els.map(el => el.jsonValue()))
|
|
2905
2812
|
const selected = els.reduce((prev, cur) => prev || cur)
|
|
2906
2813
|
return truth(`checkable ${option}`, 'to be checked')[assertType](selected)
|
|
2907
2814
|
}
|
|
2908
2815
|
|
|
2909
2816
|
async function findVisibleFields(locator) {
|
|
2910
2817
|
const els = await findFields.call(this, locator)
|
|
2911
|
-
const visible = await Promise.all(els.map(
|
|
2818
|
+
const visible = await Promise.all(els.map(el => el.boundingBox()))
|
|
2912
2819
|
return els.filter((el, index) => visible[index])
|
|
2913
2820
|
}
|
|
2914
2821
|
|
|
@@ -2961,15 +2868,15 @@ async function proceedSeeInField(assertType, field, value) {
|
|
|
2961
2868
|
const els = await findVisibleFields.call(this, field)
|
|
2962
2869
|
assertElementExists(els, field, 'Field')
|
|
2963
2870
|
const el = els[0]
|
|
2964
|
-
const tag = await el.getProperty('tagName').then(
|
|
2965
|
-
const fieldType = await el.getProperty('type').then(
|
|
2871
|
+
const tag = await el.getProperty('tagName').then(el => el.jsonValue())
|
|
2872
|
+
const fieldType = await el.getProperty('type').then(el => el.jsonValue())
|
|
2966
2873
|
|
|
2967
|
-
const proceedMultiple = async
|
|
2874
|
+
const proceedMultiple = async elements => {
|
|
2968
2875
|
const fields = Array.isArray(elements) ? elements : [elements]
|
|
2969
2876
|
|
|
2970
2877
|
const elementValues = []
|
|
2971
2878
|
for (const element of fields) {
|
|
2972
|
-
elementValues.push(await element.getProperty('value').then(
|
|
2879
|
+
elementValues.push(await element.getProperty('value').then(el => el.jsonValue()))
|
|
2973
2880
|
}
|
|
2974
2881
|
|
|
2975
2882
|
if (typeof value === 'boolean') {
|
|
@@ -2978,7 +2885,7 @@ async function proceedSeeInField(assertType, field, value) {
|
|
|
2978
2885
|
if (assertType === 'assert') {
|
|
2979
2886
|
equals(`select option by ${field}`)[assertType](true, elementValues.length > 0)
|
|
2980
2887
|
}
|
|
2981
|
-
elementValues.forEach(
|
|
2888
|
+
elementValues.forEach(val => stringIncludes(`fields by ${field}`)[assertType](value, val))
|
|
2982
2889
|
}
|
|
2983
2890
|
}
|
|
2984
2891
|
|
|
@@ -3006,14 +2913,14 @@ async function proceedSeeInField(assertType, field, value) {
|
|
|
3006
2913
|
}
|
|
3007
2914
|
return proceedMultiple(els[0])
|
|
3008
2915
|
}
|
|
3009
|
-
const fieldVal = await el.getProperty('value').then(
|
|
2916
|
+
const fieldVal = await el.getProperty('value').then(el => el.jsonValue())
|
|
3010
2917
|
return stringIncludes(`fields by ${field}`)[assertType](value, fieldVal)
|
|
3011
2918
|
}
|
|
3012
2919
|
|
|
3013
2920
|
async function filterFieldsByValue(elements, value, onlySelected) {
|
|
3014
2921
|
const matches = []
|
|
3015
2922
|
for (const element of elements) {
|
|
3016
|
-
const val = await element.getProperty('value').then(
|
|
2923
|
+
const val = await element.getProperty('value').then(el => el.jsonValue())
|
|
3017
2924
|
let isSelected = true
|
|
3018
2925
|
if (onlySelected) {
|
|
3019
2926
|
isSelected = await elementSelected(element)
|
|
@@ -3037,12 +2944,12 @@ async function filterFieldsBySelectionState(elements, state) {
|
|
|
3037
2944
|
}
|
|
3038
2945
|
|
|
3039
2946
|
async function elementSelected(element) {
|
|
3040
|
-
const type = await element.getProperty('type').then(
|
|
2947
|
+
const type = await element.getProperty('type').then(el => el.jsonValue())
|
|
3041
2948
|
|
|
3042
2949
|
if (type === 'checkbox' || type === 'radio') {
|
|
3043
|
-
return element.getProperty('checked').then(
|
|
2950
|
+
return element.getProperty('checked').then(el => el.jsonValue())
|
|
3044
2951
|
}
|
|
3045
|
-
return element.getProperty('selected').then(
|
|
2952
|
+
return element.getProperty('selected').then(el => el.jsonValue())
|
|
3046
2953
|
}
|
|
3047
2954
|
|
|
3048
2955
|
function isFrameLocator(locator) {
|
|
@@ -3077,9 +2984,9 @@ async function targetCreatedHandler(page) {
|
|
|
3077
2984
|
page
|
|
3078
2985
|
.$('body')
|
|
3079
2986
|
.catch(() => null)
|
|
3080
|
-
.then(
|
|
2987
|
+
.then(context => (this.context = context))
|
|
3081
2988
|
})
|
|
3082
|
-
page.on('console',
|
|
2989
|
+
page.on('console', msg => {
|
|
3083
2990
|
this.debugSection(`Browser:${ucfirst(msg.type())}`, (msg._text || '') + msg.args().join(' '))
|
|
3084
2991
|
consoleLogStore.add(msg)
|
|
3085
2992
|
})
|
|
@@ -3186,7 +3093,7 @@ async function findReactElements(locator, props = {}, state = {}) {
|
|
|
3186
3093
|
|
|
3187
3094
|
await this.page.evaluate(() => window.resq.waitToLoadReact())
|
|
3188
3095
|
const arrayHandle = await this.page.evaluateHandle(
|
|
3189
|
-
|
|
3096
|
+
obj => {
|
|
3190
3097
|
const { selector, props, state } = obj
|
|
3191
3098
|
let elements = window.resq.resq$$(selector)
|
|
3192
3099
|
if (Object.keys(props).length) {
|
|
@@ -3205,7 +3112,7 @@ async function findReactElements(locator, props = {}, state = {}) {
|
|
|
3205
3112
|
// [[div, div], [div, div]] => [div, div, div, div]
|
|
3206
3113
|
let nodes = []
|
|
3207
3114
|
|
|
3208
|
-
elements.forEach(
|
|
3115
|
+
elements.forEach(element => {
|
|
3209
3116
|
let { node, isFragment } = element
|
|
3210
3117
|
|
|
3211
3118
|
if (!node) {
|