jasmine_webos 0.0.6

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