newjs 1.7.2 → 1.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/Manifest.txt +13 -2
  2. data/Rakefile +11 -20
  3. data/app_generators/newjs/templates/test/assets/jsunittest.js +173 -135
  4. data/app_generators/newjs_iphone/templates/Html/test/assets/jsunittest.js +173 -135
  5. data/app_generators/newjs_screwunit/USAGE +5 -0
  6. data/app_generators/newjs_screwunit/newjs_screwunit_generator.rb +61 -0
  7. data/app_generators/newjs_screwunit/templates/Rakefile.erb +34 -0
  8. data/bin/newjs_screwunit +17 -0
  9. data/features/development.feature +5 -5
  10. data/features/imported_files_for_generators.feature +2 -2
  11. data/features/newjs_screwunit.feature +18 -0
  12. data/features/step_definitions/cli_steps.rb +9 -0
  13. data/features/{steps/common.rb → step_definitions/common_steps.rb} +39 -81
  14. data/features/step_definitions/file_comparison_steps.rb +10 -0
  15. data/features/support/common.rb +29 -0
  16. data/features/support/env.rb +15 -0
  17. data/features/support/matchers.rb +11 -0
  18. data/lib/newjs.rb +1 -1
  19. data/rack_generators/javascript_test/templates/assets/jsunittest.js +173 -135
  20. data/rails_generators/javascript_test/templates/assets/jsunittest.js +173 -135
  21. data/test/test_newjs_screwunit_generator.rb +43 -0
  22. data/vendor/jsunittest/History.txt +9 -0
  23. data/vendor/jsunittest/Rakefile +1 -1
  24. data/vendor/jsunittest/dist/jsunittest-0.7.3.js +1042 -0
  25. data/vendor/jsunittest/dist/jsunittest.js +173 -135
  26. data/vendor/jsunittest/src/ajax.js +2 -1
  27. data/vendor/jsunittest/src/assertions.js +49 -78
  28. data/vendor/jsunittest/src/common.js +83 -24
  29. data/vendor/jsunittest/src/jsunittest.js +7 -998
  30. data/vendor/jsunittest/src/logger.js +6 -6
  31. data/vendor/jsunittest/src/message_template.js +1 -1
  32. data/vendor/jsunittest/src/prototype/event.js +2 -2
  33. data/vendor/jsunittest/src/prototype/template.js +7 -6
  34. data/vendor/jsunittest/src/runner.js +13 -12
  35. data/vendor/jsunittest/src/test_case.js +11 -6
  36. data/vendor/jsunittest/test/unit/assertions_test.html +9 -1
  37. data/vendor/jsunittest/test/unit/common_test.html +9 -1
  38. data/vendor/jsunittest/test/unit/logger_test.html +2 -2
  39. data/vendor/jsunittest/test/unit/message_template_test.html +2 -2
  40. data/vendor/jsunittest/test/unit/runner_test.html +2 -2
  41. data/vendor/jsunittest/test/unit/template_test.html +2 -2
  42. data/vendor/jsunittest/test/unit/test_case_test.html +24 -3
  43. data/vendor/jsunittest/website/images/logo_bundle.png +0 -0
  44. data/vendor/jsunittest/website/index.html +3 -3
  45. data/vendor/jsunittest/website/index.txt +1 -1
  46. data/vendor/jsunittest/website/stylesheets/screen.css +3 -0
  47. data/vendor/jsunittest/website/tmbundle/JavaScript Unit Testing.tmbundle.tar.gz +0 -0
  48. metadata +20 -14
  49. data/features/steps/env.rb +0 -6
@@ -37,14 +37,23 @@ app_generators/newjs_iphone/templates/Html/src/library.js.erb
37
37
  app_generators/newjs_iphone/templates/Html/tasks/javascript_test_autotest_tasks.rake
38
38
  app_generators/newjs_iphone/templates/Html/test/assets/jsunittest.js
39
39
  app_generators/newjs_iphone/templates/Html/test/assets/unittest.css
40
+ app_generators/newjs_screwunit/USAGE
41
+ app_generators/newjs_screwunit/newjs_screwunit_generator.rb
42
+ app_generators/newjs_screwunit/templates/Rakefile.erb
40
43
  bin/newjs
41
44
  bin/newjs_iphone
45
+ bin/newjs_screwunit
42
46
  config/website.yml
43
47
  config/website.yml.sample
44
48
  features/development.feature
45
49
  features/imported_files_for_generators.feature
46
- features/steps/common.rb
47
- features/steps/env.rb
50
+ features/newjs_screwunit.feature
51
+ features/step_definitions/cli_steps.rb
52
+ features/step_definitions/common_steps.rb
53
+ features/step_definitions/file_comparison_steps.rb
54
+ features/support/common.rb
55
+ features/support/env.rb
56
+ features/support/matchers.rb
48
57
  javascript_test_generators/functional_test/USAGE
49
58
  javascript_test_generators/functional_test/functional_test_generator.rb
