Commit 491d40ff 491d40ff5d5501f01caab7af1adb0973c5d015c5 by Nicolas Perriault

fixed #215 - added a `--fail-fast` option to `casper test`

In order to terminate a test suite execution as soon as any
failure is encountered.
1 parent 83e3f84e
...@@ -5,6 +5,7 @@ XXXX-XX-XX, v1.0.0 ...@@ -5,6 +5,7 @@ XXXX-XX-XX, v1.0.0
5 ------------------ 5 ------------------
6 6
7 - fixed [#266](https://github.com/n1k0/casperjs/issues/266) - Fix `tester` module and its self tests 7 - fixed [#266](https://github.com/n1k0/casperjs/issues/266) - Fix `tester` module and its self tests
8 - fixed [#215](https://github.com/n1k0/casperjs/issues/215) - added a `--fail-fast` option to the `casper test` command, in order to terminate a test suite execution as soon as any failure is encountered
8 - added `Tester.assertFalse()` as an alias of `Tester.assertNot()` 9 - added `Tester.assertFalse()` as an alias of `Tester.assertNot()`
9 10
10 2012-10-31, v1.0.0-RC4 11 2012-10-31, v1.0.0-RC4
......
...@@ -154,6 +154,9 @@ var Casper = function Casper(options) { ...@@ -154,6 +154,9 @@ var Casper = function Casper(options) {
154 this.initErrorHandler(); 154 this.initErrorHandler();
155 155
156 this.on('error', function(msg, backtrace) { 156 this.on('error', function(msg, backtrace) {
157 if (msg === this.test.SKIP_MESSAGE) {
158 return this.warn(f('--fail-fast: aborted remaining tests in "%s"', this.test.currentTestFile));
159 }
157 var c = this.getColorizer(); 160 var c = this.getColorizer();
158 var match = /^(.*): __mod_error(.*):: (.*)/.exec(msg); 161 var match = /^(.*): __mod_error(.*):: (.*)/.exec(msg);
159 var notices = []; 162 var notices = [];
......
...@@ -55,6 +55,8 @@ var Tester = function Tester(casper, options) { ...@@ -55,6 +55,8 @@ var Tester = function Tester(casper, options) {
55 55
56 this.casper = casper; 56 this.casper = casper;
57 57
58 this.SKIP_MESSAGE = '__termination__';
59
58 this.currentTestFile = null; 60 this.currentTestFile = null;
59 this.currentSuiteNum = 0; 61 this.currentSuiteNum = 0;
60 this.exporter = require('xunit').create(); 62 this.exporter = require('xunit').create();
...@@ -66,6 +68,7 @@ var Tester = function Tester(casper, options) { ...@@ -66,6 +68,7 @@ var Tester = function Tester(casper, options) {
66 this.running = false; 68 this.running = false;
67 this.suites = []; 69 this.suites = [];
68 this.options = utils.mergeObjects({ 70 this.options = utils.mergeObjects({
71 failFast: false, // terminates a suite as soon as a test fails?
69 failText: "FAIL", // text to use for a successful test 72 failText: "FAIL", // text to use for a successful test
70 passText: "PASS", // text to use for a failed test 73 passText: "PASS", // text to use for a failed test
71 pad: 80 // maximum number of chars for a result line 74 pad: 80 // maximum number of chars for a result line
...@@ -648,11 +651,13 @@ Tester.prototype.configure = function configure() { ...@@ -648,11 +651,13 @@ Tester.prototype.configure = function configure() {
648 651
649 // events 652 // events
650 this.casper.on('error', function(msg, backtrace) { 653 this.casper.on('error', function(msg, backtrace) {
654 if (!utils.isString(msg) && msg.indexOf(this.SKIP_MESSAGE) === -1) {
651 var line = 0; 655 var line = 0;
652 try { 656 try {
653 line = backtrace[0].line; 657 line = backtrace[0].line;
654 } catch (e) {} 658 } catch (e) {}
655 tester.uncaughtError(msg, tester.currentTestFile, line); 659 tester.uncaughtError(msg, tester.currentTestFile, line);
660 }
656 tester.done(); 661 tester.done();
657 }); 662 });
658 663
...@@ -816,21 +821,23 @@ Tester.prototype.pass = function pass(message) { ...@@ -816,21 +821,23 @@ Tester.prototype.pass = function pass(message) {
816 */ 821 */
817 Tester.prototype.processAssertionResult = function processAssertionResult(result) { 822 Tester.prototype.processAssertionResult = function processAssertionResult(result) {
818 "use strict"; 823 "use strict";
819 var eventName, style, status; 824 var eventName= 'success',
820 if (result.success === true) { 825 message = result.message || result.standard,
821 eventName = 'success'; 826 style = 'INFO',
822 style = 'INFO';
823 status = this.options.passText; 827 status = this.options.passText;
824 this.testResults.passed++; 828 if (!result.success) {
825 } else {
826 eventName = 'fail'; 829 eventName = 'fail';
827 style = 'RED_BAR'; 830 style = 'RED_BAR';
828 status = this.options.failText; 831 status = this.options.failText;
829 this.testResults.failed++; 832 this.testResults.failed++;
833 } else {
834 this.testResults.passed++;
830 } 835 }
831 var message = result.message || result.standard;
832 this.casper.echo([this.colorize(status, style), this.formatMessage(message)].join(' ')); 836 this.casper.echo([this.colorize(status, style), this.formatMessage(message)].join(' '));
833 this.emit(eventName, result); 837 this.emit(eventName, result);
838 if (this.options.failFast && !result.success) {
839 throw this.SKIP_MESSAGE;
840 }
834 return result; 841 return result;
835 }; 842 };
836 843
......
...@@ -60,6 +60,7 @@ if (casper.cli.get('no-colors') === true) { ...@@ -60,6 +60,7 @@ if (casper.cli.get('no-colors') === true) {
60 casper.options.colorizerType = cls; 60 casper.options.colorizerType = cls;
61 casper.colorizer = colorizer.create(cls); 61 casper.colorizer = colorizer.create(cls);
62 } 62 }
63 casper.test.options.failFast = casper.cli.get('fail-fast') || false;
63 64
64 // test paths are passed as args 65 // test paths are passed as args
65 if (casper.cli.args.length) { 66 if (casper.cli.args.length) {
...@@ -97,6 +98,9 @@ this.loadIncludes.forEach(function(include){ ...@@ -97,6 +98,9 @@ this.loadIncludes.forEach(function(include){
97 casper.test.on('tests.complete', function() { 98 casper.test.on('tests.complete', function() {
98 "use strict"; 99 "use strict";
99 this.renderResults(true, undefined, casper.cli.get('xunit') || undefined); 100 this.renderResults(true, undefined, casper.cli.get('xunit') || undefined);
101 if (this.options.failFast && this.testResults.failures.length > 0) {
102 casper.warn('Test suite failed fast, all tests may not have been executed.');
103 }
100 }); 104 });
101 105
102 // run all the suites 106 // run all the suites
......
...@@ -27,7 +27,7 @@ var codes = [100, 101, 102, 118, 200, 201, 202, 203, 204, 205, 206, 207, 210, ...@@ -27,7 +27,7 @@ var codes = [100, 101, 102, 118, 200, 201, 202, 203, 204, 205, 206, 207, 210,
27 414, 415, 416, 417, 418, 422, 423, 424, 425, 426, 449, 450, 27 414, 415, 416, 417, 418, 422, 423, 424, 425, 426, 449, 450,
28 500, 501, 502, 503, 504, 505, 507, 509]; 28 500, 501, 502, 503, 504, 505, 507, 509];
29 29
30 casper.thenOpen('http://google.com').each(codes, function(self, code) { 30 casper.each(codes, function(self, code) {
31 if (code === 100) { 31 if (code === 100) {
32 // HTTP 100 is CONTINUE, so don't expect a terminated response 32 // HTTP 100 is CONTINUE, so don't expect a terminated response
33 return; 33 return;
......