webr 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/README.md +4 -0
  2. data/Rakefile +19 -0
  3. data/app/webr.rb +57 -0
  4. data/bin/webr +6 -0
  5. data/ext/jasmine/lib/jasmine.js +2423 -0
  6. data/ext/jsdom/lib/jsdom.js +70 -0
  7. data/ext/jsdom/lib/jsdom/browser/domtohtml.js +198 -0
  8. data/ext/jsdom/lib/jsdom/browser/htmlencoding.js +381 -0
  9. data/ext/jsdom/lib/jsdom/browser/htmltodom.js +151 -0
  10. data/ext/jsdom/lib/jsdom/browser/index.js +484 -0
  11. data/ext/jsdom/lib/jsdom/level1/core.js +1610 -0
  12. data/ext/jsdom/lib/jsdom/level2/core.js +406 -0
  13. data/ext/jsdom/lib/jsdom/level2/events.js +358 -0
  14. data/ext/jsdom/lib/jsdom/level2/html.js +1424 -0
  15. data/ext/jsdom/lib/jsdom/level2/index.js +7 -0
  16. data/ext/jsdom/lib/jsdom/level2/languages/javascript.js +17 -0
  17. data/ext/jsdom/lib/jsdom/level3/core.js +514 -0
  18. data/ext/jsdom/lib/jsdom/level3/events.js +296 -0
  19. data/ext/jsdom/lib/jsdom/level3/html.js +5 -0
  20. data/ext/jsdom/lib/jsdom/level3/index.js +7 -0
  21. data/ext/node-htmlparser/lib/node-htmlparser.js +769 -0
  22. data/ext/node-htmlparser/lib/node-htmlparser.min.js +22 -0
  23. data/ext/request/request.js +116 -0
  24. data/js/jasmine-start.js +10 -0
  25. data/js/webr.js +97 -0
  26. data/jspec/jasmine_spec.js +23 -0
  27. data/lib/webr.rb +17 -0
  28. data/lib/webr/browser.rb +44 -0
  29. data/lib/webr/jasmine.rb +6 -0
  30. data/lib/webr/jasmine/browser.rb +15 -0
  31. data/lib/webr/jasmine/reporter.rb +16 -0
  32. data/lib/webr/jasmine/reporter/base.rb +40 -0
  33. data/lib/webr/jasmine/reporter/console.rb +79 -0
  34. data/lib/webr/jasmine/reporter/html.rb +179 -0
  35. data/lib/webr/portal.rb +19 -0
  36. data/lib/webr/runtime.rb +23 -0
  37. data/lib/webr/version.rb +3 -0
  38. data/spec/data/plain.html +13 -0
  39. data/spec/data/script-embedded.html +17 -0
  40. data/spec/data/script-external-onload.html +11 -0
  41. data/spec/data/script-external-onload.js +11 -0
  42. data/spec/data/script-external.html +11 -0
  43. data/spec/data/script-external.js +1 -0
  44. data/spec/data/script-jquery-1.4.2.html +12 -0
  45. data/spec/data/script-jquery-1.4.3.html +12 -0
  46. data/spec/data/script-jquery.js +3 -0
  47. data/spec/lib/webr/browser_spec.rb +133 -0
  48. data/spec/lib/webr/jasmine/browser_spec.rb +22 -0
  49. data/spec/lib/webr/jasmine/reporter/html_spec.rb +15 -0
  50. data/spec/spec_helper.rb +4 -0
  51. data/tasks/spec.rake +16 -0
  52. data/webr.gemspec +30 -0
  53. metadata +207 -0
