extjs-mvc 0.4.0.f → 0.4.0.g

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/Rakefile +2 -2
  2. data/VERSION +1 -1
  3. data/bin/extjs-mvc +0 -3
  4. data/lib/extjs-mvc.rb +10 -6
  5. data/lib/extjs-mvc/api.rb +0 -1
  6. metadata +8 -84
  7. data/lib/src/App.js +0 -219
  8. data/lib/src/MVC.js +0 -260
  9. data/lib/src/Presenter.js +0 -52
  10. data/lib/src/README.rdoc +0 -69
  11. data/lib/src/controller/Controller.js +0 -278
  12. data/lib/src/controller/CrudController.js +0 -460
  13. data/lib/src/lib/Array.js +0 -26
  14. data/lib/src/lib/Booter.js +0 -416
  15. data/lib/src/lib/ClassManager.js +0 -191
  16. data/lib/src/lib/ControllerClassManager.js +0 -95
  17. data/lib/src/lib/Dependencies.js +0 -44
  18. data/lib/src/lib/DispatchMatcher.js +0 -98
  19. data/lib/src/lib/Dispatcher.js +0 -129
  20. data/lib/src/lib/Environment.js +0 -43
  21. data/lib/src/lib/Inflector.js +0 -155
  22. data/lib/src/lib/ModelClassManager.js +0 -19
  23. data/lib/src/lib/Route.js +0 -139
  24. data/lib/src/lib/Router.js +0 -282
  25. data/lib/src/lib/String.js +0 -94
  26. data/lib/src/lib/ViewClassManager.js +0 -229
  27. data/lib/src/lib/notes.txt +0 -32
  28. data/lib/src/model/AdapterManager.js +0 -30
  29. data/lib/src/model/Association.js +0 -26
  30. data/lib/src/model/Base.js +0 -63
  31. data/lib/src/model/BelongsToAssociation.js +0 -116
  32. data/lib/src/model/Cache.js +0 -131
  33. data/lib/src/model/HasManyAssociation.js +0 -160
  34. data/lib/src/model/Model.js +0 -331
  35. data/lib/src/model/UrlBuilder.js +0 -106
  36. data/lib/src/model/adapters/AbstractAdapter.js +0 -296
  37. data/lib/src/model/adapters/MemoryAdapter.js +0 -103
  38. data/lib/src/model/adapters/RESTAdapter.js +0 -345
  39. data/lib/src/model/adapters/RESTJSONAdapter.js +0 -68
  40. data/lib/src/model/adapters/notes.txt +0 -42
  41. data/lib/src/model/associations/Association.js +0 -192
  42. data/lib/src/model/associations/notes.txt +0 -87
  43. data/lib/src/model/validations/Errors.js +0 -136
  44. data/lib/src/model/validations/Plugin.js +0 -139
  45. data/lib/src/model/validations/Validations.js +0 -276
  46. data/lib/src/notes/Charts.graffle +0 -0
  47. data/lib/src/overrides/Ext.Component.js +0 -21
  48. data/lib/src/overrides/Ext.extend.js +0 -142
  49. data/lib/src/spec/Array.spec.js +0 -15
  50. data/lib/src/spec/ExtMVC.spec.js +0 -65
  51. data/lib/src/spec/Model.spec.js +0 -370
  52. data/lib/src/spec/OS.spec.js +0 -83
  53. data/lib/src/spec/Router.spec.js +0 -99
  54. data/lib/src/spec/SpecHelper.js +0 -106
  55. data/lib/src/spec/String.spec.js +0 -83
  56. data/lib/src/spec/model/AbstractAdapter.spec.js +0 -49
  57. data/lib/src/spec/model/Associations.spec.js +0 -99
  58. data/lib/src/spec/model/Cache.spec.js +0 -5
  59. data/lib/src/spec/model/RESTAdapter.spec.js +0 -19
  60. data/lib/src/spec/model/ValidationErrors.spec.js +0 -64
  61. data/lib/src/spec/model/Validations.spec.js +0 -166
  62. data/lib/src/spec/model/ValidationsPlugin.spec.js +0 -108
  63. data/lib/src/spec/suite.html +0 -60
  64. data/lib/src/specs-old/JSSpec.css +0 -216
  65. data/lib/src/specs-old/JSSpec.js +0 -1512
  66. data/lib/src/specs-old/all.html +0 -66
  67. data/lib/src/specs-old/base.js +0 -14
  68. data/lib/src/specs-old/controller.js +0 -17
  69. data/lib/src/specs-old/diff_match_patch.js +0 -1
  70. data/lib/src/specs-old/model.js +0 -70
  71. data/lib/src/specs-old/route.js +0 -38
  72. data/lib/src/specs-old/router.js +0 -59
  73. data/lib/src/specs-old/string.js +0 -22
  74. data/lib/src/testrunner/JSpecFormatter.js +0 -111
  75. data/lib/src/testrunner/TestClient.js +0 -181
  76. data/lib/src/testrunner/TestGrid.js +0 -351
  77. data/lib/src/testrunner/TestRunner.js +0 -110
  78. data/lib/src/testrunner/TestViewport.js +0 -94
  79. data/lib/src/vendor.yml +0 -29
  80. data/lib/src/vendor/ext-3.1.1/vendor.yml +0 -16
  81. data/lib/src/view/FormWindow.js +0 -184
  82. data/lib/src/view/HasManyEditorGridPanel.js +0 -211
  83. data/lib/src/view/scaffold/Edit.js +0 -46
  84. data/lib/src/view/scaffold/Index.js +0 -561
  85. data/lib/src/view/scaffold/New.js +0 -20
  86. data/lib/src/view/scaffold/ScaffoldFormPanel.js +0 -255
