xian-test-jasmine 0.1.0

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