├── README.md
├── lib
└── framework.js
└── package.json
/README.md:
--------------------------------------------------------------------------------
1 | # This repo is deprecated!!
2 | Please see the [codewars-cli](http://www.github.com/codewars/codewars-cli) project. The JS test framework is now contained within that project.
3 |
4 |
5 | kata-test-framework-js
6 | ======================
7 |
8 | The framework used by Codewars for testing kata
9 |
10 |
11 | ### About
12 | This repository has been added so that Codewars users can view the code used for testing JavaScript and CoffeeScript kata.
13 | It is a part of an initiative to open-source a portion of the site. This version of the framework is almost identical to the
14 | one used on the site, with only a few security related lines of code removed. This code is not designed to be used in any other
15 | context other than on Codewars.
16 |
17 | ### Contributions
18 | The purpose of this repo is to allow other developers the opportunity to contribute to the kata framework. Any optimizations or additions are welcome.
19 |
20 | The workflow is:
21 |
22 | - Fork this repo
23 | - Make optimizations or additions to the code base
24 | - Submit pull-request
25 |
26 | Not all pull-requests will be accepted, due mostly to size constrictions. Ideally this framework should be kept as small as possible. Once
27 | a pull-request is accepted it will need to be manually merged into the actual Codewars codebase by someone on the Codewars team.
28 |
--------------------------------------------------------------------------------
/lib/framework.js:
--------------------------------------------------------------------------------
1 | (function(exports){
2 | var methodCalls = {},
3 | html = [],
4 | consoleLog = console.log,
5 | describing = false,
6 | correct = 0,
7 | incorrect = 0,
8 | failed = [],
9 | beforeCallbacks = [],
10 | afterCallbacks = [];
11 |
12 | var _expect = function(passed, msg, options){
13 | options = options || {}
14 |
15 | if(passed){
16 | var successMsg = "Test Passed"
17 | if (options.successMsg){
18 | successMsg += ": " + options.successMsg
19 | }
20 | write(logFilter('
') + successMsg +
21 | logFilter('
', true), true)
22 | correct++
23 | } else {
24 | msg = _message(msg) || 'Invalid'
25 | // extra credit feature - TODO: complete
26 | if (options.extraCredit) {
27 | msg = (options.extraCredit !== true) ? _message(options.extraCredit) : null
28 | msg = combineMessages(["Test Missed", msg], ": ");
29 | write(logFilter("") + msg +
30 | logFilter("
", true), true)
31 | incorrect++
32 | }
33 | else{
34 | write(logFilter("Test Failed: ") + msg +
35 | logFilter("
", true), true)
36 | var error = new Test.Error(msg);
37 | if (describing){
38 | failed.push(error);
39 | }
40 | else{
41 | throw error;
42 | }
43 | }
44 | }
45 | }
46 |
47 | function logFilter( msg, lf ){
48 | // detect node.js
49 | if ( this.exports ){
50 | return msg;
51 | } else {
52 | var m = msg.replace( /<[^>].*>/g, '');
53 | // Add a LF only for empty messages that don't have the *lf* set
54 | return ( m.length == 0 && ( ! lf ) ) ? "" : m + "\n";
55 | }
56 | }
57 |
58 |
59 | function write(msg, noLineBreak){
60 | if ((msg.length == 0) && (! this.exports)){
61 | return
62 | }
63 |
64 | if (html.length == 0){
65 | console.log(msg);
66 | }
67 | else{
68 | html.push(msg);
69 | if(!noLineBreak){
70 | html.push(logFilter('
'));
71 | }
72 | }
73 | }
74 |
75 | function combineMessages(msgs, separator){
76 | return msgs.filter(function(m){return m != null;}).join(separator)
77 | }
78 |
79 | function _message(msg, prefix){
80 |
81 | if (typeof msg == 'function'){
82 | msg = msg()
83 | }else if (typeof msg == 'array'){
84 | msg = combineMessages(msg, ' - ')
85 | }
86 | return prefix ? (prefix + ' - ' + msg) : msg
87 | }
88 |
89 | function logCall(name, useConsole){
90 | methodCalls[name] = Test.callCount(name) + 1
91 |
92 | if (useConsole){
93 | console.log(name + " called");
94 | }
95 | }
96 |
97 | var Test = {
98 | callCount: function(name) {
99 | return methodCalls[name] || 0
100 | },
101 | inspect: function(obj){
102 | logCall('inspect')
103 | if(typeof obj == 'string'){
104 | return obj;
105 | } else {
106 | return obj && obj !== true ? JSON.stringify(obj) : ('' + obj)
107 | }
108 | },
109 | describe: function(msg, fn) {
110 | try{
111 | if (describing) throw "cannot call describe within another describe"
112 | logCall('describe')
113 | describing = true
114 | html.push(logFilter(''));
115 | html.push(_message(msg))
116 | html.push(logFilter(':
'));
117 | // intercept console.log messages
118 | console.log = write
119 | fn();
120 | }
121 | finally{
122 | html.push(logFilter(''));
123 | // restore log
124 | console.log = consoleLog
125 | console.log(html.join(''));
126 | html = []
127 | describing = false
128 | beforeCallbacks = [];
129 | afterCallbacks = [];
130 | if (failed.length > 0){
131 | throw failed[0];
132 | }
133 | }
134 | },
135 | it: function(msg, fn) {
136 | try{
137 | logCall('it');
138 | html.push(logFilter(''))
139 | html.push(_message(msg));
140 | html.push(logFilter(':
'));
141 | beforeCallbacks.forEach(function(cb){
142 | cb()
143 | });
144 | try{
145 | fn();
146 | } finally {
147 | afterCallbacks.forEach(function(cb){
148 | cb()
149 | });
150 | }
151 | }
152 | finally{
153 | html.push(logFilter(''));
154 | }
155 | },
156 | before: function(cb) {
157 | beforeCallbacks.push(cb);
158 | },
159 | after: function(cb) {
160 | afterCallbacks.push(cb);
161 | },
162 | expect: function(passed, message, options){
163 | logCall('expect')
164 | _expect(passed, message, options)
165 | },
166 | assertSimilar: function(actual, expected, msg, options){
167 | logCall('assertSimilar')
168 | this.assertEquals(this.inspect(actual), this.inspect(expected), msg, options)
169 | },
170 | assertNotSimilar: function(actual, expected, msg, options){
171 | logCall('assertNotSimilar')
172 | this.assertNotEquals(this.inspect(actual), this.inspect(expected), msg, options)
173 | },
174 | assertEquals: function(actual, expected, msg, options) {
175 | logCall('assertEquals')
176 | if(actual !== expected){
177 | msg = _message('Expected: ' + Test.inspect(expected) + ', instead got: ' + Test.inspect(actual), msg)
178 | Test.expect(false, msg, options);
179 | }else{
180 | options = options || {}
181 | options.successMsg = options.successMsg || 'Value == ' + Test.inspect(expected)
182 | Test.expect(true, null, options)
183 | }
184 | },
185 | assertNotEquals: function(a, b, msg, options){
186 | logCall('assertNotEquals')
187 | if(a === b){
188 | msg = _message('Not Expected: ' + Test.inspect(a), msg)
189 | Test.expect(false, msg, options)
190 | }else{
191 | options = options || {}
192 | options.successMsg = options.successMsg || 'Value != ' + Test.inspect(b)
193 | Test.expect(true, null, options)
194 | }
195 | },
196 | expectNoError: function(msg, fn){
197 | logCall('expectNoError')
198 | if(!fn){
199 | fn = msg;
200 | msg = 'Unexpected error was raised'
201 | }
202 |
203 | try{
204 | fn();
205 | Test.expect(true)
206 | }catch(ex){
207 | if (ex.name == 'Test:Error'){
208 | throw ex;
209 | }
210 | else {
211 | msg += ': ' + ex.toString()
212 | Test.expect(false, msg)
213 | }
214 | }
215 | },
216 | expectError: function(msg, fn, options){
217 | logCall('expectError')
218 | if(!fn){
219 | fn = msg;
220 | msg = 'Unexpected error was raised.'
221 | }
222 |
223 | var passed = false
224 | try{
225 | fn();
226 | }catch(ex){
227 | console.log(logFilter('Expected error was thrown: ') + ex.toString())
228 | passed = true
229 | }
230 |
231 | Test.expect(passed, msg, options)
232 | },
233 | randomNumber: function(){
234 | logCall('randomNumber');
235 | return Math.round(Math.random() * 100)
236 | },
237 | randomToken: function(){
238 | return Math.random().toString(36).substr(8)
239 | },
240 | randomize: function(array){
241 | logCall('randomize');
242 | var arr = array.concat(), i = arr.length, j, x;
243 | while(i) {
244 | j = (Math.random() * i) | 0;
245 | x = arr[--i];
246 | arr[i] = arr[j];
247 | arr[j] = x;
248 | }
249 | return arr;
250 | },
251 | sample: function(array){
252 | logCall('sample');
253 | return array[~~(array.length * Math.random())]
254 | },
255 | Error: function(message){
256 | logCall('Error');
257 | this.name = "Test:Error";
258 | this.message = (message || "");
259 | }
260 | }
261 |
262 | Test.Error.prototype = Error.prototype;
263 |
264 | Test.inspect.toString = function(){}
265 | Test.randomize.toString = function(){}
266 | Test.sample.toString = function(){}
267 | Test.randomNumber.toString = function(){}
268 |
269 | Object.freeze(Test)
270 |
271 | exports.Test = Test;
272 | exports.describe = Test.describe;
273 | exports.it = Test.it;
274 | exports.before = Test.before;
275 | exports.after = Test.after
276 |
277 |
278 | })(typeof module != 'undefined' ? module.exports : this)
279 |
280 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "kata-test-framework-js",
3 | "description": "Kata test framework used by Codewars",
4 | "directories": {
5 | "lib": "./lib"
6 | },
7 | "main": "./lib/framework",
8 | "version": "0.0.1",
9 | "dependencies": {},
10 | "engine": "node >= 0.8.6"
11 | }
12 |
13 |
--------------------------------------------------------------------------------