@@ -0,0 +1,4 @@
1
+ # Webr (webber) #
2
+
3
+ webr jasmine [file_name]
4
+ -f/--format=[html, console]
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'webr'
4
+
5
+ desc 'Initialize environment'
6
+ task :init do
7
+ puts ""
8
+ puts "Initializing submodules"
9
+ puts ""
10
+ sh "git submodule init"
11
+ sh "git submodule update"
12
+ end
13
+
14
+ Bundler::GemHelper.install_tasks
15
+
16
+ for file in Dir['tasks/*.rake']
17
+ load file
18
+ end
19
+
@@ -0,0 +1,57 @@
1
+ require 'webr'
2
+ require 'optitron'
3
+
4
+ module Webr
5
+
6
+ class App < Optitron::CLI
7
+ include ERB::Util # for the #h method
8
+
9
+ desc "Run [file_name]"
10
+ def browser(file_name)
11
+ raise "No such file: #{file_name}" unless File.exist?(file_name)
12
+ file = File.expand_path(file_name)
13
+ root = File.expand_path(File.dirname(file))
14
+
15
+ browser = Webr::Browser.new
16
+ browser.open(file_name)
17
+ browser.start
18
+ end
19
+
20
+ desc "Run [file_name] using jasmine and report"
21
+ opt "format", :in => %w(html console), :default => 'console'
22
+ def jasmine(file_name)
23
+ raise "No such file: #{file_name}" unless File.exist?(file_name)
24
+ files = []
25
+ if File.directory?(file_name)
26
+ root = File.expand_path(file_name)
27
+ files += Dir["#{root}/*_spec.js"]
28
+ else
29
+ files << File.expand_path(file_name)
30
+ root = File.dirname(File.expand_path(file_name))
31
+ end
32
+
33
+ format = params["format"]
34
+
35
+ begin
36
+ browser = Webr::Jasmine::Browser.new(format)
37
+ browser.root = root
38
+ files.each do |file|
39
+ browser.scripts << file
40
+ end
41
+ browser.start
42
+ rescue Exception => e
43
+ if format == 'html'
44
+ puts "<pre>"
45
+ puts h(e.message)
46
+ puts h(e.backtrace.join("\n"))
47
+ puts "</pre>"
48
+ else
49
+ raise
50
+ end
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ App.dispatch
57
+ end
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ $:.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
5
+ $:.unshift(File.expand_path(File.dirname(__FILE__) + "/.."))
6
+ require 'app/webr'
@@ -0,0 +1,2423 @@
1
+ /**
2
+ * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
3
+ *
4
+ * @namespace
5
+ */
6
+ var jasmine = {};
7
+
8
+ /**
9
+ * @private
10
+ */
11
+ jasmine.unimplementedMethod_ = function() {
12
+ throw new Error("unimplemented method");
13
+ };
14
+
15
+ /**
16
+ * Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
17
+ * a plain old variable and may be redefined by somebody else.
18
+ *
19
+ * @private
20
+ */
21
+ jasmine.undefined = jasmine.___undefined___;
22
+
23
+ /**
24
+ * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
25
+ *
26
+ */
27
+ jasmine.DEFAULT_UPDATE_INTERVAL = 250;
28
+
29
+ /**
30
+ * Default timeout interval in milliseconds for waitsFor() blocks.
31
+ */
32
+ jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
33
+
34
+ jasmine.getGlobal = function() {
35
+ function getGlobal() {
36
+ return this;
37
+ }
38
+
39
+ return getGlobal();
40
+ };
41
+
42
+ /**
43
+ * Allows for bound functions to be compared. Internal use only.
44
+ *
45
+ * @ignore
46
+ * @private
47
+ * @param base {Object} bound 'this' for the function
48
+ * @param name {Function} function to find
49
+ */
50
+ jasmine.bindOriginal_ = function(base, name) {
51
+ var original = base[name];
52
+ if (original.apply) {
53
+ return function() {
54
+ return original.apply(base, arguments);
55
+ };
56
+ } else {
57
+ // IE support
58
+ return jasmine.getGlobal()[name];
59
+ }
60
+ };
61
+
62
+ jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
63
+ jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
64
+ jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
65
+ jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
66
+
67
+ jasmine.MessageResult = function(values) {
68
+ this.type = 'log';
69
+ this.values = values;
70
+ this.trace = new Error(); // todo: test better
71
+ };
72
+
73
+ jasmine.MessageResult.prototype.toString = function() {
74
+ var text = "";
75
+ for(var i = 0; i < this.values.length; i++) {
76
+ if (i > 0) text += " ";
77
+ if (jasmine.isString_(this.values[i])) {
78
+ text += this.values[i];
79
+ } else {
80
+ text += jasmine.pp(this.values[i]);
81
+ }
82
+ }
83
+ return text;
84
+ };
85
+
86
+ jasmine.ExpectationResult = function(params) {
87
+ this.type = 'expect';
88
+ this.matcherName = params.matcherName;
89
+ this.passed_ = params.passed;
90
+ this.expected = params.expected;
91
+ this.actual = params.actual;
92
+
93
+ this.message = this.passed_ ? 'Passed.' : params.message;
94
+ this.trace = this.passed_ ? '' : new Error(this.message);
95
+ this.error = params.error
96
+ };
97
+
98
+ jasmine.ExpectationResult.prototype.toString = function () {
99
+ return this.message;
100
+ };
101
+
102
+ jasmine.ExpectationResult.prototype.passed = function () {
103
+ return this.passed_;
104
+ };
105
+
106
+ /**
107
+ * Getter for the Jasmine environment. Ensures one gets created
108
+ */
109
+ jasmine.getEnv = function() {
110
+ return jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
111
+ };
112
+
113
+ /**
114
+ * @ignore
115
+ * @private
116
+ * @param value
117
+ * @returns {Boolean}
118
+ */
119
+ jasmine.isArray_ = function(value) {
120
+ return jasmine.isA_("Array", value);
121
+ };
122
+
123
+ /**
124
+ * @ignore
125
+ * @private
126
+ * @param value
127
+ * @returns {Boolean}
128
+ */
129
+ jasmine.isString_ = function(value) {
130
+ return jasmine.isA_("String", value);
131
+ };
132
+
133
+ /**
134
+ * @ignore
135
+ * @private
136
+ * @param value
137
+ * @returns {Boolean}
138
+ */
139
+ jasmine.isNumber_ = function(value) {
140
+ return jasmine.isA_("Number", value);
141
+ };
142
+
143
+ /**
144
+ * @ignore
145
+ * @private
146
+ * @param {String} typeName
147
+ * @param value
148
+ * @returns {Boolean}
149
+ */
150
+ jasmine.isA_ = function(typeName, value) {
151
+ return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
152
+ };
153
+
154
+ /**
155
+ * Pretty printer for expecations. Takes any object and turns it into a human-readable string.
156
+ *
157
+ * @param value {Object} an object to be outputted
158
+ * @returns {String}
159
+ */
160
+ jasmine.pp = function(value) {
161
+ var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
162
+ stringPrettyPrinter.format(value);
163
+ return stringPrettyPrinter.string;
164
+ };
165
+
166
+ /**
167
+ * Returns true if the object is a DOM Node.
168
+ *
169
+ * @param {Object} obj object to check
170
+ * @returns {Boolean}
171
+ */
172
+ jasmine.isDomNode = function(obj) {
173
+ return obj['nodeType'] > 0;
174
+ };
175
+
176
+ /**
177
+ * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
178
+ *
179
+ * @example
180
+ * // don't care about which function is passed in, as long as it's a function
181
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
182
+ *
183
+ * @param {Class} clazz
184
+ * @returns matchable object of the type clazz
185
+ */
186
+ jasmine.any = function(clazz) {
187
+ return new jasmine.Matchers.Any(clazz);
188
+ };
189
+
190
+ /**
191
+ * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
192
+ *
193
+ * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
194
+ * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
195
+ *
196
+ * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
197
+ *
198
+ * Spies are torn down at the end of every spec.
199
+ *
200
+ * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
201
+ *
202
+ * @example
203
+ * // a stub
204
+ * var myStub = jasmine.createSpy('myStub'); // can be used anywhere
205
+ *
206
+ * // spy example
207
+ * var foo = {
208
+ * not: function(bool) { return !bool; }
209
+ * }
210
+ *
211
+ * // actual foo.not will not be called, execution stops
212
+ * spyOn(foo, 'not');
213
+
214
+ // foo.not spied upon, execution will continue to implementation
215
+ * spyOn(foo, 'not').andCallThrough();
216
+ *
217
+ * // fake example
218
+ * var foo = {
219
+ * not: function(bool) { return !bool; }
220
+ * }
221
+ *
222
+ * // foo.not(val) will return val
223
+ * spyOn(foo, 'not').andCallFake(function(value) {return value;});
224
+ *
225
+ * // mock example
226
+ * foo.not(7 == 7);
227
+ * expect(foo.not).toHaveBeenCalled();
228
+ * expect(foo.not).toHaveBeenCalledWith(true);
229
+ *
230
+ * @constructor
231
+ * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
232
+ * @param {String} name
233
+ */
234
+ jasmine.Spy = function(name) {
235
+ /**
236
+ * The name of the spy, if provided.
237
+ */
238
+ this.identity = name || 'unknown';
239
+ /**
240
+ * Is this Object a spy?
241
+ */
242
+ this.isSpy = true;
243
+ /**
244
+ * The actual function this spy stubs.
245
+ */
246
+ this.plan = function() {
247
+ };
248
+ /**
249
+ * Tracking of the most recent call to the spy.
250
+ * @example
251
+ * var mySpy = jasmine.createSpy('foo');
252
+ * mySpy(1, 2);
253
+ * mySpy.mostRecentCall.args = [1, 2];
254
+ */
255
+ this.mostRecentCall = {};
256
+
257
+ /**
258
+ * Holds arguments for each call to the spy, indexed by call count
259
+ * @example
260
+ * var mySpy = jasmine.createSpy('foo');
261
+ * mySpy(1, 2);
262
+ * mySpy(7, 8);
263
+ * mySpy.mostRecentCall.args = [7, 8];
264
+ * mySpy.argsForCall[0] = [1, 2];
265
+ * mySpy.argsForCall[1] = [7, 8];
266
+ */
267
+ this.argsForCall = [];
268
+ this.calls = [];
269
+ };
270
+
271
+ /**
272
+ * Tells a spy to call through to the actual implemenatation.
273
+ *
274
+ * @example
275
+ * var foo = {
276
+ * bar: function() { // do some stuff }
277
+ * }
278
+ *
279
+ * // defining a spy on an existing property: foo.bar
280
+ * spyOn(foo, 'bar').andCallThrough();
281
+ */
282
+ jasmine.Spy.prototype.andCallThrough = function() {
283
+ this.plan = this.originalValue;
284
+ return this;
285
+ };
286
+
287
+ /**
288
+ * For setting the return value of a spy.
289
+ *
290
+ * @example
291
+ * // defining a spy from scratch: foo() returns 'baz'
292
+ * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
293
+ *
294
+ * // defining a spy on an existing property: foo.bar() returns 'baz'
295
+ * spyOn(foo, 'bar').andReturn('baz');
296
+ *
297
+ * @param {Object} value
298
+ */
299
+ jasmine.Spy.prototype.andReturn = function(value) {
300
+ this.plan = function() {
301
+ return value;
302
+ };
303
+ return this;
304
+ };
305
+
306
+ /**
307
+ * For throwing an exception when a spy is called.
308
+ *
309
+ * @example
310
+ * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
311
+ * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
312
+ *
313
+ * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
314
+ * spyOn(foo, 'bar').andThrow('baz');
315
+ *
316
+ * @param {String} exceptionMsg
317
+ */
318
+ jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
319
+ this.plan = function() {
320
+ throw exceptionMsg;
321
+ };
322
+ return this;
323
+ };
324
+
325
+ /**
326
+ * Calls an alternate implementation when a spy is called.
327
+ *
328
+ * @example
329
+ * var baz = function() {
330
+ * // do some stuff, return something
331
+ * }
332
+ * // defining a spy from scratch: foo() calls the function baz
333
+ * var foo = jasmine.createSpy('spy on foo').andCall(baz);
334
+ *
335
+ * // defining a spy on an existing property: foo.bar() calls an anonymnous function
336
+ * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
337
+ *
338
+ * @param {Function} fakeFunc
339
+ */
340
+ jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
341
+ this.plan = fakeFunc;
342
+ return this;
343
+ };
344
+
345
+ /**
346
+ * Resets all of a spy's the tracking variables so that it can be used again.
347
+ *
348
+ * @example
349
+ * spyOn(foo, 'bar');
350
+ *
351
+ * foo.bar();
352
+ *
353
+ * expect(foo.bar.callCount).toEqual(1);
354
+ *
355
+ * foo.bar.reset();
356
+ *
357
+ * expect(foo.bar.callCount).toEqual(0);
358
+ */
359
+ jasmine.Spy.prototype.reset = function() {
360
+ this.wasCalled = false;
361
+ this.callCount = 0;
362
+ this.argsForCall = [];
363
+ this.calls = [];
364
+ this.mostRecentCall = {};
365
+ };
366
+
367
+ jasmine.createSpy = function(name) {
368
+
369
+ var spyObj = function() {
370
+ spyObj.wasCalled = true;
371
+ spyObj.callCount++;
372
+ var args = jasmine.util.argsToArray(arguments);
373
+ spyObj.mostRecentCall.object = this;
374
+ spyObj.mostRecentCall.args = args;
375
+ spyObj.argsForCall.push(args);
376
+ spyObj.calls.push({object: this, args: args});
377
+ return spyObj.plan.apply(this, arguments);
378
+ };
379
+
380
+ var spy = new jasmine.Spy(name);
381
+
382
+ for (var prop in spy) {
383
+ spyObj[prop] = spy[prop];
384
+ }
385
+
386
+ spyObj.reset();
387
+
388
+ return spyObj;
389
+ };
390
+
391
+ /**
392
+ * Determines whether an object is a spy.
393
+ *
394
+ * @param {jasmine.Spy|Object} putativeSpy
395
+ * @returns {Boolean}
396
+ */
397
+ jasmine.isSpy = function(putativeSpy) {
398
+ return putativeSpy && putativeSpy.isSpy;
399
+ };
400
+
401
+ /**
402
+ * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
403
+ * large in one call.
404
+ *
405
+ * @param {String} baseName name of spy class
406
+ * @param {Array} methodNames array of names of methods to make spies
407
+ */
408
+ jasmine.createSpyObj = function(baseName, methodNames) {
409
+ if (!jasmine.isArray_(methodNames) || methodNames.length == 0) {
410
+ throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
411
+ }
412
+ var obj = {};
413
+ for (var i = 0; i < methodNames.length; i++) {
414
+ obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
415
+ }
416
+ return obj;
417
+ };
418
+
419
+ /**
420
+ * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
421
+ *
422
+ * Be careful not to leave calls to <code>jasmine.log</code> in production code.
423
+ */
424
+ jasmine.log = function() {
425
+ var spec = jasmine.getEnv().currentSpec;
426
+ spec.log.apply(spec, arguments);
427
+ };
428
+
429
+ /**
430
+ * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
431
+ *
432
+ * @example
433
+ * // spy example
434
+ * var foo = {
435
+ * not: function(bool) { return !bool; }
436
+ * }
437
+ * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
438
+ *
439
+ * @see jasmine.createSpy
440
+ * @param obj
441
+ * @param methodName
442
+ * @returns a Jasmine spy that can be chained with all spy methods
443
+ */
444
+ var spyOn = function(obj, methodName) {
445
+ return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
446
+ };
447
+
448
+ /**
449
+ * Creates a Jasmine spec that will be added to the current suite.
450
+ *
451
+ * // TODO: pending tests
452
+ *
453
+ * @example
454
+ * it('should be true', function() {
455
+ * expect(true).toEqual(true);
456
+ * });
457
+ *
458
+ * @param {String} desc description of this specification
459
+ * @param {Function} func defines the preconditions and expectations of the spec
460
+ */
461
+ var it = function(desc, func) {
462
+ return jasmine.getEnv().it(desc, func);
463
+ };
464
+
465
+ /**
466
+ * Creates a <em>disabled</em> Jasmine spec.
467
+ *
468
+ * A convenience method that allows existing specs to be disabled temporarily during development.
469
+ *
470
+ * @param {String} desc description of this specification
471
+ * @param {Function} func defines the preconditions and expectations of the spec
472
+ */
473
+ var xit = function(desc, func) {
474
+ return jasmine.getEnv().xit(desc, func);
475
+ };
476
+
477
+ /**
478
+ * Starts a chain for a Jasmine expectation.
479
+ *
480
+ * It is passed an Object that is the actual value and should chain to one of the many
481
+ * jasmine.Matchers functions.
482
+ *
483
+ * @param {Object} actual Actual value to test against and expected value
484
+ */
485
+ var expect = function(actual) {
486
+ return jasmine.getEnv().currentSpec.expect(actual);
487
+ };
488
+
489
+ /**
490
+ * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
491
+ *
492
+ * @param {Function} func Function that defines part of a jasmine spec.
493
+ */
494
+ var runs = function(func) {
495
+ jasmine.getEnv().currentSpec.runs(func);
496
+ };
497
+
498
+ /**
499
+ * Waits a fixed time period before moving to the next block.
500
+ *
501
+ * @deprecated Use waitsFor() instead
502
+ * @param {Number} timeout milliseconds to wait
503
+ */
504
+ var waits = function(timeout) {
505
+ jasmine.getEnv().currentSpec.waits(timeout);
506
+ };
507
+
508
+ /**
509
+ * Waits for the latchFunction to return true before proceeding to the next block.
510
+ *
511
+ * @param {Function} latchFunction
512
+ * @param {String} optional_timeoutMessage
513
+ * @param {Number} optional_timeout
514
+ */
515
+ var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
516
+ jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
517
+ };
518
+
519
+ /**
520
+ * A function that is called before each spec in a suite.
521
+ *
522
+ * Used for spec setup, including validating assumptions.
523
+ *
524
+ * @param {Function} beforeEachFunction
525
+ */
526
+ var beforeEach = function(beforeEachFunction) {
527
+ jasmine.getEnv().beforeEach(beforeEachFunction);
528
+ };
529
+
530
+ /**
531
+ * A function that is called after each spec in a suite.
532
+ *
533
+ * Used for restoring any state that is hijacked during spec execution.
534
+ *
535
+ * @param {Function} afterEachFunction
536
+ */
537
+ var afterEach = function(afterEachFunction) {
538
+ jasmine.getEnv().afterEach(afterEachFunction);
539
+ };
540
+
541
+ /**
542
+ * Defines a suite of specifications.
543
+ *
544
+ * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
545
+ * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
546
+ * of setup in some tests.
547
+ *
548
+ * @example
549
+ * // TODO: a simple suite
550
+ *
551
+ * // TODO: a simple suite with a nested describe block
552
+ *
553
+ * @param {String} description A string, usually the class under test.
554
+ * @param {Function} specDefinitions function that defines several specs.
555
+ */
556
+ var describe = function(description, specDefinitions) {
557
+ return jasmine.getEnv().describe(description, specDefinitions);
558
+ };
559
+
560
+ /**
561
+ * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
562
+ *
563
+ * @param {String} description A string, usually the class under test.
564
+ * @param {Function} specDefinitions function that defines several specs.
565
+ */
566
+ var xdescribe = function(description, specDefinitions) {
567
+ return jasmine.getEnv().xdescribe(description, specDefinitions);
568
+ };
569
+
570
+
571
+ // Provide the XMLHttpRequest class for IE 5.x-6.x:
572
+ jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
573
+ try {
574
+ return new ActiveXObject("Msxml2.XMLHTTP.6.0");
575
+ } catch(e) {
576
+ }
577
+ try {
578
+ return new ActiveXObject("Msxml2.XMLHTTP.3.0");
579
+ } catch(e) {
580
+ }
581
+ try {
582
+ return new ActiveXObject("Msxml2.XMLHTTP");
583
+ } catch(e) {
584
+ }
585
+ try {
586
+ return new ActiveXObject("Microsoft.XMLHTTP");
587
+ } catch(e) {
588
+ }
589
+ throw new Error("This browser does not support XMLHttpRequest.");
590
+ } : XMLHttpRequest;
591
+ /**
592
+ * @namespace
593
+ */
594
+ jasmine.util = {};
595
+
596
+ /**
597
+ * Declare that a child class inherit it's prototype from the parent class.
598
+ *
599
+ * @private
600
+ * @param {Function} childClass
601
+ * @param {Function} parentClass
602
+ */
603
+ jasmine.util.inherit = function(childClass, parentClass) {
604
+ /**
605
+ * @private
606
+ */
607
+ var subclass = function() {
608
+ };
609
+ subclass.prototype = parentClass.prototype;
610
+ childClass.prototype = new subclass;
611
+ };
612
+
613
+ jasmine.util.formatException = function(e) {
614
+ var lineNumber;
615
+ if (e.line) {
616
+ lineNumber = e.line;
617
+ }
618
+ else if (e.lineNumber) {
619
+ lineNumber = e.lineNumber;
620
+ }
621
+
622
+ var file;
623
+
624
+ if (e.sourceURL) {
625
+ file = e.sourceURL;
626
+ }
627
+ else if (e.fileName) {
628
+ file = e.fileName;
629
+ }
630
+
631
+ var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
632
+
633
+ if (file && lineNumber) {
634
+ message += ' in ' + file + ' (line ' + lineNumber + ')';
635
+ }
636
+
637
+ return message;
638
+ };
639
+
640
+ jasmine.util.htmlEscape = function(str) {
641
+ if (!str) return str;
642
+ return str.replace(/&/g, '&amp;')
643
+ .replace(/</g, '&lt;')
644
+ .replace(/>/g, '&gt;');
645
+ };
646
+
647
+ jasmine.util.argsToArray = function(args) {
648
+ var arrayOfArgs = [];
649
+ for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
650
+ return arrayOfArgs;
651
+ };
652
+
653
+ jasmine.util.extend = function(destination, source) {
654
+ for (var property in source) destination[property] = source[property];
655
+ return destination;
656
+ };
657
+
658
+ /**
659
+ * Environment for Jasmine
660
+ *
661
+ * @constructor
662
+ */
663
+ jasmine.Env = function() {
664
+ this.currentSpec = null;
665
+ this.currentSuite = null;
666
+ this.currentRunner_ = new jasmine.Runner(this);
667
+
668
+ this.reporter = new jasmine.MultiReporter();
669
+
670
+ this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
671
+ this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
672
+ this.lastUpdate = 0;
673
+ this.specFilter = function() {
674
+ return true;
675
+ };
676
+
677
+ this.nextSpecId_ = 0;
678
+ this.nextSuiteId_ = 0;
679
+ this.equalityTesters_ = [];
680
+
681
+ // wrap matchers
682
+ this.matchersClass = function() {
683
+ jasmine.Matchers.apply(this, arguments);
684
+ };
685
+ jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
686
+
687
+ jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
688
+ };
689
+
690
+
691
+ jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
692
+ jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
693
+ jasmine.Env.prototype.setInterval = jasmine.setInterval;
694
+ jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
695
+
696
+ /**
697
+ * @returns an object containing jasmine version build info, if set.
698
+ */
699
+ jasmine.Env.prototype.version = function () {
700
+ if (jasmine.version_) {
701
+ return jasmine.version_;
702
+ } else {
703
+ throw new Error('Version not set');
704
+ }
705
+ };
706
+
707
+ /**
708
+ * @returns string containing jasmine version build info, if set.
709
+ */
710
+ jasmine.Env.prototype.versionString = function() {
711
+ if (jasmine.version_) {
712
+ var version = this.version();
713
+ return version.major + "." + version.minor + "." + version.build + " revision " + version.revision;
714
+ } else {
715
+ return "version unknown";
716
+ }
717
+ };
718
+
719
+ /**
720
+ * @returns a sequential integer starting at 0
721
+ */
722
+ jasmine.Env.prototype.nextSpecId = function () {
723
+ return this.nextSpecId_++;
724
+ };
725
+
726
+ /**
727
+ * @returns a sequential integer starting at 0
728
+ */
729
+ jasmine.Env.prototype.nextSuiteId = function () {
730
+ return this.nextSuiteId_++;
731
+ };
732
+
733
+ /**
734
+ * Register a reporter to receive status updates from Jasmine.
735
+ * @param {jasmine.Reporter} reporter An object which will receive status updates.
736
+ */
737
+ jasmine.Env.prototype.addReporter = function(reporter) {
738
+ this.reporter.addReporter(reporter);
739
+ };
740
+
741
+ jasmine.Env.prototype.execute = function() {
742
+ this.currentRunner_.execute();
743
+ };
744
+
745
+ jasmine.Env.prototype.describe = function(description, specDefinitions) {
746
+ var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
747
+
748
+ var parentSuite = this.currentSuite;
749
+ if (parentSuite) {
750
+ parentSuite.add(suite);
751
+ } else {
752
+ this.currentRunner_.add(suite);
753
+ }
754
+
755
+ this.currentSuite = suite;
756
+
757
+ var declarationError = null;
758
+ try {
759
+ specDefinitions.call(suite);
760
+ } catch(e) {
761
+ declarationError = e;
762
+ }
763
+
764
+ this.currentSuite = parentSuite;
765
+
766
+ if (declarationError) {
767
+ this.it("encountered a declaration exception", function() {
768
+ throw declarationError;
769
+ });
770
+ }
771
+
772
+ return suite;
773
+ };
774
+
775
+ jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
776
+ if (this.currentSuite) {
777
+ this.currentSuite.beforeEach(beforeEachFunction);
778
+ } else {
779
+ this.currentRunner_.beforeEach(beforeEachFunction);
780
+ }
781
+ };
782
+
783
+ jasmine.Env.prototype.currentRunner = function () {
784
+ return this.currentRunner_;
785
+ };
786
+
787
+ jasmine.Env.prototype.afterEach = function(afterEachFunction) {
788
+ if (this.currentSuite) {
789
+ this.currentSuite.afterEach(afterEachFunction);
790
+ } else {
791
+ this.currentRunner_.afterEach(afterEachFunction);
792
+ }
793
+
794
+ };
795
+
796
+ jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
797
+ return {
798
+ execute: function() {
799
+ }
800
+ };
801
+ };
802
+
803
+ jasmine.Env.prototype.it = function(description, func) {
804
+ var spec = new jasmine.Spec(this, this.currentSuite, description);
805
+ this.currentSuite.add(spec);
806
+ this.currentSpec = spec;
807
+
808
+ if (func) {
809
+ spec.runs(func);
810
+ }
811
+
812
+ return spec;
813
+ };
814
+
815
+ jasmine.Env.prototype.xit = function(desc, func) {
816
+ return {
817
+ id: this.nextSpecId(),
818
+ runs: function() {
819
+ }
820
+ };
821
+ };
822
+
823
+ jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
824
+ if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
825
+ return true;
826
+ }
827
+
828
+ a.__Jasmine_been_here_before__ = b;
829
+ b.__Jasmine_been_here_before__ = a;
830
+
831
+ var hasKey = function(obj, keyName) {
832
+ return obj != null && obj[keyName] !== jasmine.undefined;
833
+ };
834
+
835
+ for (var property in b) {
836
+ if (!hasKey(a, property) && hasKey(b, property)) {
837
+ mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
838
+ }
839
+ }
840
+ for (property in a) {
841
+ if (!hasKey(b, property) && hasKey(a, property)) {
842
+ mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
843
+ }
844
+ }
845
+ for (property in b) {
846
+ if (property == '__Jasmine_been_here_before__') continue;
847
+ if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
848
+ mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
849
+ }
850
+ }
851
+
852
+ if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
853
+ mismatchValues.push("arrays were not the same length");
854
+ }
855
+
856
+ delete a.__Jasmine_been_here_before__;
857
+ delete b.__Jasmine_been_here_before__;
858
+ return (mismatchKeys.length == 0 && mismatchValues.length == 0);
859
+ };
860
+
861
+ jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
862
+ mismatchKeys = mismatchKeys || [];
863
+ mismatchValues = mismatchValues || [];
864
+
865
+ for (var i = 0; i < this.equalityTesters_.length; i++) {
866
+ var equalityTester = this.equalityTesters_[i];
867
+ var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
868
+ if (result !== jasmine.undefined) return result;
869
+ }
870
+
871
+ if (a === b) return true;
872
+
873
+ if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
874
+ return (a == jasmine.undefined && b == jasmine.undefined);
875
+ }
876
+
877
+ if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
878
+ return a === b;
879
+ }
880
+
881
+ if (a instanceof Date && b instanceof Date) {
882
+ return a.getTime() == b.getTime();
883
+ }
884
+
885
+ if (a instanceof jasmine.Matchers.Any) {
886
+ return a.matches(b);
887
+ }
888
+
889
+ if (b instanceof jasmine.Matchers.Any) {
890
+ return b.matches(a);
891
+ }
892
+
893
+ if (jasmine.isString_(a) && jasmine.isString_(b)) {
894
+ return (a == b);
895
+ }
896
+
897
+ if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
898
+ return (a == b);
899
+ }
900
+
901
+ if (typeof a === "object" && typeof b === "object") {
902
+ return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
903
+ }
904
+
905
+ //Straight check
906
+ return (a === b);
907
+ };
908
+
909
+ jasmine.Env.prototype.contains_ = function(haystack, needle) {
910
+ if (jasmine.isArray_(haystack)) {
911
+ for (var i = 0; i < haystack.length; i++) {
912
+ if (this.equals_(haystack[i], needle)) return true;
913
+ }
914
+ return false;
915
+ }
916
+ return haystack.indexOf(needle) >= 0;
917
+ };
918
+
919
+ jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
920
+ this.equalityTesters_.push(equalityTester);
921
+ };
922
+ /** No-op base class for Jasmine reporters.
923
+ *
924
+ * @constructor
925
+ */
926
+ jasmine.Reporter = function() {
927
+ };
928
+
929
+ //noinspection JSUnusedLocalSymbols
930
+ jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
931
+ };
932
+
933
+ //noinspection JSUnusedLocalSymbols
934
+ jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
935
+ };
936
+
937
+ //noinspection JSUnusedLocalSymbols
938
+ jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
939
+ };
940
+
941
+ //noinspection JSUnusedLocalSymbols
942
+ jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
943
+ };
944
+
945
+ //noinspection JSUnusedLocalSymbols
946
+ jasmine.Reporter.prototype.reportSpecResults = function(spec) {
947
+ };
948
+
949
+ //noinspection JSUnusedLocalSymbols
950
+ jasmine.Reporter.prototype.log = function(str) {
951
+ };
952
+
953
+ /**
954
+ * Blocks are functions with executable code that make up a spec.
955
+ *
956
+ * @constructor
957
+ * @param {jasmine.Env} env
958
+ * @param {Function} func
959
+ * @param {jasmine.Spec} spec
960
+ */
961
+ jasmine.Block = function(env, func, spec) {
962
+ this.env = env;
963
+ this.func = func;
964
+ this.spec = spec;
965
+ };
966
+
967
+ jasmine.Block.prototype.execute = function(onComplete) {
968
+ try {
969
+ this.func.apply(this.spec);
970
+ } catch (e) {
971
+ this.spec.fail(e);
972
+ }
973
+ onComplete();
974
+ };
975
+ /** JavaScript API reporter.
976
+ *
977
+ * @constructor
978
+ */
979
+ jasmine.JsApiReporter = function() {
980
+ this.started = false;
981
+ this.finished = false;
982
+ this.suites_ = [];
983
+ this.results_ = {};
984
+ };
985
+
986
+ jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
987
+ this.started = true;
988
+ var suites = runner.topLevelSuites();
989
+ for (var i = 0; i < suites.length; i++) {
990
+ var suite = suites[i];
991
+ this.suites_.push(this.summarize_(suite));
992
+ }
993
+ };
994
+
995
+ jasmine.JsApiReporter.prototype.suites = function() {
996
+ return this.suites_;
997
+ };
998
+
999
+ jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
1000
+ var isSuite = suiteOrSpec instanceof jasmine.Suite;
1001
+ var summary = {
1002
+ id: suiteOrSpec.id,
1003
+ name: suiteOrSpec.description,
1004
+ type: isSuite ? 'suite' : 'spec',
1005
+ children: []
1006
+ };
1007
+
1008
+ if (isSuite) {
1009
+ var children = suiteOrSpec.children();
1010
+ for (var i = 0; i < children.length; i++) {
1011
+ summary.children.push(this.summarize_(children[i]));
1012
+ }
1013
+ }
1014
+ return summary;
1015
+ };
1016
+
1017
+ jasmine.JsApiReporter.prototype.results = function() {
1018
+ return this.results_;
1019
+ };
1020
+
1021
+ jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
1022
+ return this.results_[specId];
1023
+ };
1024
+
1025
+ //noinspection JSUnusedLocalSymbols
1026
+ jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
1027
+ this.finished = true;
1028
+ };
1029
+
1030
+ //noinspection JSUnusedLocalSymbols
1031
+ jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
1032
+ };
1033
+
1034
+ //noinspection JSUnusedLocalSymbols
1035
+ jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
1036
+ this.results_[spec.id] = {
1037
+ messages: spec.results().getItems(),
1038
+ result: spec.results().failedCount > 0 ? "failed" : "passed"
1039
+ };
1040
+ };
1041
+
1042
+ //noinspection JSUnusedLocalSymbols
1043
+ jasmine.JsApiReporter.prototype.log = function(str) {
1044
+ };
1045
+
1046
+ jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
1047
+ var results = {};
1048
+ for (var i = 0; i < specIds.length; i++) {
1049
+ var specId = specIds[i];
1050
+ results[specId] = this.summarizeResult_(this.results_[specId]);
1051
+ }
1052
+ return results;
1053
+ };
1054
+
1055
+ jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
1056
+ var summaryMessages = [];
1057
+ var messagesLength = result.messages.length;
1058
+ for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
1059
+ var resultMessage = result.messages[messageIndex];
1060
+ summaryMessages.push({
1061
+ text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
1062
+ passed: resultMessage.passed ? resultMessage.passed() : true,
1063
+ type: resultMessage.type,
1064
+ message: resultMessage.message,
1065
+ trace: {
1066
+ stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
1067
+ }
1068
+ });
1069
+ }
1070
+
1071
+ return {
1072
+ result : result.result,
1073
+ messages : summaryMessages
1074
+ };
1075
+ };
1076
+
1077
+ /**
1078
+ * @constructor
1079
+ * @param {jasmine.Env} env
1080
+ * @param actual
1081
+ * @param {jasmine.Spec} spec
1082
+ */
1083
+ jasmine.Matchers = function(env, actual, spec, opt_isNot) {
1084
+ this.env = env;
1085
+ this.actual = actual;
1086
+ this.spec = spec;
1087
+ this.isNot = opt_isNot || false;
1088
+ this.reportWasCalled_ = false;
1089
+ };
1090
+
1091
+ // todo: @deprecated as of Jasmine 0.11, remove soon [xw]
1092
+ jasmine.Matchers.pp = function(str) {
1093
+ throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
1094
+ };
1095
+
1096
+ // todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
1097
+ jasmine.Matchers.prototype.report = function(result, failing_message, details) {
1098
+ throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
1099
+ };
1100
+
1101
+ jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
1102
+ for (var methodName in prototype) {
1103
+ if (methodName == 'report') continue;
1104
+ var orig = prototype[methodName];
1105
+ matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
1106
+ }
1107
+ };
1108
+
1109
+ jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
1110
+ return function() {
1111
+ var matcherArgs = jasmine.util.argsToArray(arguments);
1112
+ var result = matcherFunction.apply(this, arguments);
1113
+
1114
+ if (this.isNot) {
1115
+ result = !result;
1116
+ }
1117
+
1118
+ if (this.reportWasCalled_) return result;
1119
+
1120
+ var message;
1121
+ if (!result) {
1122
+ if (this.message) {
1123
+ message = this.message.apply(this, arguments);
1124
+ if (jasmine.isArray_(message)) {
1125
+ message = message[this.isNot ? 1 : 0];
1126
+ }
1127
+ } else {
1128
+ var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
1129
+ message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
1130
+ if (matcherArgs.length > 0) {
1131
+ for (var i = 0; i < matcherArgs.length; i++) {
1132
+ if (i > 0) message += ",";
1133
+ message += " " + jasmine.pp(matcherArgs[i]);
1134
+ }
1135
+ }
1136
+ message += ".";
1137
+ }
1138
+ }
1139
+ var expectationResult = new jasmine.ExpectationResult({
1140
+ matcherName: matcherName,
1141
+ passed: result,
1142
+ expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
1143
+ actual: this.actual,
1144
+ message: message
1145
+ });
1146
+ this.spec.addMatcherResult(expectationResult);
1147
+ return jasmine.undefined;
1148
+ };
1149
+ };
1150
+
1151
+
1152
+
1153
+
1154
+ /**
1155
+ * toBe: compares the actual to the expected using ===
1156
+ * @param expected
1157
+ */
1158
+ jasmine.Matchers.prototype.toBe = function(expected) {
1159
+ return this.actual === expected;
1160
+ };
1161
+
1162
+ /**
1163
+ * toNotBe: compares the actual to the expected using !==
1164
+ * @param expected
1165
+ * @deprecated as of 1.0. Use not.toBe() instead.
1166
+ */
1167
+ jasmine.Matchers.prototype.toNotBe = function(expected) {
1168
+ return this.actual !== expected;
1169
+ };
1170
+
1171
+ /**
1172
+ * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
1173
+ *
1174
+ * @param expected
1175
+ */
1176
+ jasmine.Matchers.prototype.toEqual = function(expected) {
1177
+ return this.env.equals_(this.actual, expected);
1178
+ };
1179
+
1180
+ /**
1181
+ * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
1182
+ * @param expected
1183
+ * @deprecated as of 1.0. Use not.toNotEqual() instead.
1184
+ */
1185
+ jasmine.Matchers.prototype.toNotEqual = function(expected) {
1186
+ return !this.env.equals_(this.actual, expected);
1187
+ };
1188
+
1189
+ /**
1190
+ * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes
1191
+ * a pattern or a String.
1192
+ *
1193
+ * @param expected
1194
+ */
1195
+ jasmine.Matchers.prototype.toMatch = function(expected) {
1196
+ return new RegExp(expected).test(this.actual);
1197
+ };
1198
+
1199
+ /**
1200
+ * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
1201
+ * @param expected
1202
+ * @deprecated as of 1.0. Use not.toMatch() instead.
1203
+ */
1204
+ jasmine.Matchers.prototype.toNotMatch = function(expected) {
1205
+ return !(new RegExp(expected).test(this.actual));
1206
+ };
1207
+
1208
+ /**
1209
+ * Matcher that compares the actual to jasmine.undefined.
1210
+ */
1211
+ jasmine.Matchers.prototype.toBeDefined = function() {
1212
+ return (this.actual !== jasmine.undefined);
1213
+ };
1214
+
1215
+ /**
1216
+ * Matcher that compares the actual to jasmine.undefined.
1217
+ */
1218
+ jasmine.Matchers.prototype.toBeUndefined = function() {
1219
+ return (this.actual === jasmine.undefined);
1220
+ };
1221
+
1222
+ /**
1223
+ * Matcher that compares the actual to null.
1224
+ */
1225
+ jasmine.Matchers.prototype.toBeNull = function() {
1226
+ return (this.actual === null);
1227
+ };
1228
+
1229
+ /**
1230
+ * Matcher that boolean not-nots the actual.
1231
+ */
1232
+ jasmine.Matchers.prototype.toBeTruthy = function() {
1233
+ return !!this.actual;
1234
+ };
1235
+
1236
+
1237
+ /**
1238
+ * Matcher that boolean nots the actual.
1239
+ */
1240
+ jasmine.Matchers.prototype.toBeFalsy = function() {
1241
+ return !this.actual;
1242
+ };
1243
+
1244
+
1245
+ /**
1246
+ * Matcher that checks to see if the actual, a Jasmine spy, was called.
1247
+ */
1248
+ jasmine.Matchers.prototype.toHaveBeenCalled = function() {
1249
+ if (arguments.length > 0) {
1250
+ throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
1251
+ }
1252
+
1253
+ if (!jasmine.isSpy(this.actual)) {
1254
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
1255
+ }
1256
+
1257
+ this.message = function() {
1258
+ return [
1259
+ "Expected spy " + this.actual.identity + " to have been called.",
1260
+ "Expected spy " + this.actual.identity + " not to have been called."
1261
+ ];
1262
+ };
1263
+
1264
+ return this.actual.wasCalled;
1265
+ };
1266
+
1267
+ /** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
1268
+ jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
1269
+
1270
+ /**
1271
+ * Matcher that checks to see if the actual, a Jasmine spy, was not called.
1272
+ *
1273
+ * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
1274
+ */
1275
+ jasmine.Matchers.prototype.wasNotCalled = function() {
1276
+ if (arguments.length > 0) {
1277
+ throw new Error('wasNotCalled does not take arguments');
1278
+ }
1279
+
1280
+ if (!jasmine.isSpy(this.actual)) {
1281
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
1282
+ }
1283
+
1284
+ this.message = function() {
1285
+ return [
1286
+ "Expected spy " + this.actual.identity + " to not have been called.",
1287
+ "Expected spy " + this.actual.identity + " to have been called."
1288
+ ];
1289
+ };
1290
+
1291
+ return !this.actual.wasCalled;
1292
+ };
1293
+
1294
+ /**
1295
+ * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
1296
+ *
1297
+ * @example
1298
+ *
1299
+ */
1300
+ jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
1301
+ var expectedArgs = jasmine.util.argsToArray(arguments);
1302
+ if (!jasmine.isSpy(this.actual)) {
1303
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
1304
+ }
1305
+ this.message = function() {
1306
+ if (this.actual.callCount == 0) {
1307
+ // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw]
1308
+ return [
1309
+ "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.",
1310
+ "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was."
1311
+ ];
1312
+ } else {
1313
+ return [
1314
+ "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall),
1315
+ "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall)
1316
+ ];
1317
+ }
1318
+ };
1319
+
1320
+ return this.env.contains_(this.actual.argsForCall, expectedArgs);
1321
+ };
1322
+
1323
+ /** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
1324
+ jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
1325
+
1326
+ /** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
1327
+ jasmine.Matchers.prototype.wasNotCalledWith = function() {
1328
+ var expectedArgs = jasmine.util.argsToArray(arguments);
1329
+ if (!jasmine.isSpy(this.actual)) {
1330
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
1331
+ }
1332
+
1333
+ this.message = function() {
1334
+ return [
1335
+ "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
1336
+ "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
1337
+ ]
1338
+ };
1339
+
1340
+ return !this.env.contains_(this.actual.argsForCall, expectedArgs);
1341
+ };
1342
+
1343
+ /**
1344
+ * Matcher that checks that the expected item is an element in the actual Array.
1345
+ *
1346
+ * @param {Object} expected
1347
+ */
1348
+ jasmine.Matchers.prototype.toContain = function(expected) {
1349
+ return this.env.contains_(this.actual, expected);
1350
+ };
1351
+
1352
+ /**
1353
+ * Matcher that checks that the expected item is NOT an element in the actual Array.
1354
+ *
1355
+ * @param {Object} expected
1356
+ * @deprecated as of 1.0. Use not.toNotContain() instead.
1357
+ */
1358
+ jasmine.Matchers.prototype.toNotContain = function(expected) {
1359
+ return !this.env.contains_(this.actual, expected);
1360
+ };
1361
+
1362
+ jasmine.Matchers.prototype.toBeLessThan = function(expected) {
1363
+ return this.actual < expected;
1364
+ };
1365
+
1366
+ jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
1367
+ return this.actual > expected;
1368
+ };
1369
+
1370
+ /**
1371
+ * Matcher that checks that the expected exception was thrown by the actual.
1372
+ *
1373
+ * @param {String} expected
1374
+ */
1375
+ jasmine.Matchers.prototype.toThrow = function(expected) {
1376
+ var result = false;
1377
+ var exception;
1378
+ if (typeof this.actual != 'function') {
1379
+ throw new Error('Actual is not a function');
1380
+ }
1381
+ try {
1382
+ this.actual();
1383
+ } catch (e) {
1384
+ exception = e;
1385
+ }
1386
+ if (exception) {
1387
+ result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
1388
+ }
1389
+
1390
+ var not = this.isNot ? "not " : "";
1391
+
1392
+ this.message = function() {
1393
+ if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
1394
+ return ["Expected function " + not + "to throw", expected ? expected.message || expected : " an exception", ", but it threw", exception.message || exception].join(' ');
1395
+ } else {
1396
+ return "Expected function to throw an exception.";
1397
+ }
1398
+ };
1399
+
1400
+ return result;
1401
+ };
1402
+
1403
+ jasmine.Matchers.Any = function(expectedClass) {
1404
+ this.expectedClass = expectedClass;
1405
+ };
1406
+
1407
+ jasmine.Matchers.Any.prototype.matches = function(other) {
1408
+ if (this.expectedClass == String) {
1409
+ return typeof other == 'string' || other instanceof String;
1410
+ }
1411
+
1412
+ if (this.expectedClass == Number) {
1413
+ return typeof other == 'number' || other instanceof Number;
1414
+ }
1415
+
1416
+ if (this.expectedClass == Function) {
1417
+ return typeof other == 'function' || other instanceof Function;
1418
+ }
1419
+
1420
+ if (this.expectedClass == Object) {
1421
+ return typeof other == 'object';
1422
+ }
1423
+
1424
+ return other instanceof this.expectedClass;
1425
+ };
1426
+
1427
+ jasmine.Matchers.Any.prototype.toString = function() {
1428
+ return '<jasmine.any(' + this.expectedClass + ')>';
1429
+ };
1430
+
1431
+ /**
1432
+ * @constructor
1433
+ */
1434
+ jasmine.MultiReporter = function() {
1435
+ this.subReporters_ = [];
1436
+ };
1437
+ jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
1438
+
1439
+ jasmine.MultiReporter.prototype.addReporter = function(reporter) {
1440
+ this.subReporters_.push(reporter);
1441
+ };
1442
+
1443
+ (function() {
1444
+ var functionNames = [
1445
+ "reportRunnerStarting",
1446
+ "reportRunnerResults",
1447
+ "reportSuiteResults",
1448
+ "reportSpecStarting",
1449
+ "reportSpecResults",
1450
+ "log"
1451
+ ];
1452
+ for (var i = 0; i < functionNames.length; i++) {
1453
+ var functionName = functionNames[i];
1454
+ jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
1455
+ return function() {
1456
+ for (var j = 0; j < this.subReporters_.length; j++) {
1457
+ var subReporter = this.subReporters_[j];
1458
+ if (subReporter[functionName]) {
1459
+ subReporter[functionName].apply(subReporter, arguments);
1460
+ }
1461
+ }
1462
+ };
1463
+ })(functionName);
1464
+ }
1465
+ })();
1466
+ /**
1467
+ * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
1468
+ *
1469
+ * @constructor
1470
+ */
1471
+ jasmine.NestedResults = function() {
1472
+ /**
1473
+ * The total count of results
1474
+ */
1475
+ this.totalCount = 0;
1476
+ /**
1477
+ * Number of passed results
1478
+ */
1479
+ this.passedCount = 0;
1480
+ /**
1481
+ * Number of failed results
1482
+ */
1483
+ this.failedCount = 0;
1484
+ /**
1485
+ * Was this suite/spec skipped?
1486
+ */
1487
+ this.skipped = false;
1488
+ /**
1489
+ * @ignore
1490
+ */
1491
+ this.items_ = [];
1492
+ };
1493
+
1494
+ /**
1495
+ * Roll up the result counts.
1496
+ *
1497
+ * @param result
1498
+ */
1499
+ jasmine.NestedResults.prototype.rollupCounts = function(result) {
1500
+ this.totalCount += result.totalCount;
1501
+ this.passedCount += result.passedCount;
1502
+ this.failedCount += result.failedCount;
1503
+ };
1504
+
1505
+ /**
1506
+ * Adds a log message.
1507
+ * @param values Array of message parts which will be concatenated later.
1508
+ */
1509
+ jasmine.NestedResults.prototype.log = function(values) {
1510
+ this.items_.push(new jasmine.MessageResult(values));
1511
+ };
1512
+
1513
+ /**
1514
+ * Getter for the results: message & results.
1515
+ */
1516
+ jasmine.NestedResults.prototype.getItems = function() {
1517
+ return this.items_;
1518
+ };
1519
+
1520
+ /**
1521
+ * Adds a result, tracking counts (total, passed, & failed)
1522
+ * @param {jasmine.ExpectationResult|jasmine.NestedResults} result
1523
+ */
1524
+ jasmine.NestedResults.prototype.addResult = function(result) {
1525
+ if (result.type != 'log') {
1526
+ if (result.items_) {
1527
+ this.rollupCounts(result);
1528
+ } else {
1529
+ this.totalCount++;
1530
+ if (result.passed()) {
1531
+ this.passedCount++;
1532
+ } else {
1533
+ this.failedCount++;
1534
+ }
1535
+ }
1536
+ }
1537
+ this.items_.push(result);
1538
+ };
1539
+
1540
+ /**
1541
+ * @returns {Boolean} True if <b>everything</b> below passed
1542
+ */
1543
+ jasmine.NestedResults.prototype.passed = function() {
1544
+ return this.passedCount === this.totalCount;
1545
+ };
1546
+ /**
1547
+ * Base class for pretty printing for expectation results.
1548
+ */
1549
+ jasmine.PrettyPrinter = function() {
1550
+ this.ppNestLevel_ = 0;
1551
+ };
1552
+
1553
+ /**
1554
+ * Formats a value in a nice, human-readable string.
1555
+ *
1556
+ * @param value
1557
+ */
1558
+ jasmine.PrettyPrinter.prototype.format = function(value) {
1559
+ if (this.ppNestLevel_ > 40) {
1560
+ throw new Error('jasmine.PrettyPrinter: format() nested too deeply!');
1561
+ }
1562
+
1563
+ this.ppNestLevel_++;
1564
+ try {
1565
+ if (value === jasmine.undefined) {
1566
+ this.emitScalar('undefined');
1567
+ } else if (value === null) {
1568
+ this.emitScalar('null');
1569
+ } else if (value === jasmine.getGlobal()) {
1570
+ this.emitScalar('<global>');
1571
+ } else if (value instanceof jasmine.Matchers.Any) {
1572
+ this.emitScalar(value.toString());
1573
+ } else if (typeof value === 'string') {
1574
+ this.emitString(value);
1575
+ } else if (jasmine.isSpy(value)) {
1576
+ this.emitScalar("spy on " + value.identity);
1577
+ } else if (value instanceof RegExp) {
1578
+ this.emitScalar(value.toString());
1579
+ } else if (typeof value === 'function') {
1580
+ this.emitScalar('Function');
1581
+ } else if (typeof value.nodeType === 'number') {
1582
+ this.emitScalar('HTMLNode');
1583
+ } else if (value instanceof Date) {
1584
+ this.emitScalar('Date(' + value + ')');
1585
+ } else if (value.__Jasmine_been_here_before__) {
1586
+ this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
1587
+ } else if (jasmine.isArray_(value) || typeof value == 'object') {
1588
+ value.__Jasmine_been_here_before__ = true;
1589
+ if (jasmine.isArray_(value)) {
1590
+ this.emitArray(value);
1591
+ } else {
1592
+ this.emitObject(value);
1593
+ }
1594
+ delete value.__Jasmine_been_here_before__;
1595
+ } else {
1596
+ this.emitScalar(value.toString());
1597
+ }
1598
+ } finally {
1599
+ this.ppNestLevel_--;
1600
+ }
1601
+ };
1602
+
1603
+ jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
1604
+ for (var property in obj) {
1605
+ if (property == '__Jasmine_been_here_before__') continue;
1606
+ fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) != null) : false);
1607
+ }
1608
+ };
1609
+
1610
+ jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
1611
+ jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
1612
+ jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
1613
+ jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
1614
+
1615
+ jasmine.StringPrettyPrinter = function() {
1616
+ jasmine.PrettyPrinter.call(this);
1617
+
1618
+ this.string = '';
1619
+ };
1620
+ jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
1621
+
1622
+ jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
1623
+ this.append(value);
1624
+ };
1625
+
1626
+ jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
1627
+ this.append("'" + value + "'");
1628
+ };
1629
+
1630
+ jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
1631
+ this.append('[ ');
1632
+ for (var i = 0; i < array.length; i++) {
1633
+ if (i > 0) {
1634
+ this.append(', ');
1635
+ }
1636
+ this.format(array[i]);
1637
+ }
1638
+ this.append(' ]');
1639
+ };
1640
+
1641
+ jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
1642
+ var self = this;
1643
+ this.append('{ ');
1644
+ var first = true;
1645
+
1646
+ this.iterateObject(obj, function(property, isGetter) {
1647
+ if (first) {
1648
+ first = false;
1649
+ } else {
1650
+ self.append(', ');
1651
+ }
1652
+
1653
+ self.append(property);
1654
+ self.append(' : ');
1655
+ if (isGetter) {
1656
+ self.append('<getter>');
1657
+ } else {
1658
+ self.format(obj[property]);
1659
+ }
1660
+ });
1661
+
1662
+ this.append(' }');
1663
+ };
1664
+
1665
+ jasmine.StringPrettyPrinter.prototype.append = function(value) {
1666
+ this.string += value;
1667
+ };
1668
+ jasmine.Queue = function(env) {
1669
+ this.env = env;
1670
+ this.blocks = [];
1671
+ this.running = false;
1672
+ this.index = 0;
1673
+ this.offset = 0;
1674
+ this.abort = false;
1675
+ };
1676
+
1677
+ jasmine.Queue.prototype.addBefore = function(block) {
1678
+ this.blocks.unshift(block);
1679
+ };
1680
+
1681
+ jasmine.Queue.prototype.add = function(block) {
1682
+ this.blocks.push(block);
1683
+ };
1684
+
1685
+ jasmine.Queue.prototype.insertNext = function(block) {
1686
+ this.blocks.splice((this.index + this.offset + 1), 0, block);
1687
+ this.offset++;
1688
+ };
1689
+
1690
+ jasmine.Queue.prototype.start = function(onComplete) {
1691
+ this.running = true;
1692
+ this.onComplete = onComplete;
1693
+ this.next_();
1694
+ };
1695
+
1696
+ jasmine.Queue.prototype.isRunning = function() {
1697
+ return this.running;
1698
+ };
1699
+
1700
+ jasmine.Queue.LOOP_DONT_RECURSE = true;
1701
+
1702
+ jasmine.Queue.prototype.next_ = function() {
1703
+ var self = this;
1704
+ var goAgain = true;
1705
+
1706
+ while (goAgain) {
1707
+ goAgain = false;
1708
+
1709
+ if (self.index < self.blocks.length && !this.abort) {
1710
+ var calledSynchronously = true;
1711
+ var completedSynchronously = false;
1712
+
1713
+ var onComplete = function () {
1714
+ if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
1715
+ completedSynchronously = true;
1716
+ return;
1717
+ }
1718
+
1719
+ if (self.blocks[self.index].abort) {
1720
+ self.abort = true;
1721
+ }
1722
+
1723
+ self.offset = 0;
1724
+ self.index++;
1725
+
1726
+ var now = new Date().getTime();
1727
+ if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
1728
+ self.env.lastUpdate = now;
1729
+ self.env.setTimeout(function() {
1730
+ self.next_();
1731
+ }, 0);
1732
+ } else {
1733
+ if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
1734
+ goAgain = true;
1735
+ } else {
1736
+ self.next_();
1737
+ }
1738
+ }
1739
+ };
1740
+ self.blocks[self.index].execute(onComplete);
1741
+
1742
+ calledSynchronously = false;
1743
+ if (completedSynchronously) {
1744
+ onComplete();
1745
+ }
1746
+
1747
+ } else {
1748
+ self.running = false;
1749
+ if (self.onComplete) {
1750
+ self.onComplete();
1751
+ }
1752
+ }
1753
+ }
1754
+ };
1755
+
1756
+ jasmine.Queue.prototype.results = function() {
1757
+ var results = new jasmine.NestedResults();
1758
+ for (var i = 0; i < this.blocks.length; i++) {
1759
+ if (this.blocks[i].results) {
1760
+ results.addResult(this.blocks[i].results());
1761
+ }
1762
+ }
1763
+ return results;
1764
+ };
1765
+
1766
+
1767
+ /**
1768
+ * Runner
1769
+ *
1770
+ * @constructor
1771
+ * @param {jasmine.Env} env
1772
+ */
1773
+ jasmine.Runner = function(env) {
1774
+ var self = this;
1775
+ self.env = env;
1776
+ self.queue = new jasmine.Queue(env);
1777
+ self.before_ = [];
1778
+ self.after_ = [];
1779
+ self.suites_ = [];
1780
+ };
1781
+
1782
+ jasmine.Runner.prototype.execute = function() {
1783
+ var self = this;
1784
+ if (self.env.reporter.reportRunnerStarting) {
1785
+ self.env.reporter.reportRunnerStarting(this);
1786
+ }
1787
+ self.queue.start(function () {
1788
+ self.finishCallback();
1789
+ });
1790
+ };
1791
+
1792
+ jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
1793
+ beforeEachFunction.typeName = 'beforeEach';
1794
+ this.before_.splice(0,0,beforeEachFunction);
1795
+ };
1796
+
1797
+ jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
1798
+ afterEachFunction.typeName = 'afterEach';
1799
+ this.after_.splice(0,0,afterEachFunction);
1800
+ };
1801
+
1802
+
1803
+ jasmine.Runner.prototype.finishCallback = function() {
1804
+ this.env.reporter.reportRunnerResults(this);
1805
+ };
1806
+
1807
+ jasmine.Runner.prototype.addSuite = function(suite) {
1808
+ this.suites_.push(suite);
1809
+ };
1810
+
1811
+ jasmine.Runner.prototype.add = function(block) {
1812
+ if (block instanceof jasmine.Suite) {
1813
+ this.addSuite(block);
1814
+ }
1815
+ this.queue.add(block);
1816
+ };
1817
+
1818
+ jasmine.Runner.prototype.specs = function () {
1819
+ var suites = this.suites();
1820
+ var specs = [];
1821
+ for (var i = 0; i < suites.length; i++) {
1822
+ specs = specs.concat(suites[i].specs());
1823
+ }
1824
+ return specs;
1825
+ };
1826
+
1827
+ jasmine.Runner.prototype.suites = function() {
1828
+ return this.suites_;
1829
+ };
1830
+
1831
+ jasmine.Runner.prototype.topLevelSuites = function() {
1832
+ var topLevelSuites = [];
1833
+ for (var i = 0; i < this.suites_.length; i++) {
1834
+ if (!this.suites_[i].parentSuite) {
1835
+ topLevelSuites.push(this.suites_[i]);
1836
+ }
1837
+ }
1838
+ return topLevelSuites;
1839
+ };
1840
+
1841
+ jasmine.Runner.prototype.results = function() {
1842
+ return this.queue.results();
1843
+ };
1844
+ /**
1845
+ * Internal representation of a Jasmine specification, or test.
1846
+ *
1847
+ * @constructor
1848
+ * @param {jasmine.Env} env
1849
+ * @param {jasmine.Suite} suite
1850
+ * @param {String} description
1851
+ */
1852
+ jasmine.Spec = function(env, suite, description) {
1853
+ if (!env) {
1854
+ throw new Error('jasmine.Env() required');
1855
+ }
1856
+ if (!suite) {
1857
+ throw new Error('jasmine.Suite() required');
1858
+ }
1859
+ var spec = this;
1860
+ spec.id = env.nextSpecId ? env.nextSpecId() : null;
1861
+ spec.env = env;
1862
+ spec.suite = suite;
1863
+ spec.description = description;
1864
+ spec.queue = new jasmine.Queue(env);
1865
+
1866
+ spec.afterCallbacks = [];
1867
+ spec.spies_ = [];
1868
+
1869
+ spec.results_ = new jasmine.NestedResults();
1870
+ spec.results_.description = description;
1871
+ spec.matchersClass = null;
1872
+ };
1873
+
1874
+ jasmine.Spec.prototype.getFullName = function() {
1875
+ return this.suite.getFullName() + ' ' + this.description + '.';
1876
+ };
1877
+
1878
+
1879
+ jasmine.Spec.prototype.results = function() {
1880
+ return this.results_;
1881
+ };
1882
+
1883
+ /**
1884
+ * All parameters are pretty-printed and concatenated together, then written to the spec's output.
1885
+ *
1886
+ * Be careful not to leave calls to <code>jasmine.log</code> in production code.
1887
+ */
1888
+ jasmine.Spec.prototype.log = function() {
1889
+ return this.results_.log(arguments);
1890
+ };
1891
+
1892
+ jasmine.Spec.prototype.runs = function (func) {
1893
+ var block = new jasmine.Block(this.env, func, this);
1894
+ this.addToQueue(block);
1895
+ return this;
1896
+ };
1897
+
1898
+ jasmine.Spec.prototype.addToQueue = function (block) {
1899
+ if (this.queue.isRunning()) {
1900
+ this.queue.insertNext(block);
1901
+ } else {
1902
+ this.queue.add(block);
1903
+ }
1904
+ };
1905
+
1906
+ /**
1907
+ * @param {jasmine.ExpectationResult} result
1908
+ */
1909
+ jasmine.Spec.prototype.addMatcherResult = function(result) {
1910
+ this.results_.addResult(result);
1911
+ };
1912
+
1913
+ jasmine.Spec.prototype.expect = function(actual) {
1914
+ var positive = new (this.getMatchersClass_())(this.env, actual, this);
1915
+ positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
1916
+ return positive;
1917
+ };
1918
+
1919
+ /**
1920
+ * Waits a fixed time period before moving to the next block.
1921
+ *
1922
+ * @deprecated Use waitsFor() instead
1923
+ * @param {Number} timeout milliseconds to wait
1924
+ */
1925
+ jasmine.Spec.prototype.waits = function(timeout) {
1926
+ var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
1927
+ this.addToQueue(waitsFunc);
1928
+ return this;
1929
+ };
1930
+
1931
+ /**
1932
+ * Waits for the latchFunction to return true before proceeding to the next block.
1933
+ *
1934
+ * @param {Function} latchFunction
1935
+ * @param {String} optional_timeoutMessage
1936
+ * @param {Number} optional_timeout
1937
+ */
1938
+ jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
1939
+ var latchFunction_ = null;
1940
+ var optional_timeoutMessage_ = null;
1941
+ var optional_timeout_ = null;
1942
+
1943
+ for (var i = 0; i < arguments.length; i++) {
1944
+ var arg = arguments[i];
1945
+ switch (typeof arg) {
1946
+ case 'function':
1947
+ latchFunction_ = arg;
1948
+ break;
1949
+ case 'string':
1950
+ optional_timeoutMessage_ = arg;
1951
+ break;
1952
+ case 'number':
1953
+ optional_timeout_ = arg;
1954
+ break;
1955
+ }
1956
+ }
1957
+
1958
+ var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
1959
+ this.addToQueue(waitsForFunc);
1960
+ return this;
1961
+ };
1962
+
1963
+ jasmine.Spec.prototype.fail = function (e) {
1964
+ var expectationResult = new jasmine.ExpectationResult({
1965
+ passed: false,
1966
+ message: e ? jasmine.util.formatException(e) : 'Exception',
1967
+ error: e
1968
+ });
1969
+ this.results_.addResult(expectationResult);
1970
+ };
1971
+
1972
+ jasmine.Spec.prototype.getMatchersClass_ = function() {
1973
+ return this.matchersClass || this.env.matchersClass;
1974
+ };
1975
+
1976
+ jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
1977
+ var parent = this.getMatchersClass_();
1978
+ var newMatchersClass = function() {
1979
+ parent.apply(this, arguments);
1980
+ };
1981
+ jasmine.util.inherit(newMatchersClass, parent);
1982
+ jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
1983
+ this.matchersClass = newMatchersClass;
1984
+ };
1985
+
1986
+ jasmine.Spec.prototype.finishCallback = function() {
1987
+ this.env.reporter.reportSpecResults(this);
1988
+ };
1989
+
1990
+ jasmine.Spec.prototype.finish = function(onComplete) {
1991
+ this.removeAllSpies();
1992
+ this.finishCallback();
1993
+ if (onComplete) {
1994
+ onComplete();
1995
+ }
1996
+ };
1997
+
1998
+ jasmine.Spec.prototype.after = function(doAfter) {
1999
+ if (this.queue.isRunning()) {
2000
+ this.queue.add(new jasmine.Block(this.env, doAfter, this));
2001
+ } else {
2002
+ this.afterCallbacks.unshift(doAfter);
2003
+ }
2004
+ };
2005
+
2006
+ jasmine.Spec.prototype.execute = function(onComplete) {
2007
+ var spec = this;
2008
+ if (!spec.env.specFilter(spec)) {
2009
+ spec.results_.skipped = true;
2010
+ spec.finish(onComplete);
2011
+ return;
2012
+ }
2013
+
2014
+ this.env.reporter.reportSpecStarting(this);
2015
+
2016
+ spec.env.currentSpec = spec;
2017
+
2018
+ spec.addBeforesAndAftersToQueue();
2019
+
2020
+ spec.queue.start(function () {
2021
+ spec.finish(onComplete);
2022
+ });
2023
+ };
2024
+
2025
+ jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
2026
+ var runner = this.env.currentRunner();
2027
+ var i;
2028
+
2029
+ for (var suite = this.suite; suite; suite = suite.parentSuite) {
2030
+ for (i = 0; i < suite.before_.length; i++) {
2031
+ this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
2032
+ }
2033
+ }
2034
+ for (i = 0; i < runner.before_.length; i++) {
2035
+ this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
2036
+ }
2037
+ for (i = 0; i < this.afterCallbacks.length; i++) {
2038
+ this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));
2039
+ }
2040
+ for (suite = this.suite; suite; suite = suite.parentSuite) {
2041
+ for (i = 0; i < suite.after_.length; i++) {
2042
+ this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));
2043
+ }
2044
+ }
2045
+ for (i = 0; i < runner.after_.length; i++) {
2046
+ this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
2047
+ }
2048
+ };
2049
+
2050
+ jasmine.Spec.prototype.explodes = function() {
2051
+ throw 'explodes function should not have been called';
2052
+ };
2053
+
2054
+ jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
2055
+ if (obj == jasmine.undefined) {
2056
+ throw "spyOn could not find an object to spy upon for " + methodName + "()";
2057
+ }
2058
+
2059
+ if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
2060
+ throw methodName + '() method does not exist';
2061
+ }
2062
+
2063
+ if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
2064
+ throw new Error(methodName + ' has already been spied upon');
2065
+ }
2066
+
2067
+ var spyObj = jasmine.createSpy(methodName);
2068
+
2069
+ this.spies_.push(spyObj);
2070
+ spyObj.baseObj = obj;
2071
+ spyObj.methodName = methodName;
2072
+ spyObj.originalValue = obj[methodName];
2073
+
2074
+ obj[methodName] = spyObj;
2075
+
2076
+ return spyObj;
2077
+ };
2078
+
2079
+ jasmine.Spec.prototype.removeAllSpies = function() {
2080
+ for (var i = 0; i < this.spies_.length; i++) {
2081
+ var spy = this.spies_[i];
2082
+ spy.baseObj[spy.methodName] = spy.originalValue;
2083
+ }
2084
+ this.spies_ = [];
2085
+ };
2086
+
2087
+ /**
2088
+ * Internal representation of a Jasmine suite.
2089
+ *
2090
+ * @constructor
2091
+ * @param {jasmine.Env} env
2092
+ * @param {String} description
2093
+ * @param {Function} specDefinitions
2094
+ * @param {jasmine.Suite} parentSuite
2095
+ */
2096
+ jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
2097
+ var self = this;
2098
+ self.id = env.nextSuiteId ? env.nextSuiteId() : null;
2099
+ self.description = description;
2100
+ self.queue = new jasmine.Queue(env);
2101
+ self.parentSuite = parentSuite;
2102
+ self.env = env;
2103
+ self.before_ = [];
2104
+ self.after_ = [];
2105
+ self.children_ = [];
2106
+ self.suites_ = [];
2107
+ self.specs_ = [];
2108
+ };
2109
+
2110
+ jasmine.Suite.prototype.getFullName = function() {
2111
+ var fullName = this.description;
2112
+ for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
2113
+ fullName = parentSuite.description + ' ' + fullName;
2114
+ }
2115
+ return fullName;
2116
+ };
2117
+
2118
+ jasmine.Suite.prototype.finish = function(onComplete) {
2119
+ this.env.reporter.reportSuiteResults(this);
2120
+ this.finished = true;
2121
+ if (typeof(onComplete) == 'function') {
2122
+ onComplete();
2123
+ }
2124
+ };
2125
+
2126
+ jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
2127
+ beforeEachFunction.typeName = 'beforeEach';
2128
+ this.before_.unshift(beforeEachFunction);
2129
+ };
2130
+
2131
+ jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
2132
+ afterEachFunction.typeName = 'afterEach';
2133
+ this.after_.unshift(afterEachFunction);
2134
+ };
2135
+
2136
+ jasmine.Suite.prototype.results = function() {
2137
+ return this.queue.results();
2138
+ };
2139
+
2140
+ jasmine.Suite.prototype.add = function(suiteOrSpec) {
2141
+ this.children_.push(suiteOrSpec);
2142
+ if (suiteOrSpec instanceof jasmine.Suite) {
2143
+ this.suites_.push(suiteOrSpec);
2144
+ this.env.currentRunner().addSuite(suiteOrSpec);
2145
+ } else {
2146
+ this.specs_.push(suiteOrSpec);
2147
+ }
2148
+ this.queue.add(suiteOrSpec);
2149
+ };
2150
+
2151
+ jasmine.Suite.prototype.specs = function() {
2152
+ return this.specs_;
2153
+ };
2154
+
2155
+ jasmine.Suite.prototype.suites = function() {
2156
+ return this.suites_;
2157
+ };
2158
+
2159
+ jasmine.Suite.prototype.children = function() {
2160
+ return this.children_;
2161
+ };
2162
+
2163
+ jasmine.Suite.prototype.execute = function(onComplete) {
2164
+ var self = this;
2165
+ this.queue.start(function () {
2166
+ self.finish(onComplete);
2167
+ });
2168
+ };
2169
+ jasmine.WaitsBlock = function(env, timeout, spec) {
2170
+ this.timeout = timeout;
2171
+ jasmine.Block.call(this, env, null, spec);
2172
+ };
2173
+
2174
+ jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
2175
+
2176
+ jasmine.WaitsBlock.prototype.execute = function (onComplete) {
2177
+ this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
2178
+ this.env.setTimeout(function () {
2179
+ onComplete();
2180
+ }, this.timeout);
2181
+ };
2182
+ /**
2183
+ * A block which waits for some condition to become true, with timeout.
2184
+ *
2185
+ * @constructor
2186
+ * @extends jasmine.Block
2187
+ * @param {jasmine.Env} env The Jasmine environment.
2188
+ * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
2189
+ * @param {Function} latchFunction A function which returns true when the desired condition has been met.
2190
+ * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
2191
+ * @param {jasmine.Spec} spec The Jasmine spec.
2192
+ */
2193
+ jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
2194
+ this.timeout = timeout || env.defaultTimeoutInterval;
2195
+ this.latchFunction = latchFunction;
2196
+ this.message = message;
2197
+ this.totalTimeSpentWaitingForLatch = 0;
2198
+ jasmine.Block.call(this, env, null, spec);
2199
+ };
2200
+ jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
2201
+
2202
+ jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
2203
+
2204
+ jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
2205
+ this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
2206
+ var latchFunctionResult;
2207
+ try {
2208
+ latchFunctionResult = this.latchFunction.apply(this.spec);
2209
+ } catch (e) {
2210
+ this.spec.fail(e);
2211
+ onComplete();
2212
+ return;
2213
+ }
2214
+
2215
+ if (latchFunctionResult) {
2216
+ onComplete();
2217
+ } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
2218
+ var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
2219
+ this.spec.fail({
2220
+ name: 'timeout',
2221
+ message: message
2222
+ });
2223
+
2224
+ this.abort = true;
2225
+ onComplete();
2226
+ } else {
2227
+ this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
2228
+ var self = this;
2229
+ this.env.setTimeout(function() {
2230
+ self.execute(onComplete);
2231
+ }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
2232
+ }
2233
+ };
2234
+ // Mock setTimeout, clearTimeout
2235
+ // Contributed by Pivotal Computer Systems, www.pivotalsf.com
2236
+
2237
+ jasmine.FakeTimer = function() {
2238
+ this.reset();
2239
+
2240
+ var self = this;
2241
+ self.setTimeout = function(funcToCall, millis) {
2242
+ self.timeoutsMade++;
2243
+ self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
2244
+ return self.timeoutsMade;
2245
+ };
2246
+
2247
+ self.setInterval = function(funcToCall, millis) {
2248
+ self.timeoutsMade++;
2249
+ self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
2250
+ return self.timeoutsMade;
2251
+ };
2252
+
2253
+ self.clearTimeout = function(timeoutKey) {
2254
+ self.scheduledFunctions[timeoutKey] = jasmine.undefined;
2255
+ };
2256
+
2257
+ self.clearInterval = function(timeoutKey) {
2258
+ self.scheduledFunctions[timeoutKey] = jasmine.undefined;
2259
+ };
2260
+
2261
+ };
2262
+
2263
+ jasmine.FakeTimer.prototype.reset = function() {
2264
+ this.timeoutsMade = 0;
2265
+ this.scheduledFunctions = {};
2266
+ this.nowMillis = 0;
2267
+ };
2268
+
2269
+ jasmine.FakeTimer.prototype.tick = function(millis) {
2270
+ var oldMillis = this.nowMillis;
2271
+ var newMillis = oldMillis + millis;
2272
+ this.runFunctionsWithinRange(oldMillis, newMillis);
2273
+ this.nowMillis = newMillis;
2274
+ };
2275
+
2276
+ jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
2277
+ var scheduledFunc;
2278
+ var funcsToRun = [];
2279
+ for (var timeoutKey in this.scheduledFunctions) {
2280
+ scheduledFunc = this.scheduledFunctions[timeoutKey];
2281
+ if (scheduledFunc != jasmine.undefined &&
2282
+ scheduledFunc.runAtMillis >= oldMillis &&
2283
+ scheduledFunc.runAtMillis <= nowMillis) {
2284
+ funcsToRun.push(scheduledFunc);
2285
+ this.scheduledFunctions[timeoutKey] = jasmine.undefined;
2286
+ }
2287
+ }
2288
+
2289
+ if (funcsToRun.length > 0) {
2290
+ funcsToRun.sort(function(a, b) {
2291
+ return a.runAtMillis - b.runAtMillis;
2292
+ });
2293
+ for (var i = 0; i < funcsToRun.length; ++i) {
2294
+ try {
2295
+ var funcToRun = funcsToRun[i];
2296
+ this.nowMillis = funcToRun.runAtMillis;
2297
+ funcToRun.funcToCall();
2298
+ if (funcToRun.recurring) {
2299
+ this.scheduleFunction(funcToRun.timeoutKey,
2300
+ funcToRun.funcToCall,
2301
+ funcToRun.millis,
2302
+ true);
2303
+ }
2304
+ } catch(e) {
2305
+ }
2306
+ }
2307
+ this.runFunctionsWithinRange(oldMillis, nowMillis);
2308
+ }
2309
+ };
2310
+
2311
+ jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
2312
+ this.scheduledFunctions[timeoutKey] = {
2313
+ runAtMillis: this.nowMillis + millis,
2314
+ funcToCall: funcToCall,
2315
+ recurring: recurring,
2316
+ timeoutKey: timeoutKey,
2317
+ millis: millis
2318
+ };
2319
+ };
2320
+
2321
+ /**
2322
+ * @namespace
2323
+ */
2324
+ jasmine.Clock = {
2325
+ defaultFakeTimer: new jasmine.FakeTimer(),
2326
+
2327
+ reset: function() {
2328
+ jasmine.Clock.assertInstalled();
2329
+ jasmine.Clock.defaultFakeTimer.reset();
2330
+ },
2331
+
2332
+ tick: function(millis) {
2333
+ jasmine.Clock.assertInstalled();
2334
+ jasmine.Clock.defaultFakeTimer.tick(millis);
2335
+ },
2336
+
2337
+ runFunctionsWithinRange: function(oldMillis, nowMillis) {
2338
+ jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
2339
+ },
2340
+
2341
+ scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
2342
+ jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
2343
+ },
2344
+
2345
+ useMock: function() {
2346
+ if (!jasmine.Clock.isInstalled()) {
2347
+ var spec = jasmine.getEnv().currentSpec;
2348
+ spec.after(jasmine.Clock.uninstallMock);
2349
+
2350
+ jasmine.Clock.installMock();
2351
+ }
2352
+ },
2353
+
2354
+ installMock: function() {
2355
+ jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
2356
+ },
2357
+
2358
+ uninstallMock: function() {
2359
+ jasmine.Clock.assertInstalled();
2360
+ jasmine.Clock.installed = jasmine.Clock.real;
2361
+ },
2362
+
2363
+ real: {
2364
+ setTimeout: jasmine.getGlobal().setTimeout,
2365
+ clearTimeout: jasmine.getGlobal().clearTimeout,
2366
+ setInterval: jasmine.getGlobal().setInterval,
2367
+ clearInterval: jasmine.getGlobal().clearInterval
2368
+ },
2369
+
2370
+ assertInstalled: function() {
2371
+ if (!jasmine.Clock.isInstalled()) {
2372
+ throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
2373
+ }
2374
+ },
2375
+
2376
+ isInstalled: function() {
2377
+ return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
2378
+ },
2379
+
2380
+ installed: null
2381
+ };
2382
+ jasmine.Clock.installed = jasmine.Clock.real;
2383
+
2384
+ //else for IE support
2385
+ jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
2386
+ if (jasmine.Clock.installed.setTimeout.apply) {
2387
+ return jasmine.Clock.installed.setTimeout.apply(this, arguments);
2388
+ } else {
2389
+ return jasmine.Clock.installed.setTimeout(funcToCall, millis);
2390
+ }
2391
+ };
2392
+
2393
+ jasmine.getGlobal().setInterval = function(funcToCall, millis) {
2394
+ if (jasmine.Clock.installed.setInterval.apply) {
2395
+ return jasmine.Clock.installed.setInterval.apply(this, arguments);
2396
+ } else {
2397
+ return jasmine.Clock.installed.setInterval(funcToCall, millis);
2398
+ }
2399
+ };
2400
+
2401
+ jasmine.getGlobal().clearTimeout = function(timeoutKey) {
2402
+ if (jasmine.Clock.installed.clearTimeout.apply) {
2403
+ return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
2404
+ } else {
2405
+ return jasmine.Clock.installed.clearTimeout(timeoutKey);
2406
+ }
2407
+ };
2408
+
2409
+ jasmine.getGlobal().clearInterval = function(timeoutKey) {
2410
+ if (jasmine.Clock.installed.clearTimeout.apply) {
2411
+ return jasmine.Clock.installed.clearInterval.apply(this, arguments);
2412
+ } else {
2413
+ return jasmine.Clock.installed.clearInterval(timeoutKey);
2414
+ }
2415
+ };
2416
+
2417
+
2418
+ jasmine.version_= {
2419
+ "major": 1,
2420
+ "minor": 0,
2421
+ "build": 1,
2422
+ "revision": 1288183920
2423
+ };