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/Nightmare.js
CHANGED
|
@@ -1,29 +1,24 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
|
|
3
|
-
const urlResolve = require('url').resolve
|
|
4
|
-
|
|
5
|
-
const Helper = require('@codeceptjs/helper')
|
|
6
|
-
const { includes: stringIncludes } = require('../assert/include')
|
|
7
|
-
const { urlEquals } = require('../assert/equal')
|
|
8
|
-
const { equals } = require('../assert/equal')
|
|
9
|
-
const { empty } = require('../assert/empty')
|
|
10
|
-
const { truth } = require('../assert/truth')
|
|
11
|
-
const Locator = require('../locator')
|
|
12
|
-
const ElementNotFound = require('./errors/ElementNotFound')
|
|
13
|
-
const {
|
|
14
|
-
xpathLocator,
|
|
15
|
-
fileExists,
|
|
16
|
-
screenshotOutputFolder,
|
|
17
|
-
toCamelCase,
|
|
18
|
-
} = require('../utils');
|
|
1
|
+
const path = require('path')
|
|
2
|
+
|
|
3
|
+
const urlResolve = require('url').resolve
|
|
4
|
+
|
|
5
|
+
const Helper = require('@codeceptjs/helper')
|
|
6
|
+
const { includes: stringIncludes } = require('../assert/include')
|
|
7
|
+
const { urlEquals } = require('../assert/equal')
|
|
8
|
+
const { equals } = require('../assert/equal')
|
|
9
|
+
const { empty } = require('../assert/empty')
|
|
10
|
+
const { truth } = require('../assert/truth')
|
|
11
|
+
const Locator = require('../locator')
|
|
12
|
+
const ElementNotFound = require('./errors/ElementNotFound')
|
|
13
|
+
const { xpathLocator, fileExists, screenshotOutputFolder, toCamelCase } = require('../utils')
|
|
19
14
|
|
|
20
15
|
const specialKeys = {
|
|
21
16
|
Backspace: '\u0008',
|
|
22
17
|
Enter: '\u000d',
|
|
23
18
|
Delete: '\u007f',
|
|
24
|
-
}
|
|
19
|
+
}
|
|
25
20
|
|
|
26
|
-
let withinStatus = false
|
|
21
|
+
let withinStatus = false
|
|
27
22
|
|
|
28
23
|
/**
|
|
29
24
|
* Nightmare helper wraps [Nightmare](https://github.com/segmentio/nightmare) library to provide
|
|
@@ -54,12 +49,12 @@ let withinStatus = false;
|
|
|
54
49
|
*/
|
|
55
50
|
class Nightmare extends Helper {
|
|
56
51
|
constructor(config) {
|
|
57
|
-
super(config)
|
|
52
|
+
super(config)
|
|
58
53
|
|
|
59
|
-
this.isRunning = false
|
|
54
|
+
this.isRunning = false
|
|
60
55
|
|
|
61
56
|
// override defaults with config
|
|
62
|
-
this._setConfig(config)
|
|
57
|
+
this._setConfig(config)
|
|
63
58
|
}
|
|
64
59
|
|
|
65
60
|
_validateConfig(config) {
|
|
@@ -75,235 +70,268 @@ class Nightmare extends Helper {
|
|
|
75
70
|
keepCookies: false,
|
|
76
71
|
js_errors: null,
|
|
77
72
|
enableHAR: false,
|
|
78
|
-
}
|
|
73
|
+
}
|
|
79
74
|
|
|
80
|
-
return Object.assign(defaults, config)
|
|
75
|
+
return Object.assign(defaults, config)
|
|
81
76
|
}
|
|
82
77
|
|
|
83
78
|
static _config() {
|
|
84
79
|
return [
|
|
85
80
|
{ name: 'url', message: 'Base url of site to be tested', default: 'http://localhost' },
|
|
86
81
|
{
|
|
87
|
-
name: 'show',
|
|
82
|
+
name: 'show',
|
|
83
|
+
message: 'Show browser window',
|
|
84
|
+
default: true,
|
|
85
|
+
type: 'confirm',
|
|
88
86
|
},
|
|
89
|
-
]
|
|
87
|
+
]
|
|
90
88
|
}
|
|
91
89
|
|
|
92
90
|
static _checkRequirements() {
|
|
93
91
|
try {
|
|
94
|
-
require('nightmare')
|
|
92
|
+
require('nightmare')
|
|
95
93
|
} catch (e) {
|
|
96
|
-
return ['nightmare']
|
|
94
|
+
return ['nightmare']
|
|
97
95
|
}
|
|
98
96
|
}
|
|
99
97
|
|
|
100
98
|
async _init() {
|
|
101
|
-
this.Nightmare = require('nightmare')
|
|
99
|
+
this.Nightmare = require('nightmare')
|
|
102
100
|
|
|
103
101
|
if (this.options.enableHAR) {
|
|
104
|
-
require('nightmare-har-plugin').install(this.Nightmare)
|
|
102
|
+
require('nightmare-har-plugin').install(this.Nightmare)
|
|
105
103
|
}
|
|
106
104
|
|
|
107
105
|
this.Nightmare.action('findElements', function (locator, contextEl, done) {
|
|
108
106
|
if (!done) {
|
|
109
|
-
done = contextEl
|
|
110
|
-
contextEl = null
|
|
107
|
+
done = contextEl
|
|
108
|
+
contextEl = null
|
|
111
109
|
}
|
|
112
110
|
|
|
113
|
-
const by = Object.keys(locator)[0]
|
|
114
|
-
const value = locator[by]
|
|
111
|
+
const by = Object.keys(locator)[0]
|
|
112
|
+
const value = locator[by]
|
|
115
113
|
|
|
116
|
-
this.evaluate_now(
|
|
117
|
-
|
|
114
|
+
this.evaluate_now(
|
|
115
|
+
(by, locator, contextEl) => window.codeceptjs.findAndStoreElements(by, locator, contextEl),
|
|
116
|
+
done,
|
|
117
|
+
by,
|
|
118
|
+
value,
|
|
119
|
+
contextEl,
|
|
120
|
+
)
|
|
121
|
+
})
|
|
118
122
|
|
|
119
123
|
this.Nightmare.action('findElement', function (locator, contextEl, done) {
|
|
120
124
|
if (!done) {
|
|
121
|
-
done = contextEl
|
|
122
|
-
contextEl = null
|
|
125
|
+
done = contextEl
|
|
126
|
+
contextEl = null
|
|
123
127
|
}
|
|
124
128
|
|
|
125
|
-
const by = Object.keys(locator)[0]
|
|
126
|
-
const value = locator[by]
|
|
129
|
+
const by = Object.keys(locator)[0]
|
|
130
|
+
const value = locator[by]
|
|
127
131
|
|
|
128
|
-
this.evaluate_now(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
132
|
+
this.evaluate_now(
|
|
133
|
+
(by, locator, contextEl) => {
|
|
134
|
+
const res = window.codeceptjs.findAndStoreElement(by, locator, contextEl)
|
|
135
|
+
if (res === null) {
|
|
136
|
+
throw new Error(`Element ${new Locator(locator)} couldn't be located by ${by}`)
|
|
137
|
+
}
|
|
138
|
+
return res
|
|
139
|
+
},
|
|
140
|
+
done,
|
|
141
|
+
by,
|
|
142
|
+
value,
|
|
143
|
+
contextEl,
|
|
144
|
+
)
|
|
145
|
+
})
|
|
136
146
|
|
|
137
147
|
this.Nightmare.action('asyncScript', function () {
|
|
138
|
-
let args = Array.prototype.slice.call(arguments)
|
|
139
|
-
const done = args.pop()
|
|
140
|
-
args = args.splice(1, 0, done)
|
|
141
|
-
this.evaluate_now.apply(this, args)
|
|
142
|
-
})
|
|
148
|
+
let args = Array.prototype.slice.call(arguments)
|
|
149
|
+
const done = args.pop()
|
|
150
|
+
args = args.splice(1, 0, done)
|
|
151
|
+
this.evaluate_now.apply(this, args)
|
|
152
|
+
})
|
|
143
153
|
|
|
144
154
|
this.Nightmare.action('enterText', function (el, text, clean, done) {
|
|
145
|
-
const child = this.child
|
|
146
|
-
const typeFn = () => child.call('type', text, done)
|
|
147
|
-
|
|
148
|
-
this.evaluate_now(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
155
|
+
const child = this.child
|
|
156
|
+
const typeFn = () => child.call('type', text, done)
|
|
157
|
+
|
|
158
|
+
this.evaluate_now(
|
|
159
|
+
(el, clean) => {
|
|
160
|
+
const element = window.codeceptjs.fetchElement(el)
|
|
161
|
+
if (clean) element.value = ''
|
|
162
|
+
element.focus()
|
|
163
|
+
},
|
|
164
|
+
() => {
|
|
165
|
+
if (clean) return typeFn()
|
|
166
|
+
child.call('pressKey', 'End', typeFn) // type End before
|
|
167
|
+
},
|
|
168
|
+
el,
|
|
169
|
+
clean,
|
|
170
|
+
)
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
this.Nightmare.action(
|
|
174
|
+
'pressKey',
|
|
175
|
+
(ns, options, parent, win, renderer, done) => {
|
|
176
|
+
parent.respondTo('pressKey', (ch, done) => {
|
|
177
|
+
win.webContents.sendInputEvent({
|
|
178
|
+
type: 'keyDown',
|
|
179
|
+
keyCode: ch,
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
win.webContents.sendInputEvent({
|
|
183
|
+
type: 'char',
|
|
184
|
+
keyCode: ch,
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
win.webContents.sendInputEvent({
|
|
188
|
+
type: 'keyUp',
|
|
189
|
+
keyCode: ch,
|
|
190
|
+
})
|
|
191
|
+
done()
|
|
192
|
+
})
|
|
193
|
+
done()
|
|
194
|
+
},
|
|
195
|
+
function (key, done) {
|
|
196
|
+
this.child.call('pressKey', key, done)
|
|
197
|
+
},
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
this.Nightmare.action(
|
|
201
|
+
'triggerMouseEvent',
|
|
202
|
+
(ns, options, parent, win, renderer, done) => {
|
|
203
|
+
parent.respondTo('triggerMouseEvent', (evt, done) => {
|
|
204
|
+
win.webContents.sendInputEvent(evt)
|
|
205
|
+
done()
|
|
206
|
+
})
|
|
207
|
+
done()
|
|
208
|
+
},
|
|
209
|
+
function (event, done) {
|
|
210
|
+
this.child.call('triggerMouseEvent', event, done)
|
|
211
|
+
},
|
|
212
|
+
)
|
|
190
213
|
|
|
191
214
|
this.Nightmare.action(
|
|
192
215
|
'upload',
|
|
193
216
|
(ns, options, parent, win, renderer, done) => {
|
|
194
217
|
parent.respondTo('upload', (selector, pathsToUpload, done) => {
|
|
195
|
-
parent.emit('log', 'paths', pathsToUpload)
|
|
218
|
+
parent.emit('log', 'paths', pathsToUpload)
|
|
196
219
|
try {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
win.webContents.debugger.attach('1.1')
|
|
220
|
+
// attach the debugger
|
|
221
|
+
// NOTE: this will fail if devtools is open
|
|
222
|
+
win.webContents.debugger.attach('1.1')
|
|
200
223
|
} catch (e) {
|
|
201
|
-
parent.emit('log', 'problem attaching', e)
|
|
202
|
-
return done(e)
|
|
224
|
+
parent.emit('log', 'problem attaching', e)
|
|
225
|
+
return done(e)
|
|
203
226
|
}
|
|
204
227
|
|
|
205
228
|
win.webContents.debugger.sendCommand('DOM.getDocument', {}, (err, domDocument) => {
|
|
206
|
-
win.webContents.debugger.sendCommand(
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
nodeId: queryResult.nodeId,
|
|
218
|
-
files: pathsToUpload,
|
|
219
|
-
}, (err) => {
|
|
220
|
-
if (Object.keys(err)
|
|
221
|
-
.length > 0) {
|
|
222
|
-
parent.emit('log', 'problem setting input', err);
|
|
223
|
-
return done(err);
|
|
229
|
+
win.webContents.debugger.sendCommand(
|
|
230
|
+
'DOM.querySelector',
|
|
231
|
+
{
|
|
232
|
+
nodeId: domDocument.root.nodeId,
|
|
233
|
+
selector,
|
|
234
|
+
},
|
|
235
|
+
(err, queryResult) => {
|
|
236
|
+
// HACK: chromium errors appear to be unpopulated objects?
|
|
237
|
+
if (Object.keys(err).length > 0) {
|
|
238
|
+
parent.emit('log', 'problem selecting', err)
|
|
239
|
+
return done(err)
|
|
224
240
|
}
|
|
225
|
-
win.webContents.debugger.
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
241
|
+
win.webContents.debugger.sendCommand(
|
|
242
|
+
'DOM.setFileInputFiles',
|
|
243
|
+
{
|
|
244
|
+
nodeId: queryResult.nodeId,
|
|
245
|
+
files: pathsToUpload,
|
|
246
|
+
},
|
|
247
|
+
(err) => {
|
|
248
|
+
if (Object.keys(err).length > 0) {
|
|
249
|
+
parent.emit('log', 'problem setting input', err)
|
|
250
|
+
return done(err)
|
|
251
|
+
}
|
|
252
|
+
win.webContents.debugger.detach()
|
|
253
|
+
done(null, pathsToUpload)
|
|
254
|
+
},
|
|
255
|
+
)
|
|
256
|
+
},
|
|
257
|
+
)
|
|
258
|
+
})
|
|
259
|
+
})
|
|
260
|
+
done()
|
|
232
261
|
},
|
|
233
262
|
function (selector, pathsToUpload, done) {
|
|
234
263
|
if (!Array.isArray(pathsToUpload)) {
|
|
235
|
-
pathsToUpload = [pathsToUpload]
|
|
264
|
+
pathsToUpload = [pathsToUpload]
|
|
236
265
|
}
|
|
237
266
|
this.child.call('upload', selector, pathsToUpload, (err, stuff) => {
|
|
238
|
-
done(err, stuff)
|
|
239
|
-
})
|
|
267
|
+
done(err, stuff)
|
|
268
|
+
})
|
|
240
269
|
},
|
|
241
|
-
)
|
|
270
|
+
)
|
|
242
271
|
|
|
243
|
-
return Promise.resolve()
|
|
272
|
+
return Promise.resolve()
|
|
244
273
|
}
|
|
245
274
|
|
|
246
275
|
async _beforeSuite() {
|
|
247
276
|
if (!this.options.restart && !this.isRunning) {
|
|
248
|
-
this.debugSection('Session', 'Starting singleton browser session')
|
|
249
|
-
return this._startBrowser()
|
|
277
|
+
this.debugSection('Session', 'Starting singleton browser session')
|
|
278
|
+
return this._startBrowser()
|
|
250
279
|
}
|
|
251
280
|
}
|
|
252
281
|
|
|
253
282
|
async _before() {
|
|
254
|
-
if (this.options.restart) return this._startBrowser()
|
|
255
|
-
if (!this.isRunning) return this._startBrowser()
|
|
256
|
-
return this.browser
|
|
283
|
+
if (this.options.restart) return this._startBrowser()
|
|
284
|
+
if (!this.isRunning) return this._startBrowser()
|
|
285
|
+
return this.browser
|
|
257
286
|
}
|
|
258
287
|
|
|
259
288
|
async _after() {
|
|
260
|
-
if (!this.isRunning) return
|
|
289
|
+
if (!this.isRunning) return
|
|
261
290
|
if (this.options.restart) {
|
|
262
|
-
this.isRunning = false
|
|
263
|
-
return this._stopBrowser()
|
|
291
|
+
this.isRunning = false
|
|
292
|
+
return this._stopBrowser()
|
|
264
293
|
}
|
|
265
294
|
if (this.options.enableHAR) {
|
|
266
|
-
await this.browser.resetHAR()
|
|
295
|
+
await this.browser.resetHAR()
|
|
267
296
|
}
|
|
268
|
-
if (this.options.keepBrowserState) return
|
|
297
|
+
if (this.options.keepBrowserState) return
|
|
269
298
|
if (this.options.keepCookies) {
|
|
270
|
-
await this.browser.cookies.clearAll()
|
|
299
|
+
await this.browser.cookies.clearAll()
|
|
271
300
|
}
|
|
272
|
-
this.debugSection('Session', 'cleaning up')
|
|
273
|
-
return this.executeScript(() => localStorage.clear())
|
|
301
|
+
this.debugSection('Session', 'cleaning up')
|
|
302
|
+
return this.executeScript(() => localStorage.clear())
|
|
274
303
|
}
|
|
275
304
|
|
|
276
|
-
_afterSuite() {
|
|
277
|
-
}
|
|
305
|
+
_afterSuite() {}
|
|
278
306
|
|
|
279
307
|
_finishTest() {
|
|
280
308
|
if (!this.options.restart && this.isRunning) {
|
|
281
|
-
this._stopBrowser()
|
|
309
|
+
this._stopBrowser()
|
|
282
310
|
}
|
|
283
311
|
}
|
|
284
312
|
|
|
285
313
|
async _startBrowser() {
|
|
286
|
-
this.context = this.options.rootElement
|
|
314
|
+
this.context = this.options.rootElement
|
|
287
315
|
if (this.options.enableHAR) {
|
|
288
|
-
this.browser = this.Nightmare(Object.assign(require('nightmare-har-plugin').getDevtoolsOptions(), this.options))
|
|
289
|
-
await this.browser
|
|
290
|
-
await this.browser.waitForDevtools()
|
|
316
|
+
this.browser = this.Nightmare(Object.assign(require('nightmare-har-plugin').getDevtoolsOptions(), this.options))
|
|
317
|
+
await this.browser
|
|
318
|
+
await this.browser.waitForDevtools()
|
|
291
319
|
} else {
|
|
292
|
-
this.browser = this.Nightmare(this.options)
|
|
293
|
-
await this.browser
|
|
320
|
+
this.browser = this.Nightmare(this.options)
|
|
321
|
+
await this.browser
|
|
294
322
|
}
|
|
295
|
-
await this.browser.goto('about:blank')
|
|
296
|
-
this.isRunning = true
|
|
297
|
-
this.browser.on('dom-ready', () => this._injectClientScripts())
|
|
298
|
-
this.browser.on('did-start-loading', () => this._injectClientScripts())
|
|
299
|
-
this.browser.on('will-navigate', () => this._injectClientScripts())
|
|
323
|
+
await this.browser.goto('about:blank') // Load a blank page so .saveScreenshot (/evaluate) will work
|
|
324
|
+
this.isRunning = true
|
|
325
|
+
this.browser.on('dom-ready', () => this._injectClientScripts())
|
|
326
|
+
this.browser.on('did-start-loading', () => this._injectClientScripts())
|
|
327
|
+
this.browser.on('will-navigate', () => this._injectClientScripts())
|
|
300
328
|
this.browser.on('console', (type, message) => {
|
|
301
|
-
this.debug(`${type}: ${message}`)
|
|
302
|
-
})
|
|
329
|
+
this.debug(`${type}: ${message}`)
|
|
330
|
+
})
|
|
303
331
|
|
|
304
332
|
if (this.options.windowSize) {
|
|
305
|
-
const size = this.options.windowSize.split('x')
|
|
306
|
-
return this.browser.viewport(parseInt(size[0], 10), parseInt(size[1], 10))
|
|
333
|
+
const size = this.options.windowSize.split('x')
|
|
334
|
+
return this.browser.viewport(parseInt(size[0], 10), parseInt(size[1], 10))
|
|
307
335
|
}
|
|
308
336
|
}
|
|
309
337
|
|
|
@@ -316,45 +344,49 @@ class Nightmare extends Helper {
|
|
|
316
344
|
* ```
|
|
317
345
|
*/
|
|
318
346
|
async grabHAR() {
|
|
319
|
-
return this.browser.getHAR()
|
|
347
|
+
return this.browser.getHAR()
|
|
320
348
|
}
|
|
321
349
|
|
|
322
350
|
async saveHAR(fileName) {
|
|
323
|
-
const outputFile = path.join(global.output_dir, fileName)
|
|
324
|
-
this.debug(`HAR is saving to ${outputFile}`)
|
|
351
|
+
const outputFile = path.join(global.output_dir, fileName)
|
|
352
|
+
this.debug(`HAR is saving to ${outputFile}`)
|
|
325
353
|
|
|
326
354
|
await this.browser.getHAR().then((har) => {
|
|
327
|
-
require('fs').writeFileSync(outputFile, JSON.stringify({ log: har }))
|
|
328
|
-
})
|
|
355
|
+
require('fs').writeFileSync(outputFile, JSON.stringify({ log: har }))
|
|
356
|
+
})
|
|
329
357
|
}
|
|
330
358
|
|
|
331
359
|
async resetHAR() {
|
|
332
|
-
await this.browser.resetHAR()
|
|
360
|
+
await this.browser.resetHAR()
|
|
333
361
|
}
|
|
334
362
|
|
|
335
363
|
async _stopBrowser() {
|
|
336
364
|
return this.browser.end().catch((error) => {
|
|
337
|
-
this.debugSection('Error on End', error)
|
|
338
|
-
})
|
|
365
|
+
this.debugSection('Error on End', error)
|
|
366
|
+
})
|
|
339
367
|
}
|
|
340
368
|
|
|
341
369
|
async _withinBegin(locator) {
|
|
342
|
-
this.context = locator
|
|
343
|
-
locator = new Locator(locator, 'css')
|
|
344
|
-
withinStatus = true
|
|
345
|
-
return this.browser.evaluate(
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
370
|
+
this.context = locator
|
|
371
|
+
locator = new Locator(locator, 'css')
|
|
372
|
+
withinStatus = true
|
|
373
|
+
return this.browser.evaluate(
|
|
374
|
+
(by, locator) => {
|
|
375
|
+
const el = window.codeceptjs.findElement(by, locator)
|
|
376
|
+
if (!el) throw new Error(`Element by ${by}: ${locator} not found`)
|
|
377
|
+
window.codeceptjs.within = el
|
|
378
|
+
},
|
|
379
|
+
locator.type,
|
|
380
|
+
locator.value,
|
|
381
|
+
)
|
|
350
382
|
}
|
|
351
383
|
|
|
352
384
|
_withinEnd() {
|
|
353
|
-
this.context = this.options.rootElement
|
|
354
|
-
withinStatus = false
|
|
385
|
+
this.context = this.options.rootElement
|
|
386
|
+
withinStatus = false
|
|
355
387
|
return this.browser.evaluate(() => {
|
|
356
|
-
window.codeceptjs.within = null
|
|
357
|
-
})
|
|
388
|
+
window.codeceptjs.within = null
|
|
389
|
+
})
|
|
358
390
|
}
|
|
359
391
|
|
|
360
392
|
/**
|
|
@@ -377,10 +409,14 @@ class Nightmare extends Helper {
|
|
|
377
409
|
* ```
|
|
378
410
|
*/
|
|
379
411
|
_locate(locator) {
|
|
380
|
-
locator = new Locator(locator, 'css')
|
|
381
|
-
return this.browser.evaluate(
|
|
382
|
-
|
|
383
|
-
|
|
412
|
+
locator = new Locator(locator, 'css')
|
|
413
|
+
return this.browser.evaluate(
|
|
414
|
+
(by, locator) => {
|
|
415
|
+
return window.codeceptjs.findAndStoreElements(by, locator)
|
|
416
|
+
},
|
|
417
|
+
locator.type,
|
|
418
|
+
locator.value,
|
|
419
|
+
)
|
|
384
420
|
}
|
|
385
421
|
|
|
386
422
|
/**
|
|
@@ -392,7 +428,7 @@ class Nightmare extends Helper {
|
|
|
392
428
|
* ```
|
|
393
429
|
*/
|
|
394
430
|
haveHeader(header, value) {
|
|
395
|
-
return this.browser.header(header, value)
|
|
431
|
+
return this.browser.header(header, value)
|
|
396
432
|
}
|
|
397
433
|
|
|
398
434
|
/**
|
|
@@ -401,223 +437,237 @@ class Nightmare extends Helper {
|
|
|
401
437
|
*
|
|
402
438
|
*/
|
|
403
439
|
async amOnPage(url, headers = null) {
|
|
404
|
-
if (
|
|
405
|
-
url = urlResolve(this.options.url, url)
|
|
440
|
+
if (!/^\w+\:\/\//.test(url)) {
|
|
441
|
+
url = urlResolve(this.options.url, url)
|
|
406
442
|
}
|
|
407
|
-
const currentUrl = await this.browser.url()
|
|
443
|
+
const currentUrl = await this.browser.url()
|
|
408
444
|
if (url === currentUrl) {
|
|
409
445
|
// navigating to the same url will cause an error in nightmare, so don't do it
|
|
410
|
-
return
|
|
446
|
+
return
|
|
411
447
|
}
|
|
412
448
|
return this.browser.goto(url, headers).then((res) => {
|
|
413
|
-
this.debugSection('URL', res.url)
|
|
414
|
-
this.debugSection('Code', res.code)
|
|
415
|
-
this.debugSection('Headers', JSON.stringify(res.headers))
|
|
416
|
-
})
|
|
449
|
+
this.debugSection('URL', res.url)
|
|
450
|
+
this.debugSection('Code', res.code)
|
|
451
|
+
this.debugSection('Headers', JSON.stringify(res.headers))
|
|
452
|
+
})
|
|
417
453
|
}
|
|
418
454
|
|
|
419
455
|
/**
|
|
420
456
|
* {{> seeInTitle }}
|
|
421
457
|
*/
|
|
422
458
|
async seeInTitle(text) {
|
|
423
|
-
const title = await this.browser.title()
|
|
424
|
-
stringIncludes('web page title').assert(text, title)
|
|
459
|
+
const title = await this.browser.title()
|
|
460
|
+
stringIncludes('web page title').assert(text, title)
|
|
425
461
|
}
|
|
426
462
|
|
|
427
463
|
/**
|
|
428
464
|
* {{> dontSeeInTitle }}
|
|
429
465
|
*/
|
|
430
466
|
async dontSeeInTitle(text) {
|
|
431
|
-
const title = await this.browser.title()
|
|
432
|
-
stringIncludes('web page title').negate(text, title)
|
|
467
|
+
const title = await this.browser.title()
|
|
468
|
+
stringIncludes('web page title').negate(text, title)
|
|
433
469
|
}
|
|
434
470
|
|
|
435
471
|
/**
|
|
436
472
|
* {{> grabTitle }}
|
|
437
473
|
*/
|
|
438
474
|
async grabTitle() {
|
|
439
|
-
return this.browser.title()
|
|
475
|
+
return this.browser.title()
|
|
440
476
|
}
|
|
441
477
|
|
|
442
478
|
/**
|
|
443
479
|
* {{> grabCurrentUrl }}
|
|
444
480
|
*/
|
|
445
481
|
async grabCurrentUrl() {
|
|
446
|
-
return this.browser.url()
|
|
482
|
+
return this.browser.url()
|
|
447
483
|
}
|
|
448
484
|
|
|
449
485
|
/**
|
|
450
486
|
* {{> seeInCurrentUrl }}
|
|
451
487
|
*/
|
|
452
488
|
async seeInCurrentUrl(url) {
|
|
453
|
-
const currentUrl = await this.browser.url()
|
|
454
|
-
stringIncludes('url').assert(url, currentUrl)
|
|
489
|
+
const currentUrl = await this.browser.url()
|
|
490
|
+
stringIncludes('url').assert(url, currentUrl)
|
|
455
491
|
}
|
|
456
492
|
|
|
457
493
|
/**
|
|
458
494
|
* {{> dontSeeInCurrentUrl }}
|
|
459
495
|
*/
|
|
460
496
|
async dontSeeInCurrentUrl(url) {
|
|
461
|
-
const currentUrl = await this.browser.url()
|
|
462
|
-
stringIncludes('url').negate(url, currentUrl)
|
|
497
|
+
const currentUrl = await this.browser.url()
|
|
498
|
+
stringIncludes('url').negate(url, currentUrl)
|
|
463
499
|
}
|
|
464
500
|
|
|
465
501
|
/**
|
|
466
502
|
* {{> seeCurrentUrlEquals }}
|
|
467
503
|
*/
|
|
468
504
|
async seeCurrentUrlEquals(url) {
|
|
469
|
-
const currentUrl = await this.browser.url()
|
|
470
|
-
urlEquals(this.options.url).assert(url, currentUrl)
|
|
505
|
+
const currentUrl = await this.browser.url()
|
|
506
|
+
urlEquals(this.options.url).assert(url, currentUrl)
|
|
471
507
|
}
|
|
472
508
|
|
|
473
509
|
/**
|
|
474
510
|
* {{> dontSeeCurrentUrlEquals }}
|
|
475
511
|
*/
|
|
476
512
|
async dontSeeCurrentUrlEquals(url) {
|
|
477
|
-
const currentUrl = await this.browser.url()
|
|
478
|
-
urlEquals(this.options.url).negate(url, currentUrl)
|
|
513
|
+
const currentUrl = await this.browser.url()
|
|
514
|
+
urlEquals(this.options.url).negate(url, currentUrl)
|
|
479
515
|
}
|
|
480
516
|
|
|
481
517
|
/**
|
|
482
518
|
* {{> see }}
|
|
483
519
|
*/
|
|
484
520
|
async see(text, context = null) {
|
|
485
|
-
return proceedSee.call(this, 'assert', text, context)
|
|
521
|
+
return proceedSee.call(this, 'assert', text, context)
|
|
486
522
|
}
|
|
487
523
|
|
|
488
524
|
/**
|
|
489
525
|
* {{> dontSee }}
|
|
490
526
|
*/
|
|
491
527
|
dontSee(text, context = null) {
|
|
492
|
-
return proceedSee.call(this, 'negate', text, context)
|
|
528
|
+
return proceedSee.call(this, 'negate', text, context)
|
|
493
529
|
}
|
|
494
530
|
|
|
495
531
|
/**
|
|
496
532
|
* {{> seeElement }}
|
|
497
533
|
*/
|
|
498
534
|
async seeElement(locator) {
|
|
499
|
-
locator = new Locator(locator, 'css')
|
|
500
|
-
const num = await this.browser.evaluate(
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
535
|
+
locator = new Locator(locator, 'css')
|
|
536
|
+
const num = await this.browser.evaluate(
|
|
537
|
+
(by, locator) => {
|
|
538
|
+
return window.codeceptjs.findElements(by, locator).filter((e) => e.offsetWidth > 0 && e.offsetHeight > 0).length
|
|
539
|
+
},
|
|
540
|
+
locator.type,
|
|
541
|
+
locator.value,
|
|
542
|
+
)
|
|
543
|
+
equals('number of elements on a page').negate(0, num)
|
|
504
544
|
}
|
|
505
545
|
|
|
506
546
|
/**
|
|
507
547
|
* {{> dontSeeElement }}
|
|
508
548
|
*/
|
|
509
549
|
async dontSeeElement(locator) {
|
|
510
|
-
locator = new Locator(locator, 'css')
|
|
511
|
-
locator = new Locator(locator, 'css')
|
|
512
|
-
const num = await this.browser.evaluate(
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
550
|
+
locator = new Locator(locator, 'css')
|
|
551
|
+
locator = new Locator(locator, 'css')
|
|
552
|
+
const num = await this.browser.evaluate(
|
|
553
|
+
(by, locator) => {
|
|
554
|
+
return window.codeceptjs.findElements(by, locator).filter((e) => e.offsetWidth > 0 && e.offsetHeight > 0).length
|
|
555
|
+
},
|
|
556
|
+
locator.type,
|
|
557
|
+
locator.value,
|
|
558
|
+
)
|
|
559
|
+
equals('number of elements on a page').assert(0, num)
|
|
516
560
|
}
|
|
517
561
|
|
|
518
562
|
/**
|
|
519
563
|
* {{> seeElementInDOM }}
|
|
520
564
|
*/
|
|
521
565
|
async seeElementInDOM(locator) {
|
|
522
|
-
locator = new Locator(locator, 'css')
|
|
523
|
-
const els = await this.browser.findElements(locator.toStrict())
|
|
524
|
-
empty('elements').negate(els.fill('ELEMENT'))
|
|
566
|
+
locator = new Locator(locator, 'css')
|
|
567
|
+
const els = await this.browser.findElements(locator.toStrict())
|
|
568
|
+
empty('elements').negate(els.fill('ELEMENT'))
|
|
525
569
|
}
|
|
526
570
|
|
|
527
571
|
/**
|
|
528
572
|
* {{> dontSeeElementInDOM }}
|
|
529
573
|
*/
|
|
530
574
|
async dontSeeElementInDOM(locator) {
|
|
531
|
-
locator = new Locator(locator, 'css')
|
|
532
|
-
const els = await this.browser.findElements(locator.toStrict())
|
|
533
|
-
empty('elements').assert(els.fill('ELEMENT'))
|
|
575
|
+
locator = new Locator(locator, 'css')
|
|
576
|
+
const els = await this.browser.findElements(locator.toStrict())
|
|
577
|
+
empty('elements').assert(els.fill('ELEMENT'))
|
|
534
578
|
}
|
|
535
579
|
|
|
536
580
|
/**
|
|
537
581
|
* {{> seeInSource }}
|
|
538
582
|
*/
|
|
539
583
|
async seeInSource(text) {
|
|
540
|
-
const source = await this.browser.evaluate(() => document.documentElement.outerHTML)
|
|
541
|
-
stringIncludes('HTML source of a page').assert(text, source)
|
|
584
|
+
const source = await this.browser.evaluate(() => document.documentElement.outerHTML)
|
|
585
|
+
stringIncludes('HTML source of a page').assert(text, source)
|
|
542
586
|
}
|
|
543
587
|
|
|
544
588
|
/**
|
|
545
589
|
* {{> dontSeeInSource }}
|
|
546
590
|
*/
|
|
547
591
|
async dontSeeInSource(text) {
|
|
548
|
-
const source = await this.browser.evaluate(() => document.documentElement.outerHTML)
|
|
549
|
-
stringIncludes('HTML source of a page').negate(text, source)
|
|
592
|
+
const source = await this.browser.evaluate(() => document.documentElement.outerHTML)
|
|
593
|
+
stringIncludes('HTML source of a page').negate(text, source)
|
|
550
594
|
}
|
|
551
595
|
|
|
552
596
|
/**
|
|
553
597
|
* {{> seeNumberOfElements }}
|
|
554
598
|
*/
|
|
555
599
|
async seeNumberOfElements(locator, num) {
|
|
556
|
-
const elements = await this._locate(locator)
|
|
557
|
-
return equals(
|
|
600
|
+
const elements = await this._locate(locator)
|
|
601
|
+
return equals(
|
|
602
|
+
`expected number of elements (${new Locator(locator)}) is ${num}, but found ${elements.length}`,
|
|
603
|
+
).assert(elements.length, num)
|
|
558
604
|
}
|
|
559
605
|
|
|
560
606
|
/**
|
|
561
607
|
* {{> seeNumberOfVisibleElements }}
|
|
562
608
|
*/
|
|
563
609
|
async seeNumberOfVisibleElements(locator, num) {
|
|
564
|
-
const res = await this.grabNumberOfVisibleElements(locator)
|
|
565
|
-
return equals(`expected number of visible elements (${
|
|
610
|
+
const res = await this.grabNumberOfVisibleElements(locator)
|
|
611
|
+
return equals(`expected number of visible elements (${new Locator(locator)}) is ${num}, but found ${res}`).assert(
|
|
612
|
+
res,
|
|
613
|
+
num,
|
|
614
|
+
)
|
|
566
615
|
}
|
|
567
616
|
|
|
568
617
|
/**
|
|
569
618
|
* {{> grabNumberOfVisibleElements }}
|
|
570
619
|
*/
|
|
571
620
|
async grabNumberOfVisibleElements(locator) {
|
|
572
|
-
locator = new Locator(locator, 'css')
|
|
621
|
+
locator = new Locator(locator, 'css')
|
|
573
622
|
|
|
574
|
-
const num = await this.browser.evaluate(
|
|
575
|
-
|
|
576
|
-
.filter(e => e.offsetWidth > 0 && e.offsetHeight > 0).length
|
|
577
|
-
|
|
623
|
+
const num = await this.browser.evaluate(
|
|
624
|
+
(by, locator) => {
|
|
625
|
+
return window.codeceptjs.findElements(by, locator).filter((e) => e.offsetWidth > 0 && e.offsetHeight > 0).length
|
|
626
|
+
},
|
|
627
|
+
locator.type,
|
|
628
|
+
locator.value,
|
|
629
|
+
)
|
|
578
630
|
|
|
579
|
-
return num
|
|
631
|
+
return num
|
|
580
632
|
}
|
|
581
633
|
|
|
582
634
|
/**
|
|
583
635
|
* {{> click }}
|
|
584
636
|
*/
|
|
585
637
|
async click(locator, context = null) {
|
|
586
|
-
const el = await findClickable.call(this, locator, context)
|
|
587
|
-
assertElementExists(el, locator, 'Clickable')
|
|
588
|
-
return this.browser.evaluate(el => window.codeceptjs.clickEl(el), el)
|
|
589
|
-
.wait(this.options.waitForAction);
|
|
638
|
+
const el = await findClickable.call(this, locator, context)
|
|
639
|
+
assertElementExists(el, locator, 'Clickable')
|
|
640
|
+
return this.browser.evaluate((el) => window.codeceptjs.clickEl(el), el).wait(this.options.waitForAction)
|
|
590
641
|
}
|
|
591
642
|
|
|
592
643
|
/**
|
|
593
644
|
* {{> doubleClick }}
|
|
594
645
|
*/
|
|
595
646
|
async doubleClick(locator, context = null) {
|
|
596
|
-
const el = await findClickable.call(this, locator, context)
|
|
597
|
-
assertElementExists(el, locator, 'Clickable')
|
|
598
|
-
return this.browser.evaluate(el => window.codeceptjs.doubleClickEl(el), el)
|
|
599
|
-
.wait(this.options.waitForAction);
|
|
647
|
+
const el = await findClickable.call(this, locator, context)
|
|
648
|
+
assertElementExists(el, locator, 'Clickable')
|
|
649
|
+
return this.browser.evaluate((el) => window.codeceptjs.doubleClickEl(el), el).wait(this.options.waitForAction)
|
|
600
650
|
}
|
|
601
651
|
|
|
602
652
|
/**
|
|
603
653
|
* {{> rightClick }}
|
|
604
654
|
*/
|
|
605
655
|
async rightClick(locator, context = null) {
|
|
606
|
-
const el = await findClickable.call(this, locator, context)
|
|
607
|
-
assertElementExists(el, locator, 'Clickable')
|
|
608
|
-
return this.browser.evaluate(el => window.codeceptjs.rightClickEl(el), el)
|
|
609
|
-
.wait(this.options.waitForAction);
|
|
656
|
+
const el = await findClickable.call(this, locator, context)
|
|
657
|
+
assertElementExists(el, locator, 'Clickable')
|
|
658
|
+
return this.browser.evaluate((el) => window.codeceptjs.rightClickEl(el), el).wait(this.options.waitForAction)
|
|
610
659
|
}
|
|
611
660
|
|
|
612
661
|
/**
|
|
613
662
|
* {{> moveCursorTo }}
|
|
614
663
|
*/
|
|
615
664
|
async moveCursorTo(locator, offsetX = 0, offsetY = 0) {
|
|
616
|
-
locator = new Locator(locator, 'css')
|
|
617
|
-
const el = await this.browser.findElement(locator.toStrict())
|
|
618
|
-
assertElementExists(el, locator)
|
|
619
|
-
return this.browser
|
|
620
|
-
.
|
|
665
|
+
locator = new Locator(locator, 'css')
|
|
666
|
+
const el = await this.browser.findElement(locator.toStrict())
|
|
667
|
+
assertElementExists(el, locator)
|
|
668
|
+
return this.browser
|
|
669
|
+
.evaluate((el, x, y) => window.codeceptjs.hoverEl(el, x, y), el, offsetX, offsetY)
|
|
670
|
+
.wait(this.options.waitForAction) // wait for hover event to happen
|
|
621
671
|
}
|
|
622
672
|
|
|
623
673
|
/**
|
|
@@ -626,8 +676,7 @@ class Nightmare extends Helper {
|
|
|
626
676
|
* Wrapper for synchronous [evaluate](https://github.com/segmentio/nightmare#evaluatefn-arg1-arg2)
|
|
627
677
|
*/
|
|
628
678
|
async executeScript(...args) {
|
|
629
|
-
return this.browser.evaluate.apply(this.browser, args)
|
|
630
|
-
.catch(err => err); // Nightmare's first argument is error :(
|
|
679
|
+
return this.browser.evaluate.apply(this.browser, args).catch((err) => err) // Nightmare's first argument is error :(
|
|
631
680
|
}
|
|
632
681
|
|
|
633
682
|
/**
|
|
@@ -637,8 +686,7 @@ class Nightmare extends Helper {
|
|
|
637
686
|
* Unlike NightmareJS implementation calling `done` will return its first argument.
|
|
638
687
|
*/
|
|
639
688
|
async executeAsyncScript(...args) {
|
|
640
|
-
return this.browser.evaluate.apply(this.browser, args)
|
|
641
|
-
.catch(err => err); // Nightmare's first argument is error :(
|
|
689
|
+
return this.browser.evaluate.apply(this.browser, args).catch((err) => err) // Nightmare's first argument is error :(
|
|
642
690
|
}
|
|
643
691
|
|
|
644
692
|
/**
|
|
@@ -646,72 +694,68 @@ class Nightmare extends Helper {
|
|
|
646
694
|
*/
|
|
647
695
|
async resizeWindow(width, height) {
|
|
648
696
|
if (width === 'maximize') {
|
|
649
|
-
throw new Error(
|
|
697
|
+
throw new Error("Nightmare doesn't support resizeWindow to maximum!")
|
|
650
698
|
}
|
|
651
|
-
return this.browser.viewport(width, height).wait(this.options.waitForAction)
|
|
699
|
+
return this.browser.viewport(width, height).wait(this.options.waitForAction)
|
|
652
700
|
}
|
|
653
701
|
|
|
654
702
|
/**
|
|
655
703
|
* {{> checkOption }}
|
|
656
704
|
*/
|
|
657
705
|
async checkOption(field, context = null) {
|
|
658
|
-
const els = await findCheckable.call(this, field, context)
|
|
659
|
-
assertElementExists(els[0], field, 'Checkbox or radio')
|
|
660
|
-
return this.browser.evaluate(els => window.codeceptjs.checkEl(els[0]), els)
|
|
661
|
-
.wait(this.options.waitForAction);
|
|
706
|
+
const els = await findCheckable.call(this, field, context)
|
|
707
|
+
assertElementExists(els[0], field, 'Checkbox or radio')
|
|
708
|
+
return this.browser.evaluate((els) => window.codeceptjs.checkEl(els[0]), els).wait(this.options.waitForAction)
|
|
662
709
|
}
|
|
663
710
|
|
|
664
711
|
/**
|
|
665
712
|
* {{> uncheckOption }}
|
|
666
713
|
*/
|
|
667
714
|
async uncheckOption(field, context = null) {
|
|
668
|
-
const els = await findCheckable.call(this, field, context)
|
|
669
|
-
assertElementExists(els[0], field, 'Checkbox or radio')
|
|
670
|
-
return this.browser.evaluate(els => window.codeceptjs.unCheckEl(els[0]), els)
|
|
671
|
-
.wait(this.options.waitForAction);
|
|
715
|
+
const els = await findCheckable.call(this, field, context)
|
|
716
|
+
assertElementExists(els[0], field, 'Checkbox or radio')
|
|
717
|
+
return this.browser.evaluate((els) => window.codeceptjs.unCheckEl(els[0]), els).wait(this.options.waitForAction)
|
|
672
718
|
}
|
|
673
719
|
|
|
674
720
|
/**
|
|
675
721
|
* {{> fillField }}
|
|
676
722
|
*/
|
|
677
723
|
async fillField(field, value) {
|
|
678
|
-
const el = await findField.call(this, field)
|
|
679
|
-
assertElementExists(el, field, 'Field')
|
|
680
|
-
return this.browser.enterText(el, value.toString(), true)
|
|
681
|
-
.wait(this.options.waitForAction);
|
|
724
|
+
const el = await findField.call(this, field)
|
|
725
|
+
assertElementExists(el, field, 'Field')
|
|
726
|
+
return this.browser.enterText(el, value.toString(), true).wait(this.options.waitForAction)
|
|
682
727
|
}
|
|
683
728
|
|
|
684
729
|
/**
|
|
685
730
|
* {{> clearField }}
|
|
686
731
|
*/
|
|
687
732
|
async clearField(field) {
|
|
688
|
-
return this.fillField(field, '')
|
|
733
|
+
return this.fillField(field, '')
|
|
689
734
|
}
|
|
690
735
|
|
|
691
736
|
/**
|
|
692
737
|
* {{> appendField }}
|
|
693
738
|
*/
|
|
694
739
|
async appendField(field, value) {
|
|
695
|
-
const el = await findField.call(this, field)
|
|
696
|
-
assertElementExists(el, field, 'Field')
|
|
697
|
-
return this.browser.enterText(el, value.toString(), false)
|
|
698
|
-
.wait(this.options.waitForAction);
|
|
740
|
+
const el = await findField.call(this, field)
|
|
741
|
+
assertElementExists(el, field, 'Field')
|
|
742
|
+
return this.browser.enterText(el, value.toString(), false).wait(this.options.waitForAction)
|
|
699
743
|
}
|
|
700
744
|
|
|
701
745
|
/**
|
|
702
746
|
* {{> seeInField }}
|
|
703
747
|
*/
|
|
704
748
|
async seeInField(field, value) {
|
|
705
|
-
const _value =
|
|
706
|
-
return proceedSeeInField.call(this, 'assert', field, _value)
|
|
749
|
+
const _value = typeof value === 'boolean' ? value : value.toString()
|
|
750
|
+
return proceedSeeInField.call(this, 'assert', field, _value)
|
|
707
751
|
}
|
|
708
752
|
|
|
709
753
|
/**
|
|
710
754
|
* {{> dontSeeInField }}
|
|
711
755
|
*/
|
|
712
756
|
async dontSeeInField(field, value) {
|
|
713
|
-
const _value =
|
|
714
|
-
return proceedSeeInField.call(this, 'negate', field, _value)
|
|
757
|
+
const _value = typeof value === 'boolean' ? value : value.toString()
|
|
758
|
+
return proceedSeeInField.call(this, 'negate', field, _value)
|
|
715
759
|
}
|
|
716
760
|
|
|
717
761
|
/**
|
|
@@ -720,12 +764,12 @@ class Nightmare extends Helper {
|
|
|
720
764
|
*/
|
|
721
765
|
async pressKey(key) {
|
|
722
766
|
if (Array.isArray(key)) {
|
|
723
|
-
key = key.join('+')
|
|
767
|
+
key = key.join('+') // should work with accelerators...
|
|
724
768
|
}
|
|
725
769
|
if (Object.keys(specialKeys).indexOf(key) >= 0) {
|
|
726
|
-
key = specialKeys[key]
|
|
770
|
+
key = specialKeys[key]
|
|
727
771
|
}
|
|
728
|
-
return this.browser.pressKey(key).wait(this.options.waitForAction)
|
|
772
|
+
return this.browser.pressKey(key).wait(this.options.waitForAction)
|
|
729
773
|
}
|
|
730
774
|
|
|
731
775
|
/**
|
|
@@ -739,21 +783,21 @@ class Nightmare extends Helper {
|
|
|
739
783
|
}
|
|
740
784
|
*/
|
|
741
785
|
async triggerMouseEvent(event) {
|
|
742
|
-
return this.browser.triggerMouseEvent(event).wait(this.options.waitForAction)
|
|
786
|
+
return this.browser.triggerMouseEvent(event).wait(this.options.waitForAction)
|
|
743
787
|
}
|
|
744
788
|
|
|
745
789
|
/**
|
|
746
790
|
* {{> seeCheckboxIsChecked }}
|
|
747
791
|
*/
|
|
748
792
|
async seeCheckboxIsChecked(field) {
|
|
749
|
-
return proceedIsChecked.call(this, 'assert', field)
|
|
793
|
+
return proceedIsChecked.call(this, 'assert', field)
|
|
750
794
|
}
|
|
751
795
|
|
|
752
796
|
/**
|
|
753
797
|
* {{> dontSeeCheckboxIsChecked }}
|
|
754
798
|
*/
|
|
755
799
|
async dontSeeCheckboxIsChecked(field) {
|
|
756
|
-
return proceedIsChecked.call(this, 'negate', field)
|
|
800
|
+
return proceedIsChecked.call(this, 'negate', field)
|
|
757
801
|
}
|
|
758
802
|
|
|
759
803
|
/**
|
|
@@ -762,167 +806,171 @@ class Nightmare extends Helper {
|
|
|
762
806
|
* Doesn't work if the Chromium DevTools panel is open (as Chromium allows only one attachment to the debugger at a time. [See more](https://github.com/rosshinkley/nightmare-upload#important-note-about-setting-file-upload-inputs))
|
|
763
807
|
*/
|
|
764
808
|
async attachFile(locator, pathToFile) {
|
|
765
|
-
const file = path.join(global.codecept_dir, pathToFile)
|
|
809
|
+
const file = path.join(global.codecept_dir, pathToFile)
|
|
766
810
|
|
|
767
|
-
locator = new Locator(locator, 'css')
|
|
811
|
+
locator = new Locator(locator, 'css')
|
|
768
812
|
if (!locator.isCSS()) {
|
|
769
|
-
throw new Error('Only CSS locator allowed for attachFile in Nightmare helper')
|
|
813
|
+
throw new Error('Only CSS locator allowed for attachFile in Nightmare helper')
|
|
770
814
|
}
|
|
771
815
|
|
|
772
816
|
if (!fileExists(file)) {
|
|
773
|
-
throw new Error(`File at ${file} can not be found on local system`)
|
|
817
|
+
throw new Error(`File at ${file} can not be found on local system`)
|
|
774
818
|
}
|
|
775
|
-
return this.browser.upload(locator.value, file)
|
|
819
|
+
return this.browser.upload(locator.value, file)
|
|
776
820
|
}
|
|
777
821
|
|
|
778
822
|
/**
|
|
779
823
|
* {{> grabTextFromAll }}
|
|
780
824
|
*/
|
|
781
825
|
async grabTextFromAll(locator) {
|
|
782
|
-
locator = new Locator(locator, 'css')
|
|
783
|
-
const els = await this.browser.findElements(locator.toStrict())
|
|
784
|
-
const texts = []
|
|
785
|
-
const getText = el => window.codeceptjs.fetchElement(el).innerText
|
|
826
|
+
locator = new Locator(locator, 'css')
|
|
827
|
+
const els = await this.browser.findElements(locator.toStrict())
|
|
828
|
+
const texts = []
|
|
829
|
+
const getText = (el) => window.codeceptjs.fetchElement(el).innerText
|
|
786
830
|
for (const el of els) {
|
|
787
|
-
texts.push(await this.browser.evaluate(getText, el))
|
|
831
|
+
texts.push(await this.browser.evaluate(getText, el))
|
|
788
832
|
}
|
|
789
|
-
return texts
|
|
833
|
+
return texts
|
|
790
834
|
}
|
|
791
835
|
|
|
792
836
|
/**
|
|
793
837
|
* {{> grabTextFrom }}
|
|
794
838
|
*/
|
|
795
839
|
async grabTextFrom(locator) {
|
|
796
|
-
locator = new Locator(locator, 'css')
|
|
797
|
-
const els = await this.browser.findElement(locator.toStrict())
|
|
798
|
-
assertElementExists(els, locator)
|
|
799
|
-
const texts = await this.grabTextFromAll(locator)
|
|
840
|
+
locator = new Locator(locator, 'css')
|
|
841
|
+
const els = await this.browser.findElement(locator.toStrict())
|
|
842
|
+
assertElementExists(els, locator)
|
|
843
|
+
const texts = await this.grabTextFromAll(locator)
|
|
800
844
|
if (texts.length > 1) {
|
|
801
|
-
this.debugSection('GrabText', `Using first element out of ${texts.length}`)
|
|
845
|
+
this.debugSection('GrabText', `Using first element out of ${texts.length}`)
|
|
802
846
|
}
|
|
803
847
|
|
|
804
|
-
return texts[0]
|
|
848
|
+
return texts[0]
|
|
805
849
|
}
|
|
806
850
|
|
|
807
851
|
/**
|
|
808
852
|
* {{> grabValueFromAll }}
|
|
809
853
|
*/
|
|
810
854
|
async grabValueFromAll(locator) {
|
|
811
|
-
locator = new Locator(locator, 'css')
|
|
812
|
-
const els = await this.browser.findElements(locator.toStrict())
|
|
813
|
-
const values = []
|
|
814
|
-
const getValues = el => window.codeceptjs.fetchElement(el).value
|
|
855
|
+
locator = new Locator(locator, 'css')
|
|
856
|
+
const els = await this.browser.findElements(locator.toStrict())
|
|
857
|
+
const values = []
|
|
858
|
+
const getValues = (el) => window.codeceptjs.fetchElement(el).value
|
|
815
859
|
for (const el of els) {
|
|
816
|
-
values.push(await this.browser.evaluate(getValues, el))
|
|
860
|
+
values.push(await this.browser.evaluate(getValues, el))
|
|
817
861
|
}
|
|
818
862
|
|
|
819
|
-
return values
|
|
863
|
+
return values
|
|
820
864
|
}
|
|
821
865
|
|
|
822
866
|
/**
|
|
823
867
|
* {{> grabValueFrom }}
|
|
824
868
|
*/
|
|
825
869
|
async grabValueFrom(locator) {
|
|
826
|
-
const el = await findField.call(this, locator)
|
|
827
|
-
assertElementExists(el, locator, 'Field')
|
|
828
|
-
const values = await this.grabValueFromAll(locator)
|
|
870
|
+
const el = await findField.call(this, locator)
|
|
871
|
+
assertElementExists(el, locator, 'Field')
|
|
872
|
+
const values = await this.grabValueFromAll(locator)
|
|
829
873
|
if (values.length > 1) {
|
|
830
|
-
this.debugSection('GrabValue', `Using first element out of ${values.length}`)
|
|
874
|
+
this.debugSection('GrabValue', `Using first element out of ${values.length}`)
|
|
831
875
|
}
|
|
832
876
|
|
|
833
|
-
return values[0]
|
|
877
|
+
return values[0]
|
|
834
878
|
}
|
|
835
879
|
|
|
836
880
|
/**
|
|
837
881
|
* {{> grabAttributeFromAll }}
|
|
838
882
|
*/
|
|
839
883
|
async grabAttributeFromAll(locator, attr) {
|
|
840
|
-
locator = new Locator(locator, 'css')
|
|
841
|
-
const els = await this.browser.findElements(locator.toStrict())
|
|
842
|
-
const array = []
|
|
884
|
+
locator = new Locator(locator, 'css')
|
|
885
|
+
const els = await this.browser.findElements(locator.toStrict())
|
|
886
|
+
const array = []
|
|
843
887
|
|
|
844
888
|
for (let index = 0; index < els.length; index++) {
|
|
845
|
-
const el = els[index]
|
|
846
|
-
array.push(
|
|
889
|
+
const el = els[index]
|
|
890
|
+
array.push(
|
|
891
|
+
await this.browser.evaluate((el, attr) => window.codeceptjs.fetchElement(el).getAttribute(attr), el, attr),
|
|
892
|
+
)
|
|
847
893
|
}
|
|
848
894
|
|
|
849
|
-
return array
|
|
895
|
+
return array
|
|
850
896
|
}
|
|
851
897
|
|
|
852
898
|
/**
|
|
853
899
|
* {{> grabAttributeFrom }}
|
|
854
900
|
*/
|
|
855
901
|
async grabAttributeFrom(locator, attr) {
|
|
856
|
-
locator = new Locator(locator, 'css')
|
|
857
|
-
const els = await this.browser.findElement(locator.toStrict())
|
|
858
|
-
assertElementExists(els, locator)
|
|
902
|
+
locator = new Locator(locator, 'css')
|
|
903
|
+
const els = await this.browser.findElement(locator.toStrict())
|
|
904
|
+
assertElementExists(els, locator)
|
|
859
905
|
|
|
860
|
-
const attrs = await this.grabAttributeFromAll(locator, attr)
|
|
906
|
+
const attrs = await this.grabAttributeFromAll(locator, attr)
|
|
861
907
|
if (attrs.length > 1) {
|
|
862
|
-
this.debugSection('GrabAttribute', `Using first element out of ${attrs.length}`)
|
|
908
|
+
this.debugSection('GrabAttribute', `Using first element out of ${attrs.length}`)
|
|
863
909
|
}
|
|
864
910
|
|
|
865
|
-
return attrs[0]
|
|
911
|
+
return attrs[0]
|
|
866
912
|
}
|
|
867
913
|
|
|
868
914
|
/**
|
|
869
915
|
* {{> grabHTMLFromAll }}
|
|
870
916
|
*/
|
|
871
917
|
async grabHTMLFromAll(locator) {
|
|
872
|
-
locator = new Locator(locator, 'css')
|
|
873
|
-
const els = await this.browser.findElements(locator.toStrict())
|
|
874
|
-
const array = []
|
|
918
|
+
locator = new Locator(locator, 'css')
|
|
919
|
+
const els = await this.browser.findElements(locator.toStrict())
|
|
920
|
+
const array = []
|
|
875
921
|
|
|
876
922
|
for (let index = 0; index < els.length; index++) {
|
|
877
|
-
const el = els[index]
|
|
878
|
-
array.push(await this.browser.evaluate(el => window.codeceptjs.fetchElement(el).innerHTML, el))
|
|
923
|
+
const el = els[index]
|
|
924
|
+
array.push(await this.browser.evaluate((el) => window.codeceptjs.fetchElement(el).innerHTML, el))
|
|
879
925
|
}
|
|
880
|
-
this.debugSection('GrabHTML', array)
|
|
926
|
+
this.debugSection('GrabHTML', array)
|
|
881
927
|
|
|
882
|
-
return array
|
|
928
|
+
return array
|
|
883
929
|
}
|
|
884
930
|
|
|
885
931
|
/**
|
|
886
932
|
* {{> grabHTMLFrom }}
|
|
887
933
|
*/
|
|
888
934
|
async grabHTMLFrom(locator) {
|
|
889
|
-
locator = new Locator(locator, 'css')
|
|
890
|
-
const els = await this.browser.findElement(locator.toStrict())
|
|
891
|
-
assertElementExists(els, locator)
|
|
892
|
-
const html = await this.grabHTMLFromAll(locator)
|
|
935
|
+
locator = new Locator(locator, 'css')
|
|
936
|
+
const els = await this.browser.findElement(locator.toStrict())
|
|
937
|
+
assertElementExists(els, locator)
|
|
938
|
+
const html = await this.grabHTMLFromAll(locator)
|
|
893
939
|
if (html.length > 1) {
|
|
894
|
-
this.debugSection('GrabHTML', `Using first element out of ${html.length}`)
|
|
940
|
+
this.debugSection('GrabHTML', `Using first element out of ${html.length}`)
|
|
895
941
|
}
|
|
896
942
|
|
|
897
|
-
return html[0]
|
|
943
|
+
return html[0]
|
|
898
944
|
}
|
|
899
945
|
|
|
900
946
|
/**
|
|
901
947
|
* {{> grabCssPropertyFrom }}
|
|
902
948
|
*/
|
|
903
949
|
async grabCssPropertyFrom(locator, cssProperty) {
|
|
904
|
-
locator = new Locator(locator, 'css')
|
|
905
|
-
const els = await this.browser.findElements(locator.toStrict())
|
|
906
|
-
const array = []
|
|
950
|
+
locator = new Locator(locator, 'css')
|
|
951
|
+
const els = await this.browser.findElements(locator.toStrict())
|
|
952
|
+
const array = []
|
|
907
953
|
|
|
908
954
|
const getCssPropForElement = async (el, prop) => {
|
|
909
|
-
return (
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
955
|
+
return (
|
|
956
|
+
await this.browser.evaluate((el) => {
|
|
957
|
+
return window.getComputedStyle(window.codeceptjs.fetchElement(el))
|
|
958
|
+
}, el)
|
|
959
|
+
)[toCamelCase(prop)]
|
|
960
|
+
}
|
|
913
961
|
|
|
914
962
|
for (const el of els) {
|
|
915
|
-
assertElementExists(el, locator)
|
|
916
|
-
const cssValue = await getCssPropForElement(el, cssProperty)
|
|
917
|
-
array.push(cssValue)
|
|
963
|
+
assertElementExists(el, locator)
|
|
964
|
+
const cssValue = await getCssPropForElement(el, cssProperty)
|
|
965
|
+
array.push(cssValue)
|
|
918
966
|
}
|
|
919
|
-
this.debugSection('HTML', array)
|
|
967
|
+
this.debugSection('HTML', array)
|
|
920
968
|
|
|
921
|
-
return array.length > 1 ? array : array[0]
|
|
969
|
+
return array.length > 1 ? array : array[0]
|
|
922
970
|
}
|
|
923
971
|
|
|
924
972
|
_injectClientScripts() {
|
|
925
|
-
return this.browser.inject('js', path.join(__dirname, 'clientscripts', 'nightmare.js'))
|
|
973
|
+
return this.browser.inject('js', path.join(__dirname, 'clientscripts', 'nightmare.js'))
|
|
926
974
|
}
|
|
927
975
|
|
|
928
976
|
/**
|
|
@@ -930,41 +978,41 @@ class Nightmare extends Helper {
|
|
|
930
978
|
*/
|
|
931
979
|
async selectOption(select, option) {
|
|
932
980
|
const fetchAndCheckOption = function (el, locator) {
|
|
933
|
-
el = window.codeceptjs.fetchElement(el)
|
|
934
|
-
const found = document.evaluate(locator, el, null, 5, null)
|
|
935
|
-
let current = null
|
|
936
|
-
const items = []
|
|
937
|
-
while (current = found.iterateNext()) {
|
|
938
|
-
items.push(current)
|
|
981
|
+
el = window.codeceptjs.fetchElement(el)
|
|
982
|
+
const found = document.evaluate(locator, el, null, 5, null)
|
|
983
|
+
let current = null
|
|
984
|
+
const items = []
|
|
985
|
+
while ((current = found.iterateNext())) {
|
|
986
|
+
items.push(current)
|
|
939
987
|
}
|
|
940
988
|
for (let i = 0; i < items.length; i++) {
|
|
941
|
-
current = items[i]
|
|
989
|
+
current = items[i]
|
|
942
990
|
if (current instanceof HTMLOptionElement) {
|
|
943
|
-
current.selected = true
|
|
944
|
-
if (!el.multiple) el.value = current.value
|
|
991
|
+
current.selected = true
|
|
992
|
+
if (!el.multiple) el.value = current.value
|
|
945
993
|
}
|
|
946
|
-
const event = document.createEvent('HTMLEvents')
|
|
947
|
-
event.initEvent('change', true, true)
|
|
948
|
-
el.dispatchEvent(event)
|
|
994
|
+
const event = document.createEvent('HTMLEvents')
|
|
995
|
+
event.initEvent('change', true, true)
|
|
996
|
+
el.dispatchEvent(event)
|
|
949
997
|
}
|
|
950
|
-
return !!current
|
|
951
|
-
}
|
|
998
|
+
return !!current
|
|
999
|
+
}
|
|
952
1000
|
|
|
953
|
-
const el = await findField.call(this, select)
|
|
954
|
-
assertElementExists(el, select, 'Selectable field')
|
|
1001
|
+
const el = await findField.call(this, select)
|
|
1002
|
+
assertElementExists(el, select, 'Selectable field')
|
|
955
1003
|
if (!Array.isArray(option)) {
|
|
956
|
-
option = [option]
|
|
1004
|
+
option = [option]
|
|
957
1005
|
}
|
|
958
1006
|
|
|
959
1007
|
for (const key in option) {
|
|
960
|
-
const opt = xpathLocator.literal(option[key])
|
|
961
|
-
const checked = await this.browser.evaluate(fetchAndCheckOption, el, Locator.select.byVisibleText(opt))
|
|
1008
|
+
const opt = xpathLocator.literal(option[key])
|
|
1009
|
+
const checked = await this.browser.evaluate(fetchAndCheckOption, el, Locator.select.byVisibleText(opt))
|
|
962
1010
|
|
|
963
1011
|
if (!checked) {
|
|
964
|
-
await this.browser.evaluate(fetchAndCheckOption, el, Locator.select.byValue(opt))
|
|
1012
|
+
await this.browser.evaluate(fetchAndCheckOption, el, Locator.select.byValue(opt))
|
|
965
1013
|
}
|
|
966
1014
|
}
|
|
967
|
-
return this.browser.wait(this.options.waitForAction)
|
|
1015
|
+
return this.browser.wait(this.options.waitForAction)
|
|
968
1016
|
}
|
|
969
1017
|
|
|
970
1018
|
/**
|
|
@@ -974,7 +1022,7 @@ class Nightmare extends Helper {
|
|
|
974
1022
|
* [See more](https://github.com/segmentio/nightmare/blob/master/Readme.md#cookiessetcookie)
|
|
975
1023
|
*/
|
|
976
1024
|
async setCookie(cookie) {
|
|
977
|
-
return this.browser.cookies.set(cookie)
|
|
1025
|
+
return this.browser.cookies.set(cookie)
|
|
978
1026
|
}
|
|
979
1027
|
|
|
980
1028
|
/**
|
|
@@ -982,16 +1030,16 @@ class Nightmare extends Helper {
|
|
|
982
1030
|
*
|
|
983
1031
|
*/
|
|
984
1032
|
async seeCookie(name) {
|
|
985
|
-
const res = await this.browser.cookies.get(name)
|
|
986
|
-
truth(`cookie ${name}`, 'to be set').assert(res)
|
|
1033
|
+
const res = await this.browser.cookies.get(name)
|
|
1034
|
+
truth(`cookie ${name}`, 'to be set').assert(res)
|
|
987
1035
|
}
|
|
988
1036
|
|
|
989
1037
|
/**
|
|
990
1038
|
* {{> dontSeeCookie }}
|
|
991
1039
|
*/
|
|
992
1040
|
async dontSeeCookie(name) {
|
|
993
|
-
const res = await this.browser.cookies.get(name)
|
|
994
|
-
truth(`cookie ${name}`, 'to be set').negate(res)
|
|
1041
|
+
const res = await this.browser.cookies.get(name)
|
|
1042
|
+
truth(`cookie ${name}`, 'to be set').negate(res)
|
|
995
1043
|
}
|
|
996
1044
|
|
|
997
1045
|
/**
|
|
@@ -1002,7 +1050,7 @@ class Nightmare extends Helper {
|
|
|
1002
1050
|
* Multiple cookies can be received by passing query object `I.grabCookie({ secure: true});`. If you'd like get all cookies for all urls, use: `.grabCookie({ url: null }).`
|
|
1003
1051
|
*/
|
|
1004
1052
|
async grabCookie(name) {
|
|
1005
|
-
return this.browser.cookies.get(name)
|
|
1053
|
+
return this.browser.cookies.get(name)
|
|
1006
1054
|
}
|
|
1007
1055
|
|
|
1008
1056
|
/**
|
|
@@ -1010,34 +1058,34 @@ class Nightmare extends Helper {
|
|
|
1010
1058
|
*/
|
|
1011
1059
|
async clearCookie(cookie) {
|
|
1012
1060
|
if (!cookie) {
|
|
1013
|
-
return this.browser.cookies.clearAll()
|
|
1061
|
+
return this.browser.cookies.clearAll()
|
|
1014
1062
|
}
|
|
1015
|
-
return this.browser.cookies.clear(cookie)
|
|
1063
|
+
return this.browser.cookies.clear(cookie)
|
|
1016
1064
|
}
|
|
1017
1065
|
|
|
1018
1066
|
/**
|
|
1019
1067
|
* {{> waitForFunction }}
|
|
1020
1068
|
*/
|
|
1021
1069
|
async waitForFunction(fn, argsOrSec = null, sec = null) {
|
|
1022
|
-
let args = []
|
|
1070
|
+
let args = []
|
|
1023
1071
|
if (argsOrSec) {
|
|
1024
1072
|
if (Array.isArray(argsOrSec)) {
|
|
1025
|
-
args = argsOrSec
|
|
1073
|
+
args = argsOrSec
|
|
1026
1074
|
} else if (typeof argsOrSec === 'number') {
|
|
1027
|
-
sec = argsOrSec
|
|
1075
|
+
sec = argsOrSec
|
|
1028
1076
|
}
|
|
1029
1077
|
}
|
|
1030
|
-
this.browser.options.waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1031
|
-
return this.browser.wait(fn, ...args)
|
|
1078
|
+
this.browser.options.waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1079
|
+
return this.browser.wait(fn, ...args)
|
|
1032
1080
|
}
|
|
1033
1081
|
|
|
1034
1082
|
/**
|
|
1035
1083
|
* {{> wait }}
|
|
1036
1084
|
*/
|
|
1037
1085
|
async wait(sec) {
|
|
1038
|
-
return new Promise((
|
|
1039
|
-
setTimeout(done, sec * 1000)
|
|
1040
|
-
})
|
|
1086
|
+
return new Promise((done) => {
|
|
1087
|
+
setTimeout(done, sec * 1000)
|
|
1088
|
+
})
|
|
1041
1089
|
}
|
|
1042
1090
|
|
|
1043
1091
|
/**
|
|
@@ -1045,113 +1093,136 @@ class Nightmare extends Helper {
|
|
|
1045
1093
|
*/
|
|
1046
1094
|
async waitForText(text, sec, context = null) {
|
|
1047
1095
|
if (!context) {
|
|
1048
|
-
context = this.context
|
|
1096
|
+
context = this.context
|
|
1049
1097
|
}
|
|
1050
|
-
const locator = new Locator(context, 'css')
|
|
1051
|
-
this.browser.options.waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1052
|
-
return this.browser
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1098
|
+
const locator = new Locator(context, 'css')
|
|
1099
|
+
this.browser.options.waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1100
|
+
return this.browser
|
|
1101
|
+
.wait(
|
|
1102
|
+
(by, locator, text) => {
|
|
1103
|
+
return window.codeceptjs.findElement(by, locator).innerText.indexOf(text) > -1
|
|
1104
|
+
},
|
|
1105
|
+
locator.type,
|
|
1106
|
+
locator.value,
|
|
1107
|
+
text,
|
|
1108
|
+
)
|
|
1109
|
+
.catch((err) => {
|
|
1110
|
+
if (err.message.indexOf('Cannot read property') > -1) {
|
|
1111
|
+
throw new Error(`element (${JSON.stringify(context)}) is not in DOM. Unable to wait text.`)
|
|
1112
|
+
} else if (err.message && err.message.indexOf('.wait() timed out after') > -1) {
|
|
1113
|
+
throw new Error(`there is no element(${JSON.stringify(context)}) with text "${text}" after ${sec} sec`)
|
|
1114
|
+
} else throw err
|
|
1115
|
+
})
|
|
1061
1116
|
}
|
|
1062
1117
|
|
|
1063
1118
|
/**
|
|
1064
1119
|
* {{> waitForVisible }}
|
|
1065
1120
|
*/
|
|
1066
1121
|
waitForVisible(locator, sec) {
|
|
1067
|
-
this.browser.options.waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1068
|
-
locator = new Locator(locator, 'css')
|
|
1069
|
-
|
|
1070
|
-
return this.browser
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1122
|
+
this.browser.options.waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1123
|
+
locator = new Locator(locator, 'css')
|
|
1124
|
+
|
|
1125
|
+
return this.browser
|
|
1126
|
+
.wait(
|
|
1127
|
+
(by, locator) => {
|
|
1128
|
+
const el = window.codeceptjs.findElement(by, locator)
|
|
1129
|
+
if (!el) return false
|
|
1130
|
+
return el.offsetWidth > 0 && el.offsetHeight > 0
|
|
1131
|
+
},
|
|
1132
|
+
locator.type,
|
|
1133
|
+
locator.value,
|
|
1134
|
+
)
|
|
1135
|
+
.catch((err) => {
|
|
1136
|
+
if (err.message && err.message.indexOf('.wait() timed out after') > -1) {
|
|
1137
|
+
throw new Error(`element (${JSON.stringify(locator)}) still not visible on page after ${sec} sec`)
|
|
1138
|
+
} else throw err
|
|
1139
|
+
})
|
|
1079
1140
|
}
|
|
1080
1141
|
|
|
1081
1142
|
/**
|
|
1082
1143
|
* {{> waitToHide }}
|
|
1083
1144
|
*/
|
|
1084
1145
|
async waitToHide(locator, sec = null) {
|
|
1085
|
-
return this.waitForInvisible(locator, sec)
|
|
1146
|
+
return this.waitForInvisible(locator, sec)
|
|
1086
1147
|
}
|
|
1087
1148
|
|
|
1088
1149
|
/**
|
|
1089
1150
|
* {{> waitForInvisible }}
|
|
1090
1151
|
*/
|
|
1091
1152
|
waitForInvisible(locator, sec) {
|
|
1092
|
-
this.browser.options.waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1093
|
-
locator = new Locator(locator, 'css')
|
|
1094
|
-
|
|
1095
|
-
return this.browser
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1153
|
+
this.browser.options.waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1154
|
+
locator = new Locator(locator, 'css')
|
|
1155
|
+
|
|
1156
|
+
return this.browser
|
|
1157
|
+
.wait(
|
|
1158
|
+
(by, locator) => {
|
|
1159
|
+
const el = window.codeceptjs.findElement(by, locator)
|
|
1160
|
+
if (!el) return true
|
|
1161
|
+
return !(el.offsetWidth > 0 && el.offsetHeight > 0)
|
|
1162
|
+
},
|
|
1163
|
+
locator.type,
|
|
1164
|
+
locator.value,
|
|
1165
|
+
)
|
|
1166
|
+
.catch((err) => {
|
|
1167
|
+
if (err.message && err.message.indexOf('.wait() timed out after') > -1) {
|
|
1168
|
+
throw new Error(`element (${JSON.stringify(locator)}) still visible after ${sec} sec`)
|
|
1169
|
+
} else throw err
|
|
1170
|
+
})
|
|
1104
1171
|
}
|
|
1105
1172
|
|
|
1106
1173
|
/**
|
|
1107
1174
|
* {{> waitForElement }}
|
|
1108
1175
|
*/
|
|
1109
1176
|
async waitForElement(locator, sec) {
|
|
1110
|
-
this.browser.options.waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1111
|
-
locator = new Locator(locator, 'css')
|
|
1177
|
+
this.browser.options.waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1178
|
+
locator = new Locator(locator, 'css')
|
|
1112
1179
|
|
|
1113
|
-
return this.browser
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1180
|
+
return this.browser
|
|
1181
|
+
.wait((by, locator) => window.codeceptjs.findElement(by, locator) !== null, locator.type, locator.value)
|
|
1182
|
+
.catch((err) => {
|
|
1183
|
+
if (err.message && err.message.indexOf('.wait() timed out after') > -1) {
|
|
1184
|
+
throw new Error(`element (${JSON.stringify(locator)}) still not present on page after ${sec} sec`)
|
|
1185
|
+
} else throw err
|
|
1186
|
+
})
|
|
1118
1187
|
}
|
|
1119
1188
|
|
|
1120
1189
|
async waitUntilExists(locator, sec) {
|
|
1121
1190
|
console.log(`waitUntilExists deprecated:
|
|
1122
1191
|
* use 'waitForElement' to wait for element to be attached
|
|
1123
|
-
* use 'waitForDetached to wait for element to be removed'`)
|
|
1124
|
-
return this.waitForDetached(locator, sec)
|
|
1192
|
+
* use 'waitForDetached to wait for element to be removed'`)
|
|
1193
|
+
return this.waitForDetached(locator, sec)
|
|
1125
1194
|
}
|
|
1126
1195
|
|
|
1127
1196
|
/**
|
|
1128
1197
|
* {{> waitForDetached }}
|
|
1129
1198
|
*/
|
|
1130
1199
|
async waitForDetached(locator, sec) {
|
|
1131
|
-
this.browser.options.waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1132
|
-
sec = this.browser.options.waitForTimeout / 1000
|
|
1133
|
-
locator = new Locator(locator, 'css')
|
|
1200
|
+
this.browser.options.waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
1201
|
+
sec = this.browser.options.waitForTimeout / 1000
|
|
1202
|
+
locator = new Locator(locator, 'css')
|
|
1134
1203
|
|
|
1135
|
-
return this.browser
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1204
|
+
return this.browser
|
|
1205
|
+
.wait((by, locator) => window.codeceptjs.findElement(by, locator) === null, locator.type, locator.value)
|
|
1206
|
+
.catch((err) => {
|
|
1207
|
+
if (err.message && err.message.indexOf('.wait() timed out after') > -1) {
|
|
1208
|
+
throw new Error(`element (${JSON.stringify(locator)}) still on page after ${sec} sec`)
|
|
1209
|
+
} else throw err
|
|
1210
|
+
})
|
|
1140
1211
|
}
|
|
1141
1212
|
|
|
1142
1213
|
/**
|
|
1143
1214
|
* {{> refreshPage }}
|
|
1144
1215
|
*/
|
|
1145
1216
|
async refreshPage() {
|
|
1146
|
-
return this.browser.refresh()
|
|
1217
|
+
return this.browser.refresh()
|
|
1147
1218
|
}
|
|
1148
1219
|
|
|
1149
1220
|
/**
|
|
1150
1221
|
* Reload the page
|
|
1151
1222
|
*/
|
|
1152
1223
|
refresh() {
|
|
1153
|
-
console.log('Deprecated in favor of refreshPage')
|
|
1154
|
-
return this.browser.refresh()
|
|
1224
|
+
console.log('Deprecated in favor of refreshPage')
|
|
1225
|
+
return this.browser.refresh()
|
|
1155
1226
|
}
|
|
1156
1227
|
|
|
1157
1228
|
/**
|
|
@@ -1159,70 +1230,74 @@ class Nightmare extends Helper {
|
|
|
1159
1230
|
*
|
|
1160
1231
|
*/
|
|
1161
1232
|
async saveElementScreenshot(locator, fileName) {
|
|
1162
|
-
const outputFile = screenshotOutputFolder(fileName)
|
|
1233
|
+
const outputFile = screenshotOutputFolder(fileName)
|
|
1163
1234
|
|
|
1164
|
-
const rect = await this.grabElementBoundingRect(locator)
|
|
1235
|
+
const rect = await this.grabElementBoundingRect(locator)
|
|
1165
1236
|
|
|
1166
1237
|
const button_clip = {
|
|
1167
1238
|
x: Math.floor(rect.x),
|
|
1168
1239
|
y: Math.floor(rect.y),
|
|
1169
1240
|
width: Math.floor(rect.width),
|
|
1170
1241
|
height: Math.floor(rect.height),
|
|
1171
|
-
}
|
|
1242
|
+
}
|
|
1172
1243
|
|
|
1173
|
-
this.debug(`Screenshot of ${
|
|
1244
|
+
this.debug(`Screenshot of ${new Locator(locator)} element has been saved to ${outputFile}`)
|
|
1174
1245
|
// take the screenshot
|
|
1175
|
-
await this.browser.screenshot(outputFile, button_clip)
|
|
1246
|
+
await this.browser.screenshot(outputFile, button_clip)
|
|
1176
1247
|
}
|
|
1177
1248
|
|
|
1178
1249
|
/**
|
|
1179
1250
|
* {{> grabElementBoundingRect }}
|
|
1180
1251
|
*/
|
|
1181
1252
|
async grabElementBoundingRect(locator, prop) {
|
|
1182
|
-
locator = new Locator(locator, 'css')
|
|
1253
|
+
locator = new Locator(locator, 'css')
|
|
1183
1254
|
|
|
1184
|
-
const rect = await this.browser.evaluate(
|
|
1185
|
-
|
|
1255
|
+
const rect = await this.browser.evaluate(
|
|
1256
|
+
async (by, locator) => {
|
|
1257
|
+
// store the button in a variable
|
|
1186
1258
|
|
|
1187
|
-
|
|
1259
|
+
const build_cluster_btn = await window.codeceptjs.findElement(by, locator)
|
|
1188
1260
|
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1261
|
+
// use the getClientRects() function on the button to determine
|
|
1262
|
+
// the size and location
|
|
1263
|
+
const rect = build_cluster_btn.getBoundingClientRect()
|
|
1192
1264
|
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1265
|
+
// convert the rectangle to a clip object and return it
|
|
1266
|
+
return {
|
|
1267
|
+
x: rect.left,
|
|
1268
|
+
y: rect.top,
|
|
1269
|
+
width: rect.width,
|
|
1270
|
+
height: rect.height,
|
|
1271
|
+
}
|
|
1272
|
+
},
|
|
1273
|
+
locator.type,
|
|
1274
|
+
locator.value,
|
|
1275
|
+
)
|
|
1201
1276
|
|
|
1202
|
-
if (prop) return rect[prop]
|
|
1203
|
-
return rect
|
|
1277
|
+
if (prop) return rect[prop]
|
|
1278
|
+
return rect
|
|
1204
1279
|
}
|
|
1205
1280
|
|
|
1206
1281
|
/**
|
|
1207
1282
|
* {{> saveScreenshot }}
|
|
1208
1283
|
*/
|
|
1209
1284
|
async saveScreenshot(fileName, fullPage = this.options.fullPageScreenshots) {
|
|
1210
|
-
const outputFile = screenshotOutputFolder(fileName)
|
|
1285
|
+
const outputFile = screenshotOutputFolder(fileName)
|
|
1211
1286
|
|
|
1212
|
-
this.debug(`Screenshot is saving to ${outputFile}`)
|
|
1287
|
+
this.debug(`Screenshot is saving to ${outputFile}`)
|
|
1213
1288
|
|
|
1214
1289
|
if (!fullPage) {
|
|
1215
|
-
return this.browser.screenshot(outputFile)
|
|
1290
|
+
return this.browser.screenshot(outputFile)
|
|
1216
1291
|
}
|
|
1217
1292
|
const { height, width } = await this.browser.evaluate(() => {
|
|
1218
|
-
return { height: document.body.scrollHeight, width: document.body.scrollWidth }
|
|
1219
|
-
})
|
|
1220
|
-
await this.browser.viewport(width, height)
|
|
1221
|
-
return this.browser.screenshot(outputFile)
|
|
1293
|
+
return { height: document.body.scrollHeight, width: document.body.scrollWidth }
|
|
1294
|
+
})
|
|
1295
|
+
await this.browser.viewport(width, height)
|
|
1296
|
+
return this.browser.screenshot(outputFile)
|
|
1222
1297
|
}
|
|
1223
1298
|
|
|
1224
1299
|
async _failed() {
|
|
1225
|
-
if (withinStatus !== false) await this._withinEnd()
|
|
1300
|
+
if (withinStatus !== false) await this._withinEnd()
|
|
1226
1301
|
}
|
|
1227
1302
|
|
|
1228
1303
|
/**
|
|
@@ -1230,28 +1305,40 @@ class Nightmare extends Helper {
|
|
|
1230
1305
|
*/
|
|
1231
1306
|
async scrollTo(locator, offsetX = 0, offsetY = 0) {
|
|
1232
1307
|
if (typeof locator === 'number' && typeof offsetX === 'number') {
|
|
1233
|
-
offsetY = offsetX
|
|
1234
|
-
offsetX = locator
|
|
1235
|
-
locator = null
|
|
1308
|
+
offsetY = offsetX
|
|
1309
|
+
offsetX = locator
|
|
1310
|
+
locator = null
|
|
1236
1311
|
}
|
|
1237
1312
|
if (locator) {
|
|
1238
|
-
locator = new Locator(locator, 'css')
|
|
1239
|
-
return this.browser.evaluate(
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1313
|
+
locator = new Locator(locator, 'css')
|
|
1314
|
+
return this.browser.evaluate(
|
|
1315
|
+
(by, locator, offsetX, offsetY) => {
|
|
1316
|
+
const el = window.codeceptjs.findElement(by, locator)
|
|
1317
|
+
if (!el) throw new Error(`Element not found ${by}: ${locator}`)
|
|
1318
|
+
const rect = el.getBoundingClientRect()
|
|
1319
|
+
window.scrollTo(rect.left + offsetX, rect.top + offsetY)
|
|
1320
|
+
},
|
|
1321
|
+
locator.type,
|
|
1322
|
+
locator.value,
|
|
1323
|
+
offsetX,
|
|
1324
|
+
offsetY,
|
|
1325
|
+
)
|
|
1245
1326
|
}
|
|
1246
1327
|
// eslint-disable-next-line prefer-arrow-callback
|
|
1247
|
-
return this.executeScript(
|
|
1328
|
+
return this.executeScript(
|
|
1329
|
+
function (x, y) {
|
|
1330
|
+
return window.scrollTo(x, y)
|
|
1331
|
+
},
|
|
1332
|
+
offsetX,
|
|
1333
|
+
offsetY,
|
|
1334
|
+
)
|
|
1248
1335
|
}
|
|
1249
1336
|
|
|
1250
1337
|
/**
|
|
1251
1338
|
* {{> scrollPageToTop }}
|
|
1252
1339
|
*/
|
|
1253
1340
|
async scrollPageToTop() {
|
|
1254
|
-
return this.executeScript(() => window.scrollTo(0, 0))
|
|
1341
|
+
return this.executeScript(() => window.scrollTo(0, 0))
|
|
1255
1342
|
}
|
|
1256
1343
|
|
|
1257
1344
|
/**
|
|
@@ -1260,16 +1347,13 @@ class Nightmare extends Helper {
|
|
|
1260
1347
|
async scrollPageToBottom() {
|
|
1261
1348
|
/* eslint-disable prefer-arrow-callback, comma-dangle */
|
|
1262
1349
|
return this.executeScript(function () {
|
|
1263
|
-
const body = document.body
|
|
1264
|
-
const html = document.documentElement
|
|
1265
|
-
window.scrollTo(
|
|
1266
|
-
|
|
1267
|
-
body.offsetHeight,
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
html.offsetHeight
|
|
1271
|
-
));
|
|
1272
|
-
});
|
|
1350
|
+
const body = document.body
|
|
1351
|
+
const html = document.documentElement
|
|
1352
|
+
window.scrollTo(
|
|
1353
|
+
0,
|
|
1354
|
+
Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),
|
|
1355
|
+
)
|
|
1356
|
+
})
|
|
1273
1357
|
/* eslint-enable */
|
|
1274
1358
|
}
|
|
1275
1359
|
|
|
@@ -1281,135 +1365,143 @@ class Nightmare extends Helper {
|
|
|
1281
1365
|
function getScrollPosition() {
|
|
1282
1366
|
return {
|
|
1283
1367
|
x: window.pageXOffset,
|
|
1284
|
-
y: window.pageYOffset
|
|
1285
|
-
}
|
|
1368
|
+
y: window.pageYOffset,
|
|
1369
|
+
}
|
|
1286
1370
|
}
|
|
1287
1371
|
/* eslint-enable comma-dangle */
|
|
1288
|
-
return this.executeScript(getScrollPosition)
|
|
1372
|
+
return this.executeScript(getScrollPosition)
|
|
1289
1373
|
}
|
|
1290
1374
|
}
|
|
1291
1375
|
|
|
1292
|
-
module.exports = Nightmare
|
|
1376
|
+
module.exports = Nightmare
|
|
1293
1377
|
|
|
1294
1378
|
async function proceedSee(assertType, text, context) {
|
|
1295
|
-
let description
|
|
1296
|
-
let locator
|
|
1379
|
+
let description
|
|
1380
|
+
let locator
|
|
1297
1381
|
if (!context) {
|
|
1298
1382
|
if (this.context === this.options.rootElement) {
|
|
1299
|
-
locator = new Locator(this.context, 'css')
|
|
1300
|
-
description = 'web application'
|
|
1383
|
+
locator = new Locator(this.context, 'css')
|
|
1384
|
+
description = 'web application'
|
|
1301
1385
|
} else {
|
|
1302
|
-
description = `current context ${this.context}
|
|
1303
|
-
locator = new Locator({ xpath: './/*' })
|
|
1386
|
+
description = `current context ${this.context}`
|
|
1387
|
+
locator = new Locator({ xpath: './/*' })
|
|
1304
1388
|
}
|
|
1305
1389
|
} else {
|
|
1306
|
-
locator = new Locator(context, 'css')
|
|
1307
|
-
description = `element ${locator.toString()}
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
const texts = await this.browser.evaluate(
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1390
|
+
locator = new Locator(context, 'css')
|
|
1391
|
+
description = `element ${locator.toString()}`
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
const texts = await this.browser.evaluate(
|
|
1395
|
+
(by, locator) => {
|
|
1396
|
+
return window.codeceptjs.findElements(by, locator).map((el) => el.innerText)
|
|
1397
|
+
},
|
|
1398
|
+
locator.type,
|
|
1399
|
+
locator.value,
|
|
1400
|
+
)
|
|
1401
|
+
const allText = texts.join(' | ')
|
|
1402
|
+
return stringIncludes(description)[assertType](text, allText)
|
|
1315
1403
|
}
|
|
1316
1404
|
|
|
1317
1405
|
async function proceedSeeInField(assertType, field, value) {
|
|
1318
|
-
const el = await findField.call(this, field)
|
|
1319
|
-
assertElementExists(el, field, 'Field')
|
|
1320
|
-
const tag = await this.browser.evaluate(el => window.codeceptjs.fetchElement(el).tagName, el)
|
|
1321
|
-
const fieldVal = await this.browser.evaluate(el => window.codeceptjs.fetchElement(el).value, el)
|
|
1406
|
+
const el = await findField.call(this, field)
|
|
1407
|
+
assertElementExists(el, field, 'Field')
|
|
1408
|
+
const tag = await this.browser.evaluate((el) => window.codeceptjs.fetchElement(el).tagName, el)
|
|
1409
|
+
const fieldVal = await this.browser.evaluate((el) => window.codeceptjs.fetchElement(el).value, el)
|
|
1322
1410
|
if (tag === 'select') {
|
|
1323
1411
|
// locate option by values and check them
|
|
1324
|
-
const text = await this.browser.evaluate(
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1412
|
+
const text = await this.browser.evaluate(
|
|
1413
|
+
(el, val) => {
|
|
1414
|
+
return el.querySelector(`option[value="${val}"]`).innerText
|
|
1415
|
+
},
|
|
1416
|
+
el,
|
|
1417
|
+
xpathLocator.literal(fieldVal),
|
|
1418
|
+
)
|
|
1419
|
+
return equals(`select option by ${field}`)[assertType](value, text)
|
|
1328
1420
|
}
|
|
1329
|
-
return stringIncludes(`field by ${field}`)[assertType](value, fieldVal)
|
|
1421
|
+
return stringIncludes(`field by ${field}`)[assertType](value, fieldVal)
|
|
1330
1422
|
}
|
|
1331
1423
|
|
|
1332
1424
|
async function proceedIsChecked(assertType, option) {
|
|
1333
|
-
const els = await findCheckable.call(this, option)
|
|
1334
|
-
assertElementExists(els, option, 'Checkable')
|
|
1425
|
+
const els = await findCheckable.call(this, option)
|
|
1426
|
+
assertElementExists(els, option, 'Checkable')
|
|
1335
1427
|
const selected = await this.browser.evaluate((els) => {
|
|
1336
|
-
return els.map(el => window.codeceptjs.fetchElement(el).checked).reduce((prev, cur) => prev || cur)
|
|
1337
|
-
}, els)
|
|
1338
|
-
return truth(`checkable ${option}`, 'to be checked')[assertType](selected)
|
|
1428
|
+
return els.map((el) => window.codeceptjs.fetchElement(el).checked).reduce((prev, cur) => prev || cur)
|
|
1429
|
+
}, els)
|
|
1430
|
+
return truth(`checkable ${option}`, 'to be checked')[assertType](selected)
|
|
1339
1431
|
}
|
|
1340
1432
|
|
|
1341
1433
|
async function findCheckable(locator, context) {
|
|
1342
|
-
let contextEl = null
|
|
1434
|
+
let contextEl = null
|
|
1343
1435
|
if (context) {
|
|
1344
|
-
contextEl = await this.browser.findElement(
|
|
1436
|
+
contextEl = await this.browser.findElement(new Locator(context, 'css').toStrict())
|
|
1345
1437
|
}
|
|
1346
1438
|
|
|
1347
|
-
const matchedLocator = new Locator(locator)
|
|
1439
|
+
const matchedLocator = new Locator(locator)
|
|
1348
1440
|
if (!matchedLocator.isFuzzy()) {
|
|
1349
|
-
return this.browser.findElements(matchedLocator.toStrict(), contextEl)
|
|
1441
|
+
return this.browser.findElements(matchedLocator.toStrict(), contextEl)
|
|
1350
1442
|
}
|
|
1351
1443
|
|
|
1352
|
-
const literal = xpathLocator.literal(locator)
|
|
1353
|
-
let els = await this.browser.findElements({ xpath: Locator.checkable.byText(literal) }, contextEl)
|
|
1444
|
+
const literal = xpathLocator.literal(locator)
|
|
1445
|
+
let els = await this.browser.findElements({ xpath: Locator.checkable.byText(literal) }, contextEl)
|
|
1354
1446
|
if (els.length) {
|
|
1355
|
-
return els
|
|
1447
|
+
return els
|
|
1356
1448
|
}
|
|
1357
|
-
els = await this.browser.findElements({ xpath: Locator.checkable.byName(literal) }, contextEl)
|
|
1449
|
+
els = await this.browser.findElements({ xpath: Locator.checkable.byName(literal) }, contextEl)
|
|
1358
1450
|
if (els.length) {
|
|
1359
|
-
return els
|
|
1451
|
+
return els
|
|
1360
1452
|
}
|
|
1361
|
-
return this.browser.findElements({ css: locator }, contextEl)
|
|
1453
|
+
return this.browser.findElements({ css: locator }, contextEl)
|
|
1362
1454
|
}
|
|
1363
1455
|
|
|
1364
1456
|
async function findClickable(locator, context) {
|
|
1365
|
-
let contextEl = null
|
|
1457
|
+
let contextEl = null
|
|
1366
1458
|
if (context) {
|
|
1367
|
-
contextEl = await this.browser.findElement(
|
|
1459
|
+
contextEl = await this.browser.findElement(new Locator(context, 'css').toStrict())
|
|
1368
1460
|
}
|
|
1369
1461
|
|
|
1370
|
-
const matchedLocator = new Locator(locator)
|
|
1462
|
+
const matchedLocator = new Locator(locator)
|
|
1371
1463
|
if (!matchedLocator.isFuzzy()) {
|
|
1372
|
-
return this.browser.findElement(matchedLocator.toStrict(), contextEl)
|
|
1464
|
+
return this.browser.findElement(matchedLocator.toStrict(), contextEl)
|
|
1373
1465
|
}
|
|
1374
1466
|
|
|
1375
|
-
const literal = xpathLocator.literal(locator)
|
|
1467
|
+
const literal = xpathLocator.literal(locator)
|
|
1376
1468
|
|
|
1377
|
-
let els = await this.browser.findElements({ xpath: Locator.clickable.narrow(literal) }, contextEl)
|
|
1469
|
+
let els = await this.browser.findElements({ xpath: Locator.clickable.narrow(literal) }, contextEl)
|
|
1378
1470
|
if (els.length) {
|
|
1379
|
-
return els[0]
|
|
1471
|
+
return els[0]
|
|
1380
1472
|
}
|
|
1381
1473
|
|
|
1382
|
-
els = await this.browser.findElements({ xpath: Locator.clickable.wide(literal) }, contextEl)
|
|
1474
|
+
els = await this.browser.findElements({ xpath: Locator.clickable.wide(literal) }, contextEl)
|
|
1383
1475
|
if (els.length) {
|
|
1384
|
-
return els[0]
|
|
1476
|
+
return els[0]
|
|
1385
1477
|
}
|
|
1386
1478
|
|
|
1387
|
-
return this.browser.findElement({ css: locator }, contextEl)
|
|
1479
|
+
return this.browser.findElement({ css: locator }, contextEl)
|
|
1388
1480
|
}
|
|
1389
1481
|
|
|
1390
1482
|
async function findField(locator) {
|
|
1391
|
-
const matchedLocator = new Locator(locator)
|
|
1483
|
+
const matchedLocator = new Locator(locator)
|
|
1392
1484
|
if (!matchedLocator.isFuzzy()) {
|
|
1393
|
-
return this.browser.findElements(matchedLocator.toStrict())
|
|
1485
|
+
return this.browser.findElements(matchedLocator.toStrict())
|
|
1394
1486
|
}
|
|
1395
|
-
const literal = xpathLocator.literal(locator)
|
|
1487
|
+
const literal = xpathLocator.literal(locator)
|
|
1396
1488
|
|
|
1397
|
-
let els = await this.browser.findElements({ xpath: Locator.field.labelEquals(literal) })
|
|
1489
|
+
let els = await this.browser.findElements({ xpath: Locator.field.labelEquals(literal) })
|
|
1398
1490
|
if (els.length) {
|
|
1399
|
-
return els[0]
|
|
1491
|
+
return els[0]
|
|
1400
1492
|
}
|
|
1401
1493
|
|
|
1402
|
-
els = await this.browser.findElements({ xpath: Locator.field.labelContains(literal) })
|
|
1494
|
+
els = await this.browser.findElements({ xpath: Locator.field.labelContains(literal) })
|
|
1403
1495
|
if (els.length) {
|
|
1404
|
-
return els[0]
|
|
1496
|
+
return els[0]
|
|
1405
1497
|
}
|
|
1406
|
-
els = await this.browser.findElements({ xpath: Locator.field.byName(literal) })
|
|
1498
|
+
els = await this.browser.findElements({ xpath: Locator.field.byName(literal) })
|
|
1407
1499
|
if (els.length) {
|
|
1408
|
-
return els[0]
|
|
1500
|
+
return els[0]
|
|
1409
1501
|
}
|
|
1410
|
-
return this.browser.findElement({ css: locator })
|
|
1502
|
+
return this.browser.findElement({ css: locator })
|
|
1411
1503
|
}
|
|
1412
1504
|
|
|
1413
1505
|
function assertElementExists(el, locator, prefix, suffix) {
|
|
1414
|
-
if (el === null) throw new ElementNotFound(locator, prefix, suffix)
|
|
1506
|
+
if (el === null) throw new ElementNotFound(locator, prefix, suffix)
|
|
1415
1507
|
}
|