introduced global setUp() and tearDown() hooks
Showing
5 changed files
with
237 additions
and
44 deletions
... | @@ -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,25 +1041,45 @@ Tester.prototype.done = function done() { | ... | @@ -1006,25 +1041,45 @@ Tester.prototype.done = function done() { |
1006 | this.processError(error); | 1041 | this.processError(error); |
1007 | } | 1042 | } |
1008 | } | 1043 | } |
1009 | if (this.currentSuite && this.currentSuite.planned && | 1044 | |
1010 | this.currentSuite.planned !== this.executed + this.currentSuite.skipped && | 1045 | var next = function() { |
1011 | !this.currentSuite.failed) { | 1046 | if (this.currentSuite && this.currentSuite.planned && |
1012 | this.dubious(this.currentSuite.planned, this.executed, this.currentSuite.name); | 1047 | this.currentSuite.planned !== this.executed + this.currentSuite.skipped && |
1013 | } else if (planned && planned !== this.executed) { | 1048 | !this.currentSuite.failed) { |
1014 | // BC | 1049 | this.dubious(this.currentSuite.planned, this.executed, this.currentSuite.name); |
1015 | this.dubious(planned, this.executed); | 1050 | } else if (planned && planned !== this.executed) { |
1016 | } | 1051 | // BC |
1017 | if (this.currentSuite) { | 1052 | this.dubious(planned, this.executed); |
1018 | this.suiteResults.push(this.currentSuite); | 1053 | } |
1019 | this.currentSuite = undefined; | 1054 | if (this.currentSuite) { |
1020 | this.executed = 0; | 1055 | this.suiteResults.push(this.currentSuite); |
1056 | this.currentSuite = undefined; | ||
1057 | this.executed = 0; | ||
1058 | } | ||
1059 | this.emit('test.done'); | ||
1060 | this.casper.currentHTTPResponse = {}; | ||
1061 | this.running = this.started = false; | ||
1062 | var nextTest = this.queue.shift(); | ||
1063 | if (nextTest) { | ||
1064 | this.begin.apply(this, nextTest); | ||
1065 | } | ||
1066 | }.bind(this); | ||
1067 | |||
1068 | if (!this._tearDown) { | ||
1069 | return next(); | ||
1021 | } | 1070 | } |
1022 | this.emit('test.done'); | 1071 | |
1023 | this.casper.currentHTTPResponse = {}; | 1072 | try { |
1024 | this.running = this.started = false; | 1073 | if (this._tearDown.length > 0) { |
1025 | var nextTest = this.queue.shift(); | 1074 | // async |
1026 | if (nextTest) { | 1075 | this._tearDown.call(this, next); |
1027 | this.begin.apply(this, nextTest); | 1076 | } else { |
1077 | // sync | ||
1078 | this._tearDown.call(this); | ||
1079 | next(); | ||
1080 | } | ||
1081 | } catch (error) { | ||
1082 | this.processError(error); | ||
1028 | } | 1083 | } |
1029 | }; | 1084 | }; |
1030 | 1085 | ... | ... |
tests/suites/tester/setup-teardown-async.js
0 → 100644
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 | }); |
tests/suites/tester/setup-teardown.js
0 → 100644
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 | }); |
-
Please register or sign in to post a comment