phantomjs-binaries 1.8.0 → 1.8.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/modules/cli.js DELETED
@@ -1,138 +0,0 @@
1
- /*!
2
- * Casper is a navigation utility for PhantomJS.
3
- *
4
- * Documentation: http://casperjs.org/
5
- * Repository: http://github.com/n1k0/casperjs
6
- *
7
- * Copyright (c) 2011-2012 Nicolas Perriault
8
- *
9
- * Part of source code is Copyright Joyent, Inc. and other Node contributors.
10
- *
11
- * Permission is hereby granted, free of charge, to any person obtaining a
12
- * copy of this software and associated documentation files (the "Software"),
13
- * to deal in the Software without restriction, including without limitation
14
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15
- * and/or sell copies of the Software, and to permit persons to whom the
16
- * Software is furnished to do so, subject to the following conditions:
17
- *
18
- * The above copyright notice and this permission notice shall be included
19
- * in all copies or substantial portions of the Software.
20
- *
21
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
- * DEALINGS IN THE SOFTWARE.
28
- *
29
- */
30
-
31
- /*global CasperError console exports phantom require*/
32
-
33
- var system = require('system');
34
- var utils = require('utils');
35
-
36
- /**
37
- * Extracts, normalize ad organize PhantomJS CLI arguments in a dedicated
38
- * Object.
39
- *
40
- * @param array phantomArgs system.args value
41
- * @return Object
42
- */
43
- exports.parse = function parse(phantomArgs) {
44
- "use strict";
45
- var extract = {
46
- args: [],
47
- options: {},
48
- raw: {
49
- args: [],
50
- options: {}
51
- },
52
- drop: function drop(what) {
53
- if (utils.isNumber(what)) {
54
- // deleting an arg by its position
55
- this.args = this.args.filter(function _filter(arg, index) {
56
- return index !== what;
57
- });
58
- } else if (utils.isString(what)) {
59
- // deleting an arg by its value
60
- this.args = this.args.filter(function _filter(arg) {
61
- return arg !== what;
62
- });
63
- // deleting an option by its name (key)
64
- var self = this;
65
- Object.keys(this.options).forEach(function _forEach(option) {
66
- if (option === what) {
67
- delete self.options[what];
68
- }
69
- });
70
- } else {
71
- throw new CasperError("cannot drop argument of type " + typeof what);
72
- }
73
- },
74
- has: function has(what) {
75
- if (utils.isNumber(what)) {
76
- return what in this.args;
77
- } else if (utils.isString(what)) {
78
- return what in this.options;
79
- } else {
80
- throw new CasperError("Unsupported cli arg tester " + typeof what);
81
- }
82
- },
83
- get: function get(what) {
84
- if (utils.isNumber(what)) {
85
- return this.args[what];
86
- } else if (utils.isString(what)) {
87
- return this.options[what];
88
- } else {
89
- throw new CasperError("Unsupported cli arg getter " + typeof what);
90
- }
91
- }
92
- };
93
- phantomArgs.forEach(function _forEach(arg) {
94
- if (arg.indexOf('--') === 0) {
95
- // named option
96
- var optionMatch = arg.match(/^--(.*?)=(.*)/i);
97
- if (optionMatch) {
98
- extract.options[optionMatch[1]] = castArgument(optionMatch[2]);
99
- extract.raw.options[optionMatch[1]] = optionMatch[2];
100
- } else {
101
- // flag
102
- var flagMatch = arg.match(/^--(.*)/);
103
- if (flagMatch) {
104
- extract.options[flagMatch[1]] = extract.raw.options[flagMatch[1]] = true;
105
- }
106
- }
107
- } else {
108
- // positional arg
109
- extract.args.push(castArgument(arg));
110
- extract.raw.args.push(castArgument(arg));
111
- }
112
- });
113
- extract.raw = utils.mergeObjects(extract.raw, {
114
- drop: extract.drop,
115
- has: extract.has,
116
- get: extract.get
117
- });
118
- return extract;
119
- };
120
-
121
- /**
122
- * Cast a string argument to its typed equivalent.
123
- *
124
- * @param String arg
125
- * @return Mixed
126
- */
127
- function castArgument(arg) {
128
- "use strict";
129
- if (arg.match(/^-?\d+$/)) {
130
- return parseInt(arg, 10);
131
- } else if (arg.match(/^-?\d+\.\d+$/)) {
132
- return parseFloat(arg);
133
- } else if (arg.match(/^(true|false)$/i)) {
134
- return arg.trim().toLowerCase() === "true" ? true : false;
135
- } else {
136
- return arg;
137
- }
138
- }
@@ -1,781 +0,0 @@
1
- /*!
2
- * Casper is a navigation utility for PhantomJS.
3
- *
4
- * Documentation: http://casperjs.org/
5
- * Repository: http://github.com/n1k0/casperjs
6
- *
7
- * Copyright (c) 2011-2012 Nicolas Perriault
8
- *
9
- * Part of source code is Copyright Joyent, Inc. and other Node contributors.
10
- *
11
- * Permission is hereby granted, free of charge, to any person obtaining a
12
- * copy of this software and associated documentation files (the "Software"),
13
- * to deal in the Software without restriction, including without limitation
14
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15
- * and/or sell copies of the Software, and to permit persons to whom the
16
- * Software is furnished to do so, subject to the following conditions:
17
- *
18
- * The above copyright notice and this permission notice shall be included
19
- * in all copies or substantial portions of the Software.
20
- *
21
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
- * DEALINGS IN THE SOFTWARE.
28
- *
29
- */
30
-
31
- /*global console escape exports NodeList window*/
32
-
33
- (function(exports) {
34
- "use strict";
35
-
36
- exports.create = function create(options) {
37
- return new this.ClientUtils(options);
38
- };
39
-
40
- /**
41
- * Casper client-side helpers.
42
- */
43
- exports.ClientUtils = function ClientUtils(options) {
44
- /*jshint maxstatements:40*/
45
- // private members
46
- var BASE64_ENCODE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
47
- var BASE64_DECODE_CHARS = new Array(
48
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
49
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
50
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
51
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
52
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
53
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
54
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
55
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
56
- );
57
- var SUPPORTED_SELECTOR_TYPES = ['css', 'xpath'];
58
-
59
- // public members
60
- this.options = options || {};
61
- this.options.scope = this.options.scope || document;
62
- /**
63
- * Clicks on the DOM element behind the provided selector.
64
- *
65
- * @param String selector A CSS3 selector to the element to click
66
- * @return Boolean
67
- */
68
- this.click = function click(selector) {
69
- return this.mouseEvent('click', selector);
70
- };
71
-
72
- /**
73
- * Decodes a base64 encoded string. Succeeds where window.atob() fails.
74
- *
75
- * @param String str The base64 encoded contents
76
- * @return string
77
- */
78
- this.decode = function decode(str) {
79
- /*jshint maxstatements:30 maxcomplexity:30 */
80
- var c1, c2, c3, c4, i = 0, len = str.length, out = "";
81
- while (i < len) {
82
- do {
83
- c1 = BASE64_DECODE_CHARS[str.charCodeAt(i++) & 0xff];
84
- } while (i < len && c1 === -1);
85
- if (c1 === -1) {
86
- break;
87
- }
88
- do {
89
- c2 = BASE64_DECODE_CHARS[str.charCodeAt(i++) & 0xff];
90
- } while (i < len && c2 === -1);
91
- if (c2 === -1) {
92
- break;
93
- }
94
- out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));
95
- do {
96
- c3 = str.charCodeAt(i++) & 0xff;
97
- if (c3 === 61)
98
- return out;
99
- c3 = BASE64_DECODE_CHARS[c3];
100
- } while (i < len && c3 === -1);
101
- if (c3 === -1) {
102
- break;
103
- }
104
- out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));
105
- do {
106
- c4 = str.charCodeAt(i++) & 0xff;
107
- if (c4 === 61) {
108
- return out;
109
- }
110
- c4 = BASE64_DECODE_CHARS[c4];
111
- } while (i < len && c4 === -1);
112
- if (c4 === -1) {
113
- break;
114
- }
115
- out += String.fromCharCode(((c3 & 0x03) << 6) | c4);
116
- }
117
- return out;
118
- };
119
-
120
- /**
121
- * Echoes something to casper console.
122
- *
123
- * @param String message
124
- * @return
125
- */
126
- this.echo = function echo(message) {
127
- console.log("[casper.echo] " + message);
128
- };
129
-
130
- /**
131
- * Base64 encodes a string, even binary ones. Succeeds where
132
- * window.btoa() fails.
133
- *
134
- * @param String str The string content to encode
135
- * @return string
136
- */
137
- this.encode = function encode(str) {
138
- /*jshint maxstatements:30 */
139
- var out = "", i = 0, len = str.length, c1, c2, c3;
140
- while (i < len) {
141
- c1 = str.charCodeAt(i++) & 0xff;
142
- if (i === len) {
143
- out += BASE64_ENCODE_CHARS.charAt(c1 >> 2);
144
- out += BASE64_ENCODE_CHARS.charAt((c1 & 0x3) << 4);
145
- out += "==";
146
- break;
147
- }
148
- c2 = str.charCodeAt(i++);
149
- if (i === len) {
150
- out += BASE64_ENCODE_CHARS.charAt(c1 >> 2);
151
- out += BASE64_ENCODE_CHARS.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
152
- out += BASE64_ENCODE_CHARS.charAt((c2 & 0xF) << 2);
153
- out += "=";
154
- break;
155
- }
156
- c3 = str.charCodeAt(i++);
157
- out += BASE64_ENCODE_CHARS.charAt(c1 >> 2);
158
- out += BASE64_ENCODE_CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
159
- out += BASE64_ENCODE_CHARS.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
160
- out += BASE64_ENCODE_CHARS.charAt(c3 & 0x3F);
161
- }
162
- return out;
163
- };
164
-
165
- /**
166
- * Checks if a given DOM element exists in remote page.
167
- *
168
- * @param String selector CSS3 selector
169
- * @return Boolean
170
- */
171
- this.exists = function exists(selector) {
172
- try {
173
- return this.findAll(selector).length > 0;
174
- } catch (e) {
175
- return false;
176
- }
177
- };
178
-
179
- /**
180
- * Fetches innerText within the element(s) matching a given CSS3
181
- * selector.
182
- *
183
- * @param String selector A CSS3 selector
184
- * @return String
185
- */
186
- this.fetchText = function fetchText(selector) {
187
- var text = '', elements = this.findAll(selector);
188
- if (elements && elements.length) {
189
- Array.prototype.forEach.call(elements, function _forEach(element) {
190
- text += element.textContent || element.innerText;
191
- });
192
- }
193
- return text;
194
- };
195
-
196
- /**
197
- * Fills a form with provided field values, and optionnaly submits it.
198
- *
199
- * @param HTMLElement|String form A form element, or a CSS3 selector to a form element
200
- * @param Object vals Field values
201
- * @return Object An object containing setting result for each field, including file uploads
202
- */
203
- this.fill = function fill(form, vals) {
204
- /*jshint maxcomplexity:8*/
205
- var out = {
206
- errors: [],
207
- fields: [],
208
- files: []
209
- };
210
- if (!(form instanceof HTMLElement) || typeof form === "string") {
211
- this.log("attempting to fetch form element from selector: '" + form + "'", "info");
212
- try {
213
- form = this.findOne(form);
214
- } catch (e) {
215
- if (e.name === "SYNTAX_ERR") {
216
- out.errors.push("invalid form selector provided: '" + form + "'");
217
- return out;
218
- }
219
- }
220
- }
221
- if (!form) {
222
- out.errors.push("form not found");
223
- return out;
224
- }
225
- for (var name in vals) {
226
- if (!vals.hasOwnProperty(name)) {
227
- continue;
228
- }
229
- var field = this.findAll('[name="' + name + '"]', form);
230
- var value = vals[name];
231
- if (!field || field.length === 0) {
232
- out.errors.push('no field named "' + name + '" in form');
233
- continue;
234
- }
235
- try {
236
- out.fields[name] = this.setField(field, value);
237
- } catch (err) {
238
- if (err.name === "FileUploadError") {
239
- out.files.push({
240
- name: name,
241
- path: err.path
242
- });
243
- } else if(err.name === "FieldNotFound") {
244
- out.errors.push('Form field named "' + name + '" was not found.');
245
- } else {
246
- out.errors.push(err.toString());
247
- }
248
- }
249
- }
250
- return out;
251
- };
252
-
253
- /**
254
- * Finds all DOM elements matching by the provided selector.
255
- *
256
- * @param String selector CSS3 selector
257
- * @param HTMLElement|null scope Element to search child elements within
258
- * @return NodeList|undefined
259
- */
260
- this.findAll = function findAll(selector, scope) {
261
- scope = scope || this.options.scope;
262
- try {
263
- var pSelector = this.processSelector(selector);
264
- if (pSelector.type === 'xpath') {
265
- return this.getElementsByXPath(pSelector.path, scope);
266
- } else {
267
- return scope.querySelectorAll(pSelector.path);
268
- }
269
- } catch (e) {
270
- this.log('findAll(): invalid selector provided "' + selector + '":' + e, "error");
271
- }
272
- };
273
-
274
- /**
275
- * Finds a DOM element by the provided selector.
276
- *
277
- * @param String selector CSS3 selector
278
- * @param HTMLElement|null scope Element to search child elements within
279
- * @return HTMLElement|undefined
280
- */
281
- this.findOne = function findOne(selector, scope) {
282
- scope = scope || this.options.scope;
283
- try {
284
- var pSelector = this.processSelector(selector);
285
- if (pSelector.type === 'xpath') {
286
- return this.getElementByXPath(pSelector.path, scope);
287
- } else {
288
- return scope.querySelector(pSelector.path);
289
- }
290
- } catch (e) {
291
- this.log('findOne(): invalid selector provided "' + selector + '":' + e, "error");
292
- }
293
- };
294
-
295
- /**
296
- * Downloads a resource behind an url and returns its base64-encoded
297
- * contents.
298
- *
299
- * @param String url The resource url
300
- * @param String method The request method, optional (default: GET)
301
- * @param Object data The request data, optional
302
- * @return String Base64 contents string
303
- */
304
- this.getBase64 = function getBase64(url, method, data) {
305
- return this.encode(this.getBinary(url, method, data));
306
- };
307
-
308
- /**
309
- * Retrieves string contents from a binary file behind an url. Silently
310
- * fails but log errors.
311
- *
312
- * @param String url Url.
313
- * @param String method HTTP method.
314
- * @param Object data Request parameters.
315
- * @return String
316
- */
317
- this.getBinary = function getBinary(url, method, data) {
318
- try {
319
- return this.sendAJAX(url, method, data, false);
320
- } catch (e) {
321
- if (e.name === "NETWORK_ERR" && e.code === 101) {
322
- this.log("getBinary(): Unfortunately, casperjs cannot make cross domain ajax requests", "warning");
323
- }
324
- this.log("getBinary(): Error while fetching " + url + ": " + e, "error");
325
- return "";
326
- }
327
- };
328
-
329
- /**
330
- * Retrieves total document height.
331
- * http://james.padolsey.com/javascript/get-document-height-cross-browser/
332
- *
333
- * @return {Number}
334
- */
335
- this.getDocumentHeight = function getDocumentHeight() {
336
- return Math.max(
337
- Math.max(document.body.scrollHeight, document.documentElement.scrollHeight),
338
- Math.max(document.body.offsetHeight, document.documentElement.offsetHeight),
339
- Math.max(document.body.clientHeight, document.documentElement.clientHeight)
340
- );
341
- };
342
-
343
- /**
344
- * Retrieves bounding rect coordinates of the HTML element matching the
345
- * provided CSS3 selector in the following form:
346
- *
347
- * {top: y, left: x, width: w, height:, h}
348
- *
349
- * @param String selector
350
- * @return Object or null
351
- */
352
- this.getElementBounds = function getElementBounds(selector) {
353
- try {
354
- var clipRect = this.findOne(selector).getBoundingClientRect();
355
- return {
356
- top: clipRect.top,
357
- left: clipRect.left,
358
- width: clipRect.width,
359
- height: clipRect.height
360
- };
361
- } catch (e) {
362
- this.log("Unable to fetch bounds for element " + selector, "warning");
363
- }
364
- };
365
-
366
- /**
367
- * Retrieves the list of bounding rect coordinates for all the HTML elements matching the
368
- * provided CSS3 selector, in the following form:
369
- *
370
- * [{top: y, left: x, width: w, height:, h},
371
- * {top: y, left: x, width: w, height:, h},
372
- * ...]
373
- *
374
- * @param String selector
375
- * @return Array
376
- */
377
- this.getElementsBounds = function getElementsBounds(selector) {
378
- var elements = this.findAll(selector);
379
- var self = this;
380
- try {
381
- return Array.prototype.map.call(elements, function(element) {
382
- var clipRect = element.getBoundingClientRect();
383
- return {
384
- top: clipRect.top,
385
- left: clipRect.left,
386
- width: clipRect.width,
387
- height: clipRect.height
388
- };
389
- });
390
- } catch (e) {
391
- this.log("Unable to fetch bounds for elements matching " + selector, "warning");
392
- }
393
- };
394
-
395
- /**
396
- * Retrieves information about the node matching the provided selector.
397
- *
398
- * @param String|Object selector CSS3/XPath selector
399
- * @return Object
400
- */
401
- this.getElementInfo = function getElementInfo(selector) {
402
- var element = this.findOne(selector);
403
- var bounds = this.getElementBounds(selector);
404
- var attributes = {};
405
- [].forEach.call(element.attributes, function(attr) {
406
- attributes[attr.name.toLowerCase()] = attr.value;
407
- });
408
- return {
409
- nodeName: element.nodeName.toLowerCase(),
410
- attributes: attributes,
411
- tag: element.outerHTML,
412
- html: element.innerHTML,
413
- text: element.innerText,
414
- x: bounds.left,
415
- y: bounds.top,
416
- width: bounds.width,
417
- height: bounds.height,
418
- visible: this.visible(selector)
419
- };
420
- };
421
-
422
- /**
423
- * Retrieves a single DOM element matching a given XPath expression.
424
- *
425
- * @param String expression The XPath expression
426
- * @param HTMLElement|null scope Element to search child elements within
427
- * @return HTMLElement or null
428
- */
429
- this.getElementByXPath = function getElementByXPath(expression, scope) {
430
- scope = scope || this.options.scope;
431
- var a = document.evaluate(expression, scope, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
432
- if (a.snapshotLength > 0) {
433
- return a.snapshotItem(0);
434
- }
435
- };
436
-
437
- /**
438
- * Retrieves all DOM elements matching a given XPath expression.
439
- *
440
- * @param String expression The XPath expression
441
- * @param HTMLElement|null scope Element to search child elements within
442
- * @return Array
443
- */
444
- this.getElementsByXPath = function getElementsByXPath(expression, scope) {
445
- scope = scope || this.options.scope;
446
- var nodes = [];
447
- var a = document.evaluate(expression, scope, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
448
- for (var i = 0; i < a.snapshotLength; i++) {
449
- nodes.push(a.snapshotItem(i));
450
- }
451
- return nodes;
452
- };
453
-
454
- /**
455
- * Retrieves the value of a form field.
456
- *
457
- * @param String inputName The for input name attr value
458
- * @return Mixed
459
- */
460
- this.getFieldValue = function getFieldValue(inputName) {
461
- function getSingleValue(input) {
462
- try {
463
- type = input.getAttribute('type').toLowerCase();
464
- } catch (e) {
465
- type = 'other';
466
- }
467
- if (['checkbox', 'radio'].indexOf(type) === -1) {
468
- return input.value;
469
- }
470
- // single checkbox or… radio button (weird, I know)
471
- if (input.hasAttribute('value')) {
472
- return input.checked ? input.getAttribute('value') : undefined;
473
- }
474
- return input.checked;
475
- }
476
- function getMultipleValues(inputs) {
477
- type = inputs[0].getAttribute('type').toLowerCase();
478
- if (type === 'radio') {
479
- var value;
480
- [].forEach.call(inputs, function(radio) {
481
- value = radio.checked ? radio.value : undefined;
482
- });
483
- return value;
484
- } else if (type === 'checkbox') {
485
- var values = [];
486
- [].forEach.call(inputs, function(checkbox) {
487
- if (checkbox.checked) {
488
- values.push(checkbox.value);
489
- }
490
- });
491
- return values;
492
- }
493
- }
494
- var inputs = this.findAll('[name="' + inputName + '"]'), type;
495
- switch (inputs.length) {
496
- case 0: return null;
497
- case 1: return getSingleValue(inputs[0]);
498
- default: return getMultipleValues(inputs);
499
- }
500
- };
501
-
502
- /**
503
- * Retrieves a given form all of its field values.
504
- *
505
- * @param String selector A DOM CSS3/XPath selector
506
- * @return Object
507
- */
508
- this.getFormValues = function getFormValues(selector) {
509
- var form = this.findOne(selector);
510
- var values = {};
511
- var self = this;
512
- [].forEach.call(form.elements, function(element) {
513
- var name = element.getAttribute('name');
514
- if (name) {
515
- values[name] = self.getFieldValue(name);
516
- }
517
- });
518
- return values;
519
- };
520
-
521
- /**
522
- * Logs a message. Will format the message a way CasperJS will be able
523
- * to log phantomjs side.
524
- *
525
- * @param String message The message to log
526
- * @param String level The log level
527
- */
528
- this.log = function log(message, level) {
529
- console.log("[casper:" + (level || "debug") + "] " + message);
530
- };
531
-
532
- /**
533
- * Dispatches a mouse event to the DOM element behind the provided selector.
534
- *
535
- * @param String type Type of event to dispatch
536
- * @param String selector A CSS3 selector to the element to click
537
- * @return Boolean
538
- */
539
- this.mouseEvent = function mouseEvent(type, selector) {
540
- var elem = this.findOne(selector);
541
- if (!elem) {
542
- this.log("mouseEvent(): Couldn't find any element matching '" + selector + "' selector", "error");
543
- return false;
544
- }
545
- try {
546
- var evt = document.createEvent("MouseEvents");
547
- var center_x = 1, center_y = 1;
548
- try {
549
- var pos = elem.getBoundingClientRect();
550
- center_x = Math.floor((pos.left + pos.right) / 2),
551
- center_y = Math.floor((pos.top + pos.bottom) / 2);
552
- } catch(e) {}
553
- evt.initMouseEvent(type, true, true, window, 1, 1, 1, center_x, center_y, false, false, false, false, 0, elem);
554
- // dispatchEvent return value is false if at least one of the event
555
- // handlers which handled this event called preventDefault;
556
- // so we cannot returns this results as it cannot accurately informs on the status
557
- // of the operation
558
- // let's assume the event has been sent ok it didn't raise any error
559
- elem.dispatchEvent(evt);
560
- return true;
561
- } catch (e) {
562
- this.log("Failed dispatching " + type + "mouse event on " + selector + ": " + e, "error");
563
- return false;
564
- }
565
- };
566
-
567
- /**
568
- * Processes a selector input, either as a string or an object.
569
- *
570
- * If passed an object, if must be of the form:
571
- *
572
- * selectorObject = {
573
- * type: <'css' or 'xpath'>,
574
- * path: <a string>
575
- * }
576
- *
577
- * @param String|Object selector The selector string or object
578
- *
579
- * @return an object containing 'type' and 'path' keys
580
- */
581
- this.processSelector = function processSelector(selector) {
582
- var selectorObject = {
583
- toString: function toString() {
584
- return this.type + ' selector: ' + this.path;
585
- }
586
- };
587
- if (typeof selector === "string") {
588
- // defaults to CSS selector
589
- selectorObject.type = "css";
590
- selectorObject.path = selector;
591
- return selectorObject;
592
- } else if (typeof selector === "object") {
593
- // validation
594
- if (!selector.hasOwnProperty('type') || !selector.hasOwnProperty('path')) {
595
- throw new Error("Incomplete selector object");
596
- } else if (SUPPORTED_SELECTOR_TYPES.indexOf(selector.type) === -1) {
597
- throw new Error("Unsupported selector type: " + selector.type);
598
- }
599
- if (!selector.hasOwnProperty('toString')) {
600
- selector.toString = selectorObject.toString;
601
- }
602
- return selector;
603
- }
604
- throw new Error("Unsupported selector type: " + typeof selector);
605
- };
606
-
607
- /**
608
- * Removes all DOM elements matching a given XPath expression.
609
- *
610
- * @param String expression The XPath expression
611
- * @return Array
612
- */
613
- this.removeElementsByXPath = function removeElementsByXPath(expression) {
614
- var a = document.evaluate(expression, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
615
- for (var i = 0; i < a.snapshotLength; i++) {
616
- a.snapshotItem(i).parentNode.removeChild(a.snapshotItem(i));
617
- }
618
- };
619
-
620
- /**
621
- * Performs an AJAX request.
622
- *
623
- * @param String url Url.
624
- * @param String method HTTP method (default: GET).
625
- * @param Object data Request parameters.
626
- * @param Boolean async Asynchroneous request? (default: false)
627
- * @return String Response text.
628
- */
629
- this.sendAJAX = function sendAJAX(url, method, data, async) {
630
- var xhr = new XMLHttpRequest(),
631
- dataString = "",
632
- dataList = [];
633
- method = method && method.toUpperCase() || "GET";
634
- xhr.open(method, url, !!async);
635
- this.log("sendAJAX(): Using HTTP method: '" + method + "'", "debug");
636
- xhr.overrideMimeType("text/plain; charset=x-user-defined");
637
- if (method === "POST") {
638
- if (typeof data === "object") {
639
- for (var k in data) {
640
- dataList.push(encodeURIComponent(k) + "=" + encodeURIComponent(data[k].toString()));
641
- }
642
- dataString = dataList.join('&');
643
- this.log("sendAJAX(): Using request data: '" + dataString + "'", "debug");
644
- } else if (typeof data === "string") {
645
- dataString = data;
646
- }
647
- xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
648
- }
649
- xhr.send(method === "POST" ? dataString : null);
650
- return xhr.responseText;
651
- };
652
-
653
- /**
654
- * Sets a field (or a set of fields) value. Fails silently, but log
655
- * error messages.
656
- *
657
- * @param HTMLElement|NodeList field One or more element defining a field
658
- * @param mixed value The field value to set
659
- */
660
- this.setField = function setField(field, value) {
661
- /*jshint maxcomplexity:99 */
662
- var logValue, fields, out;
663
- value = logValue = (value || "");
664
- if (field instanceof NodeList) {
665
- fields = field;
666
- field = fields[0];
667
- }
668
- if (!(field instanceof HTMLElement)) {
669
- var error = new Error('Invalid field type; only HTMLElement and NodeList are supported');
670
- error.name = 'FieldNotFound';
671
- throw error;
672
- }
673
- if (this.options && this.options.safeLogs && field.getAttribute('type') === "password") {
674
- // obfuscate password value
675
- logValue = new Array(value.length + 1).join("*");
676
- }
677
- this.log('Set "' + field.getAttribute('name') + '" field value to ' + logValue, "debug");
678
- try {
679
- field.focus();
680
- } catch (e) {
681
- this.log("Unable to focus() input field " + field.getAttribute('name') + ": " + e, "warning");
682
- }
683
- var nodeName = field.nodeName.toLowerCase();
684
- switch (nodeName) {
685
- case "input":
686
- var type = field.getAttribute('type') || "text";
687
- switch (type.toLowerCase()) {
688
- case "color":
689
- case "date":
690
- case "datetime":
691
- case "datetime-local":
692
- case "email":
693
- case "hidden":
694
- case "month":
695
- case "number":
696
- case "password":
697
- case "range":
698
- case "search":
699
- case "tel":
700
- case "text":
701
- case "time":
702
- case "url":
703
- case "week":
704
- field.value = value;
705
- break;
706
- case "checkbox":
707
- if (fields.length > 1) {
708
- var values = value;
709
- if (!Array.isArray(values)) {
710
- values = [values];
711
- }
712
- Array.prototype.forEach.call(fields, function _forEach(f) {
713
- f.checked = values.indexOf(f.value) !== -1 ? true : false;
714
- });
715
- } else {
716
- field.checked = value ? true : false;
717
- }
718
- break;
719
- case "file":
720
- throw {
721
- name: "FileUploadError",
722
- message: "File field must be filled using page.uploadFile",
723
- path: value
724
- };
725
- case "radio":
726
- if (fields) {
727
- Array.prototype.forEach.call(fields, function _forEach(e) {
728
- e.checked = (e.value === value);
729
- });
730
- } else {
731
- out = 'Provided radio elements are empty';
732
- }
733
- break;
734
- default:
735
- out = "Unsupported input field type: " + type;
736
- break;
737
- }
738
- break;
739
- case "select":
740
- case "textarea":
741
- field.value = value;
742
- break;
743
- default:
744
- out = 'Unsupported field type: ' + nodeName;
745
- break;
746
- }
747
- // firing the `change` event
748
- var changeEvent = document.createEvent("HTMLEvents");
749
- changeEvent.initEvent('change', true, true);
750
- field.dispatchEvent(changeEvent);
751
- // blur the field
752
- try {
753
- field.blur();
754
- } catch (err) {
755
- this.log("Unable to blur() input field " + field.getAttribute('name') + ": " + err, "warning");
756
- }
757
- return out;
758
- };
759
-
760
- /**
761
- * Checks if a given DOM element is visible in remote page.
762
- *
763
- * @param String selector CSS3 selector
764
- * @return Boolean
765
- */
766
- this.visible = function visible(selector) {
767
- try {
768
- var comp,
769
- el = this.findOne(selector);
770
-
771
- if (el) {
772
- comp = window.getComputedStyle(el, null);
773
- return comp.visibility !== 'hidden' && comp.display !== 'none' && el.offsetHeight > 0 && el.offsetWidth > 0;
774
- }
775
- return false;
776
- } catch (e) {
777
- return false;
778
- }
779
- };
780
- };
781
- })(typeof exports === "object" ? exports : window);