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/tester.js DELETED
@@ -1,1161 +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 exports phantom require __utils__*/
32
-
33
- var fs = require('fs');
34
- var events = require('events');
35
- var utils = require('utils');
36
- var f = utils.format;
37
-
38
- exports.create = function create(casper, options) {
39
- "use strict";
40
- return new Tester(casper, options);
41
- };
42
-
43
- /**
44
- * Casper tester: makes assertions, stores test results and display then.
45
- *
46
- * @param Casper casper A valid Casper instance
47
- * @param Object|null options Options object
48
- */
49
- var Tester = function Tester(casper, options) {
50
- "use strict";
51
- /*jshint maxstatements:30*/
52
-
53
- if (!utils.isCasperObject(casper)) {
54
- throw new CasperError("Tester needs a Casper instance");
55
- }
56
-
57
- var self = this;
58
-
59
- this.casper = casper;
60
-
61
- this.SKIP_MESSAGE = '__termination__';
62
-
63
- this.aborted = false;
64
- this.executed = 0;
65
- this.currentTestFile = null;
66
- this.currentSuiteNum = 0;
67
- this.exporter = require('xunit').create();
68
- this.loadIncludes = {
69
- includes: [],
70
- pre: [],
71
- post: []
72
- };
73
- this.running = false;
74
- this.suites = [];
75
- this.options = utils.mergeObjects({
76
- failFast: false, // terminates a suite as soon as a test fails?
77
- failText: "FAIL", // text to use for a successful test
78
- passText: "PASS", // text to use for a failed test
79
- pad: 80 , // maximum number of chars for a result line
80
- warnText: "WARN" // text to use for a dubious test
81
- }, options);
82
-
83
- // properties
84
- this.testResults = {
85
- passed: 0,
86
- failed: 0,
87
- passes: [],
88
- failures: [],
89
- passesTime: [],
90
- failuresTime: []
91
- };
92
-
93
- // measuring test duration
94
- this.currentTestStartTime = null;
95
- this.lastAssertTime = 0;
96
-
97
- this.configure();
98
-
99
- this.on('success', function onSuccess(success) {
100
- this.testResults.passes.push(success);
101
- var timeElapsed = new Date() - this.currentTestStartTime;
102
- this.testResults.passesTime.push(timeElapsed - this.lastAssertTime);
103
- this.exporter.addSuccess(fs.absolute(success.file), success.message || success.standard, timeElapsed - this.lastAssertTime);
104
- this.lastAssertTime = timeElapsed;
105
- });
106
-
107
- this.on('fail', function onFail(failure) {
108
- // export
109
- var timeElapsed = new Date() - this.currentTestStartTime;
110
- this.testResults.failuresTime.push(timeElapsed - this.lastAssertTime);
111
- this.exporter.addFailure(
112
- fs.absolute(failure.file),
113
- failure.message || failure.standard,
114
- failure.standard || "test failed",
115
- failure.type || "unknown",
116
- (timeElapsed - this.lastAssertTime)
117
- );
118
- this.lastAssertTime = timeElapsed;
119
- this.testResults.failures.push(failure);
120
-
121
- // special printing
122
- if (failure.type) {
123
- this.comment(' type: ' + failure.type);
124
- }
125
- if (failure.values && Object.keys(failure.values).length > 0) {
126
- for (var name in failure.values) {
127
- var comment = ' ' + name + ': ';
128
- var value = failure.values[name];
129
- try {
130
- comment += utils.serialize(failure.values[name]);
131
- } catch (e) {
132
- try {
133
- comment += utils.serialize(failure.values[name].toString());
134
- } catch (e2) {
135
- comment += '(unserializable value)';
136
- }
137
- }
138
- this.comment(comment);
139
- }
140
- }
141
- });
142
-
143
- // casper events
144
- this.casper.on('error', function onCasperError(msg, backtrace) {
145
- if (!phantom.casperTest) {
146
- return;
147
- }
148
- if (msg === self.SKIP_MESSAGE) {
149
- this.warn(f('--fail-fast: aborted remaining tests in "%s"', self.currentTestFile));
150
- self.aborted = true;
151
- return self.done();
152
- }
153
- var line = 0;
154
- if (!utils.isString(msg)) {
155
- try {
156
- line = backtrace[0].line;
157
- } catch (e) {}
158
- }
159
- self.uncaughtError(msg, self.currentTestFile, line);
160
- self.done();
161
- });
162
-
163
- this.casper.on('step.error', function onStepError(e) {
164
- if (e.message !== self.SKIP_MESSAGE) {
165
- self.uncaughtError(e, self.currentTestFile);
166
- }
167
- self.done();
168
- });
169
- };
170
-
171
- // Tester class is an EventEmitter
172
- utils.inherits(Tester, events.EventEmitter);
173
- exports.Tester = Tester;
174
-
175
- /**
176
- * Asserts that a condition strictly resolves to true. Also returns an
177
- * "assertion object" containing useful informations about the test case
178
- * results.
179
- *
180
- * This method is also used as the base one used for all other `assert*`
181
- * family methods; supplementary informations are then passed using the
182
- * `context` argument.
183
- *
184
- * @param Boolean subject The condition to test
185
- * @param String message Test description
186
- * @param Object|null context Assertion context object (Optional)
187
- * @return Object An assertion result object
188
- */
189
- Tester.prototype.assert = Tester.prototype.assertTrue = function assert(subject, message, context) {
190
- "use strict";
191
- this.executed++;
192
- return this.processAssertionResult(utils.mergeObjects({
193
- success: subject === true,
194
- type: "assert",
195
- standard: "Subject is strictly true",
196
- message: message,
197
- file: this.currentTestFile,
198
- values: {
199
- subject: utils.getPropertyPath(context, 'values.subject') || subject
200
- }
201
- }, context || {}));
202
- };
203
-
204
- /**
205
- * Asserts that two values are strictly equals.
206
- *
207
- * @param Mixed subject The value to test
208
- * @param Mixed expected The expected value
209
- * @param String message Test description (Optional)
210
- * @return Object An assertion result object
211
- */
212
- Tester.prototype.assertEquals = Tester.prototype.assertEqual = function assertEquals(subject, expected, message) {
213
- "use strict";
214
- return this.assert(this.testEquals(subject, expected), message, {
215
- type: "assertEquals",
216
- standard: "Subject equals the expected value",
217
- values: {
218
- subject: subject,
219
- expected: expected
220
- }
221
- });
222
- };
223
-
224
- /**
225
- * Asserts that two values are strictly not equals.
226
- *
227
- * @param Mixed subject The value to test
228
- * @param Mixed expected The unwanted value
229
- * @param String|null message Test description (Optional)
230
- * @return Object An assertion result object
231
- */
232
- Tester.prototype.assertNotEquals = function assertNotEquals(subject, shouldnt, message) {
233
- "use strict";
234
- return this.assert(!this.testEquals(subject, shouldnt), message, {
235
- type: "assertNotEquals",
236
- standard: "Subject doesn't equal what it shouldn't be",
237
- values: {
238
- subject: subject,
239
- shouldnt: shouldnt
240
- }
241
- });
242
- };
243
-
244
- /**
245
- * Asserts that a code evaluation in remote DOM resolves to true.
246
- *
247
- * @param Function fn A function to be evaluated in remote DOM
248
- * @param String message Test description
249
- * @param Object params Object/Array containing the parameters to inject into the function (optional)
250
- * @return Object An assertion result object
251
- */
252
- Tester.prototype.assertEval = Tester.prototype.assertEvaluate = function assertEval(fn, message, params) {
253
- "use strict";
254
- return this.assert(this.casper.evaluate(fn, params), message, {
255
- type: "assertEval",
256
- standard: "Evaluated function returns true",
257
- values: {
258
- fn: fn,
259
- params: params
260
- }
261
- });
262
- };
263
-
264
- /**
265
- * Asserts that the result of a code evaluation in remote DOM equals
266
- * an expected value.
267
- *
268
- * @param Function fn The function to be evaluated in remote DOM
269
- * @param Boolean expected The expected value
270
- * @param String|null message Test description
271
- * @param Object|null params Object containing the parameters to inject into the function (optional)
272
- * @return Object An assertion result object
273
- */
274
- Tester.prototype.assertEvalEquals = Tester.prototype.assertEvalEqual = function assertEvalEquals(fn, expected, message, params) {
275
- "use strict";
276
- var subject = this.casper.evaluate(fn, params);
277
- return this.assert(this.testEquals(subject, expected), message, {
278
- type: "assertEvalEquals",
279
- standard: "Evaluated function returns the expected value",
280
- values: {
281
- fn: fn,
282
- params: params,
283
- subject: subject,
284
- expected: expected
285
- }
286
- });
287
- };
288
-
289
- /**
290
- * Asserts that a given input field has the provided value.
291
- *
292
- * @param String inputName The name attribute of the input element
293
- * @param String expected The expected value of the input element
294
- * @param String message Test description
295
- * @return Object An assertion result object
296
- */
297
- Tester.prototype.assertField = function assertField(inputName, expected, message) {
298
- "use strict";
299
- var actual = this.casper.evaluate(function(inputName) {
300
- return __utils__.getFieldValue(inputName);
301
- }, inputName);
302
- return this.assert(this.testEquals(actual, expected), message, {
303
- type: 'assertField',
304
- standard: f('"%s" input field has the value "%s"', inputName, expected),
305
- values: {
306
- inputName: inputName,
307
- actual: actual,
308
- expected: expected
309
- }
310
- });
311
- };
312
-
313
- /**
314
- * Asserts that an element matching the provided selector expression exists in
315
- * remote DOM.
316
- *
317
- * @param String selector Selector expression
318
- * @param String message Test description
319
- * @return Object An assertion result object
320
- */
321
- Tester.prototype.assertExists = Tester.prototype.assertExist = Tester.prototype.assertSelectorExists = Tester.prototype.assertSelectorExist = function assertExists(selector, message) {
322
- "use strict";
323
- return this.assert(this.casper.exists(selector), message, {
324
- type: "assertExists",
325
- standard: f("Found an element matching: %s", selector),
326
- values: {
327
- selector: selector
328
- }
329
- });
330
- };
331
-
332
- /**
333
- * Asserts that an element matching the provided selector expression does not
334
- * exists in remote DOM.
335
- *
336
- * @param String selector Selector expression
337
- * @param String message Test description
338
- * @return Object An assertion result object
339
- */
340
- Tester.prototype.assertDoesntExist = Tester.prototype.assertNotExists = function assertDoesntExist(selector, message) {
341
- "use strict";
342
- return this.assert(!this.casper.exists(selector), message, {
343
- type: "assertDoesntExist",
344
- standard: f("No element found matching selector: %s", selector),
345
- values: {
346
- selector: selector
347
- }
348
- });
349
- };
350
-
351
- /**
352
- * Asserts that current HTTP status is the one passed as argument.
353
- *
354
- * @param Number status HTTP status code
355
- * @param String message Test description
356
- * @return Object An assertion result object
357
- */
358
- Tester.prototype.assertHttpStatus = function assertHttpStatus(status, message) {
359
- "use strict";
360
- var currentHTTPStatus = this.casper.currentHTTPStatus;
361
- return this.assert(this.testEquals(this.casper.currentHTTPStatus, status), message, {
362
- type: "assertHttpStatus",
363
- standard: f("HTTP status code is: %s", status),
364
- values: {
365
- current: currentHTTPStatus,
366
- expected: status
367
- }
368
- });
369
- };
370
-
371
- /**
372
- * Asserts that a provided string matches a provided RegExp pattern.
373
- *
374
- * @param String subject The string to test
375
- * @param RegExp pattern A RegExp object instance
376
- * @param String message Test description
377
- * @return Object An assertion result object
378
- */
379
- Tester.prototype.assertMatch = Tester.prototype.assertMatches = function assertMatch(subject, pattern, message) {
380
- "use strict";
381
- if (utils.betterTypeOf(pattern) !== "regexp") {
382
- throw new CasperError('Invalid regexp.');
383
- }
384
- return this.assert(pattern.test(subject), message, {
385
- type: "assertMatch",
386
- standard: "Subject matches the provided pattern",
387
- values: {
388
- subject: subject,
389
- pattern: pattern.toString()
390
- }
391
- });
392
- };
393
-
394
- /**
395
- * Asserts a condition resolves to false.
396
- *
397
- * @param Boolean condition The condition to test
398
- * @param String message Test description
399
- * @return Object An assertion result object
400
- */
401
- Tester.prototype.assertNot = Tester.prototype.assertFalse = function assertNot(condition, message) {
402
- "use strict";
403
- return this.assert(!condition, message, {
404
- type: "assertNot",
405
- standard: "Subject is falsy",
406
- values: {
407
- condition: condition
408
- }
409
- });
410
- };
411
-
412
- /**
413
- * Asserts that a selector expression is not currently visible.
414
- *
415
- * @param String expected selector expression
416
- * @param String message Test description
417
- * @return Object An assertion result object
418
- */
419
- Tester.prototype.assertNotVisible = Tester.prototype.assertInvisible = function assertNotVisible(selector, message) {
420
- "use strict";
421
- return this.assert(!this.casper.visible(selector), message, {
422
- type: "assertVisible",
423
- standard: "Selector is not visible",
424
- values: {
425
- selector: selector
426
- }
427
- });
428
- };
429
-
430
- /**
431
- * Asserts that the provided function called with the given parameters
432
- * will raise an exception.
433
- *
434
- * @param Function fn The function to test
435
- * @param Array args The arguments to pass to the function
436
- * @param String message Test description
437
- * @return Object An assertion result object
438
- */
439
- Tester.prototype.assertRaises = Tester.prototype.assertRaise = Tester.prototype.assertThrows = function assertRaises(fn, args, message) {
440
- "use strict";
441
- var context = {
442
- type: "assertRaises",
443
- standard: "Function raises an error"
444
- };
445
- try {
446
- fn.apply(null, args);
447
- this.assert(false, message, context);
448
- } catch (error) {
449
- this.assert(true, message, utils.mergeObjects(context, {
450
- values: {
451
- error: error
452
- }
453
- }));
454
- }
455
- };
456
-
457
- /**
458
- * Asserts that the current page has a resource that matches the provided test
459
- *
460
- * @param Function/String test A test function that is called with every response
461
- * @param String message Test description
462
- * @return Object An assertion result object
463
- */
464
- Tester.prototype.assertResourceExists = Tester.prototype.assertResourceExist = function assertResourceExists(test, message) {
465
- "use strict";
466
- return this.assert(this.casper.resourceExists(test), message, {
467
- type: "assertResourceExists",
468
- standard: "Expected resource has been found",
469
- values: {
470
- test: test
471
- }
472
- });
473
- };
474
-
475
- /**
476
- * Asserts that given text doesn't exist in the document body.
477
- *
478
- * @param String text Text not to be found
479
- * @param String message Test description
480
- * @return Object An assertion result object
481
- */
482
- Tester.prototype.assertTextDoesntExist = Tester.prototype.assertTextDoesntExist = function assertTextDoesntExist(text, message) {
483
- "use strict";
484
- var textFound = (this.casper.evaluate(function _evaluate() {
485
- return document.body.textContent || document.body.innerText;
486
- }).indexOf(text) === -1);
487
- return this.assert(textFound, message, {
488
- type: "assertTextDoesntExists",
489
- standard: "Text doesn't exist within the document body",
490
- values: {
491
- text: text
492
- }
493
- });
494
- };
495
-
496
- /**
497
- * Asserts that given text exists in the document body.
498
- *
499
- * @param String text Text to be found
500
- * @param String message Test description
501
- * @return Object An assertion result object
502
- */
503
- Tester.prototype.assertTextExists = Tester.prototype.assertTextExist = function assertTextExists(text, message) {
504
- "use strict";
505
- var textFound = (this.casper.evaluate(function _evaluate() {
506
- return document.body.textContent || document.body.innerText;
507
- }).indexOf(text) !== -1);
508
- return this.assert(textFound, message, {
509
- type: "assertTextExists",
510
- standard: "Found expected text within the document body",
511
- values: {
512
- text: text
513
- }
514
- });
515
- };
516
-
517
- /**
518
- * Asserts a subject is truthy.
519
- *
520
- * @param Mixed subject Test subject
521
- * @param String message Test description
522
- * @return Object An assertion result object
523
- */
524
- Tester.prototype.assertTruthy = function assertTruthy(subject, message) {
525
- "use strict";
526
- /*jshint eqeqeq:false*/
527
- return this.assert(utils.isTruthy(subject), message, {
528
- type: "assertTruthy",
529
- standard: "Subject is truthy",
530
- values: {
531
- subject: subject
532
- }
533
- });
534
- };
535
-
536
- /**
537
- * Asserts a subject is falsy.
538
- *
539
- * @param Mixed subject Test subject
540
- * @param String message Test description
541
- * @return Object An assertion result object
542
- */
543
- Tester.prototype.assertFalsy = function assertFalsy(subject, message) {
544
- "use strict";
545
- /*jshint eqeqeq:false*/
546
- return this.assert(utils.isFalsy(subject), message, {
547
- type: "assertFalsy",
548
- standard: "Subject is falsy",
549
- values: {
550
- subject: subject
551
- }
552
- });
553
- };
554
-
555
- /**
556
- * Asserts that given text exists in the provided selector.
557
- *
558
- * @param String selector Selector expression
559
- * @param String text Text to be found
560
- * @param String message Test description
561
- * @return Object An assertion result object
562
- */
563
- Tester.prototype.assertSelectorHasText = Tester.prototype.assertSelectorContains = function assertSelectorHasText(selector, text, message) {
564
- "use strict";
565
- var textFound = this.casper.fetchText(selector).indexOf(text) !== -1;
566
- return this.assert(textFound, message, {
567
- type: "assertSelectorHasText",
568
- standard: f('Found "%s" within the selector "%s"', text, selector),
569
- values: {
570
- selector: selector,
571
- text: text
572
- }
573
- });
574
- };
575
-
576
- /**
577
- * Asserts that given text does not exist in the provided selector.
578
- *
579
- * @param String selector Selector expression
580
- * @param String text Text not to be found
581
- * @param String message Test description
582
- * @return Object An assertion result object
583
- */
584
- Tester.prototype.assertSelectorDoesntHaveText = Tester.prototype.assertSelectorDoesntContain = function assertSelectorDoesntHaveText(selector, text, message) {
585
- "use strict";
586
- var textFound = this.casper.fetchText(selector).indexOf(text) === -1;
587
- return this.assert(textFound, message, {
588
- type: "assertSelectorDoesntHaveText",
589
- standard: f('Did not find "%s" within the selector "%s"', text, selector),
590
- values: {
591
- selector: selector,
592
- text: text
593
- }
594
- });
595
- };
596
-
597
- /**
598
- * Asserts that title of the remote page equals to the expected one.
599
- *
600
- * @param String expected The expected title string
601
- * @param String message Test description
602
- * @return Object An assertion result object
603
- */
604
- Tester.prototype.assertTitle = function assertTitle(expected, message) {
605
- "use strict";
606
- var currentTitle = this.casper.getTitle();
607
- return this.assert(this.testEquals(currentTitle, expected), message, {
608
- type: "assertTitle",
609
- standard: f('Page title is: "%s"', expected),
610
- values: {
611
- subject: currentTitle,
612
- expected: expected
613
- }
614
- });
615
- };
616
-
617
- /**
618
- * Asserts that title of the remote page matched the provided pattern.
619
- *
620
- * @param RegExp pattern The pattern to test the title against
621
- * @param String message Test description
622
- * @return Object An assertion result object
623
- */
624
- Tester.prototype.assertTitleMatch = Tester.prototype.assertTitleMatches = function assertTitleMatch(pattern, message) {
625
- "use strict";
626
- if (utils.betterTypeOf(pattern) !== "regexp") {
627
- throw new CasperError('Invalid regexp.');
628
- }
629
- var currentTitle = this.casper.getTitle();
630
- return this.assert(pattern.test(currentTitle), message, {
631
- type: "assertTitle",
632
- details: "Page title does not match the provided pattern",
633
- values: {
634
- subject: currentTitle,
635
- pattern: pattern.toString()
636
- }
637
- });
638
- };
639
-
640
- /**
641
- * Asserts that the provided subject is of the given type.
642
- *
643
- * @param mixed subject The value to test
644
- * @param String type The javascript type name
645
- * @param String message Test description
646
- * @return Object An assertion result object
647
- */
648
- Tester.prototype.assertType = function assertType(subject, type, message) {
649
- "use strict";
650
- var actual = utils.betterTypeOf(subject);
651
- return this.assert(this.testEquals(actual, type), message, {
652
- type: "assertType",
653
- standard: f('Subject type is: "%s"', type),
654
- values: {
655
- subject: subject,
656
- type: type,
657
- actual: actual
658
- }
659
- });
660
- };
661
-
662
- /**
663
- * Asserts that a the current page url matches a given pattern. A pattern may be
664
- * either a RegExp object or a String. The method will test if the URL matches
665
- * the pattern or contains the String.
666
- *
667
- * @param RegExp|String pattern The test pattern
668
- * @param String message Test description
669
- * @return Object An assertion result object
670
- */
671
- Tester.prototype.assertUrlMatch = Tester.prototype.assertUrlMatches = function assertUrlMatch(pattern, message) {
672
- "use strict";
673
- var currentUrl = this.casper.getCurrentUrl(),
674
- patternType = utils.betterTypeOf(pattern),
675
- result;
676
- if (patternType === "regexp") {
677
- result = pattern.test(currentUrl);
678
- } else if (patternType === "string") {
679
- result = currentUrl.indexOf(pattern) !== -1;
680
- } else {
681
- throw new CasperError("assertUrlMatch() only accepts strings or regexps");
682
- }
683
- return this.assert(result, message, {
684
- type: "assertUrlMatch",
685
- standard: "Current url matches the provided pattern",
686
- values: {
687
- currentUrl: currentUrl,
688
- pattern: pattern.toString()
689
- }
690
- });
691
- };
692
-
693
- /**
694
- * Asserts that a selector expression is currently visible.
695
- *
696
- * @param String expected selector expression
697
- * @param String message Test description
698
- * @return Object An assertion result object
699
- */
700
- Tester.prototype.assertVisible = function assertVisible(selector, message) {
701
- "use strict";
702
- return this.assert(this.casper.visible(selector), message, {
703
- type: "assertVisible",
704
- standard: "Selector is visible",
705
- values: {
706
- selector: selector
707
- }
708
- });
709
- };
710
-
711
- /**
712
- * Prints out a colored bar onto the console.
713
- *
714
- */
715
- Tester.prototype.bar = function bar(text, style) {
716
- "use strict";
717
- this.casper.echo(text, style, this.options.pad);
718
- };
719
-
720
- /**
721
- * Retrieves the sum of all durations of the tests which were
722
- * executed in the current suite
723
- *
724
- * @return Number duration of all tests executed until now (in the current suite)
725
- */
726
- Tester.prototype.calculateSuiteDuration = function calculateSuiteDuration() {
727
- "use strict";
728
- return this.testResults.passesTime.concat(this.testResults.failuresTime).reduce(function add(a, b) {
729
- return a + b;
730
- }, 0);
731
- };
732
-
733
- /**
734
- * Render a colorized output. Basically a proxy method for
735
- * Casper.Colorizer#colorize()
736
- */
737
- Tester.prototype.colorize = function colorize(message, style) {
738
- "use strict";
739
- return this.casper.getColorizer().colorize(message, style);
740
- };
741
-
742
- /**
743
- * Writes a comment-style formatted message to stdout.
744
- *
745
- * @param String message
746
- */
747
- Tester.prototype.comment = function comment(message) {
748
- "use strict";
749
- this.casper.echo('# ' + message, 'COMMENT');
750
- };
751
-
752
- /**
753
- * Configure casper callbacks for testing purpose.
754
- *
755
- */
756
- Tester.prototype.configure = function configure() {
757
- "use strict";
758
- var tester = this;
759
-
760
- // Do not hook casper if we're not testing
761
- if (!phantom.casperTest) {
762
- return;
763
- }
764
-
765
- // specific timeout callbacks
766
- this.casper.options.onStepTimeout = function test_onStepTimeout(timeout, step) {
767
- tester.fail(f("Step timeout occured at step %s (%dms)", step, timeout));
768
- };
769
-
770
- this.casper.options.onTimeout = function test_onTimeout(timeout) {
771
- tester.fail(f("Timeout occured (%dms)", timeout));
772
- };
773
-
774
- this.casper.options.onWaitTimeout = function test_onWaitTimeout(timeout) {
775
- tester.fail(f("Wait timeout occured (%dms)", timeout));
776
- };
777
- };
778
-
779
- /**
780
- * Declares the current test suite done.
781
- *
782
- * @param Number planned Number of planned tests
783
- */
784
- Tester.prototype.done = function done(planned) {
785
- "use strict";
786
- if (planned > 0 && planned !== this.executed) {
787
- this.fail(f('%s: %d tests planned, %d tests executed',
788
- this.currentTestFile, planned, this.executed));
789
- }
790
- this.emit('test.done');
791
- this.running = false;
792
- };
793
-
794
- /**
795
- * Writes an error-style formatted message to stdout.
796
- *
797
- * @param String message
798
- */
799
- Tester.prototype.error = function error(message) {
800
- "use strict";
801
- this.casper.echo(message, 'ERROR');
802
- };
803
-
804
- /**
805
- * Executes a file, wraping and evaluating its code in an isolated
806
- * environment where only the current `casper` instance is passed.
807
- *
808
- * @param String file Absolute path to some js/coffee file
809
- */
810
- Tester.prototype.exec = function exec(file) {
811
- "use strict";
812
- file = this.filter('exec.file', file) || file;
813
- if (!fs.isFile(file) || !utils.isJsFile(file)) {
814
- var e = new CasperError(f("Cannot exec %s: can only exec() files with .js or .coffee extensions", file));
815
- e.fileName = file;
816
- throw e;
817
- }
818
- this.currentTestFile = file;
819
- phantom.injectJs(file);
820
- };
821
-
822
- /**
823
- * Adds a failed test entry to the stack.
824
- *
825
- * @param String message
826
- */
827
- Tester.prototype.fail = function fail(message) {
828
- "use strict";
829
- return this.assert(false, message, {
830
- type: "fail",
831
- standard: "explicit call to fail()"
832
- });
833
- };
834
-
835
- /**
836
- * Recursively finds all test files contained in a given directory.
837
- *
838
- * @param String dir Path to some directory to scan
839
- */
840
- Tester.prototype.findTestFiles = function findTestFiles(dir) {
841
- "use strict";
842
- var self = this;
843
- if (!fs.isDirectory(dir)) {
844
- return [];
845
- }
846
- var entries = fs.list(dir).filter(function _filter(entry) {
847
- return entry !== '.' && entry !== '..';
848
- }).map(function _map(entry) {
849
- return fs.absolute(fs.pathJoin(dir, entry));
850
- });
851
- entries.forEach(function _forEach(entry) {
852
- if (fs.isDirectory(entry)) {
853
- entries = entries.concat(self.findTestFiles(entry));
854
- }
855
- });
856
- return entries.filter(function _filter(entry) {
857
- return utils.isJsFile(fs.absolute(fs.pathJoin(dir, entry)));
858
- }).sort();
859
- };
860
-
861
- /**
862
- * Formats a message to highlight some parts of it.
863
- *
864
- * @param String message
865
- * @param String style
866
- */
867
- Tester.prototype.formatMessage = function formatMessage(message, style) {
868
- "use strict";
869
- var parts = /^([a-z0-9_\.]+\(\))(.*)/i.exec(message);
870
- if (!parts) {
871
- return message;
872
- }
873
- return this.colorize(parts[1], 'PARAMETER') + this.colorize(parts[2], style);
874
- };
875
-
876
- /**
877
- * Retrieves current failure data and all failed cases.
878
- *
879
- * @return Object casedata An object containg information about cases
880
- * @return Number casedata.length The number of failed cases
881
- * @return Array casedata.cases An array of all the failed case objects
882
- */
883
- Tester.prototype.getFailures = function getFailures() {
884
- "use strict";
885
- return {
886
- length: this.testResults.failed,
887
- cases: this.testResults.failures
888
- };
889
- };
890
-
891
- /**
892
- * Retrieves current passed data and all passed cases.
893
- *
894
- * @return Object casedata An object containg information about cases
895
- * @return Number casedata.length The number of passed cases
896
- * @return Array casedata.cases An array of all the passed case objects
897
- */
898
- Tester.prototype.getPasses = function getPasses() {
899
- "use strict";
900
- return {
901
- length: this.testResults.passed,
902
- cases: this.testResults.passes
903
- };
904
- };
905
-
906
- /**
907
- * Retrieves the array where all the durations of failed tests are stored
908
- *
909
- * @return Array durations of failed tests
910
- */
911
- Tester.prototype.getFailuresTime = function getFailuresTime() {
912
- "use strict";
913
- return this.testResults.failuresTime;
914
- }
915
-
916
- /**
917
- * Retrieves the array where all the durations of passed tests are stored
918
- *
919
- * @return Array durations of passed tests
920
- */
921
- Tester.prototype.getPassesTime = function getPassesTime() {
922
- "use strict";
923
- return this.testResults.passesTime;
924
- }
925
-
926
-
927
- /**
928
- * Writes an info-style formatted message to stdout.
929
- *
930
- * @param String message
931
- */
932
- Tester.prototype.info = function info(message) {
933
- "use strict";
934
- this.casper.echo(message, 'PARAMETER');
935
- };
936
-
937
- /**
938
- * Adds a successful test entry to the stack.
939
- *
940
- * @param String message
941
- */
942
- Tester.prototype.pass = function pass(message) {
943
- "use strict";
944
- return this.assert(true, message, {
945
- type: "pass",
946
- standard: "explicit call to pass()"
947
- });
948
- };
949
-
950
- /**
951
- * Processes an assertion result by emitting the appropriate event and
952
- * printing result onto the console.
953
- *
954
- * @param Object result An assertion result object
955
- * @return Object The passed assertion result Object
956
- */
957
- Tester.prototype.processAssertionResult = function processAssertionResult(result) {
958
- "use strict";
959
- var eventName= 'success',
960
- message = result.message || result.standard,
961
- style = 'INFO',
962
- status = this.options.passText;
963
- if (!result.success) {
964
- eventName = 'fail';
965
- style = 'RED_BAR';
966
- status = this.options.failText;
967
- this.testResults.failed++;
968
- } else {
969
- this.testResults.passed++;
970
- }
971
- this.casper.echo([this.colorize(status, style), this.formatMessage(message)].join(' '));
972
- this.emit(eventName, result);
973
- if (this.options.failFast && !result.success) {
974
- throw this.SKIP_MESSAGE;
975
- }
976
- return result;
977
- };
978
-
979
- /**
980
- * Renders a detailed report for each failed test.
981
- *
982
- * @param Array failures
983
- */
984
- Tester.prototype.renderFailureDetails = function renderFailureDetails(failures) {
985
- "use strict";
986
- if (failures.length === 0) {
987
- return;
988
- }
989
- this.casper.echo(f("\nDetails for the %d failed test%s:\n", failures.length, failures.length > 1 ? "s" : ""), "PARAMETER");
990
- failures.forEach(function _forEach(failure) {
991
- var type, message, line;
992
- type = failure.type || "unknown";
993
- line = ~~failure.line;
994
- message = failure.message;
995
- this.casper.echo(f('In %s:%s', failure.file, line));
996
- this.casper.echo(f(' %s: %s', type, message || failure.standard || "(no message was entered)"), "COMMENT");
997
- }.bind(this));
998
- };
999
-
1000
- /**
1001
- * Render tests results, an optionally exit phantomjs.
1002
- *
1003
- * @param Boolean exit
1004
- */
1005
- Tester.prototype.renderResults = function renderResults(exit, status, save) {
1006
- "use strict";
1007
- /*jshint maxstatements:20*/
1008
- save = save || this.options.save;
1009
- var total = this.testResults.passed + this.testResults.failed, statusText, style, result;
1010
- var exitStatus = ~~(status || (this.testResults.failed > 0 ? 1 : 0));
1011
- if (total === 0) {
1012
- statusText = this.options.warnText;
1013
- style = 'WARN_BAR';
1014
- result = f("%s Looks like you didn't run any test.", statusText);
1015
- } else {
1016
- if (this.testResults.failed > 0) {
1017
- statusText = this.options.failText;
1018
- style = 'RED_BAR';
1019
- } else {
1020
- statusText = this.options.passText;
1021
- style = 'GREEN_BAR';
1022
- }
1023
- result = f('%s %s tests executed in %ss, %d passed, %d failed.',
1024
- statusText, total, utils.ms2seconds(this.calculateSuiteDuration()),
1025
- this.testResults.passed, this.testResults.failed);
1026
- }
1027
- this.casper.echo(result, style, this.options.pad);
1028
- if (this.testResults.failed > 0) {
1029
- this.renderFailureDetails(this.testResults.failures);
1030
- }
1031
- if (save) {
1032
- this.saveResults(save);
1033
- }
1034
- if (exit === true) {
1035
- this.casper.exit(exitStatus);
1036
- }
1037
- };
1038
-
1039
- /**
1040
- * Runs al suites contained in the paths passed as arguments.
1041
- *
1042
- */
1043
- Tester.prototype.runSuites = function runSuites() {
1044
- "use strict";
1045
- var testFiles = [], self = this;
1046
- if (arguments.length === 0) {
1047
- throw new CasperError("runSuites() needs at least one path argument");
1048
- }
1049
- this.loadIncludes.includes.forEach(function _forEachInclude(include) {
1050
- phantom.injectJs(include);
1051
- });
1052
-
1053
- this.loadIncludes.pre.forEach(function _forEachPreTest(preTestFile) {
1054
- testFiles = testFiles.concat(preTestFile);
1055
- });
1056
-
1057
- Array.prototype.forEach.call(arguments, function _forEachArgument(path) {
1058
- if (!fs.exists(path)) {
1059
- self.bar(f("Path %s doesn't exist", path), "RED_BAR");
1060
- }
1061
- if (fs.isDirectory(path)) {
1062
- testFiles = testFiles.concat(self.findTestFiles(path));
1063
- } else if (fs.isFile(path)) {
1064
- testFiles.push(path);
1065
- }
1066
- });
1067
-
1068
- this.loadIncludes.post.forEach(function _forEachPostTest(postTestFile) {
1069
- testFiles = testFiles.concat(postTestFile);
1070
- });
1071
-
1072
- if (testFiles.length === 0) {
1073
- this.bar(f("No test file found in %s, aborting.", Array.prototype.slice.call(arguments)), "RED_BAR");
1074
- this.casper.exit(1);
1075
- }
1076
- self.currentSuiteNum = 0;
1077
- self.currentTestStartTime = new Date();
1078
- self.lastAssertTime = 0;
1079
- var interval = setInterval(function _check(self) {
1080
- if (self.running) {
1081
- return;
1082
- }
1083
- if (self.currentSuiteNum === testFiles.length || self.aborted) {
1084
- self.emit('tests.complete');
1085
- clearInterval(interval);
1086
- self.exporter.setSuiteDuration(self.calculateSuiteDuration());
1087
- self.aborted = false;
1088
- } else {
1089
- self.runTest(testFiles[self.currentSuiteNum]);
1090
- self.exporter.setSuiteDuration(self.calculateSuiteDuration());
1091
- self.currentSuiteNum++;
1092
- self.passesTime = [];
1093
- self.failuresTime = [];
1094
- }
1095
- }, 100, this);
1096
- };
1097
-
1098
- /**
1099
- * Runs a test file
1100
- *
1101
- */
1102
- Tester.prototype.runTest = function runTest(testFile) {
1103
- "use strict";
1104
- this.bar(f('Test file: %s', testFile), 'INFO_BAR');
1105
- this.running = true; // this.running is set back to false with done()
1106
- this.executed = 0;
1107
- this.exec(testFile);
1108
- };
1109
-
1110
- /**
1111
- * Saves results to file.
1112
- *
1113
- * @param String filename Target file path.
1114
- */
1115
- Tester.prototype.saveResults = function saveResults(filepath) {
1116
- "use strict";
1117
- // FIXME: looks like phantomjs has a pb with fs.isWritable https://groups.google.com/forum/#!topic/casperjs/hcUdwgGZOrU
1118
- // if (!fs.isWritable(filepath)) {
1119
- // throw new CasperError(f('Path %s is not writable.', filepath));
1120
- // }
1121
- try {
1122
- fs.write(filepath, this.exporter.getXML(), 'w');
1123
- this.casper.echo(f('Result log stored in %s', filepath), 'INFO', 80);
1124
- } catch (e) {
1125
- this.casper.echo(f('Unable to write results to %s: %s', filepath, e), 'ERROR', 80);
1126
- }
1127
- };
1128
-
1129
- /**
1130
- * Tests equality between the two passed arguments.
1131
- *
1132
- * @param Mixed v1
1133
- * @param Mixed v2
1134
- * @param Boolean
1135
- */
1136
- Tester.prototype.testEquals = Tester.prototype.testEqual = function testEquals(v1, v2) {
1137
- "use strict";
1138
- return utils.equals(v1, v2);
1139
- };
1140
-
1141
- /**
1142
- * Processes an error caught while running tests contained in a given test
1143
- * file.
1144
- *
1145
- * @param Error|String error The error
1146
- * @param String file Test file where the error occurred
1147
- * @param Number line Line number (optional)
1148
- */
1149
- Tester.prototype.uncaughtError = function uncaughtError(error, file, line) {
1150
- "use strict";
1151
- return this.processAssertionResult({
1152
- success: false,
1153
- type: "uncaughtError",
1154
- file: file,
1155
- line: ~~line || "unknown",
1156
- message: utils.isObject(error) ? error.message : error,
1157
- values: {
1158
- error: error
1159
- }
1160
- });
1161
- };