50
59
  javascript_test_generators/functional_test/templates/test/assets/jshoulda.js
@@ -125,6 +134,7 @@ test/test_helper.rb
125
134
  test/test_install_website_generator.rb
126
135
  test/test_newjs_generator.rb
127
136
  test/test_newjs_iphone_generator.rb
137
+ test/test_newjs_screwunit_generator.rb
128
138
  test/test_page_generator.rb
129
139
  test/test_plain_theme_generator.rb
130
140
  test/test_rack_javascript_test.rb
@@ -206,6 +216,7 @@ vendor/jsunittest/Rakefile
206
216
  vendor/jsunittest/config/deploy.rb
207
217
  vendor/jsunittest/config/website.yml.sample
208
218
  vendor/jsunittest/dist/jsunittest-0.7.2.js
219
+ vendor/jsunittest/dist/jsunittest-0.7.3.js
209
220
  vendor/jsunittest/dist/jsunittest.js
210
221
  vendor/jsunittest/dist/unittest.css
211
222
  vendor/jsunittest/lib/jstest.rb
data/Rakefile CHANGED
@@ -1,26 +1,17 @@
1
- %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
2
- require File.dirname(__FILE__) + '/lib/newjs'
1
+ gem 'hoe', '>= 2.3'
2
+ require 'hoe'
3
+ require './lib/newjs'
3
4
 
4
- # Generate all the Rake tasks
5
- # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
- $hoe = Hoe.new('newjs', Newjs::VERSION) do |p|
7
- p.developer('Dr Nic Williams', 'drnicwilliams@gmail.com')
8
- p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
- # p.extra_deps = [
10
- # ['activesupport','>= 2.0.2'],
11
- # ]
12
- p.extra_dev_deps = [
13
- ['newgem', ">= #{::Newgem::VERSION}"]
14
- ]
15
-
16
- p.clean_globs |= %w[**/.DS_Store tmp *.log]
17
- path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
18
- p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
19
- p.rsync_args = '-av --delete --ignore-errors'
5
+ Hoe.plugin :newgem
6
+ Hoe.plugin :website
7
+ Hoe.plugin :cucumberfeatures
8
+
9
+ Hoe.spec('newjs') do
10
+ developer 'Dr Nic Williams', 'drnicwilliams@gmail.com'
11
+ extra_dev_deps << ['newgem', ">= #{::Newgem::VERSION}"]
12
+ $hoe = self
20
13
  end
21
14
 
22
- require 'newgem/tasks' # load /tasks/*.rake
23
15
  Dir['tasks/**/*.rake'].each { |t| load t }
24
16
 
25
- # TODO - want other tests/tasks run by default? Add them to the list
26
17
  task :default => [:features]
