phantomjs-binaries 1.8.0 → 1.8.0.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.
data/bin/usage.txt DELETED
@@ -1,11 +0,0 @@
1
-
2
- Usage: casperjs [options] script.[js|coffee] [script argument [script argument ...]]
3
- casperjs [options] test [test path [test path ...]]
4
- casperjs [options] selftest
5
-
6
- Options:
7
-
8
- --help Prints this help
9
- --version Prints out CasperJS version
10
-
11
- Read the docs http://casperjs.org/
data/modules/casper.js DELETED
@@ -1,2101 +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 __utils__*/
32
-
33
- var colorizer = require('colorizer');
34
- var events = require('events');
35
- var fs = require('fs');
36
- var http = require('http');
37
- var mouse = require('mouse');
38
- var pagestack = require('pagestack');
39
- var qs = require('querystring');
40
- var tester = require('tester');
41
- var utils = require('utils');
42
- var f = utils.format;
43
-
44
-
45
- var defaultUserAgent = phantom.defaultPageSettings.userAgent
46
- .replace('PhantomJS', f("CasperJS/%s", phantom.casperVersion) + '+Phantomjs');
47
-
48
- exports.create = function create(options) {
49
- "use strict";
50
- return new Casper(options);
51
- };
52
-
53
- /**
54
- * Shortcut to build an XPath selector object.
55
- *
56
- * @param String expression The XPath expression
57
- * @return Object
58
- * @see http://casperjs.org/selectors.html
59
- */
60
- function selectXPath(expression) {
61
- "use strict";
62
- return {
63
- type: 'xpath',
64
- path: expression,
65
- toString: function() {
66
- return this.type + ' selector: ' + this.path;
67
- }
68
- };
69
- }
70
- exports.selectXPath = selectXPath;
71
-
72
- /**
73
- * Main Casper object.
74
- *
75
- * @param Object options Casper options
76
- */
77
- var Casper = function Casper(options) {
78
- "use strict";
79
- /*jshint maxstatements:40*/
80
- // init & checks
81
- if (!(this instanceof Casper)) {
82
- return new Casper(options);
83
- }
84
- // default options
85
- this.defaults = {
86
- clientScripts: [],
87
- colorizerType: 'Colorizer',
88
- exitOnError: true,
89
- logLevel: "error",
90
- httpStatusHandlers: {},
91
- safeLogs: true,
92
- onAlert: null,
93
- onDie: null,
94
- onError: null,
95
- onLoadError: null,
96
- onPageInitialized: null,
97
- onResourceReceived: null,
98
- onResourceRequested: null,
99
- onStepComplete: null,
100
- onStepTimeout: function _onStepTimeout(timeout, stepNum) {
101
- this.die("Maximum step execution timeout exceeded for step " + stepNum);
102
- },
103
- onTimeout: function _onTimeout(timeout) {
104
- this.die(f("Script timeout of %dms reached, exiting.", timeout));
105
- },
106
- onWaitTimeout: function _onWaitTimeout(timeout) {
107
- this.die(f("Wait timeout of %dms expired, exiting.", timeout));
108
- },
109
- page: null,
110
- pageSettings: {
111
- localToRemoteUrlAccessEnabled: true,
112
- userAgent: defaultUserAgent
113
- },
114
- remoteScripts: [],
115
- stepTimeout: null,
116
- timeout: null,
117
- verbose: false,
118
- waitTimeout: 5000
119
- };
120
- // options
121
- this.options = utils.mergeObjects(this.defaults, options);
122
- // properties
123
- this.checker = null;
124
- this.cli = phantom.casperArgs;
125
- this.colorizer = this.getColorizer();
126
- this.currentResponse = undefined;
127
- this.currentUrl = 'about:blank';
128
- this.currentHTTPStatus = null;
129
- this.history = [];
130
- this.loadInProgress = false;
131
- this.navigationRequested = false;
132
- this.logFormats = {};
133
- this.logLevels = ["debug", "info", "warning", "error"];
134
- this.logStyles = {
135
- debug: 'INFO',
136
- info: 'PARAMETER',
137
- warning: 'COMMENT',
138
- error: 'ERROR'
139
- };
140
- this.mouse = mouse.create(this);
141
- this.page = null;
142
- this.pendingWait = false;
143
- this.popups = pagestack.create();
144
- this.requestUrl = 'about:blank';
145
- this.resources = [];
146
- this.result = {
147
- log: [],
148
- status: "success",
149
- time: 0
150
- };
151
- this.started = false;
152
- this.step = -1;
153
- this.steps = [];
154
- this.test = tester.create(this);
155
-
156
- // init phantomjs error handler
157
- this.initErrorHandler();
158
-
159
- this.on('error', function(msg, backtrace) {
160
- if (msg === this.test.SKIP_MESSAGE) {
161
- return;
162
- }
163
- var c = this.getColorizer();
164
- var match = /^(.*): __mod_error(.*):: (.*)/.exec(msg);
165
- var notices = [];
166
- if (match && match.length === 4) {
167
- notices.push(' in module ' + match[2]);
168
- msg = match[3];
169
- }
170
- console.error(c.colorize(msg, 'RED_BAR', 80));
171
- notices.forEach(function(notice) {
172
- console.error(c.colorize(notice, 'COMMENT'));
173
- });
174
- backtrace.forEach(function(item) {
175
- var message = fs.absolute(item.file) + ":" + c.colorize(item.line, "COMMENT");
176
- if (item['function']) {
177
- message += " in " + c.colorize(item['function'], "PARAMETER");
178
- }
179
- console.error(" " + message);
180
- });
181
- });
182
-
183
- // deprecated feature event handler
184
- this.on('deprecated', function onDeprecated(message) {
185
- this.warn('[deprecated] ' + message);
186
- });
187
-
188
- // dispatching an event when instance has been constructed
189
- this.emit('init');
190
- };
191
-
192
- // Casper class is an EventEmitter
193
- utils.inherits(Casper, events.EventEmitter);
194
-
195
- /**
196
- * Go a step back in browser's history
197
- *
198
- * @return Casper
199
- */
200
- Casper.prototype.back = function back() {
201
- "use strict";
202
- this.checkStarted();
203
- return this.then(function _step() {
204
- this.emit('back');
205
- this.evaluate(function _evaluate() {
206
- history.back();
207
- });
208
- });
209
- };
210
-
211
- /**
212
- * Encodes a resource using the base64 algorithm synchronously using
213
- * client-side XMLHttpRequest.
214
- *
215
- * NOTE: we cannot use window.btoa() for some strange reasons here.
216
- *
217
- * @param String url The url to download
218
- * @param String method The method to use, optional: default GET
219
- * @param String data The data to send, optional
220
- * @return string Base64 encoded result
221
- */
222
- Casper.prototype.base64encode = function base64encode(url, method, data) {
223
- "use strict";
224
- return this.evaluate(function _evaluate(url, method, data) {
225
- return __utils__.getBase64(url, method, data);
226
- }, url, method, data);
227
- };
228
-
229
- /**
230
- * Proxy method for WebPage#render. Adds a clipRect parameter for
231
- * automatically set page clipRect setting values and sets it back once
232
- * done. If the cliprect parameter is omitted, the full page viewport
233
- * area will be rendered.
234
- *
235
- * @param String targetFile A target filename
236
- * @param mixed clipRect An optional clipRect object (optional)
237
- * @return Casper
238
- */
239
- Casper.prototype.capture = function capture(targetFile, clipRect) {
240
- "use strict";
241
- /*jshint maxstatements:20*/
242
- this.checkStarted();
243
- var previousClipRect;
244
- targetFile = fs.absolute(targetFile);
245
- if (clipRect) {
246
- if (!utils.isClipRect(clipRect)) {
247
- throw new CasperError("clipRect must be a valid ClipRect object.");
248
- }
249
- previousClipRect = this.page.clipRect;
250
- this.page.clipRect = clipRect;
251
- this.log(f("Capturing page to %s with clipRect %s", targetFile, JSON.stringify(clipRect)), "debug");
252
- } else {
253
- this.log(f("Capturing page to %s", targetFile), "debug");
254
- }
255
- if (!this.page.render(this.filter('capture.target_filename', targetFile) || targetFile)) {
256
- this.log(f("Failed to save screenshot to %s; please check permissions", targetFile), "error");
257
- } else {
258
- this.log(f("Capture saved to %s", targetFile), "info");
259
- this.emit('capture.saved', targetFile);
260
- }
261
- if (previousClipRect) {
262
- this.page.clipRect = previousClipRect;
263
- }
264
- return this;
265
- };
266
-
267
- /**
268
- * Returns a Base64 representation of a binary image capture of the current
269
- * page, or an area within the page, in a given format.
270
- *
271
- * Supported image formats are `bmp`, `jpg`, `jpeg`, `png`, `ppm`, `tiff`,
272
- * `xbm` and `xpm`.
273
- *
274
- * @param String format The image format
275
- * @param String|Object|undefined selector DOM CSS3/XPath selector or clipRect object (optional)
276
- * @return Casper
277
- */
278
- Casper.prototype.captureBase64 = function captureBase64(format, area) {
279
- "use strict";
280
- /*jshint maxstatements:20*/
281
- this.checkStarted();
282
- var base64, previousClipRect, formats = ['bmp', 'jpg', 'jpeg', 'png', 'ppm', 'tiff', 'xbm', 'xpm'];
283
- if (formats.indexOf(format.toLowerCase()) === -1) {
284
- throw new CasperError(f('Unsupported format "%s"', format));
285
- }
286
- if (utils.isClipRect(area)) {
287
- // if area is a clipRect object
288
- this.log(f("Capturing base64 %s representation of %s", format, utils.serialize(area)), "debug");
289
- previousClipRect = this.page.clipRect;
290
- this.page.clipRect = area;
291
- base64 = this.page.renderBase64(format);
292
- } else if (utils.isValidSelector(area)) {
293
- // if area is a selector string or object
294
- this.log(f("Capturing base64 %s representation of %s", format, area), "debug");
295
- base64 = this.captureBase64(format, this.getElementBounds(area));
296
- } else {
297
- // whole page capture
298
- this.log(f("Capturing base64 %s representation of page", format), "debug");
299
- base64 = this.page.renderBase64(format);
300
- }
301
- if (previousClipRect) {
302
- this.page.clipRect = previousClipRect;
303
- }
304
- return base64;
305
- };
306
-
307
- /**
308
- * Captures the page area matching the provided selector.
309
- *
310
- * @param String targetFile Target destination file path.
311
- * @param String selector DOM CSS3/XPath selector
312
- * @return Casper
313
- */
314
- Casper.prototype.captureSelector = function captureSelector(targetFile, selector) {
315
- "use strict";
316
- return this.capture(targetFile, this.getElementBounds(selector));
317
- };
318
-
319
- /**
320
- * Checks for any further navigation step to process.
321
- *
322
- * @param Casper self A self reference
323
- * @param function onComplete An options callback to apply on completion
324
- */
325
- Casper.prototype.checkStep = function checkStep(self, onComplete) {
326
- "use strict";
327
- if (self.pendingWait || self.loadInProgress || self.navigationRequested) {
328
- return;
329
- }
330
- var step = self.steps[self.step++];
331
- if (utils.isFunction(step)) {
332
- self.runStep(step);
333
- } else {
334
- self.result.time = new Date().getTime() - self.startTime;
335
- self.log(f("Done %s steps in %dms", self.steps.length, self.result.time), "info");
336
- clearInterval(self.checker);
337
- self.step -= 1;
338
- self.emit('run.complete');
339
- if (utils.isFunction(onComplete)) {
340
- onComplete.call(self, self);
341
- } else {
342
- // default behavior is to exit
343
- self.exit();
344
- }
345
- }
346
- };
347
-
348
- /**
349
- * Checks if this instance is started.
350
- *
351
- * @return Boolean
352
- * @throws CasperError
353
- */
354
- Casper.prototype.checkStarted = function checkStarted() {
355
- "use strict";
356
- if (!this.started) {
357
- throw new CasperError(f("Casper is not started, can't execute `%s()`",
358
- checkStarted.caller.name));
359
- }
360
- };
361
-
362
- /**
363
- * Clears the current page execution environment context. Useful to avoid
364
- * having previously loaded DOM contents being still active (refs #34).
365
- *
366
- * Think of it as a way to stop javascript execution within the remote DOM
367
- * environment.
368
- *
369
- * @return Casper
370
- */
371
- Casper.prototype.clear = function clear() {
372
- "use strict";
373
- this.checkStarted();
374
- this.page.content = '';
375
- return this;
376
- };
377
-
378
- /**
379
- * Emulates a click on the element from the provided selector using the mouse
380
- * pointer, if possible.
381
- *
382
- * In case of success, `true` is returned, `false` otherwise.
383
- *
384
- * @param String selector A DOM CSS3 compatible selector
385
- * @return Boolean
386
- */
387
- Casper.prototype.click = function click(selector) {
388
- "use strict";
389
- this.checkStarted();
390
- var success = this.mouseEvent('click', selector);
391
- this.evaluate(function(selector) {
392
- document.querySelector(selector).focus();
393
- }, selector);
394
- return success;
395
- };
396
-
397
- /**
398
- * Emulates a click on the element having `label` as innerText. The first
399
- * element matching this label will be selected, so use with caution.
400
- *
401
- * @param String label Element innerText value
402
- * @param String tag An element tag name (eg. `a` or `button`) (optional)
403
- * @return Boolean
404
- */
405
- Casper.prototype.clickLabel = function clickLabel(label, tag) {
406
- "use strict";
407
- this.checkStarted();
408
- tag = tag || "*";
409
- var escapedLabel = label.toString().replace(/"/g, '\\"');
410
- var selector = selectXPath(f('//%s[text()="%s"]', tag, escapedLabel));
411
- return this.click(selector);
412
- };
413
-
414
- /**
415
- * Configures HTTP authentication parameters. Will try parsing auth credentials from
416
- * the passed location first, then check for configured settings if any.
417
- *
418
- * @param String location Requested url
419
- * @param Object settings Request settings
420
- * @return Casper
421
- */
422
- Casper.prototype.configureHttpAuth = function configureHttpAuth(location, settings) {
423
- "use strict";
424
- var username, password, httpAuthMatch = location.match(/^https?:\/\/(.+):(.+)@/i);
425
- this.checkStarted();
426
- if (httpAuthMatch) {
427
- this.page.settings.userName = httpAuthMatch[1];
428
- this.page.settings.password = httpAuthMatch[2];
429
- } else if (utils.isObject(settings) && settings.username) {
430
- this.page.settings.userName = settings.username;
431
- this.page.settings.password = settings.password;
432
- } else {
433
- return;
434
- }
435
- this.emit('http.auth', username, password);
436
- this.log("Setting HTTP authentication for user " + username, "info");
437
- return this;
438
- };
439
-
440
- /**
441
- * Creates a step definition.
442
- *
443
- * @param Function fn The step function to call
444
- * @param Object options Step options
445
- * @return Function The final step function
446
- */
447
- Casper.prototype.createStep = function createStep(fn, options) {
448
- "use strict";
449
- if (!utils.isFunction(fn)) {
450
- throw new CasperError("createStep(): a step definition must be a function");
451
- }
452
- fn.options = utils.isObject(options) ? options : {};
453
- this.emit('step.created', fn);
454
- return fn;
455
- };
456
-
457
- /**
458
- * Logs the HTML code of the current page.
459
- *
460
- * @param String selector A DOM CSS3/XPath selector (optional)
461
- * @param Boolean outer Whether to fetch outer HTML contents (default: false)
462
- * @return Casper
463
- */
464
- Casper.prototype.debugHTML = function debugHTML(selector, outer) {
465
- "use strict";
466
- this.checkStarted();
467
- return this.echo(this.getHTML(selector, outer));
468
- };
469
-
470
- /**
471
- * Logs the textual contents of the current page.
472
- *
473
- * @return Casper
474
- */
475
- Casper.prototype.debugPage = function debugPage() {
476
- "use strict";
477
- this.checkStarted();
478
- this.echo(this.evaluate(function _evaluate() {
479
- return document.body.textContent || document.body.innerText;
480
- }));
481
- return this;
482
- };
483
-
484
- /**
485
- * Exit phantom on failure, with a logged error message.
486
- *
487
- * @param String message An optional error message
488
- * @param Number status An optional exit status code (must be > 0)
489
- * @return Casper
490
- */
491
- Casper.prototype.die = function die(message, status) {
492
- "use strict";
493
- this.result.status = "error";
494
- this.result.time = new Date().getTime() - this.startTime;
495
- if (!utils.isString(message) || !message.length) {
496
- message = "Suite explicitely interrupted without any message given.";
497
- }
498
- this.log(message, "error");
499
- this.echo(message, "ERROR");
500
- this.emit('die', message, status);
501
- if (utils.isFunction(this.options.onDie)) {
502
- this.options.onDie.call(this, this, message, status);
503
- }
504
- return this.exit(~~status > 0 ? ~~status : 1);
505
- };
506
-
507
- /**
508
- * Downloads a resource and saves it on the filesystem.
509
- *
510
- * @param String url The url of the resource to download
511
- * @param String targetPath The destination file path
512
- * @param String method The HTTP method to use (default: GET)
513
- * @param String data Optional data to pass performing the request
514
- * @return Casper
515
- */
516
- Casper.prototype.download = function download(url, targetPath, method, data) {
517
- "use strict";
518
- this.checkStarted();
519
- var cu = require('clientutils').create(utils.mergeObjects({}, this.options));
520
- try {
521
- fs.write(targetPath, cu.decode(this.base64encode(url, method, data)), 'wb');
522
- this.emit('downloaded.file', targetPath);
523
- this.log(f("Downloaded and saved resource in %s", targetPath));
524
- } catch (e) {
525
- this.log(f("Error while downloading %s to %s: %s", url, targetPath, e), "error");
526
- }
527
- return this;
528
- };
529
-
530
- /**
531
- * Iterates over the values of a provided array and execute a callback
532
- * for @ item.
533
- *
534
- * @param Array array
535
- * @param Function fn Callback: function(self, item, index)
536
- * @return Casper
537
- */
538
- Casper.prototype.each = function each(array, fn) {
539
- "use strict";
540
- if (!utils.isArray(array)) {
541
- this.log("each() only works with arrays", "error");
542
- return this;
543
- }
544
- (function _each(self) {
545
- array.forEach(function _forEach(item, i) {
546
- fn.call(self, self, item, i);
547
- });
548
- })(this);
549
- return this;
550
- };
551
-
552
- /**
553
- * Prints something to stdout.
554
- *
555
- * @param String text A string to echo to stdout
556
- * @param String style An optional style name
557
- * @param Number pad An optional pad value
558
- * @return Casper
559
- */
560
- Casper.prototype.echo = function echo(text, style, pad) {
561
- "use strict";
562
- if (!utils.isString(text)) {
563
- try {
564
- text = text.toString();
565
- } catch (e) {
566
- try {
567
- text = utils.serialize(text);
568
- } catch (e2) {
569
- text = '';
570
- }
571
- }
572
- }
573
- var message = style ? this.colorizer.colorize(text, style, pad) : text;
574
- console.log(this.filter('echo.message', message) || message);
575
- return this;
576
- };
577
-
578
- /**
579
- * Evaluates an expression in the page context, a bit like what
580
- * WebPage#evaluate does, but the passed function can also accept
581
- * parameters if a context Object is also passed:
582
- *
583
- * casper.evaluate(function(username, password) {
584
- * document.querySelector('#username').value = username;
585
- * document.querySelector('#password').value = password;
586
- * document.querySelector('#submit').click();
587
- * }, 'Bazoonga', 'baz00nga');
588
- *
589
- * @param Function fn The function to be evaluated within current page DOM
590
- * @param Object context Object containing the parameters to inject into the function
591
- * @return mixed
592
- * @see WebPage#evaluate
593
- */
594
- Casper.prototype.evaluate = function evaluate(fn, context) {
595
- "use strict";
596
- this.checkStarted();
597
- // preliminary checks
598
- if (!utils.isFunction(fn) && !utils.isString(fn)) { // phantomjs allows functions defs as string
599
- throw new CasperError("evaluate() only accepts functions or strings");
600
- }
601
- // ensure client utils are always injected
602
- this.injectClientUtils();
603
- // function context
604
- if (arguments.length === 1) {
605
- return this.page.evaluate(fn);
606
- } else if (arguments.length === 2) {
607
- // check for closure signature if it matches context
608
- if (utils.isObject(context) && eval(fn).length === Object.keys(context).length) {
609
- context = utils.objectValues(context);
610
- } else {
611
- context = [context];
612
- }
613
- } else {
614
- // phantomjs-style signature
615
- context = [].slice.call(arguments).slice(1);
616
- }
617
- return this.page.evaluate.apply(this.page, [fn].concat(context));
618
- };
619
-
620
- /**
621
- * Evaluates an expression within the current page DOM and die() if it
622
- * returns false.
623
- *
624
- * @param function fn The expression to evaluate
625
- * @param String message The error message to log
626
- * @param Number status An optional exit status code (must be > 0)
627
- *
628
- * @return Casper
629
- */
630
- Casper.prototype.evaluateOrDie = function evaluateOrDie(fn, message, status) {
631
- "use strict";
632
- this.checkStarted();
633
- if (!this.evaluate(fn)) {
634
- return this.die(message, status);
635
- }
636
- return this;
637
- };
638
-
639
- /**
640
- * Checks if an element matching the provided DOM CSS3/XPath selector exists in
641
- * current page DOM.
642
- *
643
- * @param String selector A DOM CSS3/XPath selector
644
- * @return Boolean
645
- */
646
- Casper.prototype.exists = function exists(selector) {
647
- "use strict";
648
- this.checkStarted();
649
- return this.evaluate(function _evaluate(selector) {
650
- return __utils__.exists(selector);
651
- }, selector);
652
- };
653
-
654
- /**
655
- * Exits phantom.
656
- *
657
- * @param Number status Status
658
- * @return Casper
659
- */
660
- Casper.prototype.exit = function exit(status) {
661
- "use strict";
662
- this.emit('exit', status);
663
- phantom.exit(status);
664
- };
665
-
666
- /**
667
- * Fetches plain text contents contained in the DOM element(s) matching a given CSS3/XPath
668
- * selector.
669
- *
670
- * @param String selector A DOM CSS3/XPath selector
671
- * @return String
672
- */
673
- Casper.prototype.fetchText = function fetchText(selector) {
674
- "use strict";
675
- this.checkStarted();
676
- return this.evaluate(function _evaluate(selector) {
677
- return __utils__.fetchText(selector);
678
- }, selector);
679
- };
680
-
681
- /**
682
- * Fills a form with provided field values.
683
- *
684
- * @param String selector A DOM CSS3/XPath selector to the target form to fill
685
- * @param Object vals Field values
686
- * @param Boolean submit Submit the form?
687
- */
688
- Casper.prototype.fill = function fill(selector, vals, submit) {
689
- "use strict";
690
- this.checkStarted();
691
- submit = submit === true ? submit : false;
692
- if (!utils.isObject(vals)) {
693
- throw new CasperError("Form values must be provided as an object");
694
- }
695
- this.emit('fill', selector, vals, submit);
696
- var fillResults = this.evaluate(function _evaluate(selector, values) {
697
- return __utils__.fill(selector, values);
698
- }, selector, vals);
699
- if (!fillResults) {
700
- throw new CasperError("Unable to fill form");
701
- } else if (fillResults.errors.length > 0) {
702
- throw new CasperError(f('Errors encountered while filling form: %s',
703
- fillResults.errors.join('; ')));
704
- }
705
- // File uploads
706
- if (fillResults.files && fillResults.files.length > 0) {
707
- if (utils.isObject(selector) && selector.type === 'xpath') {
708
- this.warn('Filling file upload fields is currently not supported using ' +
709
- 'XPath selectors; Please use a CSS selector instead.');
710
- } else {
711
- (function _each(self) {
712
- fillResults.files.forEach(function _forEach(file) {
713
- var fileFieldSelector = [selector, 'input[name="' + file.name + '"]'].join(' ');
714
- self.page.uploadFile(fileFieldSelector, file.path);
715
- });
716
- })(this);
717
- }
718
- }
719
- // Form submission?
720
- if (submit) {
721
- this.evaluate(function _evaluate(selector) {
722
- var form = __utils__.findOne(selector);
723
- var method = (form.getAttribute('method') || "GET").toUpperCase();
724
- var action = form.getAttribute('action') || "unknown";
725
- __utils__.log('submitting form to ' + action + ', HTTP ' + method, 'info');
726
- if (typeof form.submit === "function") {
727
- form.submit();
728
- } else {
729
- // http://www.spiration.co.uk/post/1232/Submit-is-not-a-function
730
- form.submit.click();
731
- }
732
- }, selector);
733
- }
734
- };
735
-
736
- /**
737
- * Go a step forward in browser's history
738
- *
739
- * @return Casper
740
- */
741
- Casper.prototype.forward = function forward(then) {
742
- "use strict";
743
- this.checkStarted();
744
- return this.then(function _step() {
745
- this.emit('forward');
746
- this.evaluate(function _evaluate() {
747
- history.forward();
748
- });
749
- });
750
- };
751
-
752
- /**
753
- * Creates a new Colorizer instance. Sets `Casper.options.type` to change the
754
- * colorizer type name (see the `colorizer` module).
755
- *
756
- * @return Object
757
- */
758
- Casper.prototype.getColorizer = function getColorizer() {
759
- "use strict";
760
- return colorizer.create(this.options.colorizerType || 'Colorizer');
761
- };
762
-
763
- /**
764
- * Retrieves current page contents, dealing with exotic other content types than HTML.
765
- *
766
- * @return String
767
- */
768
- Casper.prototype.getPageContent = function getPageContent() {
769
- "use strict";
770
- this.checkStarted();
771
- var contentType = utils.getPropertyPath(this, 'currentResponse.contentType');
772
- if (!utils.isString(contentType)) {
773
- return this.page.frameContent;
774
- }
775
- // for some reason webkit/qtwebkit will always enclose body contents within html tags
776
- var sanitizedHtml = this.evaluate(function checkHtml() {
777
- if (__utils__.findOne('head').childNodes.length === 0 &&
778
- __utils__.findOne('body').childNodes.length === 1 &&
779
- __utils__.findOne('body pre[style]')) {
780
- return __utils__.findOne('body pre').textContent.trim();
781
- }
782
- });
783
- return sanitizedHtml ? sanitizedHtml : this.page.frameContent;
784
- };
785
-
786
- /**
787
- * Retrieves current document url.
788
- *
789
- * @return String
790
- */
791
- Casper.prototype.getCurrentUrl = function getCurrentUrl() {
792
- "use strict";
793
- this.checkStarted();
794
- var url = this.evaluate(function _evaluate() {
795
- return document.location.href;
796
- });
797
- try {
798
- return decodeURIComponent(url);
799
- } catch (e) {
800
- /*global unescape*/
801
- return unescape(url);
802
- }
803
- };
804
-
805
- /**
806
- * Retrieves the value of an attribute on the first element matching the provided
807
- * DOM CSS3/XPath selector.
808
- *
809
- * @param String selector A DOM CSS3/XPath selector
810
- * @param String attribute The attribute name to lookup
811
- * @return String The requested DOM element attribute value
812
- */
813
- Casper.prototype.getElementAttribute =
814
- Casper.prototype.getElementAttr = function getElementAttr(selector, attribute) {
815
- "use strict";
816
- this.checkStarted();
817
- return this.evaluate(function _evaluate(selector, attribute) {
818
- return document.querySelector(selector).getAttribute(attribute);
819
- }, selector, attribute);
820
- };
821
-
822
- /**
823
- * Retrieves boundaries for a DOM element matching the provided DOM CSS3/XPath selector.
824
- *
825
- * @param String selector A DOM CSS3/XPath selector
826
- * @return Object
827
- */
828
- Casper.prototype.getElementBounds = function getElementBounds(selector) {
829
- "use strict";
830
- this.checkStarted();
831
- if (!this.exists(selector)) {
832
- throw new CasperError("No element matching selector found: " + selector);
833
- }
834
- var clipRect = this.evaluate(function _evaluate(selector) {
835
- return __utils__.getElementBounds(selector);
836
- }, selector);
837
- if (!utils.isClipRect(clipRect)) {
838
- throw new CasperError('Could not fetch boundaries for element matching selector: ' + selector);
839
- }
840
- return clipRect;
841
- };
842
-
843
- /**
844
- * Retrieves information about the node matching the provided selector.
845
- *
846
- * @param String|Objects selector CSS3/XPath selector
847
- * @return Object
848
- */
849
- Casper.prototype.getElementInfo = function getElementInfo(selector) {
850
- "use strict";
851
- this.checkStarted();
852
- if (!this.exists(selector)) {
853
- throw new CasperError(f("Cannot get informations from %s: element not found.", selector));
854
- }
855
- return this.evaluate(function(selector) {
856
- return __utils__.getElementInfo(selector);
857
- }, selector);
858
- };
859
-
860
- /**
861
- * Retrieves boundaries for all the DOM elements matching the provided DOM CSS3/XPath selector.
862
- *
863
- * @param String selector A DOM CSS3/XPath selector
864
- * @return Array
865
- */
866
- Casper.prototype.getElementsBounds = function getElementBounds(selector) {
867
- "use strict";
868
- this.checkStarted();
869
- if (!this.exists(selector)) {
870
- throw new CasperError("No element matching selector found: " + selector);
871
- }
872
- return this.evaluate(function _evaluate(selector) {
873
- return __utils__.getElementsBounds(selector);
874
- }, selector);
875
- };
876
-
877
- /**
878
- * Retrieves a given form all of its field values.
879
- *
880
- * @param String selector A DOM CSS3/XPath selector
881
- * @return Object
882
- */
883
- Casper.prototype.getFormValues = function(selector) {
884
- "use strict";
885
- this.checkStarted();
886
- if (!this.exists(selector)) {
887
- throw new CasperError(f('Form matching selector "%s" not found', selector));
888
- }
889
- return this.evaluate(function(selector) {
890
- return __utils__.getFormValues(selector);
891
- }, selector);
892
- };
893
-
894
- /**
895
- * Retrieves global variable.
896
- *
897
- * @param String name The name of the global variable to retrieve
898
- * @return mixed
899
- */
900
- Casper.prototype.getGlobal = function getGlobal(name) {
901
- "use strict";
902
- this.checkStarted();
903
- var result = this.evaluate(function _evaluate(name) {
904
- var result = {};
905
- try {
906
- result.value = JSON.stringify(window[name]);
907
- } catch (e) {
908
- var message = f("Unable to JSON encode window.%s: %s", name, e);
909
- __utils__.log(message, "error");
910
- result.error = message;
911
- }
912
- return result;
913
- }, name);
914
- if (!utils.isObject(result)) {
915
- throw new CasperError(f('Could not retrieve global value for "%s"', name));
916
- } else if ('error' in result) {
917
- throw new CasperError(result.error);
918
- } else if (utils.isString(result.value)) {
919
- return JSON.parse(result.value);
920
- }
921
- };
922
-
923
- /**
924
- * Retrieves current HTML code matching the provided CSS3/XPath selector.
925
- * Returns the HTML contents for the whole page if no arg is passed.
926
- *
927
- * @param String selector A DOM CSS3/XPath selector
928
- * @param Boolean outer Whether to fetch outer HTML contents (default: false)
929
- * @return String
930
- */
931
- Casper.prototype.getHTML = function getHTML(selector, outer) {
932
- "use strict";
933
- this.checkStarted();
934
- if (!selector) {
935
- return this.page.frameContent;
936
- }
937
- if (!this.exists(selector)) {
938
- throw new CasperError("No element matching selector found: " + selector);
939
- }
940
- return this.evaluate(function getSelectorHTML(selector, outer) {
941
- var element = __utils__.findOne(selector);
942
- return outer ? element.outerHTML : element.innerHTML;
943
- }, selector, !!outer);
944
- };
945
-
946
- /**
947
- * Retrieves current page title, if any.
948
- *
949
- * @return String
950
- */
951
- Casper.prototype.getTitle = function getTitle() {
952
- "use strict";
953
- this.checkStarted();
954
- return this.evaluate(function _evaluate() {
955
- return document.title;
956
- });
957
- };
958
-
959
- /**
960
- * Handles received HTTP resource.
961
- *
962
- * @param Object resource PhantomJS HTTP resource
963
- */
964
- Casper.prototype.handleReceivedResource = function(resource) {
965
- "use strict";
966
- /*jshint maxstatements:20*/
967
- if (resource.stage !== "end") {
968
- return;
969
- }
970
- this.resources.push(resource);
971
- if (resource.url !== this.requestUrl) {
972
- return;
973
- }
974
- this.currentHTTPStatus = null;
975
- this.currentResponse = undefined;
976
- if (utils.isHTTPResource(resource)) {
977
- this.emit('page.resource.received', resource);
978
- this.currentResponse = resource;
979
- this.currentHTTPStatus = resource.status;
980
- this.emit('http.status.' + resource.status, resource);
981
- if (utils.isObject(this.options.httpStatusHandlers) &&
982
- resource.status in this.options.httpStatusHandlers &&
983
- utils.isFunction(this.options.httpStatusHandlers[resource.status])) {
984
- this.options.httpStatusHandlers[resource.status].call(this, this, resource);
985
- }
986
- }
987
- this.currentUrl = resource.url;
988
- this.emit('location.changed', resource.url);
989
- };
990
-
991
- /**
992
- * Initializes PhantomJS error handler.
993
- *
994
- */
995
- Casper.prototype.initErrorHandler = function initErrorHandler() {
996
- "use strict";
997
- var casper = this;
998
- phantom.onError = function phantom_onError(msg, backtrace) {
999
- casper.emit('error', msg, backtrace);
1000
- if (casper.options.exitOnError === true) {
1001
- casper.exit(1);
1002
- }
1003
- };
1004
- };
1005
-
1006
- /**
1007
- * Injects configured local client scripts.
1008
- *
1009
- * @return Casper
1010
- */
1011
- Casper.prototype.injectClientScripts = function injectClientScripts() {
1012
- "use strict";
1013
- this.checkStarted();
1014
- if (!this.options.clientScripts) {
1015
- return;
1016
- }
1017
- if (utils.isString(this.options.clientScripts)) {
1018
- this.options.clientScripts = [this.options.clientScripts];
1019
- }
1020
- if (!utils.isArray(this.options.clientScripts)) {
1021
- throw new CasperError("The clientScripts option must be an array");
1022
- }
1023
- this.options.clientScripts.forEach(function _forEach(script) {
1024
- if (this.page.injectJs(script)) {
1025
- this.log(f('Automatically injected %s client side', script), "debug");
1026
- } else {
1027
- this.warn('Failed injecting %s client side', script);
1028
- }
1029
- }.bind(this));
1030
- return this;
1031
- };
1032
-
1033
- /**
1034
- * Injects Client-side utilities in current page context.
1035
- *
1036
- */
1037
- Casper.prototype.injectClientUtils = function injectClientUtils() {
1038
- "use strict";
1039
- this.checkStarted();
1040
- var clientUtilsInjected = this.page.evaluate(function() {
1041
- return typeof __utils__ === "object";
1042
- });
1043
- if (true === clientUtilsInjected) {
1044
- return;
1045
- }
1046
- var clientUtilsPath = require('fs').pathJoin(phantom.casperPath, 'modules', 'clientutils.js');
1047
- if (true === this.page.injectJs(clientUtilsPath)) {
1048
- this.log("Successfully injected Casper client-side utilities", "debug");
1049
- } else {
1050
- this.warn("Failed to inject Casper client-side utilities");
1051
- }
1052
- // ClientUtils and Casper shares the same options
1053
- // These are not the lines I'm the most proud of in my life, but it works.
1054
- /*global __options*/
1055
- this.page.evaluate(function() {
1056
- window.__utils__ = new window.ClientUtils(__options);
1057
- }.toString().replace('__options', JSON.stringify(this.options)));
1058
- };
1059
-
1060
- /**
1061
- * Loads and include remote client scripts to current page.
1062
- *
1063
- * @return Casper
1064
- */
1065
- Casper.prototype.includeRemoteScripts = function includeRemoteScripts() {
1066
- "use strict";
1067
- var numScripts = this.options.remoteScripts.length, loaded = 0;
1068
- if (numScripts === 0) {
1069
- return this;
1070
- }
1071
- this.waitStart();
1072
- this.options.remoteScripts.forEach(function(scriptUrl) {
1073
- this.log(f("Loading remote script: %s", scriptUrl), "debug");
1074
- this.page.includeJs(scriptUrl, function() {
1075
- loaded++;
1076
- this.log(f("Remote script %s loaded", scriptUrl), "debug");
1077
- if (loaded === numScripts) {
1078
- this.log("All remote scripts loaded.", "debug");
1079
- this.waitDone();
1080
- }
1081
- }.bind(this));
1082
- }.bind(this));
1083
- return this;
1084
- };
1085
-
1086
- /**
1087
- * Logs a message.
1088
- *
1089
- * @param String message The message to log
1090
- * @param String level The log message level (from Casper.logLevels property)
1091
- * @param String space Space from where the logged event occurred (default: "phantom")
1092
- * @return Casper
1093
- */
1094
- Casper.prototype.log = function log(message, level, space) {
1095
- "use strict";
1096
- level = level && this.logLevels.indexOf(level) > -1 ? level : "debug";
1097
- space = space ? space : "phantom";
1098
- if (level === "error" && utils.isFunction(this.options.onError)) {
1099
- this.options.onError.call(this, this, message, space);
1100
- }
1101
- if (this.logLevels.indexOf(level) < this.logLevels.indexOf(this.options.logLevel)) {
1102
- return this; // skip logging
1103
- }
1104
- var entry = {
1105
- level: level,
1106
- space: space,
1107
- message: message,
1108
- date: new Date().toString()
1109
- };
1110
- if (level in this.logFormats && utils.isFunction(this.logFormats[level])) {
1111
- message = this.logFormats[level](message, level, space);
1112
- } else {
1113
- message = f('%s [%s] %s',
1114
- this.colorizer.colorize(f('[%s]', level), this.logStyles[level]),
1115
- space,
1116
- message);
1117
- }
1118
- if (this.options.verbose) {
1119
- this.echo(this.filter('log.message', message) || message); // direct output
1120
- }
1121
- this.result.log.push(entry);
1122
- this.emit('log', entry);
1123
- return this;
1124
- };
1125
-
1126
- /**
1127
- * Emulates an event on the element from the provided selector using the mouse
1128
- * pointer, if possible.
1129
- *
1130
- * In case of success, `true` is returned, `false` otherwise.
1131
- *
1132
- * @param String type Type of event to emulate
1133
- * @param String selector A DOM CSS3 compatible selector
1134
- * @return Boolean
1135
- */
1136
- Casper.prototype.mouseEvent = function mouseEvent(type, selector) {
1137
- "use strict";
1138
- this.checkStarted();
1139
- this.log("Mouse event '" + type + "' on selector: " + selector, "debug");
1140
- if (!this.exists(selector)) {
1141
- throw new CasperError(f("Cannot dispatch %s event on nonexistent selector: %s", type, selector));
1142
- }
1143
- if (this.evaluate(function(type, selector) {
1144
- return window.__utils__.mouseEvent(type, selector);
1145
- }, type, selector)) {
1146
- return true;
1147
- }
1148
- // fallback onto native QtWebKit mouse events
1149
- try {
1150
- return this.mouse.processEvent(type, selector);
1151
- } catch (e) {
1152
- this.log(f("Couldn't emulate '%s' event on %s: %s", type, selector, e), "error");
1153
- }
1154
- return false;
1155
- };
1156
-
1157
- /**
1158
- * Performs an HTTP request, with optional settings.
1159
- *
1160
- * Available settings are:
1161
- *
1162
- * - String method: The HTTP method to use
1163
- * - Object data: The data to use to perform the request, eg. {foo: 'bar'}
1164
- * - Object headers: Custom request headers object, eg. {'Cache-Control': 'max-age=0'}
1165
- *
1166
- * @param String location The url to open
1167
- * @param Object settings The request settings (optional)
1168
- * @return Casper
1169
- */
1170
- Casper.prototype.open = function open(location, settings) {
1171
- "use strict";
1172
- /*jshint maxstatements:30*/
1173
- var baseCustomHeaders = this.page.customHeaders,
1174
- customHeaders = settings && settings.headers || {};
1175
- this.checkStarted();
1176
- settings = utils.isObject(settings) ? settings : {};
1177
- settings.method = settings.method || "get";
1178
- // http method
1179
- // taken from https://github.com/ariya/phantomjs/blob/master/src/webpage.cpp#L302
1180
- var methods = ["get", "head", "put", "post", "delete"];
1181
- if (settings.method && (!utils.isString(settings.method) || methods.indexOf(settings.method) === -1)) {
1182
- throw new CasperError("open(): settings.method must be part of " + methods.join(', '));
1183
- }
1184
- // http data
1185
- if (settings.data) {
1186
- if (utils.isObject(settings.data)) { // query object
1187
- settings.data = qs.encode(settings.data);
1188
- } else if (!utils.isString(settings.data)) {
1189
- throw new CasperError("open(): invalid request settings data value: " + settings.data);
1190
- }
1191
- }
1192
- // clean location
1193
- location = utils.cleanUrl(location);
1194
- // current request url
1195
- this.configureHttpAuth(location, settings);
1196
- this.requestUrl = this.filter('open.location', location) || location;
1197
- this.emit('open', this.requestUrl, settings);
1198
- this.log(f('opening url: %s, HTTP %s', this.requestUrl, settings.method.toUpperCase()), "debug");
1199
- // reset resources
1200
- this.resources = [];
1201
- // custom headers
1202
- this.page.customHeaders = utils.mergeObjects(utils.clone(baseCustomHeaders), customHeaders);
1203
- // perfom request
1204
- this.page.openUrl(this.requestUrl, {
1205
- operation: settings.method,
1206
- data: settings.data
1207
- }, this.page.settings);
1208
- // revert base custom headers
1209
- this.page.customHeaders = baseCustomHeaders;
1210
- return this;
1211
- };
1212
-
1213
- /**
1214
- * Reloads current page.
1215
- *
1216
- * @param Function then a next step function
1217
- * @return Casper
1218
- */
1219
- Casper.prototype.reload = function reload(then) {
1220
- "use strict";
1221
- this.checkStarted();
1222
- // window.location.reload() is broken under phantomjs
1223
- this.then(function() {
1224
- this.open(this.getCurrentUrl());
1225
- });
1226
- if (utils.isFunction(then)) {
1227
- this.then(this.createStep(then));
1228
- }
1229
- };
1230
-
1231
- /**
1232
- * Repeats a step a given number of times.
1233
- *
1234
- * @param Number times Number of times to repeat step
1235
- * @aram function then The step closure
1236
- * @return Casper
1237
- * @see Casper#then
1238
- */
1239
- Casper.prototype.repeat = function repeat(times, then) {
1240
- "use strict";
1241
- for (var i = 0; i < times; i++) {
1242
- this.then(then);
1243
- }
1244
- return this;
1245
- };
1246
-
1247
- /**
1248
- * Checks if a given resource was loaded by the remote page.
1249
- *
1250
- * @param Function/String/RegExp test A test function, string or regular expression.
1251
- * In case a string is passed, url matching will be tested.
1252
- * @return Boolean
1253
- */
1254
- Casper.prototype.resourceExists = function resourceExists(test) {
1255
- "use strict";
1256
- this.checkStarted();
1257
- var testFn;
1258
- switch (utils.betterTypeOf(test)) {
1259
- case "string":
1260
- testFn = function _testResourceExists_String(res) {
1261
- return res.url.search(test) !== -1 && res.status !== 404;
1262
- };
1263
- break;
1264
- case "regexp":
1265
- testFn = function _testResourceExists_Regexp(res) {
1266
- return test.test(res.url) && res.status !== 404;
1267
- };
1268
- break;
1269
- case "function":
1270
- testFn = test;
1271
- testFn.name = "_testResourceExists_Function";
1272
- break;
1273
- default:
1274
- throw new CasperError("Invalid type");
1275
- }
1276
- return this.resources.some(testFn);
1277
- };
1278
-
1279
- /**
1280
- * Runs the whole suite of steps.
1281
- *
1282
- * @param function onComplete an optional callback
1283
- * @param Number time an optional amount of milliseconds for interval checking
1284
- * @return Casper
1285
- */
1286
- Casper.prototype.run = function run(onComplete, time) {
1287
- "use strict";
1288
- this.checkStarted();
1289
- if (!this.steps || this.steps.length < 1) {
1290
- throw new CasperError('No steps defined, aborting');
1291
- }
1292
- this.log(f("Running suite: %d step%s", this.steps.length, this.steps.length > 1 ? "s" : ""), "info");
1293
- this.emit('run.start');
1294
- this.checker = setInterval(this.checkStep, (time ? time: 100), this, onComplete);
1295
- return this;
1296
- };
1297
-
1298
- /**
1299
- * Runs a step.
1300
- *
1301
- * @param Function step
1302
- */
1303
- Casper.prototype.runStep = function runStep(step) {
1304
- "use strict";
1305
- this.checkStarted();
1306
- var skipLog = utils.isObject(step.options) && step.options.skipLog === true;
1307
- var stepInfo = f("Step %d/%d", this.step, this.steps.length);
1308
- var stepResult;
1309
- if (!skipLog && /^http/.test(this.getCurrentUrl())) {
1310
- this.log(stepInfo + f(' %s (HTTP %d)', this.getCurrentUrl(), this.currentHTTPStatus), "info");
1311
- }
1312
- if (utils.isNumber(this.options.stepTimeout) && this.options.stepTimeout > 0) {
1313
- var stepTimeoutCheckInterval = setInterval(function _check(self, start, stepNum) {
1314
- if (new Date().getTime() - start > self.options.stepTimeout) {
1315
- if ((self.test.currentSuiteNum + "-" + self.step) === stepNum) {
1316
- self.emit('step.timeout');
1317
- if (utils.isFunction(self.options.onStepTimeout)) {
1318
- self.options.onStepTimeout.call(self, self.options.stepTimeout, stepNum);
1319
- }
1320
- }
1321
- clearInterval(stepTimeoutCheckInterval);
1322
- }
1323
- }, this.options.stepTimeout, this, new Date().getTime(), this.test.currentSuiteNum + "-" + this.step);
1324
- }
1325
- this.emit('step.start', step);
1326
- stepResult = step.call(this, this.currentResponse);
1327
- if (utils.isFunction(this.options.onStepComplete)) {
1328
- this.options.onStepComplete.call(this, this, stepResult);
1329
- }
1330
- if (!skipLog) {
1331
- this.emit('step.complete', stepResult);
1332
- this.log(stepInfo + f(": done in %dms.", new Date().getTime() - this.startTime), "info");
1333
- }
1334
- };
1335
-
1336
- /**
1337
- * Sends keys to given element.
1338
- *
1339
- * @param String selector A DOM CSS3 compatible selector
1340
- * @param String keys A string representing the sequence of char codes to send
1341
- * @param Object options Options
1342
- * @return Casper
1343
- */
1344
- Casper.prototype.sendKeys = function(selector, keys, options) {
1345
- "use strict";
1346
- this.checkStarted();
1347
- options = utils.mergeObjects({
1348
- eventType: 'keypress'
1349
- }, options || {});
1350
- var elemInfos = this.getElementInfo(selector),
1351
- tag = elemInfos.nodeName.toLowerCase(),
1352
- type = utils.getPropertyPath(elemInfos, 'attributes.type'),
1353
- supported = ["color", "date", "datetime", "datetime-local", "email",
1354
- "hidden", "month", "number", "password", "range", "search",
1355
- "tel", "text", "time", "url", "week"];
1356
- var isTextInput = false;
1357
- if (tag === 'textarea' || (tag === 'input' && supported.indexOf(type) !== -1)) {
1358
- // clicking on the input element brings it focus
1359
- isTextInput = true;
1360
- this.click(selector);
1361
- }
1362
- this.page.sendEvent(options.eventType, keys);
1363
- if (isTextInput) {
1364
- // remove the focus
1365
- this.evaluate(function(selector) {
1366
- __utils__.findOne(selector).blur();
1367
- }, selector);
1368
- }
1369
- return this;
1370
- };
1371
-
1372
- /**
1373
- * Sets current WebPage instance the credentials for HTTP authentication.
1374
- *
1375
- * @param String username
1376
- * @param String password
1377
- * @return Casper
1378
- */
1379
- Casper.prototype.setHttpAuth = function setHttpAuth(username, password) {
1380
- "use strict";
1381
- this.checkStarted();
1382
- this.page.settings.userName = username;
1383
- this.page.settings.password = password;
1384
- return this;
1385
- };
1386
-
1387
- /**
1388
- * Configures and starts Casper.
1389
- *
1390
- * @param String location An optional location to open on start
1391
- * @param function then Next step function to execute on page loaded (optional)
1392
- * @return Casper
1393
- */
1394
- Casper.prototype.start = function start(location, then) {
1395
- "use strict";
1396
- /*jshint maxstatements:30*/
1397
- this.emit('starting');
1398
- this.log('Starting...', "info");
1399
- this.startTime = new Date().getTime();
1400
- this.history = [];
1401
- this.popups = pagestack.create();
1402
- this.steps = [];
1403
- this.step = 0;
1404
- // Option checks
1405
- if (this.logLevels.indexOf(this.options.logLevel) < 0) {
1406
- this.log(f("Unknown log level '%d', defaulting to 'warning'", this.options.logLevel), "warning");
1407
- this.options.logLevel = "warning";
1408
- }
1409
- if (!utils.isWebPage(this.page)) {
1410
- this.page = this.mainPage = utils.isWebPage(this.options.page) ? this.options.page : createPage(this);
1411
- }
1412
- this.page.settings = utils.mergeObjects(this.page.settings, this.options.pageSettings);
1413
- if (utils.isClipRect(this.options.clipRect)) {
1414
- this.page.clipRect = this.options.clipRect;
1415
- }
1416
- if (utils.isObject(this.options.viewportSize)) {
1417
- this.page.viewportSize = this.options.viewportSize;
1418
- }
1419
- // timeout handling
1420
- if (utils.isNumber(this.options.timeout) && this.options.timeout > 0) {
1421
- this.log(f("Execution timeout set to %dms", this.options.timeout), "info");
1422
- setTimeout(function _check(self) {
1423
- self.emit('timeout');
1424
- if (utils.isFunction(self.options.onTimeout)) {
1425
- self.options.onTimeout.call(self, self.options.timeout);
1426
- }
1427
- }, this.options.timeout, this);
1428
- }
1429
- this.started = true;
1430
- this.emit('started');
1431
- if (utils.isString(location) && location.length > 0) {
1432
- return this.thenOpen(location, utils.isFunction(then) ? then : this.createStep(function _step() {
1433
- this.log("start page is loaded", "debug");
1434
- }, {skipLog: true}));
1435
- }
1436
- return this;
1437
- };
1438
-
1439
- /**
1440
- * Returns the current status of current instance
1441
- *
1442
- * @param Boolean asString Export status object as string
1443
- * @return Object
1444
- */
1445
- Casper.prototype.status = function status(asString) {
1446
- "use strict";
1447
- var properties = ['currentHTTPStatus', 'loadInProgress', 'navigationRequested',
1448
- 'options', 'pendingWait', 'requestUrl', 'started', 'step', 'url'];
1449
- var currentStatus = {};
1450
- properties.forEach(function(property) {
1451
- currentStatus[property] = this[property];
1452
- }.bind(this));
1453
- return asString === true ? utils.dump(currentStatus) : currentStatus;
1454
- };
1455
-
1456
- /**
1457
- * Schedules the next step in the navigation process.
1458
- *
1459
- * @param function step A function to be called as a step
1460
- * @return Casper
1461
- */
1462
- Casper.prototype.then = function then(step) {
1463
- "use strict";
1464
- this.checkStarted();
1465
- if (!utils.isFunction(step)) {
1466
- throw new CasperError("You can only define a step as a function");
1467
- }
1468
- // check if casper is running
1469
- if (this.checker === null) {
1470
- // append step to the end of the queue
1471
- step.level = 0;
1472
- this.steps.push(step);
1473
- } else {
1474
- // insert substep a level deeper
1475
- try {
1476
- step.level = this.steps[this.step - 1].level + 1;
1477
- } catch (e) {
1478
- step.level = 0;
1479
- }
1480
- var insertIndex = this.step;
1481
- while (this.steps[insertIndex] && step.level === this.steps[insertIndex].level) {
1482
- insertIndex++;
1483
- }
1484
- this.steps.splice(insertIndex, 0, step);
1485
- }
1486
- this.emit('step.added', step);
1487
- return this;
1488
- };
1489
-
1490
- /**
1491
- * Adds a new navigation step for clicking on a provided link selector
1492
- * and execute an optional next step.
1493
- *
1494
- * @param String selector A DOM CSS3 compatible selector
1495
- * @param Function then Next step function to execute on page loaded (optional)
1496
- * @return Casper
1497
- * @see Casper#click
1498
- * @see Casper#then
1499
- */
1500
- Casper.prototype.thenClick = function thenClick(selector, then, fallbackToHref) {
1501
- "use strict";
1502
- this.checkStarted();
1503
- if (arguments.length > 2) {
1504
- this.emit("deprecated", "The thenClick() method does not process the fallbackToHref argument since 0.6");
1505
- }
1506
- this.then(function _step() {
1507
- this.click(selector);
1508
- });
1509
- return utils.isFunction(then) ? this.then(then) : this;
1510
- };
1511
-
1512
- /**
1513
- * Adds a new navigation step to perform code evaluation within the
1514
- * current retrieved page DOM.
1515
- *
1516
- * @param function fn The function to be evaluated within current page DOM
1517
- * @param object context Optional function parameters context
1518
- * @return Casper
1519
- * @see Casper#evaluate
1520
- */
1521
- Casper.prototype.thenEvaluate = function thenEvaluate(fn, context) {
1522
- "use strict";
1523
- this.checkStarted();
1524
- var args = [fn].concat([].slice.call(arguments, 1));
1525
- return this.then(function _step() {
1526
- this.evaluate.apply(this, args);
1527
- });
1528
- };
1529
-
1530
- /**
1531
- * Adds a new navigation step for opening the provided location.
1532
- *
1533
- * @param String location The URL to load
1534
- * @param function then Next step function to execute on page loaded (optional)
1535
- * @return Casper
1536
- * @see Casper#open
1537
- */
1538
- Casper.prototype.thenOpen = function thenOpen(location, settings, then) {
1539
- "use strict";
1540
- this.checkStarted();
1541
- if (!(settings && !utils.isFunction(settings))) {
1542
- then = settings;
1543
- settings = null;
1544
- }
1545
- this.then(this.createStep(function _step() {
1546
- this.open(location, settings);
1547
- }, {
1548
- skipLog: true
1549
- }));
1550
- return utils.isFunction(then) ? this.then(then) : this;
1551
- };
1552
-
1553
- /**
1554
- * Adds a new navigation step for opening and evaluate an expression
1555
- * against the DOM retrieved from the provided location.
1556
- *
1557
- * @param String location The url to open
1558
- * @param function fn The function to be evaluated within current page DOM
1559
- * @param object context Optional function parameters context
1560
- * @return Casper
1561
- * @see Casper#evaluate
1562
- * @see Casper#open
1563
- */
1564
- Casper.prototype.thenOpenAndEvaluate = function thenOpenAndEvaluate(location, fn, context) {
1565
- "use strict";
1566
- this.checkStarted();
1567
- return this.thenOpen(location).thenEvaluate(fn, context);
1568
- };
1569
-
1570
- /**
1571
- * Returns a string representation of current instance
1572
- *
1573
- * @return String
1574
- */
1575
- Casper.prototype.toString = function toString() {
1576
- "use strict";
1577
- return '[object Casper], currently at ' + this.getCurrentUrl();
1578
- };
1579
-
1580
- /**
1581
- * Sets the user-agent string currently used when requesting urls.
1582
- *
1583
- * @param String userAgent User agent string
1584
- * @return String
1585
- */
1586
- Casper.prototype.userAgent = function userAgent(agent) {
1587
- "use strict";
1588
- this.options.pageSettings.userAgent = agent;
1589
- if (this.started && this.page) {
1590
- this.page.settings.userAgent = agent;
1591
- }
1592
- return this;
1593
- };
1594
-
1595
- /**
1596
- * Changes the current viewport size.
1597
- *
1598
- * @param Number width The viewport width, in pixels
1599
- * @param Number height The viewport height, in pixels
1600
- * @return Casper
1601
- */
1602
- Casper.prototype.viewport = function viewport(width, height) {
1603
- "use strict";
1604
- this.checkStarted();
1605
- if (!utils.isNumber(width) || !utils.isNumber(height) || width <= 0 || height <= 0) {
1606
- throw new CasperError(f("Invalid viewport: %dx%d", width, height));
1607
- }
1608
- this.page.viewportSize = {
1609
- width: width,
1610
- height: height
1611
- };
1612
- this.emit('viewport.changed', [width, height]);
1613
- return this;
1614
- };
1615
-
1616
- /**
1617
- * Checks if an element matching the provided DOM CSS3/XPath selector is visible
1618
- * current page DOM by checking that offsetWidth and offsetHeight are
1619
- * both non-zero.
1620
- *
1621
- * @param String selector A DOM CSS3/XPath selector
1622
- * @return Boolean
1623
- */
1624
- Casper.prototype.visible = function visible(selector) {
1625
- "use strict";
1626
- this.checkStarted();
1627
- return this.evaluate(function _evaluate(selector) {
1628
- return __utils__.visible(selector);
1629
- }, selector);
1630
- };
1631
-
1632
- /**
1633
- * Displays a warning message onto the console and logs the event.
1634
- *
1635
- * @param String message
1636
- * @return Casper
1637
- */
1638
- Casper.prototype.warn = function warn(message) {
1639
- "use strict";
1640
- this.log(message, "warning", "phantom");
1641
- var formatted = f.apply(null, ["⚠  " + message].concat([].slice.call(arguments, 1)));
1642
- return this.echo(formatted, 'COMMENT');
1643
- };
1644
-
1645
- /**
1646
- * Adds a new step that will wait for a given amount of time (expressed
1647
- * in milliseconds) before processing an optional next one.
1648
- *
1649
- * @param Number timeout The max amount of time to wait, in milliseconds
1650
- * @param Function then Next step to process (optional)
1651
- * @return Casper
1652
- */
1653
- Casper.prototype.wait = function wait(timeout, then) {
1654
- "use strict";
1655
- this.checkStarted();
1656
- timeout = ~~timeout;
1657
- if (timeout < 1) {
1658
- this.die("wait() only accepts a positive integer > 0 as a timeout value");
1659
- }
1660
- if (then && !utils.isFunction(then)) {
1661
- this.die("wait() a step definition must be a function");
1662
- }
1663
- return this.then(function _step() {
1664
- this.waitStart();
1665
- setTimeout(function _check(self) {
1666
- self.log(f("wait() finished waiting for %dms.", timeout), "info");
1667
- if (then) {
1668
- then.call(self, self);
1669
- }
1670
- self.waitDone();
1671
- }, timeout, this);
1672
- });
1673
- };
1674
-
1675
- Casper.prototype.waitStart = function waitStart() {
1676
- "use strict";
1677
- this.emit('wait.start');
1678
- this.pendingWait = true;
1679
- };
1680
-
1681
- Casper.prototype.waitDone = function waitDone() {
1682
- "use strict";
1683
- this.emit('wait.done');
1684
- this.pendingWait = false;
1685
- };
1686
-
1687
- /**
1688
- * Waits until a function returns true to process a next step.
1689
- *
1690
- * @param Function testFx A function to be evaluated for returning condition satisfecit
1691
- * @param Function then The next step to perform (optional)
1692
- * @param Function onTimeout A callback function to call on timeout (optional)
1693
- * @param Number timeout The max amount of time to wait, in milliseconds (optional)
1694
- * @return Casper
1695
- */
1696
- Casper.prototype.waitFor = function waitFor(testFx, then, onTimeout, timeout) {
1697
- "use strict";
1698
- this.checkStarted();
1699
- timeout = timeout ? timeout : this.options.waitTimeout;
1700
- if (!utils.isFunction(testFx)) {
1701
- this.die("waitFor() needs a test function");
1702
- }
1703
- if (then && !utils.isFunction(then)) {
1704
- this.die("waitFor() next step definition must be a function");
1705
- }
1706
- return this.then(function _step() {
1707
- this.waitStart();
1708
- var start = new Date().getTime();
1709
- var condition = false;
1710
- var interval = setInterval(function _check(self, testFx, timeout, onTimeout) {
1711
- if ((new Date().getTime() - start < timeout) && !condition) {
1712
- condition = testFx.call(self, self);
1713
- } else {
1714
- self.waitDone();
1715
- if (!condition) {
1716
- self.log("Casper.waitFor() timeout", "warning");
1717
- self.emit('waitFor.timeout');
1718
- var onWaitTimeout = onTimeout ? onTimeout : self.options.onWaitTimeout;
1719
- if (!utils.isFunction(onWaitTimeout)) {
1720
- throw new CasperError('Invalid timeout function, exiting.');
1721
- }
1722
- onWaitTimeout.call(self, timeout);
1723
- } else {
1724
- self.log(f("waitFor() finished in %dms.", new Date().getTime() - start), "info");
1725
- if (then) {
1726
- self.then(then);
1727
- }
1728
- }
1729
- clearInterval(interval);
1730
- }
1731
- }, 100, this, testFx, timeout, onTimeout);
1732
- });
1733
- };
1734
-
1735
- /**
1736
- * Waits for a popup page having its url matching the provided pattern to be opened
1737
- * and loaded.
1738
- *
1739
- * @param String|RegExp urlPattern The popup url pattern
1740
- * @param Function then The next step function (optional)
1741
- * @param Function onTimeout Function to call on operation timeout (optional)
1742
- * @param Number timeout Timeout in milliseconds (optional)
1743
- * @return Casper
1744
- */
1745
- Casper.prototype.waitForPopup = function waitForPopup(urlPattern, then, onTimeout, timeout) {
1746
- "use strict";
1747
- return this.waitFor(function() {
1748
- try {
1749
- this.popups.find(urlPattern);
1750
- return true;
1751
- } catch (e) {
1752
- return false;
1753
- }
1754
- }, then, onTimeout, timeout);
1755
- };
1756
-
1757
- /**
1758
- * Waits until a given resource is loaded
1759
- *
1760
- * @param String/Function test A function to test if the resource exists.
1761
- * A string will be matched against the resources url.
1762
- * @param Function then The next step to perform (optional)
1763
- * @param Function onTimeout A callback function to call on timeout (optional)
1764
- * @param Number timeout The max amount of time to wait, in milliseconds (optional)
1765
- * @return Casper
1766
- */
1767
- Casper.prototype.waitForResource = function waitForResource(test, then, onTimeout, timeout) {
1768
- "use strict";
1769
- this.checkStarted();
1770
- timeout = timeout ? timeout : this.options.waitTimeout;
1771
- return this.waitFor(function _check() {
1772
- return this.resourceExists(test);
1773
- }, then, onTimeout, timeout);
1774
- };
1775
-
1776
- /**
1777
- * Waits until an element matching the provided DOM CSS3/XPath selector exists in
1778
- * remote DOM to process a next step.
1779
- *
1780
- * @param String selector A DOM CSS3/XPath selector
1781
- * @param Function then The next step to perform (optional)
1782
- * @param Function onTimeout A callback function to call on timeout (optional)
1783
- * @param Number timeout The max amount of time to wait, in milliseconds (optional)
1784
- * @return Casper
1785
- */
1786
- Casper.prototype.waitForSelector = function waitForSelector(selector, then, onTimeout, timeout) {
1787
- "use strict";
1788
- this.checkStarted();
1789
- timeout = timeout ? timeout : this.options.waitTimeout;
1790
- return this.waitFor(function _check() {
1791
- return this.exists(selector);
1792
- }, then, onTimeout, timeout);
1793
- };
1794
-
1795
- /**
1796
- * Waits until the page contains given HTML text.
1797
- *
1798
- * @param String text Text to wait for
1799
- * @param Function then The next step to perform (optional)
1800
- * @param Function onTimeout A callback function to call on timeout (optional)
1801
- * @param Number timeout The max amount of time to wait, in milliseconds (optional)
1802
- * @return Casper
1803
- */
1804
- Casper.prototype.waitForText = function(text, then, onTimeout, timeout) {
1805
- "use strict";
1806
- this.checkStarted();
1807
- timeout = timeout ? timeout : this.options.waitTimeout;
1808
- return this.waitFor(function _check() {
1809
- return this.getPageContent().indexOf(text) !== -1;
1810
- }, then, onTimeout, timeout);
1811
- };
1812
-
1813
- /**
1814
- * Waits until an element matching the provided DOM CSS3/XPath selector does not
1815
- * exist in the remote DOM to process a next step.
1816
- *
1817
- * @param String selector A DOM CSS3/XPath selector
1818
- * @param Function then The next step to perform (optional)
1819
- * @param Function onTimeout A callback function to call on timeout (optional)
1820
- * @param Number timeout The max amount of time to wait, in milliseconds (optional)
1821
- * @return Casper
1822
- */
1823
- Casper.prototype.waitWhileSelector = function waitWhileSelector(selector, then, onTimeout, timeout) {
1824
- "use strict";
1825
- this.checkStarted();
1826
- timeout = timeout ? timeout : this.options.waitTimeout;
1827
- return this.waitFor(function _check() {
1828
- return !this.exists(selector);
1829
- }, then, onTimeout, timeout);
1830
- };
1831
-
1832
- /**
1833
- * Waits until an element matching the provided DOM CSS3/XPath selector is
1834
- * visible in the remote DOM to process a next step.
1835
- *
1836
- * @param String selector A DOM CSS3/XPath selector
1837
- * @param Function then The next step to perform (optional)
1838
- * @param Function onTimeout A callback function to call on timeout (optional)
1839
- * @param Number timeout The max amount of time to wait, in milliseconds (optional)
1840
- * @return Casper
1841
- */
1842
- Casper.prototype.waitUntilVisible = function waitUntilVisible(selector, then, onTimeout, timeout) {
1843
- "use strict";
1844
- this.checkStarted();
1845
- timeout = timeout ? timeout : this.options.waitTimeout;
1846
- return this.waitFor(function _check() {
1847
- return this.visible(selector);
1848
- }, then, onTimeout, timeout);
1849
- };
1850
-
1851
- /**
1852
- * Waits until an element matching the provided DOM CSS3/XPath selector is no
1853
- * longer visible in remote DOM to process a next step.
1854
- *
1855
- * @param String selector A DOM CSS3/XPath selector
1856
- * @param Function then The next step to perform (optional)
1857
- * @param Function onTimeout A callback function to call on timeout (optional)
1858
- * @param Number timeout The max amount of time to wait, in milliseconds (optional)
1859
- * @return Casper
1860
- */
1861
- Casper.prototype.waitWhileVisible = function waitWhileVisible(selector, then, onTimeout, timeout) {
1862
- "use strict";
1863
- this.checkStarted();
1864
- timeout = timeout ? timeout : this.options.waitTimeout;
1865
- return this.waitFor(function _check() {
1866
- return !this.visible(selector);
1867
- }, then, onTimeout, timeout);
1868
- };
1869
-
1870
- /**
1871
- * Makes the provided frame page as the currently active one. Note that the
1872
- * active page will be reverted when finished.
1873
- *
1874
- * @param String|Number frameInfo Target frame name or number
1875
- * @param Function then Next step function
1876
- * @return Casper
1877
- */
1878
- Casper.prototype.withFrame = function withFrame(frameInfo, then) {
1879
- "use strict";
1880
- this.then(function _step() {
1881
- if (utils.isNumber(frameInfo)) {
1882
- if (frameInfo > this.page.childFramesCount() - 1) {
1883
- throw new CasperError(f('Frame number "%d" is out of bounds.', frameInfo));
1884
- }
1885
- } else if (this.page.childFramesName().indexOf(frameInfo) === -1) {
1886
- throw new CasperError(f('No frame named "%s" was found.', frameInfo));
1887
- }
1888
- // make the frame page the currently active one
1889
- this.page.switchToChildFrame(frameInfo);
1890
- });
1891
- try {
1892
- this.then(then);
1893
- } catch (e) {
1894
- // revert to main page on error
1895
- this.warn("Error while processing frame step: " + e);
1896
- this.page.switchToMainFrame();
1897
- throw e;
1898
- }
1899
- return this.then(function _step() {
1900
- // revert to main page
1901
- this.page.switchToMainFrame();
1902
- });
1903
- };
1904
-
1905
- /**
1906
- * Makes the provided frame page as the currently active one. Note that the
1907
- * active page will be reverted when finished.
1908
- *
1909
- * @param String|RegExp|WebPage popup Target frame page information
1910
- * @param Function then Next step function
1911
- * @return Casper
1912
- */
1913
- Casper.prototype.withPopup = function withPopup(popupInfo, then) {
1914
- "use strict";
1915
- this.then(function _step() {
1916
- var popupPage = this.popups.find(popupInfo);
1917
- if (!utils.isFunction(then)) {
1918
- throw new CasperError("withPopup() requires a step function.");
1919
- }
1920
- // make the popup page the currently active one
1921
- this.page = popupPage;
1922
- });
1923
- try {
1924
- this.then(then);
1925
- } catch (e) {
1926
- // revert to main page on error
1927
- this.log("error while processing popup step: " + e, "error");
1928
- this.page = this.mainPage;
1929
- throw e;
1930
- }
1931
- return this.then(function _step() {
1932
- // revert to main page
1933
- this.page = this.mainPage;
1934
- });
1935
- };
1936
-
1937
- /**
1938
- * Changes the current page zoom factor.
1939
- *
1940
- * @param Number factor The zoom factor
1941
- * @return Casper
1942
- */
1943
- Casper.prototype.zoom = function zoom(factor) {
1944
- "use strict";
1945
- this.checkStarted();
1946
- if (!utils.isNumber(factor) || factor <= 0) {
1947
- throw new CasperError("Invalid zoom factor: " + factor);
1948
- }
1949
- this.page.zoomFactor = factor;
1950
- return this;
1951
- };
1952
-
1953
- /**
1954
- * Extends Casper's prototype with provided one.
1955
- *
1956
- * @param Object proto Prototype methods to add to Casper
1957
- * @deprecated
1958
- * @since 0.6
1959
- */
1960
- Casper.extend = function(proto) {
1961
- "use strict";
1962
- this.emit("deprecated", "Casper.extend() has been deprecated since 0.6; check the docs")
1963
- if (!utils.isObject(proto)) {
1964
- throw new CasperError("extends() only accept objects as prototypes");
1965
- }
1966
- utils.mergeObjects(Casper.prototype, proto);
1967
- };
1968
-
1969
- exports.Casper = Casper;
1970
-
1971
- /**
1972
- * Creates a new WebPage instance for Casper use.
1973
- *
1974
- * @param Casper casper A Casper instance
1975
- * @return WebPage
1976
- */
1977
- function createPage(casper) {
1978
- /*jshint maxstatements:20*/
1979
- "use strict";
1980
- var page = require('webpage').create();
1981
- page.onAlert = function onAlert(message) {
1982
- casper.log('[alert] ' + message, "info", "remote");
1983
- casper.emit('remote.alert', message);
1984
- if (utils.isFunction(casper.options.onAlert)) {
1985
- casper.options.onAlert.call(casper, casper, message);
1986
- }
1987
- };
1988
- page.onConfirm = function onConfirm(message) {
1989
- if ('page.confirm' in casper._filters) {
1990
- return casper.filter('page.confirm', message);
1991
- }
1992
- return true;
1993
- };
1994
- page.onConsoleMessage = function onConsoleMessage(msg) {
1995
- // client utils casper console message
1996
- var consoleTest = /^\[casper\.echo\]\s?([\s\S]*)/.exec(msg);
1997
- if (consoleTest && consoleTest.length === 2) {
1998
- casper.echo(consoleTest[1]);
1999
- return; // don't trigger remote.message event for these
2000
- }
2001
- // client utils log messages
2002
- var logLevel = "info",
2003
- logTest = /^\[casper:(\w+)\]\s?([\s\S]*)/m.exec(msg);
2004
- if (logTest && logTest.length === 3) {
2005
- logLevel = logTest[1];
2006
- msg = logTest[2];
2007
- }
2008
- casper.log(msg, logLevel, "remote");
2009
- casper.emit('remote.message', msg);
2010
- };
2011
- page.onError = function onError(msg, trace) {
2012
- casper.emit('page.error', msg, trace);
2013
- };
2014
- page.onInitialized = function onInitialized() {
2015
- casper.emit('page.initialized', page);
2016
- if (utils.isFunction(casper.options.onPageInitialized)) {
2017
- casper.log("Post-configuring WebPage instance", "debug");
2018
- casper.options.onPageInitialized.call(casper, page);
2019
- }
2020
- };
2021
- page.onLoadStarted = function onLoadStarted() {
2022
- casper.loadInProgress = true;
2023
- casper.emit('load.started');
2024
- };
2025
- page.onLoadFinished = function onLoadFinished(status) {
2026
- /*jshint maxstatements:20*/
2027
- if (status !== "success") {
2028
- casper.emit('load.failed', {
2029
- status: status,
2030
- http_status: casper.currentHTTPStatus,
2031
- url: casper.requestUrl
2032
- });
2033
- var message = 'Loading resource failed with status=' + status;
2034
- if (casper.currentHTTPStatus) {
2035
- message += f(' (HTTP %d)', casper.currentHTTPStatus);
2036
- }
2037
- message += ': ' + casper.requestUrl;
2038
- casper.log(message, "warning");
2039
- casper.navigationRequested = false;
2040
- if (utils.isFunction(casper.options.onLoadError)) {
2041
- casper.options.onLoadError.call(casper, casper, casper.requestUrl, status);
2042
- }
2043
- }
2044
- // local client scripts
2045
- casper.injectClientScripts();
2046
- // remote client scripts
2047
- casper.includeRemoteScripts();
2048
- // Client-side utils injection
2049
- casper.injectClientUtils();
2050
- // history
2051
- casper.history.push(casper.getCurrentUrl());
2052
- casper.emit('load.finished', status);
2053
- casper.loadInProgress = false;
2054
- };
2055
- page.onNavigationRequested = function onNavigationRequested(url, navigationType, navigationLocked, isMainFrame) {
2056
- casper.log(f('Navigation requested: url=%s, type=%s, lock=%s, isMainFrame=%s',
2057
- url, navigationType, navigationLocked, isMainFrame), "debug");
2058
- if(isMainFrame) {
2059
- casper.navigationRequested = true;
2060
- }
2061
- casper.emit('navigation.requested', url, navigationType, navigationLocked, isMainFrame);
2062
- };
2063
- page.onPageCreated = function onPageCreated(popupPage) {
2064
- casper.emit('popup.created', popupPage);
2065
- popupPage.onLoadFinished = function onLoadFinished() {
2066
- casper.popups.push(popupPage);
2067
- casper.emit('popup.loaded', popupPage);
2068
- };
2069
- popupPage.onClosing = function onClosing(closedPopup) {
2070
- casper.popups.clean(closedPopup);
2071
- casper.emit('popup.closed', closedPopup);
2072
- };
2073
- };
2074
- page.onPrompt = function onPrompt(message, value) {
2075
- return casper.filter('page.prompt', message, value);
2076
- };
2077
- page.onResourceReceived = function onResourceReceived(resource) {
2078
- http.augmentResponse(resource);
2079
- casper.emit('resource.received', resource);
2080
- if (utils.isFunction(casper.options.onResourceReceived)) {
2081
- casper.options.onResourceReceived.call(casper, casper, resource);
2082
- }
2083
- casper.handleReceivedResource(resource);
2084
- };
2085
- page.onResourceRequested = function onResourceRequested(request) {
2086
- casper.emit('resource.requested', request);
2087
- if (request.url === casper.requestUrl) {
2088
- casper.emit('page.resource.requested', request);
2089
- }
2090
- if (utils.isFunction(casper.options.onResourceRequested)) {
2091
- casper.options.onResourceRequested.call(casper, casper, request);
2092
- }
2093
- };
2094
- page.onUrlChanged = function onUrlChanged(url) {
2095
- casper.log(f('url changed to "%s"', url), "debug");
2096
- casper.navigationRequested = false;
2097
- casper.emit('url.changed', url);
2098
- };
2099
- casper.emit('page.created', page);
2100
- return page;
2101
- }