codeceptjs 4.0.0-beta.2 → 4.0.0-beta.4
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 +2 -2
- package/bin/codecept.js +84 -81
- package/lib/actor.js +13 -13
- package/lib/ai.js +10 -13
- package/lib/assert/empty.js +20 -21
- package/lib/assert/equal.js +37 -39
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +46 -47
- package/lib/assert/throws.js +13 -11
- package/lib/assert/truth.js +19 -22
- package/lib/assert.js +4 -2
- package/lib/cli.js +56 -49
- package/lib/codecept.js +145 -155
- package/lib/colorUtils.js +3 -3
- package/lib/command/configMigrate.js +58 -52
- package/lib/command/definitions.js +88 -89
- package/lib/command/dryRun.js +79 -81
- package/lib/command/generate.js +197 -188
- package/lib/command/gherkin/init.js +27 -16
- package/lib/command/gherkin/snippets.js +21 -21
- package/lib/command/gherkin/steps.js +8 -8
- package/lib/command/info.js +40 -38
- package/lib/command/init.js +290 -288
- package/lib/command/interactive.js +32 -32
- package/lib/command/list.js +26 -26
- package/lib/command/run-multiple/chunk.js +5 -5
- package/lib/command/run-multiple/collection.js +3 -3
- package/lib/command/run-multiple/run.js +6 -2
- package/lib/command/run-multiple.js +113 -93
- package/lib/command/run-rerun.js +20 -25
- package/lib/command/run-workers.js +64 -66
- package/lib/command/run.js +26 -29
- package/lib/command/utils.js +80 -65
- package/lib/command/workers/runTests.js +11 -12
- package/lib/config.js +10 -9
- package/lib/container.js +40 -48
- package/lib/data/context.js +60 -59
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +29 -29
- package/lib/data/table.js +26 -20
- package/lib/event.js +163 -167
- package/lib/heal.js +14 -18
- package/lib/helper/AI.js +130 -41
- package/lib/helper/ApiDataFactory.js +74 -70
- package/lib/helper/Appium.js +416 -388
- package/lib/helper/ExpectHelper.js +40 -48
- package/lib/helper/FileSystem.js +80 -79
- package/lib/helper/GraphQL.js +44 -43
- package/lib/helper/GraphQLDataFactory.js +51 -51
- package/lib/helper/JSONResponse.js +65 -62
- package/lib/helper/Mochawesome.js +28 -28
- package/lib/helper/Nightmare.js +664 -571
- package/lib/helper/Playwright.js +1367 -1222
- package/lib/helper/Protractor.js +663 -635
- package/lib/helper/Puppeteer.js +1232 -1132
- package/lib/helper/REST.js +183 -68
- package/lib/helper/SoftExpectHelper.js +2 -2
- package/lib/helper/TestCafe.js +490 -486
- package/lib/helper/WebDriver.js +1246 -1297
- package/lib/helper/clientscripts/PollyWebDriverExt.js +1 -1
- package/lib/helper/errors/ConnectionRefused.js +1 -1
- package/lib/helper/errors/ElementAssertion.js +2 -2
- package/lib/helper/errors/ElementNotFound.js +2 -2
- package/lib/helper/errors/RemoteBrowserConnectionRefused.js +1 -1
- package/lib/helper/extras/Console.js +1 -1
- package/lib/helper/extras/PlaywrightPropEngine.js +4 -4
- package/lib/helper/extras/PlaywrightReactVueLocator.js +1 -1
- package/lib/helper/extras/PlaywrightRestartOpts.js +21 -18
- package/lib/helper/extras/Popup.js +1 -1
- package/lib/helper/extras/React.js +3 -3
- package/lib/helper/network/actions.js +14 -7
- package/lib/helper/network/utils.js +4 -3
- package/lib/helper/scripts/blurElement.js +1 -1
- package/lib/helper/scripts/focusElement.js +1 -1
- package/lib/helper/scripts/highlightElement.js +1 -1
- package/lib/helper/scripts/isElementClickable.js +1 -1
- package/lib/helper/testcafe/testControllerHolder.js +1 -1
- package/lib/helper/testcafe/testcafe-utils.js +7 -8
- package/lib/helper.js +1 -3
- package/lib/history.js +6 -5
- package/lib/hooks.js +6 -6
- package/lib/html.js +7 -7
- package/lib/index.js +25 -41
- package/lib/interfaces/bdd.js +47 -64
- package/lib/interfaces/featureConfig.js +19 -19
- package/lib/interfaces/gherkin.js +124 -118
- package/lib/interfaces/scenarioConfig.js +29 -29
- package/lib/listener/artifacts.js +9 -9
- package/lib/listener/config.js +24 -24
- package/lib/listener/exit.js +12 -12
- package/lib/listener/helpers.js +42 -42
- package/lib/listener/mocha.js +11 -11
- package/lib/listener/retry.js +32 -30
- package/lib/listener/steps.js +50 -53
- package/lib/listener/timeout.js +54 -54
- package/lib/locator.js +7 -11
- package/lib/mochaFactory.js +18 -15
- package/lib/output.js +19 -15
- package/lib/parser.js +15 -12
- package/lib/pause.js +45 -38
- package/lib/plugin/allure.js +15 -15
- package/lib/plugin/autoDelay.js +29 -37
- package/lib/plugin/autoLogin.js +70 -65
- package/lib/plugin/commentStep.js +18 -18
- package/lib/plugin/coverage.js +112 -67
- package/lib/plugin/customLocator.js +21 -20
- package/lib/plugin/debugErrors.js +24 -24
- package/lib/plugin/eachElement.js +38 -38
- package/lib/plugin/fakerTransform.js +6 -6
- package/lib/plugin/heal.js +67 -108
- package/lib/plugin/pauseOnFail.js +11 -11
- package/lib/plugin/retryFailedStep.js +32 -39
- package/lib/plugin/retryTo.js +46 -40
- package/lib/plugin/screenshotOnFail.js +109 -87
- package/lib/plugin/selenoid.js +131 -118
- package/lib/plugin/standardActingHelpers.js +2 -8
- package/lib/plugin/stepByStepReport.js +110 -91
- package/lib/plugin/stepTimeout.js +24 -23
- package/lib/plugin/subtitles.js +34 -35
- package/lib/plugin/tryTo.js +40 -30
- package/lib/plugin/wdio.js +78 -75
- package/lib/recorder.js +14 -17
- package/lib/rerun.js +11 -10
- package/lib/scenario.js +25 -23
- package/lib/secret.js +4 -3
- package/lib/session.js +10 -10
- package/lib/step.js +12 -9
- package/lib/store.js +2 -3
- package/lib/transform.js +1 -1
- package/lib/translation.js +7 -8
- package/lib/ui.js +12 -14
- package/lib/utils.js +70 -72
- package/lib/within.js +10 -10
- package/lib/workerStorage.js +27 -25
- package/lib/workers.js +29 -33
- package/package.json +67 -68
- package/translations/de-DE.js +2 -1
- package/translations/fr-FR.js +2 -2
- package/translations/index.js +9 -13
- package/translations/it-IT.js +1 -1
- package/translations/ja-JP.js +1 -1
- package/translations/pl-PL.js +1 -1
- package/translations/pt-BR.js +1 -1
- package/translations/ru-RU.js +1 -1
- package/translations/zh-CN.js +1 -1
- package/translations/zh-TW.js +1 -1
- package/typings/index.d.ts +423 -65
- package/typings/promiseBasedTypes.d.ts +41 -172
- package/typings/types.d.ts +43 -178
- package/lib/dirname.js +0 -5
- package/lib/helper/Expect.js +0 -425
- package/lib/helper/MockServer.js +0 -223
package/lib/helper/TestCafe.js
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
const assert = require('assert')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
const qrcode = require('qrcode-terminal')
|
|
6
|
+
const createTestCafe = require('testcafe')
|
|
7
|
+
const { Selector, ClientFunction } = require('testcafe')
|
|
8
|
+
|
|
9
|
+
const Helper = require('@codeceptjs/helper')
|
|
10
|
+
const ElementNotFound = require('./errors/ElementNotFound')
|
|
11
|
+
const testControllerHolder = require('./testcafe/testControllerHolder')
|
|
12
|
+
const { mapError, createTestFile, createClientFunction } = require('./testcafe/testcafe-utils')
|
|
13
|
+
|
|
14
|
+
const stringIncludes = require('../assert/include').includes
|
|
15
|
+
const { urlEquals } = require('../assert/equal')
|
|
16
|
+
const { empty } = require('../assert/empty')
|
|
17
|
+
const { truth } = require('../assert/truth')
|
|
18
|
+
const { xpathLocator, normalizeSpacesInString } = require('../utils')
|
|
19
|
+
const Locator = require('../locator')
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Client Functions
|
|
22
23
|
*/
|
|
23
|
-
const getPageUrl = t => ClientFunction(() => document.location.href).with({ boundTestRun: t })
|
|
24
|
-
const getHtmlSource = t
|
|
24
|
+
const getPageUrl = (t) => ClientFunction(() => document.location.href).with({ boundTestRun: t })
|
|
25
|
+
const getHtmlSource = (t) =>
|
|
26
|
+
ClientFunction(() => document.getElementsByTagName('html')[0].innerHTML).with({ boundTestRun: t })
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* Uses [TestCafe](https://github.com/DevExpress/testcafe) library to run cross-browser tests.
|
|
@@ -92,16 +94,16 @@ const getHtmlSource = t => ClientFunction(() => document.getElementsByTagName('h
|
|
|
92
94
|
*/
|
|
93
95
|
class TestCafe extends Helper {
|
|
94
96
|
constructor(config) {
|
|
95
|
-
super(config)
|
|
97
|
+
super(config)
|
|
96
98
|
|
|
97
|
-
this.testcafe = undefined
|
|
98
|
-
this.t = undefined
|
|
99
|
-
this.dummyTestcafeFile
|
|
99
|
+
this.testcafe = undefined // testcafe instance
|
|
100
|
+
this.t = undefined // testcafe test controller
|
|
101
|
+
this.dummyTestcafeFile // generated testcafe test file
|
|
100
102
|
|
|
101
103
|
// context is used for within() function.
|
|
102
104
|
// It requires to have _withinBeginand _withinEnd implemented.
|
|
103
105
|
// Inside _withinBegin we should define that all next element calls should be started from a specific element (this.context).
|
|
104
|
-
this.context = undefined
|
|
106
|
+
this.context = undefined // TODO Not sure if this applies to testcafe
|
|
105
107
|
|
|
106
108
|
this.options = {
|
|
107
109
|
url: 'http://localhost',
|
|
@@ -116,15 +118,15 @@ class TestCafe extends Helper {
|
|
|
116
118
|
disableScreenshots: false,
|
|
117
119
|
windowSize: undefined,
|
|
118
120
|
...config,
|
|
119
|
-
}
|
|
121
|
+
}
|
|
120
122
|
}
|
|
121
123
|
|
|
122
124
|
// TOOD Do a requirements check
|
|
123
125
|
static _checkRequirements() {
|
|
124
126
|
try {
|
|
125
|
-
require('testcafe')
|
|
127
|
+
require('testcafe')
|
|
126
128
|
} catch (e) {
|
|
127
|
-
return ['testcafe@^1.1.0']
|
|
129
|
+
return ['testcafe@^1.1.0']
|
|
128
130
|
}
|
|
129
131
|
}
|
|
130
132
|
|
|
@@ -133,33 +135,36 @@ class TestCafe extends Helper {
|
|
|
133
135
|
{ name: 'url', message: 'Base url of site to be tested', default: 'http://localhost' },
|
|
134
136
|
{ name: 'browser', message: 'Browser to be used', default: 'chrome' },
|
|
135
137
|
{
|
|
136
|
-
name: 'show',
|
|
138
|
+
name: 'show',
|
|
139
|
+
message: 'Show browser window',
|
|
140
|
+
default: true,
|
|
141
|
+
type: 'confirm',
|
|
137
142
|
},
|
|
138
|
-
]
|
|
143
|
+
]
|
|
139
144
|
}
|
|
140
145
|
|
|
141
146
|
async _configureAndStartBrowser() {
|
|
142
|
-
this.dummyTestcafeFile = createTestFile(global.output_dir)
|
|
147
|
+
this.dummyTestcafeFile = createTestFile(global.output_dir) // create a dummy test file to get hold of the test controller
|
|
143
148
|
|
|
144
|
-
this.iteration += 2
|
|
149
|
+
this.iteration += 2 // Use different ports for each test run
|
|
145
150
|
// @ts-ignore
|
|
146
|
-
this.testcafe = await createTestCafe('', null, null)
|
|
151
|
+
this.testcafe = await createTestCafe('', null, null)
|
|
147
152
|
|
|
148
|
-
this.debugSection('_before', 'Starting testcafe browser...')
|
|
153
|
+
this.debugSection('_before', 'Starting testcafe browser...')
|
|
149
154
|
|
|
150
|
-
this.isRunning = true
|
|
155
|
+
this.isRunning = true
|
|
151
156
|
|
|
152
157
|
// TODO Do we have to cleanup the runner?
|
|
153
|
-
const runner = this.testcafe.createRunner()
|
|
158
|
+
const runner = this.testcafe.createRunner()
|
|
154
159
|
|
|
155
|
-
this.options.browser !== 'remote' ? this._startBrowser(runner) : this._startRemoteBrowser(runner)
|
|
160
|
+
this.options.browser !== 'remote' ? this._startBrowser(runner) : this._startRemoteBrowser(runner)
|
|
156
161
|
|
|
157
|
-
this.t = await testControllerHolder.get()
|
|
158
|
-
assert(this.t, 'Expected to have the testcafe test controller')
|
|
162
|
+
this.t = await testControllerHolder.get()
|
|
163
|
+
assert(this.t, 'Expected to have the testcafe test controller')
|
|
159
164
|
|
|
160
165
|
if (this.options.windowSize && this.options.windowSize.indexOf('x') > 0) {
|
|
161
|
-
const dimensions = this.options.windowSize.split('x')
|
|
162
|
-
await this.t.resizeWindow(parseInt(dimensions[0], 10), parseInt(dimensions[1], 10))
|
|
166
|
+
const dimensions = this.options.windowSize.split('x')
|
|
167
|
+
await this.t.resizeWindow(parseInt(dimensions[0], 10), parseInt(dimensions[1], 10))
|
|
163
168
|
}
|
|
164
169
|
}
|
|
165
170
|
|
|
@@ -183,16 +188,16 @@ class TestCafe extends Helper {
|
|
|
183
188
|
takeScreenshotsOnFails: true,
|
|
184
189
|
})
|
|
185
190
|
.catch((err) => {
|
|
186
|
-
this.debugSection('_before', `Error ${err.toString()}`)
|
|
187
|
-
this.isRunning = false
|
|
188
|
-
this.testcafe.close()
|
|
189
|
-
})
|
|
191
|
+
this.debugSection('_before', `Error ${err.toString()}`)
|
|
192
|
+
this.isRunning = false
|
|
193
|
+
this.testcafe.close()
|
|
194
|
+
})
|
|
190
195
|
}
|
|
191
196
|
|
|
192
197
|
async _startRemoteBrowser(runner) {
|
|
193
|
-
const remoteConnection = await this.testcafe.createBrowserConnection()
|
|
194
|
-
console.log('Connect your device to the following URL or scan QR Code: ', remoteConnection.url)
|
|
195
|
-
qrcode.generate(remoteConnection.url)
|
|
198
|
+
const remoteConnection = await this.testcafe.createBrowserConnection()
|
|
199
|
+
console.log('Connect your device to the following URL or scan QR Code: ', remoteConnection.url)
|
|
200
|
+
qrcode.generate(remoteConnection.url)
|
|
196
201
|
remoteConnection.once('ready', () => {
|
|
197
202
|
runner
|
|
198
203
|
.src(this.dummyTestcafeFile)
|
|
@@ -204,70 +209,67 @@ class TestCafe extends Helper {
|
|
|
204
209
|
skipUncaughtErrors: true,
|
|
205
210
|
})
|
|
206
211
|
.catch((err) => {
|
|
207
|
-
this.debugSection('_before', `Error ${err.toString()}`)
|
|
208
|
-
this.isRunning = false
|
|
209
|
-
this.testcafe.close()
|
|
210
|
-
})
|
|
211
|
-
})
|
|
212
|
+
this.debugSection('_before', `Error ${err.toString()}`)
|
|
213
|
+
this.isRunning = false
|
|
214
|
+
this.testcafe.close()
|
|
215
|
+
})
|
|
216
|
+
})
|
|
212
217
|
}
|
|
213
218
|
|
|
214
219
|
async _stopBrowser() {
|
|
215
|
-
this.debugSection('_after', 'Stopping testcafe browser...')
|
|
220
|
+
this.debugSection('_after', 'Stopping testcafe browser...')
|
|
216
221
|
|
|
217
|
-
testControllerHolder.free()
|
|
222
|
+
testControllerHolder.free()
|
|
218
223
|
if (this.testcafe) {
|
|
219
|
-
this.testcafe.close()
|
|
224
|
+
this.testcafe.close()
|
|
220
225
|
}
|
|
221
226
|
|
|
222
|
-
fs.unlinkSync(this.dummyTestcafeFile)
|
|
223
|
-
this.t = undefined
|
|
227
|
+
fs.unlinkSync(this.dummyTestcafeFile) // remove the dummy test
|
|
228
|
+
this.t = undefined
|
|
224
229
|
|
|
225
|
-
this.isRunning = false
|
|
230
|
+
this.isRunning = false
|
|
226
231
|
}
|
|
227
232
|
|
|
228
|
-
_init() {
|
|
229
|
-
}
|
|
233
|
+
_init() {}
|
|
230
234
|
|
|
231
235
|
async _beforeSuite() {
|
|
232
236
|
if (!this.options.restart && !this.options.manualStart && !this.isRunning) {
|
|
233
|
-
this.debugSection('Session', 'Starting singleton browser session')
|
|
234
|
-
return this._configureAndStartBrowser()
|
|
237
|
+
this.debugSection('Session', 'Starting singleton browser session')
|
|
238
|
+
return this._configureAndStartBrowser()
|
|
235
239
|
}
|
|
236
240
|
}
|
|
237
241
|
|
|
238
242
|
async _before() {
|
|
239
|
-
if (this.options.restart && !this.options.manualStart) return this._configureAndStartBrowser()
|
|
240
|
-
if (!this.isRunning && !this.options.manualStart) return this._configureAndStartBrowser()
|
|
241
|
-
this.context = null
|
|
243
|
+
if (this.options.restart && !this.options.manualStart) return this._configureAndStartBrowser()
|
|
244
|
+
if (!this.isRunning && !this.options.manualStart) return this._configureAndStartBrowser()
|
|
245
|
+
this.context = null
|
|
242
246
|
}
|
|
243
247
|
|
|
244
248
|
async _after() {
|
|
245
|
-
if (!this.isRunning) return
|
|
249
|
+
if (!this.isRunning) return
|
|
246
250
|
|
|
247
251
|
if (this.options.restart) {
|
|
248
|
-
this.isRunning = false
|
|
249
|
-
return this._stopBrowser()
|
|
252
|
+
this.isRunning = false
|
|
253
|
+
return this._stopBrowser()
|
|
250
254
|
}
|
|
251
255
|
|
|
252
|
-
if (this.options.keepBrowserState) return
|
|
256
|
+
if (this.options.keepBrowserState) return
|
|
253
257
|
|
|
254
258
|
if (!this.options.keepCookies) {
|
|
255
|
-
this.debugSection('Session', 'cleaning cookies and localStorage')
|
|
256
|
-
await this.clearCookie()
|
|
259
|
+
this.debugSection('Session', 'cleaning cookies and localStorage')
|
|
260
|
+
await this.clearCookie()
|
|
257
261
|
|
|
258
262
|
// TODO IMHO that should only happen when
|
|
259
|
-
await this.executeScript(() => localStorage.clear())
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
});
|
|
263
|
+
await this.executeScript(() => localStorage.clear()).catch((err) => {
|
|
264
|
+
if (!(err.message.indexOf("Storage is disabled inside 'data:' URLs.") > -1)) throw err
|
|
265
|
+
})
|
|
263
266
|
}
|
|
264
267
|
}
|
|
265
268
|
|
|
266
|
-
_afterSuite() {
|
|
267
|
-
}
|
|
269
|
+
_afterSuite() {}
|
|
268
270
|
|
|
269
271
|
async _finishTest() {
|
|
270
|
-
if (!this.options.restart && this.isRunning) return this._stopBrowser()
|
|
272
|
+
if (!this.options.restart && this.isRunning) return this._stopBrowser()
|
|
271
273
|
}
|
|
272
274
|
|
|
273
275
|
/**
|
|
@@ -290,7 +292,7 @@ class TestCafe extends Helper {
|
|
|
290
292
|
* @param {function} fn async functuion that executed with TestCafe helper as argument
|
|
291
293
|
*/
|
|
292
294
|
useTestCafeTo(description, fn) {
|
|
293
|
-
return this._useTo(...arguments)
|
|
295
|
+
return this._useTo(...arguments)
|
|
294
296
|
}
|
|
295
297
|
|
|
296
298
|
/**
|
|
@@ -303,29 +305,28 @@ class TestCafe extends Helper {
|
|
|
303
305
|
*
|
|
304
306
|
*/
|
|
305
307
|
async _locate(locator) {
|
|
306
|
-
return findElements.call(this, this.context, locator).catch(mapError)
|
|
308
|
+
return findElements.call(this, this.context, locator).catch(mapError)
|
|
307
309
|
}
|
|
308
310
|
|
|
309
311
|
async _withinBegin(locator) {
|
|
310
|
-
const els = await this._locate(locator)
|
|
311
|
-
assertElementExists(els, locator)
|
|
312
|
-
this.context = await els.nth(0)
|
|
312
|
+
const els = await this._locate(locator)
|
|
313
|
+
assertElementExists(els, locator)
|
|
314
|
+
this.context = await els.nth(0)
|
|
313
315
|
}
|
|
314
316
|
|
|
315
317
|
async _withinEnd() {
|
|
316
|
-
this.context = null
|
|
318
|
+
this.context = null
|
|
317
319
|
}
|
|
318
320
|
|
|
319
321
|
/**
|
|
320
322
|
* {{> amOnPage }}
|
|
321
323
|
*/
|
|
322
324
|
async amOnPage(url) {
|
|
323
|
-
if (
|
|
324
|
-
url = this.options.url + url
|
|
325
|
+
if (!/^\w+\:\/\//.test(url)) {
|
|
326
|
+
url = this.options.url + url
|
|
325
327
|
}
|
|
326
328
|
|
|
327
|
-
return this.t.navigateTo(url)
|
|
328
|
-
.catch(mapError);
|
|
329
|
+
return this.t.navigateTo(url).catch(mapError)
|
|
329
330
|
}
|
|
330
331
|
|
|
331
332
|
/**
|
|
@@ -333,10 +334,10 @@ class TestCafe extends Helper {
|
|
|
333
334
|
*/
|
|
334
335
|
async resizeWindow(width, height) {
|
|
335
336
|
if (width === 'maximize') {
|
|
336
|
-
return this.t.maximizeWindow().catch(mapError)
|
|
337
|
+
return this.t.maximizeWindow().catch(mapError)
|
|
337
338
|
}
|
|
338
339
|
|
|
339
|
-
return this.t.resizeWindow(width, height).catch(mapError)
|
|
340
|
+
return this.t.resizeWindow(width, height).catch(mapError)
|
|
340
341
|
}
|
|
341
342
|
|
|
342
343
|
/**
|
|
@@ -344,13 +345,16 @@ class TestCafe extends Helper {
|
|
|
344
345
|
*
|
|
345
346
|
*/
|
|
346
347
|
async focus(locator) {
|
|
347
|
-
const els = await this._locate(locator)
|
|
348
|
-
await assertElementExists(els, locator, 'Element to focus')
|
|
349
|
-
const element = await els.nth(0)
|
|
348
|
+
const els = await this._locate(locator)
|
|
349
|
+
await assertElementExists(els, locator, 'Element to focus')
|
|
350
|
+
const element = await els.nth(0)
|
|
350
351
|
|
|
351
|
-
const focusElement = ClientFunction(() => element().focus(), {
|
|
352
|
+
const focusElement = ClientFunction(() => element().focus(), {
|
|
353
|
+
boundTestRun: this.t,
|
|
354
|
+
dependencies: { element },
|
|
355
|
+
})
|
|
352
356
|
|
|
353
|
-
return focusElement()
|
|
357
|
+
return focusElement()
|
|
354
358
|
}
|
|
355
359
|
|
|
356
360
|
/**
|
|
@@ -358,13 +362,13 @@ class TestCafe extends Helper {
|
|
|
358
362
|
*
|
|
359
363
|
*/
|
|
360
364
|
async blur(locator) {
|
|
361
|
-
const els = await this._locate(locator)
|
|
362
|
-
await assertElementExists(els, locator, 'Element to blur')
|
|
363
|
-
const element = await els.nth(0)
|
|
365
|
+
const els = await this._locate(locator)
|
|
366
|
+
await assertElementExists(els, locator, 'Element to blur')
|
|
367
|
+
const element = await els.nth(0)
|
|
364
368
|
|
|
365
|
-
const blurElement = ClientFunction(() => element().blur(), { boundTestRun: this.t, dependencies: { element } })
|
|
369
|
+
const blurElement = ClientFunction(() => element().blur(), { boundTestRun: this.t, dependencies: { element } })
|
|
366
370
|
|
|
367
|
-
return blurElement()
|
|
371
|
+
return blurElement()
|
|
368
372
|
}
|
|
369
373
|
|
|
370
374
|
/**
|
|
@@ -372,7 +376,7 @@ class TestCafe extends Helper {
|
|
|
372
376
|
*
|
|
373
377
|
*/
|
|
374
378
|
async click(locator, context = null) {
|
|
375
|
-
return proceedClick.call(this, locator, context)
|
|
379
|
+
return proceedClick.call(this, locator, context)
|
|
376
380
|
}
|
|
377
381
|
|
|
378
382
|
/**
|
|
@@ -380,7 +384,7 @@ class TestCafe extends Helper {
|
|
|
380
384
|
*/
|
|
381
385
|
async refreshPage() {
|
|
382
386
|
// eslint-disable-next-line no-restricted-globals
|
|
383
|
-
return this.t.eval(() => location.reload(true), { boundTestRun: this.t }).catch(mapError)
|
|
387
|
+
return this.t.eval(() => location.reload(true), { boundTestRun: this.t }).catch(mapError)
|
|
384
388
|
}
|
|
385
389
|
|
|
386
390
|
/**
|
|
@@ -388,37 +392,33 @@ class TestCafe extends Helper {
|
|
|
388
392
|
*
|
|
389
393
|
*/
|
|
390
394
|
async waitForVisible(locator, sec) {
|
|
391
|
-
const timeout = sec ? sec * 1000 : undefined
|
|
395
|
+
const timeout = sec ? sec * 1000 : undefined
|
|
392
396
|
|
|
393
397
|
return (await findElements.call(this, this.context, locator))
|
|
394
398
|
.with({ visibilityCheck: true, timeout })()
|
|
395
|
-
.catch(mapError)
|
|
399
|
+
.catch(mapError)
|
|
396
400
|
}
|
|
397
401
|
|
|
398
402
|
/**
|
|
399
403
|
* {{> fillField }}
|
|
400
404
|
*/
|
|
401
405
|
async fillField(field, value) {
|
|
402
|
-
const els = await findFields.call(this, field)
|
|
403
|
-
assertElementExists(els, field, 'Field')
|
|
404
|
-
const el = await els.nth(0)
|
|
405
|
-
return this.t
|
|
406
|
-
.typeText(el, value.toString(), { replace: true })
|
|
407
|
-
.catch(mapError);
|
|
406
|
+
const els = await findFields.call(this, field)
|
|
407
|
+
assertElementExists(els, field, 'Field')
|
|
408
|
+
const el = await els.nth(0)
|
|
409
|
+
return this.t.typeText(el, value.toString(), { replace: true }).catch(mapError)
|
|
408
410
|
}
|
|
409
411
|
|
|
410
412
|
/**
|
|
411
413
|
* {{> clearField }}
|
|
412
414
|
*/
|
|
413
415
|
async clearField(field) {
|
|
414
|
-
const els = await findFields.call(this, field)
|
|
415
|
-
assertElementExists(els, field, 'Field')
|
|
416
|
-
const el = await els.nth(0)
|
|
416
|
+
const els = await findFields.call(this, field)
|
|
417
|
+
assertElementExists(els, field, 'Field')
|
|
418
|
+
const el = await els.nth(0)
|
|
417
419
|
|
|
418
|
-
const res = await this.t
|
|
419
|
-
|
|
420
|
-
.pressKey('delete');
|
|
421
|
-
return res;
|
|
420
|
+
const res = await this.t.selectText(el).pressKey('delete')
|
|
421
|
+
return res
|
|
422
422
|
}
|
|
423
423
|
|
|
424
424
|
/**
|
|
@@ -426,13 +426,11 @@ class TestCafe extends Helper {
|
|
|
426
426
|
*
|
|
427
427
|
*/
|
|
428
428
|
async appendField(field, value) {
|
|
429
|
-
const els = await findFields.call(this, field)
|
|
430
|
-
assertElementExists(els, field, 'Field')
|
|
431
|
-
const el = await els.nth(0)
|
|
429
|
+
const els = await findFields.call(this, field)
|
|
430
|
+
assertElementExists(els, field, 'Field')
|
|
431
|
+
const el = await els.nth(0)
|
|
432
432
|
|
|
433
|
-
return this.t
|
|
434
|
-
.typeText(el, value.toString(), { replace: false })
|
|
435
|
-
.catch(mapError);
|
|
433
|
+
return this.t.typeText(el, value.toString(), { replace: false }).catch(mapError)
|
|
436
434
|
}
|
|
437
435
|
|
|
438
436
|
/**
|
|
@@ -440,14 +438,12 @@ class TestCafe extends Helper {
|
|
|
440
438
|
*
|
|
441
439
|
*/
|
|
442
440
|
async attachFile(field, pathToFile) {
|
|
443
|
-
const els = await findFields.call(this, field)
|
|
444
|
-
assertElementExists(els, field, 'Field')
|
|
445
|
-
const el = await els.nth(0)
|
|
446
|
-
const file = path.join(global.codecept_dir, pathToFile)
|
|
441
|
+
const els = await findFields.call(this, field)
|
|
442
|
+
assertElementExists(els, field, 'Field')
|
|
443
|
+
const el = await els.nth(0)
|
|
444
|
+
const file = path.join(global.codecept_dir, pathToFile)
|
|
447
445
|
|
|
448
|
-
return this.t
|
|
449
|
-
.setFilesToUpload(el, [file])
|
|
450
|
-
.catch(mapError);
|
|
446
|
+
return this.t.setFilesToUpload(el, [file]).catch(mapError)
|
|
451
447
|
}
|
|
452
448
|
|
|
453
449
|
/**
|
|
@@ -456,11 +452,11 @@ class TestCafe extends Helper {
|
|
|
456
452
|
* {{ keys }}
|
|
457
453
|
*/
|
|
458
454
|
async pressKey(key) {
|
|
459
|
-
assert(key, 'Expected a sequence of keys or key combinations')
|
|
455
|
+
assert(key, 'Expected a sequence of keys or key combinations')
|
|
460
456
|
|
|
461
457
|
return this.t
|
|
462
458
|
.pressKey(key.toLowerCase()) // testcafe keys are lowercase
|
|
463
|
-
.catch(mapError)
|
|
459
|
+
.catch(mapError)
|
|
464
460
|
}
|
|
465
461
|
|
|
466
462
|
/**
|
|
@@ -468,12 +464,10 @@ class TestCafe extends Helper {
|
|
|
468
464
|
*
|
|
469
465
|
*/
|
|
470
466
|
async moveCursorTo(locator, offsetX = 0, offsetY = 0) {
|
|
471
|
-
const els = (await findElements.call(this, this.context, locator)).filterVisible()
|
|
472
|
-
await assertElementExists(els, locator)
|
|
467
|
+
const els = (await findElements.call(this, this.context, locator)).filterVisible()
|
|
468
|
+
await assertElementExists(els, locator)
|
|
473
469
|
|
|
474
|
-
return this.t
|
|
475
|
-
.hover(els.nth(0), { offsetX, offsetY })
|
|
476
|
-
.catch(mapError);
|
|
470
|
+
return this.t.hover(els.nth(0), { offsetX, offsetY }).catch(mapError)
|
|
477
471
|
}
|
|
478
472
|
|
|
479
473
|
/**
|
|
@@ -481,17 +475,15 @@ class TestCafe extends Helper {
|
|
|
481
475
|
*
|
|
482
476
|
*/
|
|
483
477
|
async doubleClick(locator, context = null) {
|
|
484
|
-
let matcher
|
|
478
|
+
let matcher
|
|
485
479
|
if (context) {
|
|
486
|
-
const els = await this._locate(context)
|
|
487
|
-
await assertElementExists(els, context)
|
|
488
|
-
matcher = await els.nth(0)
|
|
480
|
+
const els = await this._locate(context)
|
|
481
|
+
await assertElementExists(els, context)
|
|
482
|
+
matcher = await els.nth(0)
|
|
489
483
|
}
|
|
490
484
|
|
|
491
|
-
const els = (await findClickable.call(this, matcher, locator)).filterVisible()
|
|
492
|
-
return this.t
|
|
493
|
-
.doubleClick(els.nth(0))
|
|
494
|
-
.catch(mapError);
|
|
485
|
+
const els = (await findClickable.call(this, matcher, locator)).filterVisible()
|
|
486
|
+
return this.t.doubleClick(els.nth(0)).catch(mapError)
|
|
495
487
|
}
|
|
496
488
|
|
|
497
489
|
/**
|
|
@@ -499,40 +491,34 @@ class TestCafe extends Helper {
|
|
|
499
491
|
*
|
|
500
492
|
*/
|
|
501
493
|
async rightClick(locator, context = null) {
|
|
502
|
-
let matcher
|
|
494
|
+
let matcher
|
|
503
495
|
if (context) {
|
|
504
|
-
const els = await this._locate(context)
|
|
505
|
-
await assertElementExists(els, context)
|
|
506
|
-
matcher = await els.nth(0)
|
|
496
|
+
const els = await this._locate(context)
|
|
497
|
+
await assertElementExists(els, context)
|
|
498
|
+
matcher = await els.nth(0)
|
|
507
499
|
}
|
|
508
|
-
const els = (await findClickable.call(this, matcher, locator)).filterVisible()
|
|
509
|
-
assertElementExists(els, locator)
|
|
510
|
-
return this.t
|
|
511
|
-
.rightClick(els.nth(0))
|
|
512
|
-
.catch(mapError);
|
|
500
|
+
const els = (await findClickable.call(this, matcher, locator)).filterVisible()
|
|
501
|
+
assertElementExists(els, locator)
|
|
502
|
+
return this.t.rightClick(els.nth(0)).catch(mapError)
|
|
513
503
|
}
|
|
514
504
|
|
|
515
505
|
/**
|
|
516
506
|
* {{> checkOption }}
|
|
517
507
|
*/
|
|
518
508
|
async checkOption(field, context = null) {
|
|
519
|
-
const el = await findCheckable.call(this, field, context)
|
|
509
|
+
const el = await findCheckable.call(this, field, context)
|
|
520
510
|
|
|
521
|
-
return this.t
|
|
522
|
-
.click(el)
|
|
523
|
-
.catch(mapError);
|
|
511
|
+
return this.t.click(el).catch(mapError)
|
|
524
512
|
}
|
|
525
513
|
|
|
526
514
|
/**
|
|
527
515
|
* {{> uncheckOption }}
|
|
528
516
|
*/
|
|
529
517
|
async uncheckOption(field, context = null) {
|
|
530
|
-
const el = await findCheckable.call(this, field, context)
|
|
518
|
+
const el = await findCheckable.call(this, field, context)
|
|
531
519
|
|
|
532
520
|
if (await el.checked) {
|
|
533
|
-
return this.t
|
|
534
|
-
.click(el)
|
|
535
|
-
.catch(mapError);
|
|
521
|
+
return this.t.click(el).catch(mapError)
|
|
536
522
|
}
|
|
537
523
|
}
|
|
538
524
|
|
|
@@ -540,58 +526,56 @@ class TestCafe extends Helper {
|
|
|
540
526
|
* {{> seeCheckboxIsChecked }}
|
|
541
527
|
*/
|
|
542
528
|
async seeCheckboxIsChecked(field) {
|
|
543
|
-
return proceedIsChecked.call(this, 'assert', field)
|
|
529
|
+
return proceedIsChecked.call(this, 'assert', field)
|
|
544
530
|
}
|
|
545
531
|
|
|
546
532
|
/**
|
|
547
533
|
* {{> dontSeeCheckboxIsChecked }}
|
|
548
534
|
*/
|
|
549
535
|
async dontSeeCheckboxIsChecked(field) {
|
|
550
|
-
return proceedIsChecked.call(this, 'negate', field)
|
|
536
|
+
return proceedIsChecked.call(this, 'negate', field)
|
|
551
537
|
}
|
|
552
538
|
|
|
553
539
|
/**
|
|
554
540
|
* {{> selectOption }}
|
|
555
541
|
*/
|
|
556
542
|
async selectOption(select, option) {
|
|
557
|
-
const els = await findFields.call(this, select)
|
|
558
|
-
assertElementExists(els, select, 'Selectable field')
|
|
543
|
+
const els = await findFields.call(this, select)
|
|
544
|
+
assertElementExists(els, select, 'Selectable field')
|
|
559
545
|
|
|
560
|
-
const el = await els.filterVisible().nth(0)
|
|
546
|
+
const el = await els.filterVisible().nth(0)
|
|
561
547
|
|
|
562
548
|
if ((await el.tagName).toLowerCase() !== 'select') {
|
|
563
|
-
throw new Error('Element is not <select>')
|
|
549
|
+
throw new Error('Element is not <select>')
|
|
564
550
|
}
|
|
565
|
-
if (!Array.isArray(option)) option = [option]
|
|
551
|
+
if (!Array.isArray(option)) option = [option]
|
|
566
552
|
|
|
567
553
|
// TODO As far as I understand the testcafe docs this should do a multi-select
|
|
568
554
|
// but it does not work
|
|
569
555
|
// const clickOpts = { ctrl: option.length > 1 };
|
|
570
|
-
await this.t.click(el).catch(mapError)
|
|
556
|
+
await this.t.click(el).catch(mapError)
|
|
571
557
|
|
|
572
558
|
for (const key of option) {
|
|
573
|
-
const opt = key
|
|
559
|
+
const opt = key
|
|
574
560
|
|
|
575
|
-
let optEl
|
|
561
|
+
let optEl
|
|
576
562
|
try {
|
|
577
|
-
optEl = el.child('option').withText(opt)
|
|
563
|
+
optEl = el.child('option').withText(opt)
|
|
578
564
|
if (await optEl.count) {
|
|
579
|
-
await this.t.click(optEl).catch(mapError)
|
|
580
|
-
continue
|
|
565
|
+
await this.t.click(optEl).catch(mapError)
|
|
566
|
+
continue
|
|
581
567
|
}
|
|
582
568
|
// eslint-disable-next-line no-empty
|
|
583
|
-
} catch (err) {
|
|
584
|
-
}
|
|
569
|
+
} catch (err) {}
|
|
585
570
|
|
|
586
571
|
try {
|
|
587
|
-
const sel = `[value="${opt}"]
|
|
588
|
-
optEl = el.find(sel)
|
|
572
|
+
const sel = `[value="${opt}"]`
|
|
573
|
+
optEl = el.find(sel)
|
|
589
574
|
if (await optEl.count) {
|
|
590
|
-
await this.t.click(optEl).catch(mapError)
|
|
575
|
+
await this.t.click(optEl).catch(mapError)
|
|
591
576
|
}
|
|
592
577
|
// eslint-disable-next-line no-empty
|
|
593
|
-
} catch (err) {
|
|
594
|
-
}
|
|
578
|
+
} catch (err) {}
|
|
595
579
|
}
|
|
596
580
|
}
|
|
597
581
|
|
|
@@ -599,28 +583,28 @@ class TestCafe extends Helper {
|
|
|
599
583
|
* {{> seeInCurrentUrl }}
|
|
600
584
|
*/
|
|
601
585
|
async seeInCurrentUrl(url) {
|
|
602
|
-
stringIncludes('url').assert(url, await getPageUrl(this.t)().catch(mapError))
|
|
586
|
+
stringIncludes('url').assert(url, await getPageUrl(this.t)().catch(mapError))
|
|
603
587
|
}
|
|
604
588
|
|
|
605
589
|
/**
|
|
606
590
|
* {{> dontSeeInCurrentUrl }}
|
|
607
591
|
*/
|
|
608
592
|
async dontSeeInCurrentUrl(url) {
|
|
609
|
-
stringIncludes('url').negate(url, await getPageUrl(this.t)().catch(mapError))
|
|
593
|
+
stringIncludes('url').negate(url, await getPageUrl(this.t)().catch(mapError))
|
|
610
594
|
}
|
|
611
595
|
|
|
612
596
|
/**
|
|
613
597
|
* {{> seeCurrentUrlEquals }}
|
|
614
598
|
*/
|
|
615
599
|
async seeCurrentUrlEquals(url) {
|
|
616
|
-
urlEquals(this.options.url).assert(url, await getPageUrl(this.t)().catch(mapError))
|
|
600
|
+
urlEquals(this.options.url).assert(url, await getPageUrl(this.t)().catch(mapError))
|
|
617
601
|
}
|
|
618
602
|
|
|
619
603
|
/**
|
|
620
604
|
* {{> dontSeeCurrentUrlEquals }}
|
|
621
605
|
*/
|
|
622
606
|
async dontSeeCurrentUrlEquals(url) {
|
|
623
|
-
urlEquals(this.options.url).negate(url, await getPageUrl(this.t)().catch(mapError))
|
|
607
|
+
urlEquals(this.options.url).negate(url, await getPageUrl(this.t)().catch(mapError))
|
|
624
608
|
}
|
|
625
609
|
|
|
626
610
|
/**
|
|
@@ -628,16 +612,14 @@ class TestCafe extends Helper {
|
|
|
628
612
|
*
|
|
629
613
|
*/
|
|
630
614
|
async see(text, context = null) {
|
|
631
|
-
let els
|
|
615
|
+
let els
|
|
632
616
|
if (context) {
|
|
633
|
-
els = (await findElements.call(this, this.context, context)).withText(normalizeSpacesInString(text))
|
|
617
|
+
els = (await findElements.call(this, this.context, context)).withText(normalizeSpacesInString(text))
|
|
634
618
|
} else {
|
|
635
|
-
els = (await findElements.call(this, this.context, '*')).withText(normalizeSpacesInString(text))
|
|
619
|
+
els = (await findElements.call(this, this.context, '*')).withText(normalizeSpacesInString(text))
|
|
636
620
|
}
|
|
637
621
|
|
|
638
|
-
return this.t
|
|
639
|
-
.expect(els.filterVisible().count).gt(0, `No element with text "${text}" found`)
|
|
640
|
-
.catch(mapError);
|
|
622
|
+
return this.t.expect(els.filterVisible().count).gt(0, `No element with text "${text}" found`).catch(mapError)
|
|
641
623
|
}
|
|
642
624
|
|
|
643
625
|
/**
|
|
@@ -645,56 +627,61 @@ class TestCafe extends Helper {
|
|
|
645
627
|
*
|
|
646
628
|
*/
|
|
647
629
|
async dontSee(text, context = null) {
|
|
648
|
-
let els
|
|
630
|
+
let els
|
|
649
631
|
if (context) {
|
|
650
|
-
els = (await findElements.call(this, this.context, context)).withText(text)
|
|
632
|
+
els = (await findElements.call(this, this.context, context)).withText(text)
|
|
651
633
|
} else {
|
|
652
|
-
els = (await findElements.call(this, this.context, 'body')).withText(text)
|
|
634
|
+
els = (await findElements.call(this, this.context, 'body')).withText(text)
|
|
653
635
|
}
|
|
654
636
|
|
|
655
637
|
return this.t
|
|
656
|
-
.expect(els.filterVisible().count)
|
|
657
|
-
.
|
|
638
|
+
.expect(els.filterVisible().count)
|
|
639
|
+
.eql(0, `Element with text "${text}" can still be seen`)
|
|
640
|
+
.catch(mapError)
|
|
658
641
|
}
|
|
659
642
|
|
|
660
643
|
/**
|
|
661
644
|
* {{> seeElement }}
|
|
662
645
|
*/
|
|
663
646
|
async seeElement(locator) {
|
|
664
|
-
const exists = (await findElements.call(this, this.context, locator)).filterVisible().exists
|
|
647
|
+
const exists = (await findElements.call(this, this.context, locator)).filterVisible().exists
|
|
665
648
|
return this.t
|
|
666
|
-
.expect(exists)
|
|
667
|
-
.
|
|
649
|
+
.expect(exists)
|
|
650
|
+
.ok(`No element "${new Locator(locator)}" found`)
|
|
651
|
+
.catch(mapError)
|
|
668
652
|
}
|
|
669
653
|
|
|
670
654
|
/**
|
|
671
655
|
* {{> dontSeeElement }}
|
|
672
656
|
*/
|
|
673
657
|
async dontSeeElement(locator) {
|
|
674
|
-
const exists = (await findElements.call(this, this.context, locator)).filterVisible().exists
|
|
658
|
+
const exists = (await findElements.call(this, this.context, locator)).filterVisible().exists
|
|
675
659
|
return this.t
|
|
676
|
-
.expect(exists)
|
|
677
|
-
.
|
|
660
|
+
.expect(exists)
|
|
661
|
+
.notOk(`Element "${new Locator(locator)}" is still visible`)
|
|
662
|
+
.catch(mapError)
|
|
678
663
|
}
|
|
679
664
|
|
|
680
665
|
/**
|
|
681
666
|
* {{> seeElementInDOM }}
|
|
682
667
|
*/
|
|
683
668
|
async seeElementInDOM(locator) {
|
|
684
|
-
const exists = (await findElements.call(this, this.context, locator)).exists
|
|
669
|
+
const exists = (await findElements.call(this, this.context, locator)).exists
|
|
685
670
|
return this.t
|
|
686
|
-
.expect(exists)
|
|
687
|
-
.
|
|
671
|
+
.expect(exists)
|
|
672
|
+
.ok(`No element "${new Locator(locator)}" found in DOM`)
|
|
673
|
+
.catch(mapError)
|
|
688
674
|
}
|
|
689
675
|
|
|
690
676
|
/**
|
|
691
677
|
* {{> dontSeeElementInDOM }}
|
|
692
678
|
*/
|
|
693
679
|
async dontSeeElementInDOM(locator) {
|
|
694
|
-
const exists = (await findElements.call(this, this.context, locator)).exists
|
|
680
|
+
const exists = (await findElements.call(this, this.context, locator)).exists
|
|
695
681
|
return this.t
|
|
696
|
-
.expect(exists)
|
|
697
|
-
.
|
|
682
|
+
.expect(exists)
|
|
683
|
+
.notOk(`Element "${new Locator(locator)}" is still in DOM`)
|
|
684
|
+
.catch(mapError)
|
|
698
685
|
}
|
|
699
686
|
|
|
700
687
|
/**
|
|
@@ -702,48 +689,45 @@ class TestCafe extends Helper {
|
|
|
702
689
|
*
|
|
703
690
|
*/
|
|
704
691
|
async seeNumberOfVisibleElements(locator, num) {
|
|
705
|
-
const count = (await findElements.call(this, this.context, locator)).filterVisible().count
|
|
706
|
-
return this.t
|
|
707
|
-
.expect(count).eql(num)
|
|
708
|
-
.catch(mapError);
|
|
692
|
+
const count = (await findElements.call(this, this.context, locator)).filterVisible().count
|
|
693
|
+
return this.t.expect(count).eql(num).catch(mapError)
|
|
709
694
|
}
|
|
710
695
|
|
|
711
696
|
/**
|
|
712
697
|
* {{> grabNumberOfVisibleElements }}
|
|
713
698
|
*/
|
|
714
699
|
async grabNumberOfVisibleElements(locator) {
|
|
715
|
-
const count = (await findElements.call(this, this.context, locator)).filterVisible().count
|
|
716
|
-
return count
|
|
700
|
+
const count = (await findElements.call(this, this.context, locator)).filterVisible().count
|
|
701
|
+
return count
|
|
717
702
|
}
|
|
718
703
|
|
|
719
704
|
/**
|
|
720
705
|
* {{> seeInField }}
|
|
721
706
|
*/
|
|
722
707
|
async seeInField(field, value) {
|
|
723
|
-
const _value =
|
|
708
|
+
const _value = typeof value === 'boolean' ? value : value.toString()
|
|
724
709
|
// const expectedValue = findElements.call(this, this.context, field).value;
|
|
725
|
-
const els = await findFields.call(this, field)
|
|
726
|
-
assertElementExists(els, field, 'Field')
|
|
727
|
-
const el = await els.nth(0)
|
|
710
|
+
const els = await findFields.call(this, field)
|
|
711
|
+
assertElementExists(els, field, 'Field')
|
|
712
|
+
const el = await els.nth(0)
|
|
728
713
|
|
|
729
714
|
return this.t
|
|
730
|
-
.expect(await el.value)
|
|
731
|
-
.
|
|
715
|
+
.expect(await el.value)
|
|
716
|
+
.eql(_value)
|
|
717
|
+
.catch(mapError)
|
|
732
718
|
}
|
|
733
719
|
|
|
734
720
|
/**
|
|
735
721
|
* {{> dontSeeInField }}
|
|
736
722
|
*/
|
|
737
723
|
async dontSeeInField(field, value) {
|
|
738
|
-
const _value =
|
|
724
|
+
const _value = typeof value === 'boolean' ? value : value.toString()
|
|
739
725
|
// const expectedValue = findElements.call(this, this.context, field).value;
|
|
740
|
-
const els = await findFields.call(this, field)
|
|
741
|
-
assertElementExists(els, field, 'Field')
|
|
742
|
-
const el = await els.nth(0)
|
|
726
|
+
const els = await findFields.call(this, field)
|
|
727
|
+
assertElementExists(els, field, 'Field')
|
|
728
|
+
const el = await els.nth(0)
|
|
743
729
|
|
|
744
|
-
return this.t
|
|
745
|
-
.expect(el.value).notEql(_value)
|
|
746
|
-
.catch(mapError);
|
|
730
|
+
return this.t.expect(el.value).notEql(_value).catch(mapError)
|
|
747
731
|
}
|
|
748
732
|
|
|
749
733
|
/**
|
|
@@ -754,26 +738,24 @@ class TestCafe extends Helper {
|
|
|
754
738
|
* ```
|
|
755
739
|
*/
|
|
756
740
|
async seeTextEquals(text, context = null) {
|
|
757
|
-
const expectedText = findElements.call(this, context, undefined).textContent
|
|
758
|
-
return this.t
|
|
759
|
-
.expect(expectedText).eql(text)
|
|
760
|
-
.catch(mapError);
|
|
741
|
+
const expectedText = findElements.call(this, context, undefined).textContent
|
|
742
|
+
return this.t.expect(expectedText).eql(text).catch(mapError)
|
|
761
743
|
}
|
|
762
744
|
|
|
763
745
|
/**
|
|
764
746
|
* {{> seeInSource }}
|
|
765
747
|
*/
|
|
766
748
|
async seeInSource(text) {
|
|
767
|
-
const source = await getHtmlSource(this.t)()
|
|
768
|
-
stringIncludes('HTML source of a page').assert(text, source)
|
|
749
|
+
const source = await getHtmlSource(this.t)()
|
|
750
|
+
stringIncludes('HTML source of a page').assert(text, source)
|
|
769
751
|
}
|
|
770
752
|
|
|
771
753
|
/**
|
|
772
754
|
* {{> dontSeeInSource }}
|
|
773
755
|
*/
|
|
774
756
|
async dontSeeInSource(text) {
|
|
775
|
-
const source = await getHtmlSource(this.t)()
|
|
776
|
-
stringIncludes('HTML source of a page').negate(text, source)
|
|
757
|
+
const source = await getHtmlSource(this.t)()
|
|
758
|
+
stringIncludes('HTML source of a page').negate(text, source)
|
|
777
759
|
}
|
|
778
760
|
|
|
779
761
|
/**
|
|
@@ -781,14 +763,14 @@ class TestCafe extends Helper {
|
|
|
781
763
|
*
|
|
782
764
|
*/
|
|
783
765
|
async saveElementScreenshot(locator, fileName) {
|
|
784
|
-
const outputFile = path.join(global.output_dir, fileName)
|
|
766
|
+
const outputFile = path.join(global.output_dir, fileName)
|
|
785
767
|
|
|
786
|
-
const sel = await findElements.call(this, this.context, locator)
|
|
787
|
-
assertElementExists(sel, locator)
|
|
788
|
-
const firstElement = await sel.filterVisible().nth(0)
|
|
768
|
+
const sel = await findElements.call(this, this.context, locator)
|
|
769
|
+
assertElementExists(sel, locator)
|
|
770
|
+
const firstElement = await sel.filterVisible().nth(0)
|
|
789
771
|
|
|
790
|
-
this.debug(`Screenshot of ${
|
|
791
|
-
return this.t.takeElementScreenshot(firstElement, fileName)
|
|
772
|
+
this.debug(`Screenshot of ${new Locator(locator)} element has been saved to ${outputFile}`)
|
|
773
|
+
return this.t.takeElementScreenshot(firstElement, fileName)
|
|
792
774
|
}
|
|
793
775
|
|
|
794
776
|
/**
|
|
@@ -796,20 +778,20 @@ class TestCafe extends Helper {
|
|
|
796
778
|
*/
|
|
797
779
|
// TODO Implement full page screenshots
|
|
798
780
|
async saveScreenshot(fileName) {
|
|
799
|
-
const outputFile = path.join(global.output_dir, fileName)
|
|
800
|
-
this.debug(`Screenshot is saving to ${outputFile}`)
|
|
781
|
+
const outputFile = path.join(global.output_dir, fileName)
|
|
782
|
+
this.debug(`Screenshot is saving to ${outputFile}`)
|
|
801
783
|
|
|
802
784
|
// TODO testcafe automatically creates thumbnail images (which cant be turned off)
|
|
803
|
-
return this.t.takeScreenshot(fileName)
|
|
785
|
+
return this.t.takeScreenshot(fileName)
|
|
804
786
|
}
|
|
805
787
|
|
|
806
788
|
/**
|
|
807
789
|
* {{> wait }}
|
|
808
790
|
*/
|
|
809
791
|
async wait(sec) {
|
|
810
|
-
return new Promise((
|
|
811
|
-
setTimeout(done, sec * 1000)
|
|
812
|
-
})
|
|
792
|
+
return new Promise((done) => {
|
|
793
|
+
setTimeout(done, sec * 1000)
|
|
794
|
+
})
|
|
813
795
|
}
|
|
814
796
|
|
|
815
797
|
/**
|
|
@@ -818,99 +800,99 @@ class TestCafe extends Helper {
|
|
|
818
800
|
* If a function returns a Promise It will wait for its resolution.
|
|
819
801
|
*/
|
|
820
802
|
async executeScript(fn, ...args) {
|
|
821
|
-
const browserFn = createClientFunction(fn, args).with({ boundTestRun: this.t })
|
|
822
|
-
return browserFn()
|
|
803
|
+
const browserFn = createClientFunction(fn, args).with({ boundTestRun: this.t })
|
|
804
|
+
return browserFn()
|
|
823
805
|
}
|
|
824
806
|
|
|
825
807
|
/**
|
|
826
808
|
* {{> grabTextFromAll }}
|
|
827
809
|
*/
|
|
828
810
|
async grabTextFromAll(locator) {
|
|
829
|
-
const sel = await findElements.call(this, this.context, locator)
|
|
830
|
-
const length = await sel.count
|
|
831
|
-
const texts = []
|
|
811
|
+
const sel = await findElements.call(this, this.context, locator)
|
|
812
|
+
const length = await sel.count
|
|
813
|
+
const texts = []
|
|
832
814
|
for (let i = 0; i < length; i++) {
|
|
833
|
-
texts.push(await sel.nth(i).innerText)
|
|
815
|
+
texts.push(await sel.nth(i).innerText)
|
|
834
816
|
}
|
|
835
817
|
|
|
836
|
-
return texts
|
|
818
|
+
return texts
|
|
837
819
|
}
|
|
838
820
|
|
|
839
821
|
/**
|
|
840
822
|
* {{> grabTextFrom }}
|
|
841
823
|
*/
|
|
842
824
|
async grabTextFrom(locator) {
|
|
843
|
-
const sel = await findElements.call(this, this.context, locator)
|
|
844
|
-
assertElementExists(sel, locator)
|
|
845
|
-
const texts = await this.grabTextFromAll(locator)
|
|
825
|
+
const sel = await findElements.call(this, this.context, locator)
|
|
826
|
+
assertElementExists(sel, locator)
|
|
827
|
+
const texts = await this.grabTextFromAll(locator)
|
|
846
828
|
if (texts.length > 1) {
|
|
847
|
-
this.debugSection('GrabText', `Using first element out of ${texts.length}`)
|
|
829
|
+
this.debugSection('GrabText', `Using first element out of ${texts.length}`)
|
|
848
830
|
}
|
|
849
831
|
|
|
850
|
-
return texts[0]
|
|
832
|
+
return texts[0]
|
|
851
833
|
}
|
|
852
834
|
|
|
853
835
|
/**
|
|
854
836
|
* {{> grabAttributeFrom }}
|
|
855
837
|
*/
|
|
856
838
|
async grabAttributeFromAll(locator, attr) {
|
|
857
|
-
const sel = await findElements.call(this, this.context, locator)
|
|
858
|
-
const length = await sel.count
|
|
859
|
-
const attrs = []
|
|
839
|
+
const sel = await findElements.call(this, this.context, locator)
|
|
840
|
+
const length = await sel.count
|
|
841
|
+
const attrs = []
|
|
860
842
|
for (let i = 0; i < length; i++) {
|
|
861
|
-
attrs.push(await (await sel.nth(i)).getAttribute(attr))
|
|
843
|
+
attrs.push(await (await sel.nth(i)).getAttribute(attr))
|
|
862
844
|
}
|
|
863
845
|
|
|
864
|
-
return attrs
|
|
846
|
+
return attrs
|
|
865
847
|
}
|
|
866
848
|
|
|
867
849
|
/**
|
|
868
850
|
* {{> grabAttributeFrom }}
|
|
869
851
|
*/
|
|
870
852
|
async grabAttributeFrom(locator, attr) {
|
|
871
|
-
const sel = await findElements.call(this, this.context, locator)
|
|
872
|
-
assertElementExists(sel, locator)
|
|
873
|
-
const attrs = await this.grabAttributeFromAll(locator, attr)
|
|
853
|
+
const sel = await findElements.call(this, this.context, locator)
|
|
854
|
+
assertElementExists(sel, locator)
|
|
855
|
+
const attrs = await this.grabAttributeFromAll(locator, attr)
|
|
874
856
|
if (attrs.length > 1) {
|
|
875
|
-
this.debugSection('GrabAttribute', `Using first element out of ${attrs.length}`)
|
|
857
|
+
this.debugSection('GrabAttribute', `Using first element out of ${attrs.length}`)
|
|
876
858
|
}
|
|
877
859
|
|
|
878
|
-
return attrs[0]
|
|
860
|
+
return attrs[0]
|
|
879
861
|
}
|
|
880
862
|
|
|
881
863
|
/**
|
|
882
864
|
* {{> grabValueFromAll }}
|
|
883
865
|
*/
|
|
884
866
|
async grabValueFromAll(locator) {
|
|
885
|
-
const sel = await findElements.call(this, this.context, locator)
|
|
886
|
-
const length = await sel.count
|
|
887
|
-
const values = []
|
|
867
|
+
const sel = await findElements.call(this, this.context, locator)
|
|
868
|
+
const length = await sel.count
|
|
869
|
+
const values = []
|
|
888
870
|
for (let i = 0; i < length; i++) {
|
|
889
|
-
values.push(await (await sel.nth(i)).value)
|
|
871
|
+
values.push(await (await sel.nth(i)).value)
|
|
890
872
|
}
|
|
891
873
|
|
|
892
|
-
return values
|
|
874
|
+
return values
|
|
893
875
|
}
|
|
894
876
|
|
|
895
877
|
/**
|
|
896
878
|
* {{> grabValueFrom }}
|
|
897
879
|
*/
|
|
898
880
|
async grabValueFrom(locator) {
|
|
899
|
-
const sel = await findElements.call(this, this.context, locator)
|
|
900
|
-
assertElementExists(sel, locator)
|
|
901
|
-
const values = await this.grabValueFromAll(locator)
|
|
881
|
+
const sel = await findElements.call(this, this.context, locator)
|
|
882
|
+
assertElementExists(sel, locator)
|
|
883
|
+
const values = await this.grabValueFromAll(locator)
|
|
902
884
|
if (values.length > 1) {
|
|
903
|
-
this.debugSection('GrabValue', `Using first element out of ${values.length}`)
|
|
885
|
+
this.debugSection('GrabValue', `Using first element out of ${values.length}`)
|
|
904
886
|
}
|
|
905
887
|
|
|
906
|
-
return values[0]
|
|
888
|
+
return values[0]
|
|
907
889
|
}
|
|
908
890
|
|
|
909
891
|
/**
|
|
910
892
|
* {{> grabSource }}
|
|
911
893
|
*/
|
|
912
894
|
async grabSource() {
|
|
913
|
-
return ClientFunction(() => document.documentElement.innerHTML).with({ boundTestRun: this.t })()
|
|
895
|
+
return ClientFunction(() => document.documentElement.innerHTML).with({ boundTestRun: this.t })()
|
|
914
896
|
}
|
|
915
897
|
|
|
916
898
|
/**
|
|
@@ -923,28 +905,30 @@ class TestCafe extends Helper {
|
|
|
923
905
|
*/
|
|
924
906
|
async grabBrowserLogs() {
|
|
925
907
|
// TODO Must map?
|
|
926
|
-
return this.t.getBrowserConsoleMessages()
|
|
908
|
+
return this.t.getBrowserConsoleMessages()
|
|
927
909
|
}
|
|
928
910
|
|
|
929
911
|
/**
|
|
930
912
|
* {{> grabCurrentUrl }}
|
|
931
913
|
*/
|
|
932
914
|
async grabCurrentUrl() {
|
|
933
|
-
return ClientFunction(() => document.location.href).with({ boundTestRun: this.t })()
|
|
915
|
+
return ClientFunction(() => document.location.href).with({ boundTestRun: this.t })()
|
|
934
916
|
}
|
|
935
917
|
|
|
936
918
|
/**
|
|
937
919
|
* {{> grabPageScrollPosition }}
|
|
938
920
|
*/
|
|
939
921
|
async grabPageScrollPosition() {
|
|
940
|
-
return ClientFunction(() => ({ x: window.pageXOffset, y: window.pageYOffset })).with({ boundTestRun: this.t })()
|
|
922
|
+
return ClientFunction(() => ({ x: window.pageXOffset, y: window.pageYOffset })).with({ boundTestRun: this.t })()
|
|
941
923
|
}
|
|
942
924
|
|
|
943
925
|
/**
|
|
944
926
|
* {{> scrollPageToTop }}
|
|
945
927
|
*/
|
|
946
928
|
scrollPageToTop() {
|
|
947
|
-
return ClientFunction(() => window.scrollTo(0, 0))
|
|
929
|
+
return ClientFunction(() => window.scrollTo(0, 0))
|
|
930
|
+
.with({ boundTestRun: this.t })()
|
|
931
|
+
.catch(mapError)
|
|
948
932
|
}
|
|
949
933
|
|
|
950
934
|
/**
|
|
@@ -952,16 +936,15 @@ class TestCafe extends Helper {
|
|
|
952
936
|
*/
|
|
953
937
|
scrollPageToBottom() {
|
|
954
938
|
return ClientFunction(() => {
|
|
955
|
-
const body = document.body
|
|
956
|
-
const html = document.documentElement
|
|
957
|
-
window.scrollTo(
|
|
958
|
-
|
|
959
|
-
body.offsetHeight,
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
)
|
|
964
|
-
}).with({ boundTestRun: this.t })().catch(mapError);
|
|
939
|
+
const body = document.body
|
|
940
|
+
const html = document.documentElement
|
|
941
|
+
window.scrollTo(
|
|
942
|
+
0,
|
|
943
|
+
Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),
|
|
944
|
+
)
|
|
945
|
+
})
|
|
946
|
+
.with({ boundTestRun: this.t })()
|
|
947
|
+
.catch(mapError)
|
|
965
948
|
}
|
|
966
949
|
|
|
967
950
|
/**
|
|
@@ -969,30 +952,30 @@ class TestCafe extends Helper {
|
|
|
969
952
|
*/
|
|
970
953
|
async scrollTo(locator, offsetX = 0, offsetY = 0) {
|
|
971
954
|
if (typeof locator === 'number' && typeof offsetX === 'number') {
|
|
972
|
-
offsetY = offsetX
|
|
973
|
-
offsetX = locator
|
|
974
|
-
locator = null
|
|
955
|
+
offsetY = offsetX
|
|
956
|
+
offsetX = locator
|
|
957
|
+
locator = null
|
|
975
958
|
}
|
|
976
959
|
|
|
977
960
|
const scrollBy = ClientFunction((offset) => {
|
|
978
961
|
if (window && window.scrollBy && offset) {
|
|
979
|
-
window.scrollBy(offset.x, offset.y)
|
|
962
|
+
window.scrollBy(offset.x, offset.y)
|
|
980
963
|
}
|
|
981
|
-
}).with({ boundTestRun: this.t })
|
|
964
|
+
}).with({ boundTestRun: this.t })
|
|
982
965
|
|
|
983
966
|
if (locator) {
|
|
984
|
-
const els = await this._locate(locator)
|
|
985
|
-
assertElementExists(els, locator, 'Element')
|
|
986
|
-
const el = await els.nth(0)
|
|
987
|
-
const x = (await el.offsetLeft) + offsetX
|
|
988
|
-
const y = (await el.offsetTop) + offsetY
|
|
967
|
+
const els = await this._locate(locator)
|
|
968
|
+
assertElementExists(els, locator, 'Element')
|
|
969
|
+
const el = await els.nth(0)
|
|
970
|
+
const x = (await el.offsetLeft) + offsetX
|
|
971
|
+
const y = (await el.offsetTop) + offsetY
|
|
989
972
|
|
|
990
|
-
return scrollBy({ x, y }).catch(mapError)
|
|
973
|
+
return scrollBy({ x, y }).catch(mapError)
|
|
991
974
|
}
|
|
992
975
|
|
|
993
|
-
const x = offsetX
|
|
994
|
-
const y = offsetY
|
|
995
|
-
return scrollBy({ x, y }).catch(mapError)
|
|
976
|
+
const x = offsetX
|
|
977
|
+
const y = offsetY
|
|
978
|
+
return scrollBy({ x, y }).catch(mapError)
|
|
996
979
|
}
|
|
997
980
|
|
|
998
981
|
/**
|
|
@@ -1000,15 +983,15 @@ class TestCafe extends Helper {
|
|
|
1000
983
|
*/
|
|
1001
984
|
async switchTo(locator) {
|
|
1002
985
|
if (Number.isInteger(locator)) {
|
|
1003
|
-
throw new Error('Not supported switching to iframe by number')
|
|
986
|
+
throw new Error('Not supported switching to iframe by number')
|
|
1004
987
|
}
|
|
1005
988
|
|
|
1006
989
|
if (!locator) {
|
|
1007
|
-
return this.t.switchToMainWindow()
|
|
990
|
+
return this.t.switchToMainWindow()
|
|
1008
991
|
}
|
|
1009
992
|
|
|
1010
|
-
const el = await findElements.call(this, this.context, locator)
|
|
1011
|
-
return this.t.switchToIframe(el)
|
|
993
|
+
const el = await findElements.call(this, this.context, locator)
|
|
994
|
+
return this.t.switchToIframe(el)
|
|
1012
995
|
}
|
|
1013
996
|
|
|
1014
997
|
// TODO Add url assertions
|
|
@@ -1018,17 +1001,20 @@ class TestCafe extends Helper {
|
|
|
1018
1001
|
*/
|
|
1019
1002
|
async setCookie(cookie) {
|
|
1020
1003
|
if (Array.isArray(cookie)) {
|
|
1021
|
-
throw new Error('cookie array is not supported')
|
|
1004
|
+
throw new Error('cookie array is not supported')
|
|
1022
1005
|
}
|
|
1023
1006
|
|
|
1024
|
-
cookie.path = cookie.path || '/'
|
|
1007
|
+
cookie.path = cookie.path || '/'
|
|
1025
1008
|
// cookie.expires = cookie.expires || (new Date()).toUTCString();
|
|
1026
1009
|
|
|
1027
|
-
const setCookie = ClientFunction(
|
|
1028
|
-
|
|
1029
|
-
|
|
1010
|
+
const setCookie = ClientFunction(
|
|
1011
|
+
() => {
|
|
1012
|
+
document.cookie = `${cookie.name}=${cookie.value};path=${cookie.path};expires=${cookie.expires};`
|
|
1013
|
+
},
|
|
1014
|
+
{ dependencies: { cookie } },
|
|
1015
|
+
).with({ boundTestRun: this.t })
|
|
1030
1016
|
|
|
1031
|
-
return setCookie()
|
|
1017
|
+
return setCookie()
|
|
1032
1018
|
}
|
|
1033
1019
|
|
|
1034
1020
|
/**
|
|
@@ -1036,16 +1022,16 @@ class TestCafe extends Helper {
|
|
|
1036
1022
|
*
|
|
1037
1023
|
*/
|
|
1038
1024
|
async seeCookie(name) {
|
|
1039
|
-
const cookie = await this.grabCookie(name)
|
|
1040
|
-
empty(`cookie ${name} to be set`).negate(cookie)
|
|
1025
|
+
const cookie = await this.grabCookie(name)
|
|
1026
|
+
empty(`cookie ${name} to be set`).negate(cookie)
|
|
1041
1027
|
}
|
|
1042
1028
|
|
|
1043
1029
|
/**
|
|
1044
1030
|
* {{> dontSeeCookie }}
|
|
1045
1031
|
*/
|
|
1046
1032
|
async dontSeeCookie(name) {
|
|
1047
|
-
const cookie = await this.grabCookie(name)
|
|
1048
|
-
empty(`cookie ${name} not to be set`).assert(cookie)
|
|
1033
|
+
const cookie = await this.grabCookie(name)
|
|
1034
|
+
empty(`cookie ${name} not to be set`).assert(cookie)
|
|
1049
1035
|
}
|
|
1050
1036
|
|
|
1051
1037
|
/**
|
|
@@ -1056,141 +1042,152 @@ class TestCafe extends Helper {
|
|
|
1056
1042
|
async grabCookie(name) {
|
|
1057
1043
|
if (!name) {
|
|
1058
1044
|
const getCookie = ClientFunction(() => {
|
|
1059
|
-
return document.cookie.split(';').map(c => c.split('='))
|
|
1060
|
-
}).with({ boundTestRun: this.t })
|
|
1061
|
-
const cookies = await getCookie()
|
|
1062
|
-
return cookies.map(cookie => ({ name: cookie[0].trim(), value: cookie[1] }))
|
|
1045
|
+
return document.cookie.split(';').map((c) => c.split('='))
|
|
1046
|
+
}).with({ boundTestRun: this.t })
|
|
1047
|
+
const cookies = await getCookie()
|
|
1048
|
+
return cookies.map((cookie) => ({ name: cookie[0].trim(), value: cookie[1] }))
|
|
1063
1049
|
}
|
|
1064
|
-
const getCookie = ClientFunction(
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1050
|
+
const getCookie = ClientFunction(
|
|
1051
|
+
() => {
|
|
1052
|
+
const v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)')
|
|
1053
|
+
return v ? v[2] : null
|
|
1054
|
+
},
|
|
1055
|
+
{ dependencies: { name } },
|
|
1056
|
+
).with({ boundTestRun: this.t })
|
|
1057
|
+
const value = await getCookie()
|
|
1058
|
+
if (value) return { name, value }
|
|
1071
1059
|
}
|
|
1072
1060
|
|
|
1073
1061
|
/**
|
|
1074
1062
|
* {{> clearCookie }}
|
|
1075
1063
|
*/
|
|
1076
1064
|
async clearCookie(cookieName) {
|
|
1077
|
-
const clearCookies = ClientFunction(
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1065
|
+
const clearCookies = ClientFunction(
|
|
1066
|
+
() => {
|
|
1067
|
+
const cookies = document.cookie.split(';')
|
|
1068
|
+
|
|
1069
|
+
for (let i = 0; i < cookies.length; i++) {
|
|
1070
|
+
const cookie = cookies[i]
|
|
1071
|
+
const eqPos = cookie.indexOf('=')
|
|
1072
|
+
const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie
|
|
1073
|
+
if (cookieName === undefined || name === cookieName) {
|
|
1074
|
+
document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT`
|
|
1075
|
+
}
|
|
1086
1076
|
}
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1077
|
+
},
|
|
1078
|
+
{ dependencies: { cookieName } },
|
|
1079
|
+
).with({ boundTestRun: this.t })
|
|
1089
1080
|
|
|
1090
|
-
return clearCookies()
|
|
1081
|
+
return clearCookies()
|
|
1091
1082
|
}
|
|
1092
1083
|
|
|
1093
1084
|
/**
|
|
1094
1085
|
* {{> waitInUrl }}
|
|
1095
1086
|
*/
|
|
1096
1087
|
async waitInUrl(urlPart, sec = null) {
|
|
1097
|
-
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1088
|
+
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1098
1089
|
|
|
1099
|
-
const clientFn = createClientFunction(
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1090
|
+
const clientFn = createClientFunction(
|
|
1091
|
+
(urlPart) => {
|
|
1092
|
+
const currUrl = decodeURIComponent(decodeURIComponent(decodeURIComponent(window.location.href)))
|
|
1093
|
+
return currUrl.indexOf(urlPart) > -1
|
|
1094
|
+
},
|
|
1095
|
+
[urlPart],
|
|
1096
|
+
).with({ boundTestRun: this.t })
|
|
1103
1097
|
|
|
1104
1098
|
return waitForFunction(clientFn, waitTimeout).catch(async () => {
|
|
1105
|
-
const currUrl = await this.grabCurrentUrl()
|
|
1106
|
-
throw new Error(`expected url to include ${urlPart}, but found ${currUrl}`)
|
|
1107
|
-
})
|
|
1099
|
+
const currUrl = await this.grabCurrentUrl()
|
|
1100
|
+
throw new Error(`expected url to include ${urlPart}, but found ${currUrl}`)
|
|
1101
|
+
})
|
|
1108
1102
|
}
|
|
1109
1103
|
|
|
1110
1104
|
/**
|
|
1111
1105
|
* {{> waitUrlEquals }}
|
|
1112
1106
|
*/
|
|
1113
1107
|
async waitUrlEquals(urlPart, sec = null) {
|
|
1114
|
-
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1108
|
+
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1115
1109
|
|
|
1116
|
-
const baseUrl = this.options.url
|
|
1110
|
+
const baseUrl = this.options.url
|
|
1117
1111
|
if (urlPart.indexOf('http') < 0) {
|
|
1118
|
-
urlPart = baseUrl + urlPart
|
|
1112
|
+
urlPart = baseUrl + urlPart
|
|
1119
1113
|
}
|
|
1120
1114
|
|
|
1121
|
-
const clientFn = createClientFunction(
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1115
|
+
const clientFn = createClientFunction(
|
|
1116
|
+
(urlPart) => {
|
|
1117
|
+
const currUrl = decodeURIComponent(decodeURIComponent(decodeURIComponent(window.location.href)))
|
|
1118
|
+
return currUrl === urlPart
|
|
1119
|
+
},
|
|
1120
|
+
[urlPart],
|
|
1121
|
+
).with({ boundTestRun: this.t })
|
|
1125
1122
|
|
|
1126
1123
|
return waitForFunction(clientFn, waitTimeout).catch(async () => {
|
|
1127
|
-
const currUrl = await this.grabCurrentUrl()
|
|
1128
|
-
throw new Error(`expected url to be ${urlPart}, but found ${currUrl}`)
|
|
1129
|
-
})
|
|
1124
|
+
const currUrl = await this.grabCurrentUrl()
|
|
1125
|
+
throw new Error(`expected url to be ${urlPart}, but found ${currUrl}`)
|
|
1126
|
+
})
|
|
1130
1127
|
}
|
|
1131
1128
|
|
|
1132
1129
|
/**
|
|
1133
1130
|
* {{> waitForFunction }}
|
|
1134
1131
|
*/
|
|
1135
1132
|
async waitForFunction(fn, argsOrSec = null, sec = null) {
|
|
1136
|
-
let args = []
|
|
1133
|
+
let args = []
|
|
1137
1134
|
if (argsOrSec) {
|
|
1138
1135
|
if (Array.isArray(argsOrSec)) {
|
|
1139
|
-
args = argsOrSec
|
|
1136
|
+
args = argsOrSec
|
|
1140
1137
|
} else if (typeof argsOrSec === 'number') {
|
|
1141
|
-
sec = argsOrSec
|
|
1138
|
+
sec = argsOrSec
|
|
1142
1139
|
}
|
|
1143
1140
|
}
|
|
1144
|
-
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1141
|
+
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1145
1142
|
|
|
1146
|
-
const clientFn = createClientFunction(fn, args).with({ boundTestRun: this.t })
|
|
1143
|
+
const clientFn = createClientFunction(fn, args).with({ boundTestRun: this.t })
|
|
1147
1144
|
|
|
1148
|
-
return waitForFunction(clientFn, waitTimeout)
|
|
1145
|
+
return waitForFunction(clientFn, waitTimeout)
|
|
1149
1146
|
}
|
|
1150
1147
|
|
|
1151
1148
|
/**
|
|
1152
1149
|
* {{> waitNumberOfVisibleElements }}
|
|
1153
1150
|
*/
|
|
1154
1151
|
async waitNumberOfVisibleElements(locator, num, sec) {
|
|
1155
|
-
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1152
|
+
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1156
1153
|
|
|
1157
1154
|
return this.t
|
|
1158
1155
|
.expect(createSelector(locator).with({ boundTestRun: this.t }).filterVisible().count)
|
|
1159
|
-
.eql(num, `The number of elements (${
|
|
1160
|
-
|
|
1156
|
+
.eql(num, `The number of elements (${new Locator(locator)}) is not ${num} after ${sec} sec`, {
|
|
1157
|
+
timeout: waitTimeout,
|
|
1158
|
+
})
|
|
1159
|
+
.catch(mapError)
|
|
1161
1160
|
}
|
|
1162
1161
|
|
|
1163
1162
|
/**
|
|
1164
1163
|
* {{> waitForElement }}
|
|
1165
1164
|
*/
|
|
1166
1165
|
async waitForElement(locator, sec) {
|
|
1167
|
-
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1166
|
+
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1168
1167
|
|
|
1169
|
-
return this.t
|
|
1170
|
-
.expect(createSelector(locator).with({ boundTestRun: this.t }).exists)
|
|
1171
|
-
.ok({ timeout: waitTimeout });
|
|
1168
|
+
return this.t.expect(createSelector(locator).with({ boundTestRun: this.t }).exists).ok({ timeout: waitTimeout })
|
|
1172
1169
|
}
|
|
1173
1170
|
|
|
1174
1171
|
/**
|
|
1175
1172
|
* {{> waitToHide }}
|
|
1176
1173
|
*/
|
|
1177
1174
|
async waitToHide(locator, sec) {
|
|
1178
|
-
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1175
|
+
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1179
1176
|
|
|
1180
1177
|
return this.t
|
|
1181
1178
|
.expect(createSelector(locator).filterHidden().with({ boundTestRun: this.t }).exists)
|
|
1182
|
-
.notOk({ timeout: waitTimeout })
|
|
1179
|
+
.notOk({ timeout: waitTimeout })
|
|
1183
1180
|
}
|
|
1184
1181
|
|
|
1185
1182
|
/**
|
|
1186
1183
|
* {{> waitForInvisible }}
|
|
1187
1184
|
*/
|
|
1188
1185
|
async waitForInvisible(locator, sec) {
|
|
1189
|
-
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1186
|
+
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1190
1187
|
|
|
1191
1188
|
return this.t
|
|
1192
1189
|
.expect(createSelector(locator).filterVisible().with({ boundTestRun: this.t }).exists)
|
|
1193
|
-
.ok({ timeout: waitTimeout })
|
|
1190
|
+
.ok({ timeout: waitTimeout })
|
|
1194
1191
|
}
|
|
1195
1192
|
|
|
1196
1193
|
/**
|
|
@@ -1198,213 +1195,220 @@ class TestCafe extends Helper {
|
|
|
1198
1195
|
*
|
|
1199
1196
|
*/
|
|
1200
1197
|
async waitForText(text, sec = null, context = null) {
|
|
1201
|
-
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1198
|
+
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1202
1199
|
|
|
1203
|
-
let els
|
|
1200
|
+
let els
|
|
1204
1201
|
if (context) {
|
|
1205
|
-
els =
|
|
1206
|
-
await this.t
|
|
1207
|
-
.expect(els.exists)
|
|
1208
|
-
.ok(`Context element ${context} not found`, { timeout: waitTimeout });
|
|
1202
|
+
els = await findElements.call(this, this.context, context)
|
|
1203
|
+
await this.t.expect(els.exists).ok(`Context element ${context} not found`, { timeout: waitTimeout })
|
|
1209
1204
|
} else {
|
|
1210
|
-
els =
|
|
1205
|
+
els = await findElements.call(this, this.context, '*')
|
|
1211
1206
|
}
|
|
1212
1207
|
|
|
1213
1208
|
return this.t
|
|
1214
1209
|
.expect(els.withText(text).filterVisible().exists)
|
|
1215
1210
|
.ok(`No element with text "${text}" found in ${context || 'body'}`, { timeout: waitTimeout })
|
|
1216
|
-
.catch(mapError)
|
|
1211
|
+
.catch(mapError)
|
|
1217
1212
|
}
|
|
1218
1213
|
}
|
|
1219
1214
|
|
|
1220
1215
|
async function waitForFunction(browserFn, waitTimeout) {
|
|
1221
|
-
const pause = () =>
|
|
1222
|
-
|
|
1223
|
-
|
|
1216
|
+
const pause = () =>
|
|
1217
|
+
new Promise((done) => {
|
|
1218
|
+
setTimeout(done, 50)
|
|
1219
|
+
})
|
|
1220
|
+
|
|
1221
|
+
const start = Date.now()
|
|
1224
1222
|
|
|
1225
|
-
const start = Date.now();
|
|
1226
|
-
// eslint-disable-next-line no-constant-condition
|
|
1227
1223
|
while (true) {
|
|
1228
|
-
let result
|
|
1224
|
+
let result
|
|
1229
1225
|
try {
|
|
1230
|
-
result = await browserFn()
|
|
1231
|
-
// eslint-disable-next-line no-empty
|
|
1226
|
+
result = await browserFn()
|
|
1232
1227
|
} catch (err) {
|
|
1233
|
-
throw new Error(`Error running function ${err.toString()}`)
|
|
1228
|
+
throw new Error(`Error running function ${err.toString()}`)
|
|
1234
1229
|
}
|
|
1235
1230
|
|
|
1236
|
-
if (result) return result
|
|
1231
|
+
if (result) return result
|
|
1237
1232
|
|
|
1238
|
-
const duration =
|
|
1233
|
+
const duration = Date.now() - start
|
|
1239
1234
|
if (duration > waitTimeout) {
|
|
1240
|
-
throw new Error('waitForFunction timed out')
|
|
1235
|
+
throw new Error('waitForFunction timed out')
|
|
1241
1236
|
}
|
|
1242
|
-
await pause()
|
|
1237
|
+
await pause() // make polling
|
|
1243
1238
|
}
|
|
1244
1239
|
}
|
|
1245
1240
|
|
|
1246
1241
|
const createSelector = (locator) => {
|
|
1247
|
-
locator = new Locator(locator, 'css')
|
|
1248
|
-
if (locator.isXPath()) return elementByXPath(locator.value)
|
|
1249
|
-
return Selector(locator.simplify())
|
|
1250
|
-
}
|
|
1242
|
+
locator = new Locator(locator, 'css')
|
|
1243
|
+
if (locator.isXPath()) return elementByXPath(locator.value)
|
|
1244
|
+
return Selector(locator.simplify())
|
|
1245
|
+
}
|
|
1251
1246
|
|
|
1252
1247
|
const elementByXPath = (xpath) => {
|
|
1253
|
-
assert(xpath, 'xpath is required')
|
|
1248
|
+
assert(xpath, 'xpath is required')
|
|
1254
1249
|
|
|
1255
|
-
return Selector(
|
|
1256
|
-
|
|
1257
|
-
|
|
1250
|
+
return Selector(
|
|
1251
|
+
() => {
|
|
1252
|
+
const iterator = document.evaluate(xpath, document, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null)
|
|
1253
|
+
const items = []
|
|
1258
1254
|
|
|
1259
|
-
|
|
1255
|
+
let item = iterator.iterateNext()
|
|
1260
1256
|
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1257
|
+
while (item) {
|
|
1258
|
+
items.push(item)
|
|
1259
|
+
item = iterator.iterateNext()
|
|
1260
|
+
}
|
|
1265
1261
|
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
}
|
|
1262
|
+
return items
|
|
1263
|
+
},
|
|
1264
|
+
{ dependencies: { xpath } },
|
|
1265
|
+
)
|
|
1266
|
+
}
|
|
1269
1267
|
|
|
1270
1268
|
const assertElementExists = async (res, locator, prefix, suffix) => {
|
|
1271
1269
|
if (!res || !(await res.count) || !(await res.nth(0).tagName)) {
|
|
1272
|
-
throw new ElementNotFound(locator, prefix, suffix)
|
|
1270
|
+
throw new ElementNotFound(locator, prefix, suffix)
|
|
1273
1271
|
}
|
|
1274
|
-
}
|
|
1272
|
+
}
|
|
1275
1273
|
|
|
1276
1274
|
async function findElements(matcher, locator) {
|
|
1277
|
-
if (locator && locator.react) throw new Error('react locators are not yet supported')
|
|
1275
|
+
if (locator && locator.react) throw new Error('react locators are not yet supported')
|
|
1278
1276
|
|
|
1279
|
-
locator = new Locator(locator, 'css')
|
|
1277
|
+
locator = new Locator(locator, 'css')
|
|
1280
1278
|
|
|
1281
1279
|
if (!locator.isXPath()) {
|
|
1282
1280
|
return matcher
|
|
1283
1281
|
? matcher.find(locator.simplify())
|
|
1284
|
-
: Selector(locator.simplify()).with({ timeout: 0, boundTestRun: this.t })
|
|
1282
|
+
: Selector(locator.simplify()).with({ timeout: 0, boundTestRun: this.t })
|
|
1285
1283
|
}
|
|
1286
1284
|
|
|
1287
|
-
if (!matcher) return elementByXPath(locator.value).with({ timeout: 0, boundTestRun: this.t })
|
|
1285
|
+
if (!matcher) return elementByXPath(locator.value).with({ timeout: 0, boundTestRun: this.t })
|
|
1288
1286
|
|
|
1289
|
-
return matcher.find(
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1287
|
+
return matcher.find(
|
|
1288
|
+
(node, idx, originNode) => {
|
|
1289
|
+
const found = document.evaluate(xpath, originNode, null, 5, null)
|
|
1290
|
+
let current = null
|
|
1291
|
+
while ((current = found.iterateNext())) {
|
|
1292
|
+
if (current === node) return true
|
|
1293
|
+
}
|
|
1294
|
+
return false
|
|
1295
|
+
},
|
|
1296
|
+
{ xpath: locator.value },
|
|
1297
|
+
)
|
|
1297
1298
|
}
|
|
1298
1299
|
|
|
1299
1300
|
async function proceedClick(locator, context = null) {
|
|
1300
|
-
let matcher
|
|
1301
|
+
let matcher
|
|
1301
1302
|
|
|
1302
1303
|
if (context) {
|
|
1303
|
-
const els = await this._locate(context)
|
|
1304
|
-
await assertElementExists(els, context)
|
|
1305
|
-
matcher = await els.nth(0)
|
|
1304
|
+
const els = await this._locate(context)
|
|
1305
|
+
await assertElementExists(els, context)
|
|
1306
|
+
matcher = await els.nth(0)
|
|
1306
1307
|
}
|
|
1307
1308
|
|
|
1308
|
-
const els = await findClickable.call(this, matcher, locator)
|
|
1309
|
+
const els = await findClickable.call(this, matcher, locator)
|
|
1309
1310
|
if (context) {
|
|
1310
|
-
await assertElementExists(
|
|
1311
|
+
await assertElementExists(
|
|
1312
|
+
els,
|
|
1313
|
+
locator,
|
|
1314
|
+
'Clickable element',
|
|
1315
|
+
`was not found inside element ${new Locator(context).toString()}`,
|
|
1316
|
+
)
|
|
1311
1317
|
} else {
|
|
1312
|
-
await assertElementExists(els, locator, 'Clickable element')
|
|
1318
|
+
await assertElementExists(els, locator, 'Clickable element')
|
|
1313
1319
|
}
|
|
1314
1320
|
|
|
1315
|
-
const firstElement = await els.filterVisible().nth(0)
|
|
1321
|
+
const firstElement = await els.filterVisible().nth(0)
|
|
1316
1322
|
|
|
1317
|
-
return this.t
|
|
1318
|
-
.click(firstElement)
|
|
1319
|
-
.catch(mapError);
|
|
1323
|
+
return this.t.click(firstElement).catch(mapError)
|
|
1320
1324
|
}
|
|
1321
1325
|
|
|
1322
1326
|
async function findClickable(matcher, locator) {
|
|
1323
|
-
if (locator && locator.react) throw new Error('react locators are not yet supported')
|
|
1327
|
+
if (locator && locator.react) throw new Error('react locators are not yet supported')
|
|
1324
1328
|
|
|
1325
|
-
locator = new Locator(locator)
|
|
1326
|
-
if (!locator.isFuzzy()) return (await findElements.call(this, matcher, locator)).filterVisible()
|
|
1329
|
+
locator = new Locator(locator)
|
|
1330
|
+
if (!locator.isFuzzy()) return (await findElements.call(this, matcher, locator)).filterVisible()
|
|
1327
1331
|
|
|
1328
|
-
let els
|
|
1332
|
+
let els
|
|
1329
1333
|
|
|
1330
1334
|
// try to use native TestCafe locator
|
|
1331
|
-
els = matcher ? matcher.find('a,button') : createSelector('a,button')
|
|
1332
|
-
els = await els.withExactText(locator.value).with({ timeout: 0, boundTestRun: this.t })
|
|
1333
|
-
if (await els.count) return els
|
|
1335
|
+
els = matcher ? matcher.find('a,button') : createSelector('a,button')
|
|
1336
|
+
els = await els.withExactText(locator.value).with({ timeout: 0, boundTestRun: this.t })
|
|
1337
|
+
if (await els.count) return els
|
|
1334
1338
|
|
|
1335
|
-
const literal = xpathLocator.literal(locator.value)
|
|
1339
|
+
const literal = xpathLocator.literal(locator.value)
|
|
1336
1340
|
|
|
1337
|
-
els = (await findElements.call(this, matcher, Locator.clickable.narrow(literal))).filterVisible()
|
|
1338
|
-
if (await els.count) return els
|
|
1341
|
+
els = (await findElements.call(this, matcher, Locator.clickable.narrow(literal))).filterVisible()
|
|
1342
|
+
if (await els.count) return els
|
|
1339
1343
|
|
|
1340
|
-
els = (await findElements.call(this, matcher, Locator.clickable.wide(literal))).filterVisible()
|
|
1341
|
-
if (await els.count) return els
|
|
1344
|
+
els = (await findElements.call(this, matcher, Locator.clickable.wide(literal))).filterVisible()
|
|
1345
|
+
if (await els.count) return els
|
|
1342
1346
|
|
|
1343
|
-
els = (await findElements.call(this, matcher, Locator.clickable.self(literal))).filterVisible()
|
|
1344
|
-
if (await els.count) return els
|
|
1347
|
+
els = (await findElements.call(this, matcher, Locator.clickable.self(literal))).filterVisible()
|
|
1348
|
+
if (await els.count) return els
|
|
1345
1349
|
|
|
1346
|
-
return findElements.call(this, matcher, locator.value)
|
|
1350
|
+
return findElements.call(this, matcher, locator.value) // by css or xpath
|
|
1347
1351
|
}
|
|
1348
1352
|
|
|
1349
1353
|
async function proceedIsChecked(assertType, option) {
|
|
1350
|
-
const els = await findCheckable.call(this, option)
|
|
1351
|
-
assertElementExists(els, option, 'Checkable')
|
|
1354
|
+
const els = await findCheckable.call(this, option)
|
|
1355
|
+
assertElementExists(els, option, 'Checkable')
|
|
1352
1356
|
|
|
1353
|
-
const selected = await els.checked
|
|
1357
|
+
const selected = await els.checked
|
|
1354
1358
|
|
|
1355
|
-
return truth(`checkable ${option}`, 'to be checked')[assertType](selected)
|
|
1359
|
+
return truth(`checkable ${option}`, 'to be checked')[assertType](selected)
|
|
1356
1360
|
}
|
|
1357
1361
|
|
|
1358
1362
|
async function findCheckable(locator, context) {
|
|
1359
|
-
assert(locator, 'locator is required')
|
|
1360
|
-
assert(this.t, 'this.t is required')
|
|
1363
|
+
assert(locator, 'locator is required')
|
|
1364
|
+
assert(this.t, 'this.t is required')
|
|
1361
1365
|
|
|
1362
|
-
let contextEl = await this.context
|
|
1366
|
+
let contextEl = await this.context
|
|
1363
1367
|
if (typeof context === 'string') {
|
|
1364
|
-
contextEl = (await findElements.call(this, contextEl,
|
|
1365
|
-
contextEl = await contextEl.nth(0)
|
|
1368
|
+
contextEl = (await findElements.call(this, contextEl, new Locator(context, 'css').simplify())).filterVisible()
|
|
1369
|
+
contextEl = await contextEl.nth(0)
|
|
1366
1370
|
}
|
|
1367
1371
|
|
|
1368
|
-
const matchedLocator = new Locator(locator)
|
|
1372
|
+
const matchedLocator = new Locator(locator)
|
|
1369
1373
|
if (!matchedLocator.isFuzzy()) {
|
|
1370
|
-
return (await findElements.call(this, contextEl, matchedLocator.simplify())).filterVisible()
|
|
1374
|
+
return (await findElements.call(this, contextEl, matchedLocator.simplify())).filterVisible()
|
|
1371
1375
|
}
|
|
1372
1376
|
|
|
1373
|
-
const literal = xpathLocator.literal(locator)
|
|
1374
|
-
let els = (await findElements.call(this, contextEl, Locator.checkable.byText(literal))).filterVisible()
|
|
1377
|
+
const literal = xpathLocator.literal(locator)
|
|
1378
|
+
let els = (await findElements.call(this, contextEl, Locator.checkable.byText(literal))).filterVisible()
|
|
1375
1379
|
if (await els.count) {
|
|
1376
|
-
return els
|
|
1380
|
+
return els
|
|
1377
1381
|
}
|
|
1378
1382
|
|
|
1379
|
-
els = (await findElements.call(this, contextEl, Locator.checkable.byName(literal))).filterVisible()
|
|
1383
|
+
els = (await findElements.call(this, contextEl, Locator.checkable.byName(literal))).filterVisible()
|
|
1380
1384
|
if (await els.count) {
|
|
1381
|
-
return els
|
|
1385
|
+
return els
|
|
1382
1386
|
}
|
|
1383
1387
|
|
|
1384
|
-
return (await findElements.call(this, contextEl, locator)).filterVisible()
|
|
1388
|
+
return (await findElements.call(this, contextEl, locator)).filterVisible()
|
|
1385
1389
|
}
|
|
1386
1390
|
|
|
1387
1391
|
async function findFields(locator) {
|
|
1388
|
-
const matchedLocator = new Locator(locator)
|
|
1392
|
+
const matchedLocator = new Locator(locator)
|
|
1389
1393
|
if (!matchedLocator.isFuzzy()) {
|
|
1390
|
-
return this._locate(matchedLocator)
|
|
1394
|
+
return this._locate(matchedLocator)
|
|
1391
1395
|
}
|
|
1392
|
-
const literal = xpathLocator.literal(locator)
|
|
1396
|
+
const literal = xpathLocator.literal(locator)
|
|
1393
1397
|
|
|
1394
|
-
let els = await this._locate({ xpath: Locator.field.labelEquals(literal) })
|
|
1398
|
+
let els = await this._locate({ xpath: Locator.field.labelEquals(literal) })
|
|
1395
1399
|
if (await els.count) {
|
|
1396
|
-
return els
|
|
1400
|
+
return els
|
|
1397
1401
|
}
|
|
1398
1402
|
|
|
1399
|
-
els = await this._locate({ xpath: Locator.field.labelContains(literal) })
|
|
1403
|
+
els = await this._locate({ xpath: Locator.field.labelContains(literal) })
|
|
1400
1404
|
if (await els.count) {
|
|
1401
|
-
return els
|
|
1405
|
+
return els
|
|
1402
1406
|
}
|
|
1403
|
-
els = await this._locate({ xpath: Locator.field.byName(literal) })
|
|
1407
|
+
els = await this._locate({ xpath: Locator.field.byName(literal) })
|
|
1404
1408
|
if (await els.count) {
|
|
1405
|
-
return els
|
|
1409
|
+
return els
|
|
1406
1410
|
}
|
|
1407
|
-
return this._locate({ css: locator })
|
|
1411
|
+
return this._locate({ css: locator })
|
|
1408
1412
|
}
|
|
1409
1413
|
|
|
1410
|
-
|
|
1414
|
+
module.exports = TestCafe
|