@@ -1,1512 +0,0 @@
1
- /**
2
- * JSSpec
3
- *
4
- * Copyright 2007 Alan Kang
5
- * - mailto:jania902@gmail.com
6
- * - http://jania.pe.kr
7
- *
8
- * http://jania.pe.kr/aw/moin.cgi/JSSpec
9
- *
10
- * Dependencies:
11
- * - diff_match_patch.js ( http://code.google.com/p/google-diff-match-patch )
12
- *
13
- * This library is free software; you can redistribute it and/or
14
- * modify it under the terms of the GNU Lesser General Public
15
- * License as published by the Free Software Foundation; either
16
- * version 2.1 of the License, or (at your option) any later version.
17
- *
18
- * This library is distributed in the hope that it will be useful,
19
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21
- * Lesser General Public License for more details.
22
- *
23
- * You should have received a copy of the GNU Lesser General Public
24
- * License along with this library; if not, write to the Free Software
25
- * Foundation, Inc, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26
- */
27
-
28
- /**
29
- * Namespace
30
- */
31
-
32
- var JSSpec = {
33
- specs: [],
34
-
35
- EMPTY_FUNCTION: function() {},
36
-
37
- Browser: {
38
- Trident: navigator.appName == "Microsoft Internet Explorer",
39
- Webkit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
40
- Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
41
- Presto: navigator.appName == "Opera"
42
- }
43
- };
44
-
45
-
46
-
47
- /**
48
- * Executor
49
- */
50
- JSSpec.Executor = function(target, onSuccess, onException) {
51
- this.target = target;
52
- this.onSuccess = typeof onSuccess == 'function' ? onSuccess : JSSpec.EMPTY_FUNCTION;
53
- this.onException = typeof onException == 'function' ? onException : JSSpec.EMPTY_FUNCTION;
54
-
55
- if(JSSpec.Browser.Trident) {
56
- // Exception handler for Trident. It helps to collect exact line number where exception occured.
57
- window.onerror = function(message, fileName, lineNumber) {
58
- var self = window._curExecutor;
59
- var ex = {message:message, fileName:fileName, lineNumber:lineNumber};
60
-
61
- if(JSSpec._secondPass) {
62
- ex = self.mergeExceptions(JSSpec._assertionFailure, ex);
63
- delete JSSpec._secondPass;
64
- delete JSSpec._assertionFailure;
65
-
66
- ex.type = "failure";
67
- self.onException(self, ex);
68
- } else if(JSSpec._assertionFailure) {
69
- JSSpec._secondPass = true;
70
- self.run();
71
- } else {
72
- self.onException(self, ex);
73
- }
74
-
75
- return true;
76
- };
77
- }
78
- };
79
- JSSpec.Executor.prototype.mergeExceptions = function(assertionFailure, normalException) {
80
- var merged = {
81
- message:assertionFailure.message,
82
- fileName:normalException.fileName,
83
- lineNumber:normalException.lineNumber
84
- };
85
-
86
- return merged;
87
- };
88
-
89
- JSSpec.Executor.prototype.run = function() {
90
- var self = this;
91
- var target = this.target;
92
- var onSuccess = this.onSuccess;
93
- var onException = this.onException;
94
-
95
- window.setTimeout(
96
- function() {
97
- var result;
98
- if(JSSpec.Browser.Trident) {
99
- window._curExecutor = self;
100
-
101
- result = self.target();
102
- self.onSuccess(self, result);
103
- } else {
104
- try {
105
- result = self.target();
106
- self.onSuccess(self, result);
107
- } catch(ex) {
108
- if(JSSpec.Browser.Webkit) ex = {message:ex.message, fileName:ex.sourceURL, lineNumber:ex.line};
109
-
110
- if(JSSpec._secondPass) {
111
- ex = self.mergeExceptions(JSSpec._assertionFailure, ex);
112
- delete JSSpec._secondPass;
113
- delete JSSpec._assertionFailure;
114
-
115
- ex.type = "failure";
116
- self.onException(self, ex);
117
- } else if(JSSpec._assertionFailure) {
118
- JSSpec._secondPass = true;
119
- self.run();
120
- } else {
121
- self.onException(self, ex);
122
- }
123
- }
124
- }
125
- },
126
- 0
127
- );
128
- };
129
-
130
-
131
-
132
- /**
133
- * CompositeExecutor composites one or more executors and execute them sequencially.
134
- */
135
- JSSpec.CompositeExecutor = function(onSuccess, onException, continueOnException) {
136
- this.queue = [];
137
- this.onSuccess = typeof onSuccess == 'function' ? onSuccess : JSSpec.EMPTY_FUNCTION;
138
- this.onException = typeof onException == 'function' ? onException : JSSpec.EMPTY_FUNCTION;
139
- this.continueOnException = !!continueOnException;
140
- };
141
-
142
- JSSpec.CompositeExecutor.prototype.addFunction = function(func) {
143
- this.addExecutor(new JSSpec.Executor(func));
144
- };
145
-
146
- JSSpec.CompositeExecutor.prototype.addExecutor = function(executor) {
147
- var last = this.queue.length == 0 ? null : this.queue[this.queue.length - 1];
148
- if(last) {
149
- last.next = executor;
150
- }
151
-
152
- executor.parent = this;
153
- executor.onSuccessBackup = executor.onSuccess;
154
- executor.onSuccess = function(result) {
155
- this.onSuccessBackup(result);
156
- if(this.next) {
157
- this.next.run();
158
- } else {
159
- this.parent.onSuccess();
160
- }
161
- };
162
- executor.onExceptionBackup = executor.onException;
163
- executor.onException = function(executor, ex) {
164
- this.onExceptionBackup(executor, ex);
165
-
166
- if(this.parent.continueOnException) {
167
- if(this.next) {
168
- this.next.run();
169
- } else {
170
- this.parent.onSuccess();
171
- }
172
- } else {
173
- this.parent.onException(executor, ex);
174
- }
175
- };
176
-
177
- this.queue.push(executor);
178
- };
179
-
180
- JSSpec.CompositeExecutor.prototype.run = function() {
181
- if(this.queue.length > 0) {
182
- this.queue[0].run();
183
- }
184
- };
185
-
186
- /**
187
- * Spec is a set of Examples in a specific context
188
- */
189
- JSSpec.Spec = function(context, entries) {
190
- this.id = JSSpec.Spec.id++;
191
- this.context = context;
192
- this.url = location.href;
193
-
194
- this.filterEntriesByEmbeddedExpressions(entries);
195
- this.extractOutSpecialEntries(entries);
196
- this.examples = this.makeExamplesFromEntries(entries);
197
- this.examplesMap = this.makeMapFromExamples(this.examples);
198
- };
199
-
200
- JSSpec.Spec.id = 0;
201
- JSSpec.Spec.prototype.getExamples = function() {
202
- return this.examples;
203
- };
204
-
205
- JSSpec.Spec.prototype.hasException = function() {
206
- return this.getTotalFailures() > 0 || this.getTotalErrors() > 0;
207
- };
208
-
209
- JSSpec.Spec.prototype.getTotalFailures = function() {
210
- var examples = this.examples;
211
- var failures = 0;
212
- for(var i = 0; i < examples.length; i++) {
213
- if(examples[i].isFailure()) failures++;
214
- }
215
- return failures;
216
- };
217
-
218
- JSSpec.Spec.prototype.getTotalErrors = function() {
219
- var examples = this.examples;
220
- var errors = 0;
221
- for(var i = 0; i < examples.length; i++) {
222
- if(examples[i].isError()) errors++;
223
- }
224
- return errors;
225
- };
226
-
227
- JSSpec.Spec.prototype.filterEntriesByEmbeddedExpressions = function(entries) {
228
- var isTrue;
229
- for(name in entries) {
230
- var m = name.match(/\[\[(.+)\]\]/);
231
- if(m && m[1]) {
232
- eval("isTrue = (" + m[1] + ")");
233
- if(!isTrue) delete entries[name];
234
- }
235
- }
236
- };
237
-
238
- JSSpec.Spec.prototype.extractOutSpecialEntries = function(entries) {
239
- this.beforeEach = JSSpec.EMPTY_FUNCTION;
240
- this.beforeAll = JSSpec.EMPTY_FUNCTION;
241
- this.afterEach = JSSpec.EMPTY_FUNCTION;
242
- this.afterAll = JSSpec.EMPTY_FUNCTION;
243
-
244
- for(name in entries) {
245
- if(name == 'before' || name == 'before each' || name == 'before_each') {
246
- this.beforeEach = entries[name];
247
- } else if(name == 'before all' || name == 'before_all') {
248
- this.beforeAll = entries[name];
249
- } else if(name == 'after' || name == 'after each' || name == 'after_each') {
250
- this.afterEach = entries[name];
251
- } else if(name == 'after all' || name == 'after_all') {
252
- this.afterAll = entries[name];
253
- }
254
- }
255
-
256
- delete entries['before'];
257
- delete entries['before each'];
258
- delete entries['before_each'];
259
- delete entries['before all'];
260
- delete entries['before_all'];
261
- delete entries['after'];
262
- delete entries['after each'];
263
- delete entries['after_each'];
264
- delete entries['after all'];
265
- delete entries['after_all'];
266
- };
267
-
268
- JSSpec.Spec.prototype.makeExamplesFromEntries = function(entries) {
269
- var examples = [];
270
- for(name in entries) {
271
- examples.push(new JSSpec.Example(name, entries[name], this.beforeEach, this.afterEach));
272
- }
273
- return examples;
274
- };
275
-
276
- JSSpec.Spec.prototype.makeMapFromExamples = function(examples) {
277
- var map = {};
278
- for(var i = 0; i < examples.length; i++) {
279
- var example = examples[i];
280
- map[example.id] = examples[i];
281
- }
282
- return map;
283
- };
284
-
285
- JSSpec.Spec.prototype.getExampleById = function(id) {
286
- return this.examplesMap[id];
287
- };
288
-
289
- JSSpec.Spec.prototype.getExecutor = function() {
290
- var self = this;
291
- var onException = function(executor, ex) {
292
- self.exception = ex;
293
- };
294
-
295
- var composite = new JSSpec.CompositeExecutor();
296
- composite.addFunction(function() {JSSpec.log.onSpecStart(self);});
297
- composite.addExecutor(new JSSpec.Executor(this.beforeAll, null, function(exec, ex) {
298
- self.exception = ex;
299
- JSSpec.log.onSpecEnd(self);
300
- }));
301
-
302
- var exampleAndAfter = new JSSpec.CompositeExecutor(null,null,true);
303
- for(var i = 0; i < this.examples.length; i++) {
304
- exampleAndAfter.addExecutor(this.examples[i].getExecutor());
305
- }
306
- exampleAndAfter.addExecutor(new JSSpec.Executor(this.afterAll, null, onException));
307
- exampleAndAfter.addFunction(function() {JSSpec.log.onSpecEnd(self);});
308
- composite.addExecutor(exampleAndAfter);
309
-
310
- return composite;
311
- };
312
-
313
- /**
314
- * Example
315
- */
316
- JSSpec.Example = function(name, target, before, after) {
317
- this.id = JSSpec.Example.id++;
318
- this.name = name;
319
- this.target = target;
320
- this.before = before;
321
- this.after = after;
322
- };
323
-
324
- JSSpec.Example.id = 0;
325
- JSSpec.Example.prototype.isFailure = function() {
326
- return this.exception && this.exception.type == "failure";
327
- };
328
-
329
- JSSpec.Example.prototype.isError = function() {
330
- return this.exception && !this.exception.type;
331
- };
332
-
333
- JSSpec.Example.prototype.getExecutor = function() {
334
- var self = this;
335
- var onException = function(executor, ex) {
336
- self.exception = ex;
337
- };
338
-
339
- var composite = new JSSpec.CompositeExecutor();
340
- composite.addFunction(function() {JSSpec.log.onExampleStart(self);});
341
- composite.addExecutor(new JSSpec.Executor(this.before, null, function(exec, ex) {
342
- self.exception = ex;
343
- JSSpec.log.onExampleEnd(self);
344
- }));
345
-
346
- var targetAndAfter = new JSSpec.CompositeExecutor(null,null,true);
347
-
348
- targetAndAfter.addExecutor(new JSSpec.Executor(this.target, null, onException));
349
- targetAndAfter.addExecutor(new JSSpec.Executor(this.after, null, onException));
350
- targetAndAfter.addFunction(function() {JSSpec.log.onExampleEnd(self);});
351
-
352
- composite.addExecutor(targetAndAfter);
353
-
354
- return composite;
355
- };
356
-
357
- /**
358
- * Runner
359
- */
360
- JSSpec.Runner = function(specs, logger) {
361
- JSSpec.log = logger;
362
-
363
- this.totalExamples = 0;
364
- this.specs = [];
365
- this.specsMap = {};
366
- this.addAllSpecs(specs);
367
- };
368
-
369
- JSSpec.Runner.prototype.addAllSpecs = function(specs) {
370
- for(var i = 0; i < specs.length; i++) {
371
- this.addSpec(specs[i]);
372
- }
373
- };
374
-
375
- JSSpec.Runner.prototype.addSpec = function(spec) {
376
- this.specs.push(spec);
377
- this.specsMap[spec.id] = spec;
378
- this.totalExamples += spec.getExamples().length;
379
- };
380
-
381
- JSSpec.Runner.prototype.getSpecById = function(id) {
382
- return this.specsMap[id];
383
- };
384
-
385
- JSSpec.Runner.prototype.getSpecByContext = function(context) {
386
- for(var i = 0; i < this.specs.length; i++) {
387
- if(this.specs[i].context == context) return this.specs[i];
388
- }
389
- return null;
390
- };
391
-
392
- JSSpec.Runner.prototype.getSpecs = function() {
393
- return this.specs;
394
- };
395
-
396
- JSSpec.Runner.prototype.hasException = function() {
397
- return this.getTotalFailures() > 0 || this.getTotalErrors() > 0;
398
- };
399
-
400
- JSSpec.Runner.prototype.getTotalFailures = function() {
401
- var specs = this.specs;
402
- var failures = 0;
403
- for(var i = 0; i < specs.length; i++) {
404
- failures += specs[i].getTotalFailures();
405
- }
406
- return failures;
407
- };
408
-
409
- JSSpec.Runner.prototype.getTotalErrors = function() {
410
- var specs = this.specs;
411
- var errors = 0;
412
- for(var i = 0; i < specs.length; i++) {
413
- errors += specs[i].getTotalErrors();
414
- }
415
- return errors;
416
- };
417
-
418
-
419
- JSSpec.Runner.prototype.run = function() {
420
- JSSpec.log.onRunnerStart();
421
- var executor = new JSSpec.CompositeExecutor(function() {JSSpec.log.onRunnerEnd()},null,true);
422
- for(var i = 0; i < this.specs.length; i++) {
423
- executor.addExecutor(this.specs[i].getExecutor());
424
- }
425
- executor.run();
426
- };
427
-
428
-
429
- JSSpec.Runner.prototype.rerun = function(context) {
430
- JSSpec.runner = new JSSpec.Runner([this.getSpecByContext(context)], JSSpec.log);
431
- JSSpec.runner.run();
432
- };
433
-
434
- /**
435
- * Logger
436
- */
437
- JSSpec.Logger = function() {
438
- this.finishedExamples = 0;
439
- this.startedAt = null;
440
- };
441
-
442
- JSSpec.Logger.prototype.onRunnerStart = function() {
443
- this._title = document.title;
444
-
445
- this.startedAt = new Date();
446
- var container = document.getElementById('jsspec_container');
447
- if(container) {
448
- container.innerHTML = "";
449
- } else {
450
- container = document.createElement("DIV");
451
- container.id = "jsspec_container";
452
- document.body.appendChild(container);
453
- }
454
-
455
- var title = document.createElement("DIV");
456
- title.id = "title";
457
- title.innerHTML = [
458
- '<h1>JSSpec</h1>',
459
- '<ul>',
460
- JSSpec.options.rerun ? '<li>[<a href="?" title="rerun all specs">X</a>] ' + JSSpec.util.escapeTags(decodeURIComponent(JSSpec.options.rerun)) + '</li>' : '',
461
- ' <li><span id="total_examples">' + JSSpec.runner.totalExamples + '</span> examples</li>',
462
- ' <li><span id="total_failures">0</span> failures</li>',
463
- ' <li><span id="total_errors">0</span> errors</li>',
464
- ' <li><span id="progress">0</span>% done</li>',
465
- ' <li><span id="total_elapsed">0</span> secs</li>',
466
- '</ul>',
467
- '<p><a href="http://jania.pe.kr/aw/moin.cgi/JSSpec">JSSpec homepage</a></p>',
468
- ].join("");
469
- container.appendChild(title);
470
-
471
- var list = document.createElement("DIV");
472
- list.id = "list";
473
- list.innerHTML = [
474
- '<h2>List</h2>',
475
- '<ul class="specs">',
476
- function() {
477
- var specs = JSSpec.runner.getSpecs();
478
- var sb = [];
479
- for(var i = 0; i < specs.length; i++) {
480
- var spec = specs[i];
481
- sb.push('<li id="spec_' + specs[i].id + '_list"><h3><a href="#spec_' + specs[i].id + '">' + JSSpec.util.escapeTags(specs[i].context) + '</a> [<a href="?rerun=' + encodeURIComponent(specs[i].context) + '">rerun</a>]</h3></li>');
482
- }
483
- return sb.join("");
484
- }(),
485
- '</ul>'
486
- ].join("");
487
- container.appendChild(list);
488
-
489
- var log = document.createElement("DIV");
490
- log.id = "log";
491
- log.innerHTML = [
492
- '<h2>Log</h2>',
493
- '<ul class="specs">',
494
- function() {
495
- var specs = JSSpec.runner.getSpecs();
496
- var sb = [];
497
- for(var i = 0; i < specs.length; i++) {
498
- var spec = specs[i];
499
- sb.push(' <li id="spec_' + specs[i].id + '">');
500
- sb.push(' <h3>' + JSSpec.util.escapeTags(specs[i].context) + ' [<a href="?rerun=' + encodeURIComponent(specs[i].context) + '">rerun</a>]</h3>');
501
- sb.push(' <ul id="spec_' + specs[i].id + '_examples" class="examples">');
502
- for(var j = 0; j < spec.examples.length; j++) {
503
- var example = spec.examples[j];
504
- sb.push(' <li id="example_' + example.id + '">')
505
- sb.push(' <h4>' + JSSpec.util.escapeTags(example.name) + '</h4>')
506
- sb.push(' </li>')
507
- }
508
- sb.push(' </ul>');
509
- sb.push(' </li>');
510
- }
511
- return sb.join("");
512
- }(),
513
- '</ul>'
514
- ].join("");
515
-
516
- container.appendChild(log);
517
-
518
- // add event handler for toggling
519
- var specs = JSSpec.runner.getSpecs();
520
- var sb = [];
521
- for(var i = 0; i < specs.length; i++) {
522
- var spec = document.getElementById("spec_" + specs[i].id);
523
- var title = spec.getElementsByTagName("H3")[0];
524
- title.onclick = function(e) {
525
- var target = document.getElementById(this.parentNode.id + "_examples");
526
- target.style.display = target.style.display == "none" ? "block" : "none";
527
- return true;
528
- }
529
- }
530
- };
531
-
532
- JSSpec.Logger.prototype.onRunnerEnd = function() {
533
- if(JSSpec.runner.hasException()) {
534
- var times = 4;
535
- var title1 = "*" + this._title;
536
- var title2 = "*F" + JSSpec.runner.getTotalFailures() + " E" + JSSpec.runner.getTotalErrors() + "* " + this._title;
537
- } else {
538
- var times = 2;
539
- var title1 = this._title;
540
- var title2 = "Success";
541
- }
542
- this.blinkTitle(times,title1,title2);
543
- };
544
-
545
- JSSpec.Logger.prototype.blinkTitle = function(times, title1, title2) {
546
- var times = times * 2;
547
- var mode = true;
548
-
549
- var f = function() {
550
- if(times > 0) {
551
- document.title = mode ? title1 : title2;
552
- mode = !mode;
553
- times--;
554
- window.setTimeout(f, 500);
555
- } else {
556
- document.title = title1;
557
- }
558
- };
559
-
560
- f();
561
- };
562
-
563
- JSSpec.Logger.prototype.onSpecStart = function(spec) {
564
- var spec_list = document.getElementById("spec_" + spec.id + "_list");
565
- var spec_log = document.getElementById("spec_" + spec.id);
566
-
567
- spec_list.className = "ongoing";
568
- spec_log.className = "ongoing";
569
- };
570
-
571
- JSSpec.Logger.prototype.onSpecEnd = function(spec) {
572
- var spec_list = document.getElementById("spec_" + spec.id + "_list");
573
- var spec_log = document.getElementById("spec_" + spec.id);
574
- var examples = document.getElementById("spec_" + spec.id + "_examples");
575
- var className = spec.hasException() ? "exception" : "success";
576
-
577
- spec_list.className = className;
578
- spec_log.className = className;
579
-
580
- if(JSSpec.options.autocollapse && !spec.hasException()) examples.style.display = "none";
581
-
582
- if(spec.exception) {
583
- heading.appendChild(document.createTextNode(" - " + spec.exception.message));
584
- }
585
- };
586
-
587
- JSSpec.Logger.prototype.onExampleStart = function(example) {
588
- var li = document.getElementById("example_" + example.id);
589
- li.className = "ongoing";
590
- };
591
-
592
- JSSpec.Logger.prototype.onExampleEnd = function(example) {
593
- var li = document.getElementById("example_" + example.id);
594
- li.className = example.exception ? "exception" : "success";
595
-
596
- if(example.exception) {
597
- var div = document.createElement("DIV");
598
- div.innerHTML = example.exception.message + "<p><br />" + " at " + example.exception.fileName + ", line " + example.exception.lineNumber + "</p>";
599
- li.appendChild(div);
600
- }
601
-
602
- var title = document.getElementById("title");
603
- var runner = JSSpec.runner;
604
-
605
- title.className = runner.hasException() ? "exception" : "success";
606
-
607
- this.finishedExamples++;
608
- document.getElementById("total_failures").innerHTML = runner.getTotalFailures();
609
- document.getElementById("total_errors").innerHTML = runner.getTotalErrors();
610
- var progress = parseInt(this.finishedExamples / runner.totalExamples * 100);
611
- document.getElementById("progress").innerHTML = progress;
612
- document.getElementById("total_elapsed").innerHTML = (new Date().getTime() - this.startedAt.getTime()) / 1000;
613
-
614
- document.title = progress + "%: " + this._title;
615
- };
616
-
617
- /**
618
- * IncludeMatcher
619
- */
620
- JSSpec.IncludeMatcher = function(actual, expected, condition) {
621
- this.actual = actual;
622
- this.expected = expected;
623
- this.condition = condition;
624
- this.match = false;
625
- this.explaination = this.makeExplain();
626
- };
627
-
628
- JSSpec.IncludeMatcher.createInstance = function(actual, expected, condition) {
629
- return new JSSpec.IncludeMatcher(actual, expected, condition);
630
- };
631
-
632
- JSSpec.IncludeMatcher.prototype.matches = function() {
633
- return this.match;
634
- };
635
-
636
- JSSpec.IncludeMatcher.prototype.explain = function() {
637
- return this.explaination;
638
- };
639
-
640
- JSSpec.IncludeMatcher.prototype.makeExplain = function() {
641
- if(typeof this.actual.length == 'undefined') {
642
- return this.makeExplainForNotArray();
643
- } else {
644
- return this.makeExplainForArray();
645
- }
646
- };
647
-
648
- JSSpec.IncludeMatcher.prototype.makeExplainForNotArray = function() {
649
- if(this.condition) {
650
- this.match = !!this.actual[this.expected];
651
- } else {
652
- this.match = !this.actual[this.expected];
653
- }
654
-
655
- var sb = [];
656
- sb.push('<p>actual value:</p>');
657
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.actual, false, this.expected) + '</p>');
658
- sb.push('<p>should ' + (this.condition ? '' : 'not') + ' include:</p>');
659
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.expected) + '</p>');
660
- return sb.join("");
661
- }
662
- ;
663
- JSSpec.IncludeMatcher.prototype.makeExplainForArray = function() {
664
- var matches;
665
- if(this.condition) {
666
- for(var i = 0; i < this.actual.length; i++) {
667
- matches = JSSpec.EqualityMatcher.createInstance(this.expected, this.actual[i]).matches();
668
- if(matches) {
669
- this.match = true;
670
- break;
671
- }
672
- }
673
- } else {
674
- for(var i = 0; i < this.actual.length; i++) {
675
- matches = JSSpec.EqualityMatcher.createInstance(this.expected, this.actual[i]).matches();
676
- if(matches) {
677
- this.match = false;
678
- break;
679
- }
680
- }
681
- }
682
-
683
- if(this.match) return "";
684
-
685
- var sb = [];
686
- sb.push('<p>actual value:</p>');
687
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.actual, false, this.condition ? null : i) + '</p>');
688
- sb.push('<p>should ' + (this.condition ? '' : 'not') + ' include:</p>');
689
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.expected) + '</p>');
690
- return sb.join("");
691
- };
692
-
693
- /**
694
- * PropertyLengthMatcher
695
- */
696
- JSSpec.PropertyLengthMatcher = function(num, property, o, condition) {
697
- this.num = num;
698
- this.o = o;
699
- this.property = property;
700
- if((property == 'characters' || property == 'items') && typeof o.length != 'undefined') {
701
- this.property = 'length';
702
- }
703
-
704
- this.condition = condition;
705
- this.conditionMet = function(x) {
706
- if(condition == 'exactly') return x.length == num;
707
- if(condition == 'at least') return x.length >= num;
708
- if(condition == 'at most') return x.length <= num;
709
-
710
- throw "Unknown condition '" + condition + "'";
711
- };
712
- this.match = false;
713
- this.explaination = this.makeExplain();
714
- };
715
-
716
- JSSpec.PropertyLengthMatcher.prototype.makeExplain = function() {
717
- if(this.o._type == 'String' && this.property == 'length') {
718
- this.match = this.conditionMet(this.o);
719
- return this.match ? '' : this.makeExplainForString();
720
- } else if(typeof this.o.length != 'undefined' && this.property == "length") {
721
- this.match = this.conditionMet(this.o);
722
- return this.match ? '' : this.makeExplainForArray();
723
- } else if(typeof this.o[this.property] != 'undefined' && this.o[this.property] != null) {
724
- this.match = this.conditionMet(this.o[this.property]);
725
- return this.match ? '' : this.makeExplainForObject();
726
- } else if(typeof this.o[this.property] == 'undefined' || this.o[this.property] == null) {
727
- this.match = false;
728
- return this.makeExplainForNoProperty();
729
- }
730
-
731
- this.match = true;
732
- };
733
-
734
- JSSpec.PropertyLengthMatcher.prototype.makeExplainForString = function() {
735
- var sb = [];
736
-
737
- var exp = this.num == 0 ?
738
- 'be an <strong>empty string</strong>' :
739
- 'have <strong>' + this.condition + ' ' + this.num + ' characters</strong>';
740
-
741
- sb.push('<p>actual value has <strong>' + this.o.length + ' characters</strong>:</p>');
742
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.o) + '</p>');
743
- sb.push('<p>but it should ' + exp + '.</p>');
744
-
745
- return sb.join("");
746
- };
747
-
748
- JSSpec.PropertyLengthMatcher.prototype.makeExplainForArray = function() {
749
- var sb = [];
750
-
751
- var exp = this.num == 0 ?
752
- 'be an <strong>empty array</strong>' :
753
- 'have <strong>' + this.condition + ' ' + this.num + ' items</strong>';
754
-
755
- sb.push('<p>actual value has <strong>' + this.o.length + ' items</strong>:</p>');
756
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.o) + '</p>');
757
- sb.push('<p>but it should ' + exp + '.</p>');
758
-
759
- return sb.join("");
760
- };
761
-
762
- JSSpec.PropertyLengthMatcher.prototype.makeExplainForObject = function() {
763
- var sb = [];
764
-
765
- var exp = this.num == 0 ?
766
- 'be <strong>empty</strong>' :
767
- 'have <strong>' + this.condition + ' ' + this.num + ' ' + this.property + '.</strong>';
768
-
769
- sb.push('<p>actual value has <strong>' + this.o[this.property].length + ' ' + this.property + '</strong>:</p>');
770
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.o, false, this.property) + '</p>');
771
- sb.push('<p>but it should ' + exp + '.</p>');
772
-
773
- return sb.join("");
774
- };
775
-
776
- JSSpec.PropertyLengthMatcher.prototype.makeExplainForNoProperty = function() {
777
- var sb = [];
778
-
779
- sb.push('<p>actual value:</p>');
780
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.o) + '</p>');
781
- sb.push('<p>should have <strong>' + this.condition + ' ' + this.num + ' ' + this.property + '</strong> but there\'s no such property.</p>');
782
-
783
- return sb.join("");
784
- };
785
-
786
- JSSpec.PropertyLengthMatcher.prototype.matches = function() {
787
- return this.match;
788
- };
789
-
790
- JSSpec.PropertyLengthMatcher.prototype.explain = function() {
791
- return this.explaination;
792
- };
793
-
794
- JSSpec.PropertyLengthMatcher.createInstance = function(num, property, o, condition) {
795
- return new JSSpec.PropertyLengthMatcher(num, property, o, condition);
796
- };
797
-
798
- /**
799
- * EqualityMatcher
800
- */
801
- JSSpec.EqualityMatcher = {};
802
-
803
- JSSpec.EqualityMatcher.createInstance = function(expected, actual) {
804
- if(expected == null || actual == null) {
805
- return new JSSpec.NullEqualityMatcher(expected, actual);
806
- } else if(expected._type && expected._type == actual._type) {
807
- if(expected._type == "String") {
808
- return new JSSpec.StringEqualityMatcher(expected, actual);
809
- } else if(expected._type == "Date") {
810
- return new JSSpec.DateEqualityMatcher(expected, actual);
811
- } else if(expected._type == "Number") {
812
- return new JSSpec.NumberEqualityMatcher(expected, actual);
813
- } else if(expected._type == "Array") {
814
- return new JSSpec.ArrayEqualityMatcher(expected, actual);
815
- } else if(expected._type == "Boolean") {
816
- return new JSSpec.BooleanEqualityMatcher(expected, actual);
817
- }
818
- }
819
-
820
- return new JSSpec.ObjectEqualityMatcher(expected, actual);
821
- };
822
-
823
- JSSpec.EqualityMatcher.basicExplain = function(expected, actual, expectedDesc, actualDesc) {
824
- var sb = [];
825
-
826
- sb.push(actualDesc || '<p>actual value:</p>');
827
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(actual) + '</p>');
828
- sb.push(expectedDesc || '<p>should be:</p>');
829
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(expected) + '</p>');
830
-
831
- return sb.join("");
832
- };
833
-
834
- JSSpec.EqualityMatcher.diffExplain = function(expected, actual) {
835
- var sb = [];
836
-
837
- sb.push('<p>diff:</p>');
838
- sb.push('<p style="margin-left:2em;">');
839
-
840
- var dmp = new diff_match_patch();
841
- var diff = dmp.diff_main(expected, actual);
842
- dmp.diff_cleanupEfficiency(diff);
843
-
844
- sb.push(JSSpec.util.inspect(dmp.diff_prettyHtml(diff), true));
845
-
846
- sb.push('</p>');
847
-
848
- return sb.join("");
849
- };
850
-
851
- /**
852
- * BooleanEqualityMatcher
853
- */
854
- JSSpec.BooleanEqualityMatcher = function(expected, actual) {
855
- this.expected = expected;
856
- this.actual = actual;
857
- };
858
-
859
- JSSpec.BooleanEqualityMatcher.prototype.explain = function() {
860
- var sb = [];
861
-
862
- sb.push('<p>actual value:</p>');
863
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.actual) + '</p>');
864
- sb.push('<p>should be:</p>');
865
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.expected) + '</p>');
866
-
867
- return sb.join("");
868
- };
869
-
870
- JSSpec.BooleanEqualityMatcher.prototype.matches = function() {
871
- return this.expected == this.actual;
872
- };
873
-
874
- /**
875
- * NullEqualityMatcher
876
- */
877
- JSSpec.NullEqualityMatcher = function(expected, actual) {
878
- this.expected = expected;
879
- this.actual = actual;
880
- };
881
-
882
- JSSpec.NullEqualityMatcher.prototype.matches = function() {
883
- return this.expected == this.actual && typeof this.expected == typeof this.actual;
884
- };
885
-
886
- JSSpec.NullEqualityMatcher.prototype.explain = function() {
887
- return JSSpec.EqualityMatcher.basicExplain(this.expected, this.actual);
888
- };
889
-
890
- JSSpec.DateEqualityMatcher = function(expected, actual) {
891
- this.expected = expected;
892
- this.actual = actual;
893
- };
894
-
895
- JSSpec.DateEqualityMatcher.prototype.matches = function() {
896
- return this.expected.getTime() == this.actual.getTime();
897
- };
898
-
899
- JSSpec.DateEqualityMatcher.prototype.explain = function() {
900
- var sb = [];
901
-
902
- sb.push(JSSpec.EqualityMatcher.basicExplain(this.expected, this.actual));
903
- sb.push(JSSpec.EqualityMatcher.diffExplain(this.expected.toString(), this.actual.toString()));
904
-
905
- return sb.join("");
906
- };
907
-
908
- /**
909
- * ObjectEqualityMatcher
910
- */
911
- JSSpec.ObjectEqualityMatcher = function(expected, actual) {
912
- this.expected = expected;
913
- this.actual = actual;
914
- this.match = this.expected == this.actual;
915
- this.explaination = this.makeExplain();
916
- };
917
-
918
- JSSpec.ObjectEqualityMatcher.prototype.matches = function() {return this.match};
919
-
920
- JSSpec.ObjectEqualityMatcher.prototype.explain = function() {return this.explaination};
921
-
922
- JSSpec.ObjectEqualityMatcher.prototype.makeExplain = function() {
923
- if(this.expected == this.actual) {
924
- this.match = true;
925
- return "";
926
- }
927
-
928
- if(JSSpec.util.isDomNode(this.expected)) {
929
- return this.makeExplainForDomNode();
930
- }
931
-
932
- var key, expectedHasItem, actualHasItem;
933
-
934
- for(key in this.expected) {
935
- expectedHasItem = this.expected[key] != null && typeof this.expected[key] != 'undefined';
936
- actualHasItem = this.actual[key] != null && typeof this.actual[key] != 'undefined';
937
- if(expectedHasItem && !actualHasItem) return this.makeExplainForMissingItem(key);
938
- }
939
- for(key in this.actual) {
940
- expectedHasItem = this.expected[key] != null && typeof this.expected[key] != 'undefined';
941
- actualHasItem = this.actual[key] != null && typeof this.actual[key] != 'undefined';
942
- if(actualHasItem && !expectedHasItem) return this.makeExplainForUnknownItem(key);
943
- }
944
-
945
- for(key in this.expected) {
946
- var matcher = JSSpec.EqualityMatcher.createInstance(this.expected[key], this.actual[key]);
947
- if(!matcher.matches()) return this.makeExplainForItemMismatch(key);
948
- }
949
-
950
- this.match = true;
951
- };
952
-
953
- JSSpec.ObjectEqualityMatcher.prototype.makeExplainForDomNode = function(key) {
954
- var sb = [];
955
-
956
- sb.push(JSSpec.EqualityMatcher.basicExplain(this.expected, this.actual));
957
-
958
- return sb.join("");
959
- };
960
-
961
- JSSpec.ObjectEqualityMatcher.prototype.makeExplainForMissingItem = function(key) {
962
- var sb = [];
963
-
964
- sb.push('<p>actual value has no item named <strong>' + JSSpec.util.inspect(key) + '</strong></p>');
965
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.actual, false, key) + '</p>');
966
- sb.push('<p>but it should have the item whose value is <strong>' + JSSpec.util.inspect(this.expected[key]) + '</strong></p>');
967
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.expected, false, key) + '</p>');
968
-
969
- return sb.join("");
970
- };
971
-
972
- JSSpec.ObjectEqualityMatcher.prototype.makeExplainForUnknownItem = function(key) {
973
- var sb = [];
974
-
975
- sb.push('<p>actual value has item named <strong>' + JSSpec.util.inspect(key) + '</strong></p>');
976
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.actual, false, key) + '</p>');
977
- sb.push('<p>but there should be no such item</p>');
978
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.expected, false, key) + '</p>');
979
-
980
- return sb.join("");
981
- };
982
-
983
- JSSpec.ObjectEqualityMatcher.prototype.makeExplainForItemMismatch = function(key) {
984
- var sb = [];
985
-
986
- sb.push('<p>actual value has an item named <strong>' + JSSpec.util.inspect(key) + '</strong> whose value is <strong>' + JSSpec.util.inspect(this.actual[key]) + '</strong></p>');
987
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.actual, false, key) + '</p>');
988
- sb.push('<p>but it\'s value should be <strong>' + JSSpec.util.inspect(this.expected[key]) + '</strong></p>');
989
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.expected, false, key) + '</p>');
990
-
991
- return sb.join("");
992
- };
993
-
994
-
995
-
996
-
997
- /**
998
- * ArrayEqualityMatcher
999
- */
1000
- JSSpec.ArrayEqualityMatcher = function(expected, actual) {
1001
- this.expected = expected;
1002
- this.actual = actual;
1003
- this.match = this.expected == this.actual;
1004
- this.explaination = this.makeExplain();
1005
- };
1006
-
1007
- JSSpec.ArrayEqualityMatcher.prototype.matches = function() {return this.match};
1008
-
1009
- JSSpec.ArrayEqualityMatcher.prototype.explain = function() {return this.explaination};
1010
-
1011
- JSSpec.ArrayEqualityMatcher.prototype.makeExplain = function() {
1012
- if(this.expected.length != this.actual.length) return this.makeExplainForLengthMismatch();
1013
-
1014
- for(var i = 0; i < this.expected.length; i++) {
1015
- var matcher = JSSpec.EqualityMatcher.createInstance(this.expected[i], this.actual[i]);
1016
- if(!matcher.matches()) return this.makeExplainForItemMismatch(i);
1017
- }
1018
-
1019
- this.match = true;
1020
- };
1021
-
1022
- JSSpec.ArrayEqualityMatcher.prototype.makeExplainForLengthMismatch = function() {
1023
- return JSSpec.EqualityMatcher.basicExplain(
1024
- this.expected,
1025
- this.actual,
1026
- '<p>but it should be <strong>' + this.expected.length + '</strong></p>',
1027
- '<p>actual value has <strong>' + this.actual.length + '</strong> items</p>'
1028
- );
1029
- };
1030
-
1031
- JSSpec.ArrayEqualityMatcher.prototype.makeExplainForItemMismatch = function(index) {
1032
- var postfix = ["th", "st", "nd", "rd", "th"][Math.min((index + 1) % 10,4)];
1033
-
1034
- var sb = [];
1035
-
1036
- sb.push('<p>' + (index + 1) + postfix + ' item (index ' + index + ') of actual value is <strong>' + JSSpec.util.inspect(this.actual[index]) + '</strong>:</p>');
1037
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.actual, false, index) + '</p>');
1038
- sb.push('<p>but it should be <strong>' + JSSpec.util.inspect(this.expected[index]) + '</strong>:</p>');
1039
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.expected, false, index) + '</p>');
1040
-
1041
- return sb.join("");
1042
- };
1043
-
1044
- /**
1045
- * NumberEqualityMatcher
1046
- */
1047
- JSSpec.NumberEqualityMatcher = function(expected, actual) {
1048
- this.expected = expected;
1049
- this.actual = actual;
1050
- };
1051
-
1052
- JSSpec.NumberEqualityMatcher.prototype.matches = function() {
1053
- if(this.expected == this.actual) return true;
1054
- };
1055
-
1056
- JSSpec.NumberEqualityMatcher.prototype.explain = function() {
1057
- return JSSpec.EqualityMatcher.basicExplain(this.expected, this.actual);
1058
- };
1059
-
1060
- /**
1061
- * StringEqualityMatcher
1062
- */
1063
- JSSpec.StringEqualityMatcher = function(expected, actual) {
1064
- this.expected = expected;
1065
- this.actual = actual;
1066
- };
1067
-
1068
- JSSpec.StringEqualityMatcher.prototype.matches = function() {
1069
- if(this.expected == this.actual) return true;
1070
- };
1071
-
1072
- JSSpec.StringEqualityMatcher.prototype.explain = function() {
1073
- var sb = [];
1074
-
1075
- sb.push(JSSpec.EqualityMatcher.basicExplain(this.expected, this.actual));
1076
- sb.push(JSSpec.EqualityMatcher.diffExplain(this.expected, this.actual));
1077
- return sb.join("");
1078
- };
1079
-
1080
- /**
1081
- * PatternMatcher
1082
- */
1083
- JSSpec.PatternMatcher = function(actual, pattern, condition) {
1084
- this.actual = actual;
1085
- this.pattern = pattern;
1086
- this.condition = condition;
1087
- this.match = false;
1088
- this.explaination = this.makeExplain();
1089
- };
1090
-
1091
- JSSpec.PatternMatcher.createInstance = function(actual, pattern, condition) {
1092
- return new JSSpec.PatternMatcher(actual, pattern, condition);
1093
- };
1094
-
1095
- JSSpec.PatternMatcher.prototype.makeExplain = function() {
1096
- var sb;
1097
- if(this.actual == null || this.actual._type != 'String') {
1098
- sb = [];
1099
- sb.push('<p>actual value:</p>');
1100
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.actual) + '</p>');
1101
- sb.push('<p>should ' + (this.condition ? '' : 'not') + ' match with pattern:</p>');
1102
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.pattern) + '</p>');
1103
- sb.push('<p>but pattern matching cannot be performed.</p>');
1104
- return sb.join("");
1105
- } else {
1106
- this.match = this.condition == !!this.actual.match(this.pattern);
1107
- if(this.match) return "";
1108
-
1109
- sb = [];
1110
- sb.push('<p>actual value:</p>');
1111
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.actual) + '</p>');
1112
- sb.push('<p>should ' + (this.condition ? '' : 'not') + ' match with pattern:</p>');
1113
- sb.push('<p style="margin-left:2em;">' + JSSpec.util.inspect(this.pattern) + '</p>');
1114
- return sb.join("");
1115
- }
1116
- };
1117
-
1118
- JSSpec.PatternMatcher.prototype.matches = function() {
1119
- return this.match;
1120
- };
1121
-
1122
- JSSpec.PatternMatcher.prototype.explain = function() {
1123
- return this.explaination;
1124
- };
1125
-
1126
- /**
1127
- * Domain Specific Languages
1128
- */
1129
- JSSpec.DSL = {};
1130
-
1131
- JSSpec.DSL.forString = {
1132
- normalizeHtml: function() {
1133
- var html = this;
1134
-
1135
- // Uniformize quotation, turn tag names and attribute names into lower case
1136
- html = html.replace(/<(\/?)(\w+)([^>]*?)>/img, function(str, closingMark, tagName, attrs) {
1137
- var sortedAttrs = JSSpec.util.sortHtmlAttrs(JSSpec.util.correctHtmlAttrQuotation(attrs).toLowerCase())
1138
- return "<" + closingMark + tagName.toLowerCase() + sortedAttrs + ">"
1139
- });
1140
-
1141
- // validation self-closing tags
1142
- html = html.replace(/<(br|hr|img)([^>]*?)>/mg, function(str, tag, attrs) {
1143
- return "<" + tag + attrs + " />";
1144
- });
1145
-
1146
- // append semi-colon at the end of style value
1147
- html = html.replace(/style="(.*?)"/mg, function(str, styleStr) {
1148
- styleStr = JSSpec.util.sortStyleEntries(styleStr.strip()); // for Safari
1149
- if(styleStr.charAt(styleStr.length - 1) != ';') styleStr += ";"
1150
-
1151
- return 'style="' + styleStr + '"'
1152
- });
1153
-
1154
- // sort style entries
1155
-
1156
- // remove empty style attributes
1157
- html = html.replace(/ style=";"/mg, "");
1158
-
1159
- // remove new-lines
1160
- html = html.replace(/\r/mg, '');
1161
- html = html.replace(/\n/mg, '');
1162
-
1163
- return html;
1164
- }
1165
- };
1166
-
1167
-
1168
-
1169
- JSSpec.DSL.describe = function(context, entries) {
1170
- JSSpec.specs.push(new JSSpec.Spec(context, entries));
1171
- };
1172
-
1173
- JSSpec.DSL.value_of = function(target) {
1174
- if(JSSpec._secondPass) return {};
1175
-
1176
- var subject = new JSSpec.DSL.Subject(target);
1177
- return subject;
1178
- };
1179
-
1180
- JSSpec.DSL.Subject = function(target) {
1181
- this.target = target;
1182
- };
1183
-
1184
- JSSpec.DSL.Subject.prototype._type = 'Subject';
1185
-
1186
- JSSpec.DSL.Subject.prototype.should_fail = function(message) {
1187
- JSSpec._assertionFailure = {message:message};
1188
- throw JSSpec._assertionFailure;
1189
- };
1190
-
1191
- JSSpec.DSL.Subject.prototype.should_be = function(expected) {
1192
- var matcher = JSSpec.EqualityMatcher.createInstance(expected, this.target);
1193
- if(!matcher.matches()) {
1194
- JSSpec._assertionFailure = {message:matcher.explain()};
1195
- throw JSSpec._assertionFailure;
1196
- }
1197
- };
1198
-
1199
- JSSpec.DSL.Subject.prototype.should_not_be = function(expected) {
1200
- // TODO JSSpec.EqualityMatcher should support 'condition'
1201
- var matcher = JSSpec.EqualityMatcher.createInstance(expected, this.target);
1202
- if(matcher.matches()) {
1203
- JSSpec._assertionFailure = {message:"'" + this.target + "' should not be '" + expected + "'"};
1204
- throw JSSpec._assertionFailure;
1205
- }
1206
- };
1207
-
1208
- JSSpec.DSL.Subject.prototype.should_be_empty = function() {
1209
- this.should_have(0, this.getType() == 'String' ? 'characters' : 'items');
1210
- };
1211
-
1212
- JSSpec.DSL.Subject.prototype.should_not_be_empty = function() {
1213
- this.should_have_at_least(1, this.getType() == 'String' ? 'characters' : 'items');
1214
- };
1215
-
1216
- JSSpec.DSL.Subject.prototype.should_be_true = function() {
1217
- this.should_be(true);
1218
- };
1219
-
1220
- JSSpec.DSL.Subject.prototype.should_be_false = function() {
1221
- this.should_be(false);
1222
- };
1223
-
1224
- JSSpec.DSL.Subject.prototype.should_be_null = function() {
1225
- this.should_be(null);
1226
- };
1227
-
1228
- JSSpec.DSL.Subject.prototype.should_be_undefined = function() {
1229
- this.should_be(undefined);
1230
- };
1231
-
1232
- JSSpec.DSL.Subject.prototype.should_not_be_null = function() {
1233
- this.should_not_be(null);
1234
- };
1235
-
1236
- JSSpec.DSL.Subject.prototype.should_not_be_undefined = function() {
1237
- this.should_not_be(undefined);
1238
- };
1239
-
1240
- JSSpec.DSL.Subject.prototype._should_have = function(num, property, condition) {
1241
- var matcher = JSSpec.PropertyLengthMatcher.createInstance(num, property, this.target, condition);
1242
- if(!matcher.matches()) {
1243
- JSSpec._assertionFailure = {message:matcher.explain()};
1244
- throw JSSpec._assertionFailure;
1245
- }
1246
- };
1247
-
1248
- JSSpec.DSL.Subject.prototype.should_have = function(num, property) {
1249
- this._should_have(num, property, "exactly");
1250
- };
1251
-
1252
- JSSpec.DSL.Subject.prototype.should_have_exactly = function(num, property) {
1253
- this._should_have(num, property, "exactly");
1254
- };
1255
-
1256
- JSSpec.DSL.Subject.prototype.should_have_at_least = function(num, property) {
1257
- this._should_have(num, property, "at least");
1258
- };
1259
-
1260
- JSSpec.DSL.Subject.prototype.should_have_at_most = function(num, property) {
1261
- this._should_have(num, property, "at most");
1262
- };
1263
-
1264
- JSSpec.DSL.Subject.prototype.should_include = function(expected) {
1265
- var matcher = JSSpec.IncludeMatcher.createInstance(this.target, expected, true);
1266
- if(!matcher.matches()) {
1267
- JSSpec._assertionFailure = {message:matcher.explain()};
1268
- throw JSSpec._assertionFailure;
1269
- }
1270
- };
1271
-
1272
- JSSpec.DSL.Subject.prototype.should_not_include = function(expected) {
1273
- var matcher = JSSpec.IncludeMatcher.createInstance(this.target, expected, false);
1274
- if(!matcher.matches()) {
1275
- JSSpec._assertionFailure = {message:matcher.explain()};
1276
- throw JSSpec._assertionFailure;
1277
- }
1278
- };
1279
-
1280
- JSSpec.DSL.Subject.prototype.should_match = function(pattern) {
1281
- var matcher = JSSpec.PatternMatcher.createInstance(this.target, pattern, true);
1282
- if(!matcher.matches()) {
1283
- JSSpec._assertionFailure = {message:matcher.explain()};
1284
- throw JSSpec._assertionFailure;
1285
- }
1286
- }
1287
- JSSpec.DSL.Subject.prototype.should_not_match = function(pattern) {
1288
- var matcher = JSSpec.PatternMatcher.createInstance(this.target, pattern, false);
1289
- if(!matcher.matches()) {
1290
- JSSpec._assertionFailure = {message:matcher.explain()};
1291
- throw JSSpec._assertionFailure;
1292
- }
1293
- };
1294
-
1295
- JSSpec.DSL.Subject.prototype.getType = function() {
1296
- if(typeof this.target == 'undefined') {
1297
- return 'undefined';
1298
- } else if(this.target == null) {
1299
- return 'null';
1300
- } else if(this.target._type) {
1301
- return this.target._type;
1302
- } else if(JSSpec.util.isDomNode(this.target)) {
1303
- return 'DomNode';
1304
- } else {
1305
- return 'object';
1306
- }
1307
- };
1308
-
1309
- /**
1310
- * Utilities
1311
- */
1312
- JSSpec.util = {
1313
- escapeTags: function(string) {
1314
- return string.replace(/</img, '&lt;').replace(/>/img, '&gt;');
1315
- },
1316
- parseOptions: function(defaults) {
1317
- var options = defaults;
1318
-
1319
- var url = location.href;
1320
- var queryIndex = url.indexOf('?');
1321
- if(queryIndex == -1) return options;
1322
-
1323
- var query = url.substring(queryIndex + 1);
1324
- var pairs = query.split('&');
1325
- for(var i = 0; i < pairs.length; i++) {
1326
- var tokens = pairs[i].split('=');
1327
- options[tokens[0]] = tokens[1];
1328
- }
1329
-
1330
- return options;
1331
- },
1332
- correctHtmlAttrQuotation: function(html) {
1333
- html = html.replace(/(\w+)=['"]([^'"]+)['"]/mg,function (str, name, value) {return name + '=' + '"' + value + '"';});
1334
- html = html.replace(/(\w+)=([^ '"]+)/mg,function (str, name, value) {return name + '=' + '"' + value + '"';});
1335
- html = html.replace(/'/mg, '"');
1336
-
1337
- return html;
1338
- },
1339
- sortHtmlAttrs: function(html) {
1340
- var attrs = [];
1341
- html.replace(/((\w+)="[^"]+")/mg, function(str, matched) {
1342
- attrs.push(matched);
1343
- });
1344
- return attrs.length == 0 ? "" : " " + attrs.sort().join(" ");
1345
- },
1346
- sortStyleEntries: function(styleText) {
1347
- var entries = styleText.split(/; /);
1348
- return entries.sort().join("; ");
1349
- },
1350
- escapeHtml: function(str) {
1351
- if(!this._div) {
1352
- this._div = document.createElement("DIV");
1353
- this._text = document.createTextNode('');
1354
- this._div.appendChild(this._text);
1355
- }
1356
- this._text.data = str;
1357
- return this._div.innerHTML;
1358
- },
1359
- isDomNode: function(o) {
1360
- // TODO: make it more stricter
1361
- return (typeof o.nodeName == 'string') && (typeof o.nodeType == 'number');
1362
- },
1363
- inspectDomPath: function(o) {
1364
- var sb = [];
1365
- while(o && o.nodeName != '#document' && o.parent) {
1366
- var siblings = o.parentNode.childNodes;
1367
- for(var i = 0; i < siblings.length; i++) {
1368
- if(siblings[i] == o) {
1369
- sb.push(o.nodeName + (i == 0 ? '' : '[' + i + ']'));
1370
- break;
1371
- }
1372
- }
1373
- o = o.parentNode;
1374
- }
1375
- return sb.join(" &gt; ");
1376
- },
1377
- inspectDomNode: function(o) {
1378
- if(o.nodeType == 1) {
1379
- var nodeName = o.nodeName.toLowerCase();
1380
- var sb = [];
1381
- sb.push('<span class="dom_value">');
1382
- sb.push("&lt;");
1383
- sb.push(nodeName);
1384
-
1385
- var attrs = o.attributes;
1386
- for(var i = 0; i < attrs.length; i++) {
1387
- if(
1388
- attrs[i].nodeValue &&
1389
- attrs[i].nodeName != 'contentEditable' &&
1390
- attrs[i].nodeName != 'style' &&
1391
- typeof attrs[i].nodeValue != 'function'
1392
- ) sb.push(' <span class="dom_attr_name">' + attrs[i].nodeName.toLowerCase() + '</span>=<span class="dom_attr_value">"' + attrs[i].nodeValue + '"</span>');
1393
- }
1394
- if(o.style && o.style.cssText) {
1395
- sb.push(' <span class="dom_attr_name">style</span>=<span class="dom_attr_value">"' + o.style.cssText + '"</span>');
1396
- }
1397
- sb.push('&gt;');
1398
- sb.push(JSSpec.util.escapeHtml(o.innerHTML));
1399
- sb.push('&lt;/' + nodeName + '&gt;');
1400
- sb.push(' <span class="dom_path">(' + JSSpec.util.inspectDomPath(o) + ')</span>' );
1401
- sb.push('</span>');
1402
- return sb.join("");
1403
- } else if(o.nodeType == 3) {
1404
- return '<span class="dom_value">#text ' + o.nodeValue + '</span>';
1405
- } else {
1406
- return '<span class="dom_value">UnknownDomNode</span>';
1407
- }
1408
- },
1409
- inspect: function(o, dontEscape, emphasisKey) {
1410
- var sb, inspected;
1411
-
1412
- if(typeof o == 'undefined') return '<span class="undefined_value">undefined</span>';
1413
- if(o == null) return '<span class="null_value">null</span>';
1414
- if(o._type == 'String') return '<span class="string_value">"' + (dontEscape ? o : JSSpec.util.escapeHtml(o)) + '"</span>';
1415
-
1416
- if(o._type == 'Date') {
1417
- return '<span class="date_value">"' + o.toString() + '"</span>';
1418
- }
1419
-
1420
- if(o._type == 'Number') return '<span class="number_value">' + (dontEscape ? o : JSSpec.util.escapeHtml(o)) + '</span>';
1421
-
1422
- if(o._type == 'Boolean') return '<span class="boolean_value">' + o + '</span>';
1423
-
1424
- if(o._type == 'RegExp') return '<span class="regexp_value">' + JSSpec.util.escapeHtml(o.toString()) + '</span>';
1425
-
1426
- if(JSSpec.util.isDomNode(o)) return JSSpec.util.inspectDomNode(o);
1427
-
1428
- if(o._type == 'Array' || typeof o.length != 'undefined') {
1429
- sb = [];
1430
- for(var i = 0; i < o.length; i++) {
1431
- inspected = JSSpec.util.inspect(o[i]);
1432
- sb.push(i == emphasisKey ? ('<strong>' + inspected + '</strong>') : inspected);
1433
- }
1434
- return '<span class="array_value">[' + sb.join(', ') + ']</span>';
1435
- }
1436
-
1437
- // object
1438
- sb = [];
1439
- for(var key in o) {
1440
- if(key == 'should') continue;
1441
-
1442
- inspected = JSSpec.util.inspect(key) + ":" + JSSpec.util.inspect(o[key]);
1443
- sb.push(key == emphasisKey ? ('<strong>' + inspected + '</strong>') : inspected);
1444
- }
1445
- return '<span class="object_value">{' + sb.join(', ') + '}</span>';
1446
- }
1447
- };
1448
-
1449
- describe = JSSpec.DSL.describe;
1450
- behavior_of = JSSpec.DSL.describe;
1451
- value_of = JSSpec.DSL.value_of;
1452
- expect = JSSpec.DSL.value_of; // @deprecated
1453
-
1454
- String.prototype._type = "String";
1455
- Number.prototype._type = "Number";
1456
- Date.prototype._type = "Date";
1457
- Array.prototype._type = "Array";
1458
- Boolean.prototype._type = "Boolean";
1459
- RegExp.prototype._type = "RegExp";
1460
-
1461
- var targets = [Array.prototype, Date.prototype, Number.prototype, String.prototype, Boolean.prototype, RegExp.prototype];
1462
-
1463
- String.prototype.normalizeHtml = JSSpec.DSL.forString.normalizeHtml;
1464
- String.prototype.asHtml = String.prototype.normalizeHtml; //@deprecated
1465
-
1466
-
1467
-
1468
- /**
1469
- * Main
1470
- */
1471
- JSSpec.defaultOptions = {
1472
- autorun: 1,
1473
- specIdBeginsWith: 0,
1474
- exampleIdBeginsWith: 0,
1475
- autocollapse: 1
1476
- };
1477
- JSSpec.options = JSSpec.util.parseOptions(JSSpec.defaultOptions);
1478
-
1479
- JSSpec.Spec.id = JSSpec.options.specIdBeginsWith;
1480
- JSSpec.Example.id = JSSpec.options.exampleIdBeginsWith;
1481
-
1482
-
1483
-
1484
- window.onload = function() {
1485
- if(JSSpec.specs.length > 0) {
1486
- if(!JSSpec.options.inSuite) {
1487
- JSSpec.runner = new JSSpec.Runner(JSSpec.specs, new JSSpec.Logger());
1488
- if(JSSpec.options.rerun) {
1489
- JSSpec.runner.rerun(decodeURIComponent(JSSpec.options.rerun));
1490
- } else {
1491
- JSSpec.runner.run();
1492
- }
1493
- } else {
1494
- // in suite, send all specs to parent
1495
- var parentWindow = window.frames.parent.window;
1496
- for(var i = 0; i < JSSpec.specs.length; i++) {
1497
- parentWindow.JSSpec.specs.push(JSSpec.specs[i]);
1498
- }
1499
- }
1500
- } else {
1501
- var links = document.getElementById('list').getElementsByTagName('A');
1502
- var frameContainer = document.createElement('DIV');
1503
- frameContainer.style.display = 'none';
1504
- document.body.appendChild(frameContainer);
1505
-
1506
- for(var i = 0; i < links.length; i++) {
1507
- var frame = document.createElement('IFRAME');
1508
- frame.src = links[i].href + '?inSuite=0&specIdBeginsWith=' + (i * 10000) + '&exampleIdBeginsWith=' + (i * 10000);
1509
- frameContainer.appendChild(frame);
1510
- }
1511
- }
1512
- }