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