rack-noncache 0.0.4 → 1.0.0

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