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