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