Commit e6c7469f e6c7469f7318174b1cc6a620acf6c53bbcd5cc59 by Nicolas Perriault

introduced global setUp() and tearDown() hooks

1 parent 19a08203
...@@ -66,7 +66,37 @@ casper.test.begin('Casperjs.org is navigable', 2, function suite(test) { ...@@ -66,7 +66,37 @@ casper.test.begin('Casperjs.org is navigable', 2, function suite(test) {
66 }); 66 });
67 ``` 67 ```
68 68
69 `Tester#begin()` has also `setUp()` and `tearDown()` capabilities if you pass it a configuration object instead of a function: 69 [`Tester#setUp()`](docs.casperjs.org/en/latest/modules/tester.html#setup) and [`Tester#tearDown()`](docs.casperjs.org/en/latest/modules/tester.html#teardown) methods have been also added in order to ease the definition of operations to be performed before and after each test defined using `Tester#begin()`:
70
71 ```js
72 casper.test.setUp(function() {
73 console.log('executed before each test');
74 });
75
76 casper.test.tearDown(function() {
77 console.log('executed after each test');
78 });
79 ```
80
81 Both can work asynchronously as well of you define the `done` argument:
82
83 ```js
84 casper.test.setUp(function(done) {
85 setTimeout(function() {
86 console.log('asynchronously executed before each test');
87 done();
88 }, 1000);
89 });
90
91 casper.test.tearDown(function(done) {
92 setTimeout(function() {
93 console.log('asynchronously executed after each test');
94 done();
95 }, 1000);
96 });
97 ```
98
99 `Tester#begin()` itself has also local `setUp()` and `tearDown()` capabilities if you pass it a configuration object instead of a function:
70 100
71 ```js 101 ```js
72 casper.test.begin('range tests', 1, { 102 casper.test.begin('range tests', 1, {
...@@ -75,9 +105,11 @@ casper.test.begin('range tests', 1, { ...@@ -75,9 +105,11 @@ casper.test.begin('range tests', 1, {
75 setUp: function(test) { 105 setUp: function(test) {
76 this.range.push(3); 106 this.range.push(3);
77 }, 107 },
108
78 tearDown: function(test) { 109 tearDown: function(test) {
79 range = []; 110 range = [];
80 }, 111 },
112
81 test: function(test) { 113 test: function(test) {
82 test.assertEquals(range.length, 3); 114 test.assertEquals(range.length, 3);
83 test.done(); 115 test.done();
...@@ -85,7 +117,7 @@ casper.test.begin('range tests', 1, { ...@@ -85,7 +117,7 @@ casper.test.begin('range tests', 1, {
85 }); 117 });
86 ``` 118 ```
87 119
88 Also, scraping and testing are now betterly separated in CasperJS, and bad code is now a bit less bad. That involves breaking up BC on some points though: 120 Scraping and testing are now better separated in CasperJS. That involves breaking up BC on some points though:
89 121
90 - The Casper object won't be created with a `test` reference if not invoked using the [`casperjs test` command](http://casperjs.org/testing.html#casper-test-command), therefore the ability to run any test without calling it has been dropped. I know, get over it. 122 - The Casper object won't be created with a `test` reference if not invoked using the [`casperjs test` command](http://casperjs.org/testing.html#casper-test-command), therefore the ability to run any test without calling it has been dropped. I know, get over it.
91 - Passing the planned number of tests to `casper.done()` has been dropped as well, because `done()` may be never called at all when big troubles happen; rather use the new `begin()` method and provide the expected number of tests using the second argument: 123 - Passing the planned number of tests to `casper.done()` has been dropped as well, because `done()` may be never called at all when big troubles happen; rather use the new `begin()` method and provide the expected number of tests using the second argument:
......
...@@ -761,6 +761,31 @@ Render test results, save results in an XUnit formatted file, and optionally exi ...@@ -761,6 +761,31 @@ Render test results, save results in an XUnit formatted file, and optionally exi
761 761
762 This method is not to be called when using the ``casperjs test`` command (see documentation for :doc:`testing <../testing>`), where it's done automatically for you. 762 This method is not to be called when using the ``casperjs test`` command (see documentation for :doc:`testing <../testing>`), where it's done automatically for you.
763 763
764 ``setUp()``
765 -------------------------------------------------------------------------------
766
767 **Signature:** ``setUp([Function fn])``
768
769 Defines a function which will be executed before every test defined using `begin()`_::
770
771 casper.test.setUp(function() {
772 casper.start().userAgent('Mosaic 0.1');
773 });
774
775 To perform asynchronous operations, use the ``done`` argument::
776
777 casper.test.setUp(function(done) {
778 casper.start('http://foo').then(function() {
779 // ...
780 }).run(done);
781 });
782
783 .. warning::
784
785 Don't specify the ``done`` argument if you don't intend to use the method asynchronously.
786
787 .. seealso:: `tearDown()`_
788
764 ``skip()`` 789 ``skip()``
765 ------------------------------------------------------------------------------- 790 -------------------------------------------------------------------------------
766 791
...@@ -774,3 +799,28 @@ Skips a given number of planned tests:: ...@@ -774,3 +799,28 @@ Skips a given number of planned tests::
774 test.skip(2, 'Two tests skipped'); 799 test.skip(2, 'Two tests skipped');
775 test.done(); 800 test.done();
776 }); 801 });
802
803 ``tearDown()``
804 -------------------------------------------------------------------------------
805
806 **Signature:** ``tearDown([Function fn])``
807
808 Defines a function which will be executed before after every test defined using `begin()`_::
809
810 casper.test.tearDown(function() {
811 casper.echo('See ya');
812 });
813
814 To perform asynchronous operations, use the ``done`` argument::
815
816 casper.test.tearDown(function(done) {
817 casper.start('http://foo/goodbye').then(function() {
818 // ...
819 }).run(done);
820 });
821
822 .. warning::
823
824 Don't specify the ``done`` argument if you don't intend to use the method asynchronously.
825
826 .. seealso:: `setUp()`_
......
...@@ -96,6 +96,8 @@ var Tester = function Tester(casper, options) { ...@@ -96,6 +96,8 @@ var Tester = function Tester(casper, options) {
96 this.casper = casper; 96 this.casper = casper;
97 97
98 // public properties 98 // public properties
99 this._setUp = undefined;
100 this._tearDown = undefined;
99 this.aborted = false; 101 this.aborted = false;
100 this.executed = 0; 102 this.executed = 0;
101 this.currentTestFile = null; 103 this.currentTestFile = null;
...@@ -892,27 +894,44 @@ Tester.prototype.bar = function bar(text, style) { ...@@ -892,27 +894,44 @@ Tester.prototype.bar = function bar(text, style) {
892 }; 894 };
893 895
894 /** 896 /**
895 * Starts a suite. 897 * Defines a function which will be executed before every test.
896 * 898 *
897 * Can be invoked two different ways: 899 * @param Function fn
900 */
901 Tester.prototype.setUp = function setUp(fn) {
902 "use strict";
903 this._setUp = fn;
904 };
905
906 /**
907 * Defines a function which will be executed after every test.
898 * 908 *
899 * casper.test.begin("suite description", plannedTests, function(test){}) 909 * @param Function fn
910 */
911 Tester.prototype.tearDown = function tearDown(fn) {
912 "use strict";
913 this._tearDown = fn;
914 };
915
916 /**
917 * Starts a suite.
900 * 918 *
901 * Or: 919 * Can be invoked different ways:
902 * 920 *
921 * casper.test.begin("suite description", plannedTests, function(test){})
903 * casper.test.begin("suite description", function(test){}) 922 * casper.test.begin("suite description", function(test){})
904 *
905 */ 923 */
906 Tester.prototype.begin = function begin() { 924 Tester.prototype.begin = function begin() {
907 "use strict"; 925 "use strict";
908 if (this.started && this.running) { 926 if (this.started && this.running)
909 return this.queue.push(arguments); 927 return this.queue.push(arguments);
910 } 928
911 function getConfig(args) { 929 function getConfig(args) {
912 var config = { 930 var config = {
913 setUp: function(){}, 931 setUp: function(){},
914 tearDown: function(){} 932 tearDown: function(){}
915 }; 933 };
934
916 if (utils.isFunction(args[1])) { 935 if (utils.isFunction(args[1])) {
917 config.test = args[1]; 936 config.test = args[1];
918 } else if (utils.isObject(args[1])) { 937 } else if (utils.isObject(args[1])) {
...@@ -926,42 +945,56 @@ Tester.prototype.begin = function begin() { ...@@ -926,42 +945,56 @@ Tester.prototype.begin = function begin() {
926 } else { 945 } else {
927 throw new CasperError('Invalid call'); 946 throw new CasperError('Invalid call');
928 } 947 }
929 if (!utils.isFunction(config.test)) { 948
949 if (!utils.isFunction(config.test))
930 throw new CasperError('begin() is missing a mandatory test function'); 950 throw new CasperError('begin() is missing a mandatory test function');
931 } 951
932 return config; 952 return config;
933 } 953 }
954
934 var description = arguments[0] || f("Untitled suite in %s", this.currentTestFile), 955 var description = arguments[0] || f("Untitled suite in %s", this.currentTestFile),
935 config = getConfig([].slice.call(arguments)); 956 config = getConfig([].slice.call(arguments)),
936 if (!this.options.concise) { 957 next = function() {
958 config.test(this, this.casper);
959 if (this.options.concise)
960 this.casper.echo([
961 this.colorize('PASS', 'INFO'),
962 this.formatMessage(description),
963 this.colorize(f('(%d test%s)',
964 config.planned,
965 config.planned > 1 ? 's' : ''), 'INFO')
966 ].join(' '));
967 }.bind(this);
968
969 if (!this.options.concise)
937 this.comment(description); 970 this.comment(description);
938 } 971
939 this.currentSuite = new TestCaseResult({ 972 this.currentSuite = new TestCaseResult({
940 name: description, 973 name: description,
941 file: this.currentTestFile, 974 file: this.currentTestFile,
942 config: config, 975 config: config,
943 planned: config.planned || undefined 976 planned: config.planned || undefined
944 }); 977 });
978
945 this.executed = 0; 979 this.executed = 0;
946 this.running = this.started = true; 980 this.running = this.started = true;
981
947 try { 982 try {
948 if (config.setUp) { 983 if (config.setUp)
949 config.setUp(this, this.casper); 984 config.setUp(this, this.casper);
950 } 985
951 config.test(this, this.casper); 986 if (!this._setUp)
987 return next();
988
989 if (this._setUp.length > 0)
990 return this._setUp.call(this, next); // async
991
992 this._setUp.call(this); // sync
993 next();
952 } catch (err) { 994 } catch (err) {
953 this.processError(err); 995 this.processError(err);
954 this.done(); 996 this.done();
955 } 997 }
956 if (this.options.concise) {
957 this.casper.echo([
958 this.colorize('PASS', 'INFO'),
959 this.formatMessage(description),
960 this.colorize(f('(%d test%s)',
961 config.planned,
962 config.planned > 1 ? 's' : ''), 'INFO')
963 ].join(' '));
964 }
965 }; 998 };
966 999
967 /** 1000 /**
...@@ -995,10 +1028,12 @@ Tester.prototype.done = function done() { ...@@ -995,10 +1028,12 @@ Tester.prototype.done = function done() {
995 "use strict"; 1028 "use strict";
996 /*jshint maxstatements:20, maxcomplexity:20*/ 1029 /*jshint maxstatements:20, maxcomplexity:20*/
997 var planned, config = this.currentSuite && this.currentSuite.config || {}; 1030 var planned, config = this.currentSuite && this.currentSuite.config || {};
1031
998 if (utils.isNumber(arguments[0])) { 1032 if (utils.isNumber(arguments[0])) {
999 this.casper.warn('done() `planned` arg is deprecated as of 1.1'); 1033 this.casper.warn('done() `planned` arg is deprecated as of 1.1');
1000 planned = arguments[0]; 1034 planned = arguments[0];
1001 } 1035 }
1036
1002 if (config && config.tearDown && utils.isFunction(config.tearDown)) { 1037 if (config && config.tearDown && utils.isFunction(config.tearDown)) {
1003 try { 1038 try {
1004 config.tearDown(this, this.casper); 1039 config.tearDown(this, this.casper);
...@@ -1006,6 +1041,8 @@ Tester.prototype.done = function done() { ...@@ -1006,6 +1041,8 @@ Tester.prototype.done = function done() {
1006 this.processError(error); 1041 this.processError(error);
1007 } 1042 }
1008 } 1043 }
1044
1045 var next = function() {
1009 if (this.currentSuite && this.currentSuite.planned && 1046 if (this.currentSuite && this.currentSuite.planned &&
1010 this.currentSuite.planned !== this.executed + this.currentSuite.skipped && 1047 this.currentSuite.planned !== this.executed + this.currentSuite.skipped &&
1011 !this.currentSuite.failed) { 1048 !this.currentSuite.failed) {
...@@ -1026,6 +1063,24 @@ Tester.prototype.done = function done() { ...@@ -1026,6 +1063,24 @@ Tester.prototype.done = function done() {
1026 if (nextTest) { 1063 if (nextTest) {
1027 this.begin.apply(this, nextTest); 1064 this.begin.apply(this, nextTest);
1028 } 1065 }
1066 }.bind(this);
1067
1068 if (!this._tearDown) {
1069 return next();
1070 }
1071
1072 try {
1073 if (this._tearDown.length > 0) {
1074 // async
1075 this._tearDown.call(this, next);
1076 } else {
1077 // sync
1078 this._tearDown.call(this);
1079 next();
1080 }
1081 } catch (error) {
1082 this.processError(error);
1083 }
1029 }; 1084 };
1030 1085
1031 /** 1086 /**
......
1 /*global casper*/
2 /*jshint strict:false*/
3
4 var setUp, tearDown;
5
6 casper.test.setUp(function(done) {
7 setTimeout(function() {
8 setUp = true;
9 done();
10 }, 50);
11 });
12
13 casper.test.tearDown(function(done) {
14 setTimeout(function() {
15 tearDown = true;
16 done();
17 }, 50);
18 });
19
20 casper.test.begin('setUp() tests', 1, function(test) {
21 test.assertTrue(setUp, 'Tester.setUp() executed the async setup function');
22 test.done();
23 });
24
25 casper.test.begin('tearDown() tests', 1, function(test) {
26 test.assertTrue(tearDown, 'Tester.tearDown() executed the async tear down function');
27 // reset
28 test.setUp();
29 test.tearDown();
30 test.done();
31 });
1 /*global casper*/
2 /*jshint strict:false*/
3
4 var setUp, tearDown;
5
6 casper.test.setUp(function() {
7 setUp = true;
8 });
9
10 casper.test.tearDown(function() {
11 tearDown = true;
12 });
13
14 casper.test.begin('setUp() tests', 1, function(test) {
15 test.assertTrue(setUp, 'Tester.setUp() executed the setup function');
16 test.done();
17 });
18
19 casper.test.begin('tearDown() tests', 1, function(test) {
20 test.assertTrue(tearDown, 'Tester.tearDown() executed the tear down function');
21 // reset
22 test.setUp();
23 test.tearDown();
24 test.done();
25 });