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