@@ -1,4 +1,4 @@
1
- /* Jsunittest, version 0.7.2
1
+ /* Jsunittest, version 0.7.3
2
2
  * (c) 2008 Dr Nic Williams
3
3
  *
4
4
  * Jsunittest is freely distributable under
@@ -11,34 +11,57 @@ var JsUnitTest = {
11
11
  Unit: {},
12
12
  inspect: function(object) {
13
13
  try {
14
- if (typeof object == "undefined") return 'undefined';
15
- if (object === null) return 'null';
14
+ if (typeof object == "undefined") {return 'undefined';}
15
+ if (object === null) {return 'null';}
16
16
  if (typeof object == "string") {
17
17
  var useDoubleQuotes = arguments[1];
18
18
  var escapedString = this.gsub(object, /[\x00-\x1f\\]/, function(match) {
19
- var character = String.specialChar[match[0]];
20
- return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
19
+ var character = {
20
+ '\b': '\\b',
21
+ '\t': '\\t',
22
+ '\n': '\\n',
23
+ '\f': '\\f',
24
+ '\r': '\\r',
25
+ '\\': '\\\\'
26
+ }[match[0]];
27
+ return character ? character : '\\u00' + JsUnitTest.toHexString(match[0].charCodeAt());
21
28
  });
22
- if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
29
+ if (useDoubleQuotes) {return '"' + escapedString.replace(/"/g, '\\"') + '"';}
23
30
  return "'" + escapedString.replace(/'/g, '\\\'') + "'";
24
- };
31
+ }
32
+ if (JsUnitTest.getClass(object) === 'Object') {
33
+ var keys_values = new Array(), prefix = 'Object: { ';
34
+ for (property in object) {
35
+ keys_values.push(property + ': ' + object[property]);
36
+ }
37
+ return (prefix + keys_values.join(', ') + ' }');
38
+ }
25
39
  return String(object);
26
40
  } catch (e) {
27
- if (e instanceof RangeError) return '...';
41
+ if (e instanceof RangeError) {return '...';}
28
42
  throw e;
29
43
  }
30
44
  },
31
- $: function(element) {
45
+
46
+ getClass: function(object) {
47
+ return Object.prototype.toString.call(object)
48
+ .match(/^\[object\s(.*)\]$/)[1];
49
+ },
50
+
51
+ $: function(element) {
32
52
  if (arguments.length > 1) {
33
- for (var i = 0, elements = [], length = arguments.length; i < length; i++)
53
+ for (var i = 0, elements = [], length = arguments.length; i < length; i++) {
34
54
  elements.push(this.$(arguments[i]));
55
+ }
35
56
  return elements;
36
57
  }
37
- if (typeof element == "string")
58
+ if (typeof element == "string") {
38
59
  element = document.getElementById(element);
60
+ }
39
61
  return element;
40
62
  },
41
- gsub: function(source, pattern, replacement) {
63
+
64
+ gsub: function(source, pattern, replacement) {
42
65
  var result = '', match;
43
66
  replacement = arguments.callee.prepareReplacement(replacement);
44
67
 
@@ -60,15 +83,48 @@ var JsUnitTest = {
60
83
  escapeHTML: function(data) {
61
84
  return data.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
62
85
  },
86
+ toHexString : function(n) {
87
+ var string = n.toString(16);
88
+ return '00'.substring(string.length) + string;
89
+ },
63
90
  arrayfromargs: function(args) {
64
91
  var myarray = new Array();
65
92
  var i;
66
93
 
67
- for (i=0;i<args.length;i++)
68
- myarray[i] = args[i];
94
+ for (i=0;i<args.length;i++) {
95
+ myarray[i] = args[i];
96
+ }
69
97
 
70
98
  return myarray;
71
99
  },
100
+
101
+ // from now we recursively zip & compare nested arrays
102
+ areArraysEqual: function(expected, actual) {
103
+ var expected_array = JsUnitTest.flattenArray(expected);
104
+ var actual_array = JsUnitTest.flattenArray(actual);
105
+ if (expected_array.length == actual_array.length) {
106
+ for (var i=0; i < expected_array.length; i++) {
107
+ if (expected_array[i] != actual_array[i]) {return false;}
108
+ }
109
+ return true;
110
+ }
111
+ return false;
112
+ },
113
+
114
+ areArraysNotEqual: function(expected, actual) {
115
+ return !this.areArraysEqual(expected, actual);
116
+ },
117
+
118
+ areHashesEqual: function(expected, actual) {
119
+ var expected_array = JsUnitTest.hashToSortedArray(expected);
120
+ var actual_array = JsUnitTest.hashToSortedArray(actual);
121
+ return this.areArraysEqual(expected_array, actual_array);
122
+ },
123
+
124
+ areHashesNotEqual: function(expected, actual) {
125
+ return !this.areHashesEqual(expected, actual);
126
+ },
127
+
72
128
  hashToSortedArray: function(hash) {
73
129
  var results = [];
74
130
  for (key in hash) {
@@ -86,7 +142,7 @@ var JsUnitTest = {
86
142
  } else {
87
143
  results.push(object);
88
144
  }
89
- };
145
+ }
90
146
  return results;
91
147
  },
92
148
  selectorMatch: function(expression, element) {
@@ -151,7 +207,7 @@ var JsUnitTest = {
151
207
 
152
208
  var match = true, name, matches;
153
209
  for (var i = 0, token; token = tokens[i]; i++) {
154
- name = token[0], matches = token[1];
210
+ name = token[0]; matches = token[1];
155
211
  if (!assertions[name](element, matches)) {
156
212
  match = false; break;
157
213
  }
@@ -159,10 +215,11 @@ var JsUnitTest = {
159
215
 
160
216
  return match;
161
217
  },
218
+
162
219
  toQueryParams: function(query, separator) {
163
220
  var query = query || window.location.search;
164
221
  var match = query.replace(/^\s+/, '').replace(/\s+$/, '').match(/([^?#]*)(#.*)?$/);
165
- if (!match) return { };
222
+ if (!match) {return { };}
166
223
 
167
224
  var hash = {};
168
225
  var parts = match[1].split(separator || '&');
@@ -171,18 +228,20 @@ var JsUnitTest = {
171
228
  if (pair[0]) {
172
229
  var key = decodeURIComponent(pair.shift());
173
230
  var value = pair.length > 1 ? pair.join('=') : pair[0];
174
- if (value != undefined) value = decodeURIComponent(value);
231
+ if (value != undefined) {value = decodeURIComponent(value);}
175
232
 
176
233
  if (key in hash) {
177
234
  var object = hash[key];
178
235
  var isArray = object != null && typeof object == "object" &&
179
- 'splice' in object && 'join' in object
180
- if (!isArray) hash[key] = [hash[key]];
236
+ 'splice' in object && 'join' in object;
237
+ if (!isArray) {hash[key] = [hash[key]];}
181
238
  hash[key].push(value);
182
239
  }
183
- else hash[key] = value;
240
+ else {
241
+ hash[key] = value;
242
+ }
184
243
  }
185
- };
244
+ }
186
245
  return hash;
187
246
  },
188
247
 
@@ -194,12 +253,12 @@ var JsUnitTest = {
194
253
  };
195
254
 
196
255
  JsUnitTest.gsub.prepareReplacement = function(replacement) {
197
- if (typeof replacement == "function") return replacement;
256
+ if (typeof replacement == "function") {return replacement;}
198
257
  var template = new Template(replacement);
199
- return function(match) { return template.evaluate(match) };
258
+ return function(match) { return template.evaluate(match); };
200
259
  };
201
260
 
202
- JsUnitTest.Version = '0.7.2';
261
+ JsUnitTest.Version = '0.7.3';
203
262
 
204
263
  JsUnitTest.Template = function(template, pattern) {
205
264
  this.template = template; //template.toString();
@@ -207,31 +266,32 @@ JsUnitTest.Template = function(template, pattern) {
207
266
  };
208
267
 
209
268
  JsUnitTest.Template.prototype.evaluate = function(object) {
210
- if (typeof object.toTemplateReplacements == "function")
269
+ if (typeof object.toTemplateReplacements == "function") {
211
270
  object = object.toTemplateReplacements();
271
+ }
212
272
 
213
273
  return JsUnitTest.gsub(this.template, this.pattern, function(match) {
214
- if (object == null) return '';
274
+ if (object == null) {return '';}
215
275
 
216
276
  var before = match[1] || '';
217
- if (before == '\\') return match[2];
277
+ if (before == '\\') {return match[2];}
218
278
 
219
279
  var ctx = object, expr = match[3];
220
280
  var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
221
281
  match = pattern.exec(expr);
222
- if (match == null) return before;
282
+ if (match == null) {return before;}
223
283
 
224
284
  while (match != null) {
225
285
  var comp = (match[1].indexOf('[]') === 0) ? match[2].gsub('\\\\]', ']') : match[1];
226
286
  ctx = ctx[comp];
227
- if (null == ctx || '' == match[3]) break;
287
+ if (null == ctx || '' == match[3]) {break;}
228
288
  expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
229
289
  match = pattern.exec(expr);
230
290
  }
231
291
 
232
292
  return before + JsUnitTest.String.interpret(ctx);
233
293
  });
234
- }
294
+ };
235
295
 
236
296
  JsUnitTest.Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
237
297
  JsUnitTest.Event = {};
@@ -246,9 +306,9 @@ JsUnitTest.Event.addEvent = function(element, type, handler) {
246
306
  element.addEventListener(type, handler, false);
247
307
  } else {
248
308
  // assign each event handler a unique ID
249
- if (!handler.$$guid) handler.$$guid = JsUnitTest.Event.addEvent.guid++;
309
+ if (!handler.$$guid) {handler.$$guid = JsUnitTest.Event.addEvent.guid++;}
250
310
  // create a hash table of event types for the element
251
- if (!element.events) element.events = {};
311
+ if (!element.events) {element.events = {};}
252
312
  // create a hash table of event handlers for each element/event pair
253
313
  var handlers = element.events[type];
254
314
  if (!handlers) {
@@ -309,11 +369,11 @@ JsUnitTest.Event.fixEvent.stopPropagation = function() {
309
369
 
310
370
  JsUnitTest.Unit.Logger = function(element) {
311
371
  this.element = JsUnitTest.$(element);
312
- if (this.element) this._createLogTable();
372
+ if (this.element) {this._createLogTable();}
313
373
  };
314
374
 
315
375
  JsUnitTest.Unit.Logger.prototype.start = function(testName) {
316
- if (!this.element) return;
376
+ if (!this.element) {return;}
317
377
  var tbody = this.element.getElementsByTagName('tbody')[0];
318
378
 
319
379
  var tr = document.createElement('tr');
@@ -322,7 +382,7 @@ JsUnitTest.Unit.Logger.prototype.start = function(testName) {
322
382
  //testname
323
383
  td = document.createElement('td');
324
384
  td.appendChild(document.createTextNode(testName));
325
- tr.appendChild(td)
385
+ tr.appendChild(td);
326
386
 
327
387
  tr.appendChild(document.createElement('td'));//status
328
388
  tr.appendChild(document.createElement('td'));//message
@@ -338,13 +398,13 @@ JsUnitTest.Unit.Logger.prototype.setStatus = function(status) {
338
398
  };
339
399
 
340
400
  JsUnitTest.Unit.Logger.prototype.finish = function(status, summary) {
341
- if (!this.element) return;
401
+ if (!this.element) {return;}
342
402
  this.setStatus(status);
343
403
  this.message(summary);
344
404
  };
345
405
 
346
406
  JsUnitTest.Unit.Logger.prototype.message = function(message) {
347
- if (!this.element) return;
407
+ if (!this.element) {return;}
348
408
  var cell = this.getMessageCell();
349
409
 
350
410
  // cell.appendChild(document.createTextNode(this._toHTML(message)));
@@ -352,7 +412,7 @@ JsUnitTest.Unit.Logger.prototype.message = function(message) {
352
412
  };
353
413
 
354
414
  JsUnitTest.Unit.Logger.prototype.summary = function(summary) {
355
- if (!this.element) return;
415
+ if (!this.element) {return;}
356
416
  var div = this.element.getElementsByTagName('div')[0];
357
417
  div.innerHTML = this._toHTML(summary);
358
418
  };
@@ -406,7 +466,7 @@ JsUnitTest.Unit.MessageTemplate.prototype.evaluate = function(params) {
406
466
  var part = this.parts[i];
407
467
  var result = (part == '?') ? JsUnitTest.inspect(params.shift()) : part.replace(/\\\?/, '?');
408
468
  results.push(result);
409
- };
469
+ }
410
470
  return results.join('');
411
471
  };
412
472
  // A generic function for performming AJAX requests
@@ -522,8 +582,9 @@ JsUnitTest.ajax = function( options ) {
522
582
 
523
583
  // If the specified type is "script", execute the returned text
524
584
  // response as if it was JavaScript
525
- if ( type == "script" )
585
+ if ( type == "script" ) {
526
586
  eval.call( window, data );
587
+ }
527
588
 
528
589
  // Return the response data (either an XML Document or a text string)
529
590
  return data;
@@ -538,170 +599,140 @@ JsUnitTest.Unit.Assertions = {
538
599
  },
539
600
 
540
601
  flunk: function(message) {
541
- this.assertBlock(message || 'Flunked', function() { return false });
602
+ this.assertBlock(message || 'Flunked', function() { return false; });
542
603
  },
543
604
 
544
605
  assertBlock: function(message, block) {
545
606
  try {
546
607
  block.call(this) ? this.pass() : this.fail(message);
547
- } catch(e) { this.error(e) }
608
+ } catch(e) { this.error(e); }
548
609
  },
549
610
 
550
611
  assert: function(expression, message) {
551
612
  message = this.buildMessage(message || 'assert', 'got <?>', expression);
552
- this.assertBlock(message, function() { return expression });
613
+ this.assertBlock(message, function() { return expression; });
553
614
  },
554
615
 
555
616
  assertEqual: function(expected, actual, message) {
556
617
  message = this.buildMessage(message || 'assertEqual', 'expected <?>, actual: <?>', expected, actual);
557
- this.assertBlock(message, function() { return expected == actual });
618
+ this.assertBlock(message, function() { return expected == actual; });
558
619
  },
559
620
 
560
621
  assertNotEqual: function(expected, actual, message) {
561
622
  message = this.buildMessage(message || 'assertNotEqual', 'expected <?>, actual: <?>', expected, actual);
562
- this.assertBlock(message, function() { return expected != actual });
623
+ this.assertBlock(message, function() { return expected != actual; });
563
624
  },
564
625
 
565
626
  assertEnumEqual: function(expected, actual, message) {
566
627
  message = this.buildMessage(message || 'assertEnumEqual', 'expected <?>, actual: <?>', expected, actual);
567
- var expected_array = JsUnitTest.flattenArray(expected);
568
- var actual_array = JsUnitTest.flattenArray(actual);
569
- this.assertBlock(message, function() {
570
- if (expected_array.length == actual_array.length) {
571
- for (var i=0; i < expected_array.length; i++) {
572
- if (expected_array[i] != actual_array[i]) return false;
573
- };
574
- return true;
575
- }
576
- return false;
577
- });
628
+ this.assertBlock(message, function() { return JsUnitTest.areArraysEqual(expected, actual); });
578
629
  },
579
630
 
580
631
  assertEnumNotEqual: function(expected, actual, message) {
581
632
  message = this.buildMessage(message || 'assertEnumNotEqual', '<?> was the same as <?>', expected, actual);
582
- var expected_array = JsUnitTest.flattenArray(expected);
583
- var actual_array = JsUnitTest.flattenArray(actual);
584
- this.assertBlock(message, function() {
585
- if (expected_array.length == actual_array.length) {
586
- for (var i=0; i < expected_array.length; i++) {
587
- if (expected_array[i] != actual_array[i]) return true;
588
- };
589
- return false;
590
- }
591
- return true;
592
- });
633
+ this.assertBlock(message, function() { return JsUnitTest.areArraysNotEqual(expected, actual); });
593
634
  },
594
635
 
595
636
  assertHashEqual: function(expected, actual, message) {
596
- message = this.buildMessage(message || 'assertHashEqual', 'expected <?>, actual: <?>', expected, actual);
597
- var expected_array = JsUnitTest.flattenArray(JsUnitTest.hashToSortedArray(expected));
598
- var actual_array = JsUnitTest.flattenArray(JsUnitTest.hashToSortedArray(actual));
599
- var block = function() {
600
- if (expected_array.length == actual_array.length) {
601
- for (var i=0; i < expected_array.length; i++) {
602
- if (expected_array[i] != actual_array[i]) return false;
603
- };
604
- return true;
605
- }
606
- return false;
607
- };
608
- this.assertBlock(message, block);
637
+ message = this.buildMessage(message || 'assertHashEqual', 'expected <?>, actual: <?>', JsUnitTest.inspect(expected), JsUnitTest.inspect(actual));
638
+ this.assertBlock(message, function() { return JsUnitTest.areHashesEqual(expected, actual); });
609
639
  },
610
640
 
611
641
  assertHashNotEqual: function(expected, actual, message) {
612
- message = this.buildMessage(message || 'assertHashNotEqual', '<?> was the same as <?>', expected, actual);
613
- var expected_array = JsUnitTest.flattenArray(JsUnitTest.hashToSortedArray(expected));
614
- var actual_array = JsUnitTest.flattenArray(JsUnitTest.hashToSortedArray(actual));
615
- // from now we recursively zip & compare nested arrays
616
- var block = function() {
617
- if (expected_array.length == actual_array.length) {
618
- for (var i=0; i < expected_array.length; i++) {
619
- if (expected_array[i] != actual_array[i]) return true;
620
- };
621
- return false;
622
- }
623
- return true;
624
- };
625
- this.assertBlock(message, block);
642
+ message = this.buildMessage(message || 'assertHashNotEqual', '<?> was the same as <?>', JsUnitTest.inspect(expected), JsUnitTest.inspect(actual));
643
+ this.assertBlock(message, function() { return JsUnitTest.areHashesNotEqual(expected, actual); });
626
644
  },
627
645
 
628
646
  assertIdentical: function(expected, actual, message) {
629
647
  message = this.buildMessage(message || 'assertIdentical', 'expected <?>, actual: <?>', expected, actual);
630
- this.assertBlock(message, function() { return expected === actual });
648
+ this.assertBlock(message, function() { return expected === actual; });
631
649
  },
632
650
 
633
651
  assertNotIdentical: function(expected, actual, message) {
634
652
  message = this.buildMessage(message || 'assertNotIdentical', 'expected <?>, actual: <?>', expected, actual);
635
- this.assertBlock(message, function() { return expected !== actual });
653
+ this.assertBlock(message, function() { return expected !== actual; });
636
654
  },
637
655
 
638
656
  assertNull: function(obj, message) {
639
657
  message = this.buildMessage(message || 'assertNull', 'got <?>', obj);
640
- this.assertBlock(message, function() { return obj === null });
658
+ this.assertBlock(message, function() { return obj === null; });
641
659
  },
642
660
 
643
661
  assertNotNull: function(obj, message) {
644
662
  message = this.buildMessage(message || 'assertNotNull', 'got <?>', obj);
645
- this.assertBlock(message, function() { return obj !== null });
663
+ this.assertBlock(message, function() { return obj !== null; });
646
664
  },
647
665
 
648
666
  assertUndefined: function(obj, message) {
649
667
  message = this.buildMessage(message || 'assertUndefined', 'got <?>', obj);
650
- this.assertBlock(message, function() { return typeof obj == "undefined" });
668
+ this.assertBlock(message, function() { return typeof obj == "undefined"; });
651
669
  },
652
670
 
653
671
  assertNotUndefined: function(obj, message) {
654
672
  message = this.buildMessage(message || 'assertNotUndefined', 'got <?>', obj);
655
- this.assertBlock(message, function() { return typeof obj != "undefined" });
673
+ this.assertBlock(message, function() { return typeof obj != "undefined"; });
656
674
  },
657
675
 
658
676
  assertNullOrUndefined: function(obj, message) {
659
677
  message = this.buildMessage(message || 'assertNullOrUndefined', 'got <?>', obj);
660
- this.assertBlock(message, function() { return obj == null });
678
+ this.assertBlock(message, function() { return obj == null; });
661
679
  },
662
680
 
663
681
  assertNotNullOrUndefined: function(obj, message) {
664
682
  message = this.buildMessage(message || 'assertNotNullOrUndefined', 'got <?>', obj);
665
- this.assertBlock(message, function() { return obj != null });
683
+ this.assertBlock(message, function() { return obj != null; });
666
684
  },
667
685
 
668
686
  assertMatch: function(expected, actual, message) {
669
687
  message = this.buildMessage(message || 'assertMatch', 'regex <?> did not match <?>', expected, actual);
670
- this.assertBlock(message, function() { return new RegExp(expected).exec(actual) });
688
+ this.assertBlock(message, function() { return new RegExp(expected).exec(actual); });
671
689
  },
672
690
 
673
691
  assertNoMatch: function(expected, actual, message) {
674
692
  message = this.buildMessage(message || 'assertNoMatch', 'regex <?> matched <?>', expected, actual);
675
- this.assertBlock(message, function() { return !(new RegExp(expected).exec(actual)) });
693
+ this.assertBlock(message, function() { return !(new RegExp(expected).exec(actual)); });
676
694
  },
677
695
 
678
696
  assertHasClass: function(element, klass, message) {
679
697
  element = JsUnitTest.$(element);
680
698
  message = this.buildMessage(message || 'assertHasClass', '? doesn\'t have class <?>.', element, klass);
681
699
  this.assertBlock(message, function() {
682
- return !!element.className.match(new RegExp(klass))
700
+ var elementClassName = element.className;
701
+ return (elementClassName.length > 0 && (elementClassName == klass ||
702
+ new RegExp("(^|\\s)" + klass + "(\\s|$)").test(elementClassName)));
703
+ // return !!element.className.match(new RegExp(klass))
704
+ });
705
+ },
706
+
707
+ assertNotHasClass: function(element, klass, message) {
708
+ element = JsUnitTest.$(element);
709
+ message = this.buildMessage(message || 'assertNotHasClass', '? does have class <?>.', element, klass);
710
+ this.assertBlock(message, function() {
711
+ var elementClassName = element.className;
712
+ return !(elementClassName.length > 0 && (elementClassName == klass ||
713
+ new RegExp("(^|\\s)" + klass + "(\\s|$)").test(elementClassName)));
683
714
  });
684
715
  },
685
716
 
686
717
  assertHidden: function(element, message) {
687
718
  element = JsUnitTest.$(element);
688
719
  message = this.buildMessage(message || 'assertHidden', '? isn\'t hidden.', element);
689
- this.assertBlock(message, function() { return !element.style.display || element.style.display == 'none' });
720
+ this.assertBlock(message, function() { return !element.style.display || element.style.display == 'none'; });
690
721
  },
691
722
 
692
723
  assertInstanceOf: function(expected, actual, message) {
693
724
  message = this.buildMessage(message || 'assertInstanceOf', '<?> was not an instance of the expected type', actual);
694
- this.assertBlock(message, function() { return actual instanceof expected });
725
+ this.assertBlock(message, function() { return actual instanceof expected; });
695
726
  },
696
727
 
697
728
  assertNotInstanceOf: function(expected, actual, message) {
698
729
  message = this.buildMessage(message || 'assertNotInstanceOf', '<?> was an instance of the expected type', actual);
699
- this.assertBlock(message, function() { return !(actual instanceof expected) });
730
+ this.assertBlock(message, function() { return !(actual instanceof expected); });
700
731
  },
701
732
 
702
733
  assertRespondsTo: function(method, obj, message) {
703
734
  message = this.buildMessage(message || 'assertRespondsTo', 'object doesn\'t respond to <?>', method);
704
- this.assertBlock(message, function() { return (method in obj && typeof obj[method] == 'function') });
735
+ this.assertBlock(message, function() { return (method in obj && typeof obj[method] == 'function'); });
705
736
  },
706
737
 
707
738
  assertRaise: function(exceptionName, method, message) {
@@ -711,8 +742,8 @@ JsUnitTest.Unit.Assertions = {
711
742
  method();
712
743
  return false;
713
744
  } catch(e) {
714
- if (e.name == exceptionName) return true;
715
- else throw e;
745
+ if (e.name == exceptionName) {return true;}
746
+ else {throw e;}
716
747
  }
717
748
  };
718
749
  this.assertBlock(message, block);
@@ -730,22 +761,23 @@ JsUnitTest.Unit.Assertions = {
730
761
 
731
762
  _isVisible: function(element) {
732
763
  element = JsUnitTest.$(element);
733
- if(!element.parentNode) return true;
764
+ if(!element.parentNode) {return true;}
734
765
  this.assertNotNull(element);
735
- if(element.style && (element.style.display == 'none'))
766
+ if(element.style && (element.style.display == 'none')) {
736
767
  return false;
768
+ }
737
769
 
738
770
  return arguments.callee.call(this, element.parentNode);
739
771
  },
740
772
 
741
773
  assertVisible: function(element, message) {
742
774
  message = this.buildMessage(message, '? was not visible.', element);
743
- this.assertBlock(message, function() { return this._isVisible(element) });
775
+ this.assertBlock(message, function() { return this._isVisible(element); });
744
776
  },
745
777
 
746
778
  assertNotVisible: function(element, message) {
747
779
  message = this.buildMessage(message, '? was not hidden and didn\'t have a hidden parent either.', element);
748
- this.assertBlock(message, function() { return !this._isVisible(element) });
780
+ this.assertBlock(message, function() { return !this._isVisible(element); });
749
781
  },
750
782
 
751
783
  assertElementsMatch: function() {
@@ -766,7 +798,7 @@ JsUnitTest.Unit.Assertions = {
766
798
  message = this.buildMessage('assertElementsMatch', 'In index <?>: expected <?> but got ?', index, expression, element);
767
799
  this.flunk(message);
768
800
  pass = false;
769
- };
801
+ }
770
802
  this.assert(pass, "Expected all elements to match.");
771
803
  },
772
804
 
@@ -799,7 +831,7 @@ JsUnitTest.Unit.Runner.prototype.portNumber = function() {
799
831
  if (window.location.search.length > 0) {
800
832
  var matches = window.location.search.match(/\:(\d{3,5})\//);
801
833
  if (matches) {
802
- return parseInt(matches[1]);
834
+ return parseInt(matches[1], 10);
803
835
  }
804
836
  }
805
837
  return null;
@@ -807,22 +839,23 @@ JsUnitTest.Unit.Runner.prototype.portNumber = function() {
807
839
 
808
840
  JsUnitTest.Unit.Runner.prototype.getTests = function(testcases) {
809
841
  var tests = [], options = this.options;
810
- if (this.queryParams.tests) tests = this.queryParams.tests.split(',');
811
- else if (options.tests) tests = options.tests;
812
- else if (options.test) tests = [option.test];
842
+ if (this.queryParams.tests) {tests = this.queryParams.tests.split(',');}
843
+ else if (options.tests) {tests = options.tests;}
844
+ else if (options.test) {tests = [option.test];}
813
845
  else {
814
846
  for (testname in testcases) {
815
- if (testname.match(/^test/)) tests.push(testname);
847
+ if (testname.match(/^test/)) {tests.push(testname);}
816
848
  }
817
849
  }
818
850
  var results = [];
819
851
  for (var i=0; i < tests.length; i++) {
820
852
  var test = tests[i];
821
- if (testcases[test])
853
+ if (testcases[test]) {
822
854
  results.push(
823
855
  new JsUnitTest.Unit.Testcase(test, testcases[test], testcases.setup, testcases.teardown)
824
856
  );
825
- };
857
+ }
858
+ }
826
859
  return results;
827
860
  };
828
861
 
@@ -841,7 +874,7 @@ JsUnitTest.Unit.Runner.prototype.getResult = function() {
841
874
  results.failures += test.failures;
842
875
  results.errors += test.errors;
843
876
  results.warnings += test.warnings;
844
- };
877
+ }
845
878
  return results;
846
879
  };
847
880
 
@@ -859,15 +892,15 @@ JsUnitTest.Unit.Runner.prototype.postResults = function() {
859
892
  JsUnitTest.ajax({
860
893
  url: url,
861
894
  type: 'GET'
862
- })
895
+ });
863
896
  }
864
897
  };
865
898
 
866
899
  JsUnitTest.Unit.Runner.prototype.runTests = function() {
867
900
  var test = this.tests[this.currentTest], actions;
868
901
 
869
- if (!test) return this.finish();
870
- if (!test.isWaiting) this.logger.start(test.name);
902
+ if (!test) {return this.finish();}
903
+ if (!test.isWaiting) {this.logger.start(test.name);}
871
904
  test.run();
872
905
  var self = this;
873
906
  if(test.isWaiting) {
@@ -880,7 +913,7 @@ JsUnitTest.Unit.Runner.prototype.runTests = function() {
880
913
  }
881
914
 
882
915
  this.logger.finish(test.status(), test.summary());
883
- if (actions = test.actions) this.logger.appendActionButtons(actions);
916
+ if (actions = test.actions) {this.logger.appendActionButtons(actions);}
884
917
  this.currentTest++;
885
918
  // tail recursive, hopefully the browser will skip the stackframe
886
919
  this.runTests();
@@ -927,7 +960,7 @@ JsUnitTest.Unit.Testcase.prototype.wait = function(time, nextPart) {
927
960
  JsUnitTest.Unit.Testcase.prototype.run = function(rethrow) {
928
961
  try {
929
962
  try {
930
- if (!this.isWaiting) this.setup();
963
+ if (!this.isWaiting) {this.setup();}
931
964
  this.isWaiting = false;
932
965
  this.test();
933
966
  } finally {
@@ -937,7 +970,7 @@ JsUnitTest.Unit.Testcase.prototype.run = function(rethrow) {
937
970
  }
938
971
  }
939
972
  catch(e) {
940
- if (rethrow) throw e;
973
+ if (rethrow) {throw e;}
941
974
  this.error(e, this);
942
975
  }
943
976
  };
@@ -981,14 +1014,19 @@ JsUnitTest.Unit.Testcase.prototype.info = function(message) {
981
1014
 
982
1015
  JsUnitTest.Unit.Testcase.prototype.error = function(error, test) {
983
1016
  this.errors++;
984
- this.actions['retry with throw'] = function() { test.run(true) };
1017
+ this.actions['retry with throw'] = function() { test.run(true); };
985
1018
  this.messages.push(error.name + ": "+ error.message + "(" + JsUnitTest.inspect(error) + ")");
1019
+ if( typeof console != "undefined" && console.error) {
1020
+ console.error("Test '" + test.name + "' died, exception and test follows");
1021
+ console.error(error);
1022
+ console.error(test.test.toString());
1023
+ }
986
1024
  };
987
1025
 
988
1026
  JsUnitTest.Unit.Testcase.prototype.status = function() {
989
- if (this.failures > 0) return 'failed';
990
- if (this.errors > 0) return 'error';
991
- if (this.warnings > 0) return 'warning';
1027
+ if (this.failures > 0) {return 'failed';}
1028
+ if (this.errors > 0) {return 'error';}
1029
+ if (this.warnings > 0) {return 'warning';}
992
1030
  return 'passed';
993
1031
  };
994
1032