Add a base for testing
This includes the following: * Add jasmine * Move the rivets build to the build folder * Add a guardfile that watches for source changes * Add a rakefile for building and minifying the source * Add a an example test case * Add vim swap files to the git ignore file
Showing
14 changed files
with
3464 additions
and
1 deletions
Gemfile
0 → 100644
Gemfile.lock
0 → 100644
1 | GEM | ||
2 | remote: http://rubygems.org/ | ||
3 | specs: | ||
4 | closure-compiler (1.1.6) | ||
5 | coffee-script (2.2.0) | ||
6 | coffee-script-source | ||
7 | execjs | ||
8 | coffee-script-source (1.3.3) | ||
9 | execjs (1.4.0) | ||
10 | multi_json (~> 1.0) | ||
11 | ffi (1.0.11) | ||
12 | guard (1.0.2) | ||
13 | ffi (>= 0.5.0) | ||
14 | thor (~> 0.14.6) | ||
15 | guard-coffeescript (0.6.0) | ||
16 | coffee-script (>= 2.2.0) | ||
17 | guard (>= 0.8.3) | ||
18 | multi_json (1.3.6) | ||
19 | thor (0.14.6) | ||
20 | |||
21 | PLATFORMS | ||
22 | ruby | ||
23 | |||
24 | DEPENDENCIES | ||
25 | closure-compiler | ||
26 | coffee-script | ||
27 | guard | ||
28 | guard-coffeescript |
Guardfile
0 → 100644
Rakefile
0 → 100644
1 | require 'rubygems' | ||
2 | |||
3 | BUILD_DIRECTORY = 'build' | ||
4 | SRC_DIRECTORY = 'src' | ||
5 | |||
6 | desc "build the toast-min.js files for distribution" | ||
7 | task :default => :clean do | ||
8 | FileUtils.mkdir_p(BUILD_DIRECTORY) | ||
9 | compile_js | ||
10 | end | ||
11 | |||
12 | task :build => :default | ||
13 | |||
14 | desc "removes the build directory" | ||
15 | task :clean do | ||
16 | print_action('Removing existing build directory') do | ||
17 | FileUtils.rm_rf('build') | ||
18 | end | ||
19 | end | ||
20 | |||
21 | def compile_js() | ||
22 | require 'coffee-script' | ||
23 | require 'closure-compiler' | ||
24 | |||
25 | source = File.read(File.join(SRC_DIRECTORY, 'rivets.coffee')) | ||
26 | FileUtils.mkdir_p(BUILD_DIRECTORY) | ||
27 | output = File.join(BUILD_DIRECTORY, 'rivets.js') | ||
28 | minified_output = File.join(BUILD_DIRECTORY, 'rivets-min.js') | ||
29 | |||
30 | compiled = '' | ||
31 | print_action("Compiling CoffeeScript to '#{output}'") do | ||
32 | File.open(output, 'w+') do |file| | ||
33 | compiled = CoffeeScript.compile(source) | ||
34 | file.write(compiled) | ||
35 | end | ||
36 | end | ||
37 | |||
38 | print_action("Minifying Javascript to '#{minified_output}'") do | ||
39 | File.open(minified_output, 'w+') do |file| | ||
40 | file.write(Closure::Compiler.new.compress(compiled)) | ||
41 | end | ||
42 | end | ||
43 | end | ||
44 | |||
45 | def print_action(action, &block) | ||
46 | print "#{action}... " | ||
47 | STDOUT.flush | ||
48 | |||
49 | if block.call() | ||
50 | puts 'done' | ||
51 | else | ||
52 | puts 'failed' | ||
53 | end | ||
54 | end |
build/rivets-min.js
0 → 100644
1 | (function(){var m,c,d,g,i,h,n,f,j=function(b,a){return function(){return b.apply(a,arguments)}},o=[].indexOf||function(b){for(var a=0,p=this.length;a<p;a++)if(a in this&&this[a]===b)return a;return-1};g=d=c=m=void 0;m=function(){function b(a,b,e,l,k){this.el=a;this.type=b;this.model=e;this.keypath=l;this.formatters=null!=k?k:[];this.unbind=j(this.unbind,this);this.publish=j(this.publish,this);this.bind=j(this.bind,this);this.set=j(this.set,this);this.routine=c[this.type]||i(this.type)}b.prototype.set= | ||
2 | function(a){var b,e,l,k;k=this.formatters;e=0;for(l=k.length;e<l;e++)b=k[e],a=d.formatters[b](a);return this.routine(this.el,a)};b.prototype.bind=function(){var a;d.adapter.subscribe(this.model,this.keypath,this.set);d.preloadData&&this.set(d.adapter.read(this.model,this.keypath));if(a=this.type,0<=o.call(h,a))return this.el.addEventListener("change",this.publish)};b.prototype.publish=function(a){return d.adapter.publish(this.model,this.keypath,n(a.target||a.srcElement))};b.prototype.unbind=function(){var a; | ||
3 | d.adapter.unsubscribe(this.model,this.keypath,this.set);if(a=this.type,0<=o.call(h,a))return this.el.removeEventListener("change",this.publish)};return b}();g=function(){function b(a,b){this.el=a;this.models=b;this.bind=j(this.bind,this);this.build=j(this.build,this);this.bindingRegExp=j(this.bindingRegExp,this);this.build()}b.prototype.bindingRegExp=function(){var a;return(a=d.prefix)?RegExp("^data-"+a+"-"):/^data-/};b.prototype.build=function(){var a,b,e,l,k,d,f,j,c,g,i,h;this.bindings=[];b=this.bindingRegExp(); | ||
4 | i=this.el.getElementsByTagName("*");h=[];c=0;for(g=i.length;c<g;c++)k=i[c],h.push(function(){var c,i,h,g;h=k.attributes;g=[];c=0;for(i=h.length;c<i;c++)a=h[c],b.test(a.name)?(j=a.name.replace(b,""),f=a.value.split("|").map(function(a){return a.trim()}),d=f.shift().split("."),l=this.models[d.shift()],e=d.join("."),g.push(this.bindings.push(new m(k,j,l,e,f)))):g.push(void 0);return g}.call(this));return h};b.prototype.bind=function(){var a,b,e,c,d;c=this.bindings;d=[];b=0;for(e=c.length;b<e;b++)a=c[b], | ||
5 | d.push(a.bind());return d};return b}();n=function(b){switch(b.type){case "text":case "textarea":case "password":case "select-one":return b.value;case "checkbox":case "radio":return b.checked}};i=function(b){return function(a,c){return c?a.setAttribute(b,c):a.removeAttribute(b)}};f=function(b,a){null==a&&(a=!1);return function(c,d){return i(b)(c,a===!d?b:!1)}};h=["value","checked","unchecked","selected","unselected"];c={checked:f("checked"),selected:f("selected"),disabled:f("disabled"),unchecked:f("checked", | ||
6 | !0),unselected:f("selected",!0),enabled:f("disabled",!0),text:function(b,a){return null!=b.innerText?b.innerText=a||"":b.textContent=a||""},html:function(b,a){return b.innerHTML=a||""},value:function(b,a){return b.value=a},show:function(b,a){return b.style.display=a?"":"none"},hide:function(b,a){return b.style.display=a?"none":""}};d={preloadData:!0};f={configure:function(b){var a,c,e;null==b&&(b={});e=[];for(a in b)c=b[a],e.push(d[a]=c);return e},register:function(b,a){return c[b]=a},bind:function(b, | ||
7 | a){var c;null==a&&(a={});c=new g(b,a);c.bind();return c}};"undefined"!==typeof module&&null!==module?module.exports=f:this.rivets=f}).call(this); |
1 | // Generated by CoffeeScript 1.3.3 | ||
2 | (function() { | 1 | (function() { |
3 | var Rivets, attributeBinding, bidirectionals, getInputValue, rivets, stateBinding, | 2 | var Rivets, attributeBinding, bidirectionals, getInputValue, rivets, stateBinding, |
4 | __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, | 3 | __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, | ... | ... |
lib/jasmine-1.2.0/MIT.LICENSE
0 → 100644
1 | Copyright (c) 2008-2011 Pivotal Labs | ||
2 | |||
3 | Permission is hereby granted, free of charge, to any person obtaining | ||
4 | a copy of this software and associated documentation files (the | ||
5 | "Software"), to deal in the Software without restriction, including | ||
6 | without limitation the rights to use, copy, modify, merge, publish, | ||
7 | distribute, sublicense, and/or sell copies of the Software, and to | ||
8 | permit persons to whom the Software is furnished to do so, subject to | ||
9 | the following conditions: | ||
10 | |||
11 | The above copyright notice and this permission notice shall be | ||
12 | included in all copies or substantial portions of the Software. | ||
13 | |||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
lib/jasmine-1.2.0/jasmine-html.js
0 → 100644
1 | jasmine.HtmlReporterHelpers = {}; | ||
2 | |||
3 | jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) { | ||
4 | var el = document.createElement(type); | ||
5 | |||
6 | for (var i = 2; i < arguments.length; i++) { | ||
7 | var child = arguments[i]; | ||
8 | |||
9 | if (typeof child === 'string') { | ||
10 | el.appendChild(document.createTextNode(child)); | ||
11 | } else { | ||
12 | if (child) { | ||
13 | el.appendChild(child); | ||
14 | } | ||
15 | } | ||
16 | } | ||
17 | |||
18 | for (var attr in attrs) { | ||
19 | if (attr == "className") { | ||
20 | el[attr] = attrs[attr]; | ||
21 | } else { | ||
22 | el.setAttribute(attr, attrs[attr]); | ||
23 | } | ||
24 | } | ||
25 | |||
26 | return el; | ||
27 | }; | ||
28 | |||
29 | jasmine.HtmlReporterHelpers.getSpecStatus = function(child) { | ||
30 | var results = child.results(); | ||
31 | var status = results.passed() ? 'passed' : 'failed'; | ||
32 | if (results.skipped) { | ||
33 | status = 'skipped'; | ||
34 | } | ||
35 | |||
36 | return status; | ||
37 | }; | ||
38 | |||
39 | jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) { | ||
40 | var parentDiv = this.dom.summary; | ||
41 | var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite'; | ||
42 | var parent = child[parentSuite]; | ||
43 | |||
44 | if (parent) { | ||
45 | if (typeof this.views.suites[parent.id] == 'undefined') { | ||
46 | this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views); | ||
47 | } | ||
48 | parentDiv = this.views.suites[parent.id].element; | ||
49 | } | ||
50 | |||
51 | parentDiv.appendChild(childElement); | ||
52 | }; | ||
53 | |||
54 | |||
55 | jasmine.HtmlReporterHelpers.addHelpers = function(ctor) { | ||
56 | for(var fn in jasmine.HtmlReporterHelpers) { | ||
57 | ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn]; | ||
58 | } | ||
59 | }; | ||
60 | |||
61 | jasmine.HtmlReporter = function(_doc) { | ||
62 | var self = this; | ||
63 | var doc = _doc || window.document; | ||
64 | |||
65 | var reporterView; | ||
66 | |||
67 | var dom = {}; | ||
68 | |||
69 | // Jasmine Reporter Public Interface | ||
70 | self.logRunningSpecs = false; | ||
71 | |||
72 | self.reportRunnerStarting = function(runner) { | ||
73 | var specs = runner.specs() || []; | ||
74 | |||
75 | if (specs.length == 0) { | ||
76 | return; | ||
77 | } | ||
78 | |||
79 | createReporterDom(runner.env.versionString()); | ||
80 | doc.body.appendChild(dom.reporter); | ||
81 | |||
82 | reporterView = new jasmine.HtmlReporter.ReporterView(dom); | ||
83 | reporterView.addSpecs(specs, self.specFilter); | ||
84 | }; | ||
85 | |||
86 | self.reportRunnerResults = function(runner) { | ||
87 | reporterView && reporterView.complete(); | ||
88 | }; | ||
89 | |||
90 | self.reportSuiteResults = function(suite) { | ||
91 | reporterView.suiteComplete(suite); | ||
92 | }; | ||
93 | |||
94 | self.reportSpecStarting = function(spec) { | ||
95 | if (self.logRunningSpecs) { | ||
96 | self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); | ||
97 | } | ||
98 | }; | ||
99 | |||
100 | self.reportSpecResults = function(spec) { | ||
101 | reporterView.specComplete(spec); | ||
102 | }; | ||
103 | |||
104 | self.log = function() { | ||
105 | var console = jasmine.getGlobal().console; | ||
106 | if (console && console.log) { | ||
107 | if (console.log.apply) { | ||
108 | console.log.apply(console, arguments); | ||
109 | } else { | ||
110 | console.log(arguments); // ie fix: console.log.apply doesn't exist on ie | ||
111 | } | ||
112 | } | ||
113 | }; | ||
114 | |||
115 | self.specFilter = function(spec) { | ||
116 | if (!focusedSpecName()) { | ||
117 | return true; | ||
118 | } | ||
119 | |||
120 | return spec.getFullName().indexOf(focusedSpecName()) === 0; | ||
121 | }; | ||
122 | |||
123 | return self; | ||
124 | |||
125 | function focusedSpecName() { | ||
126 | var specName; | ||
127 | |||
128 | (function memoizeFocusedSpec() { | ||
129 | if (specName) { | ||
130 | return; | ||
131 | } | ||
132 | |||
133 | var paramMap = []; | ||
134 | var params = doc.location.search.substring(1).split('&'); | ||
135 | |||
136 | for (var i = 0; i < params.length; i++) { | ||
137 | var p = params[i].split('='); | ||
138 | paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); | ||
139 | } | ||
140 | |||
141 | specName = paramMap.spec; | ||
142 | })(); | ||
143 | |||
144 | return specName; | ||
145 | } | ||
146 | |||
147 | function createReporterDom(version) { | ||
148 | dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' }, | ||
149 | dom.banner = self.createDom('div', { className: 'banner' }, | ||
150 | self.createDom('span', { className: 'title' }, "Jasmine "), | ||
151 | self.createDom('span', { className: 'version' }, version)), | ||
152 | |||
153 | dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}), | ||
154 | dom.alert = self.createDom('div', {className: 'alert'}), | ||
155 | dom.results = self.createDom('div', {className: 'results'}, | ||
156 | dom.summary = self.createDom('div', { className: 'summary' }), | ||
157 | dom.details = self.createDom('div', { id: 'details' })) | ||
158 | ); | ||
159 | } | ||
160 | }; | ||
161 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);jasmine.HtmlReporter.ReporterView = function(dom) { | ||
162 | this.startedAt = new Date(); | ||
163 | this.runningSpecCount = 0; | ||
164 | this.completeSpecCount = 0; | ||
165 | this.passedCount = 0; | ||
166 | this.failedCount = 0; | ||
167 | this.skippedCount = 0; | ||
168 | |||
169 | this.createResultsMenu = function() { | ||
170 | this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'}, | ||
171 | this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'), | ||
172 | ' | ', | ||
173 | this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing')); | ||
174 | |||
175 | this.summaryMenuItem.onclick = function() { | ||
176 | dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, ''); | ||
177 | }; | ||
178 | |||
179 | this.detailsMenuItem.onclick = function() { | ||
180 | showDetails(); | ||
181 | }; | ||
182 | }; | ||
183 | |||
184 | this.addSpecs = function(specs, specFilter) { | ||
185 | this.totalSpecCount = specs.length; | ||
186 | |||
187 | this.views = { | ||
188 | specs: {}, | ||
189 | suites: {} | ||
190 | }; | ||
191 | |||
192 | for (var i = 0; i < specs.length; i++) { | ||
193 | var spec = specs[i]; | ||
194 | this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views); | ||
195 | if (specFilter(spec)) { | ||
196 | this.runningSpecCount++; | ||
197 | } | ||
198 | } | ||
199 | }; | ||
200 | |||
201 | this.specComplete = function(spec) { | ||
202 | this.completeSpecCount++; | ||
203 | |||
204 | if (isUndefined(this.views.specs[spec.id])) { | ||
205 | this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom); | ||
206 | } | ||
207 | |||
208 | var specView = this.views.specs[spec.id]; | ||
209 | |||
210 | switch (specView.status()) { | ||
211 | case 'passed': | ||
212 | this.passedCount++; | ||
213 | break; | ||
214 | |||
215 | case 'failed': | ||
216 | this.failedCount++; | ||
217 | break; | ||
218 | |||
219 | case 'skipped': | ||
220 | this.skippedCount++; | ||
221 | break; | ||
222 | } | ||
223 | |||
224 | specView.refresh(); | ||
225 | this.refresh(); | ||
226 | }; | ||
227 | |||
228 | this.suiteComplete = function(suite) { | ||
229 | var suiteView = this.views.suites[suite.id]; | ||
230 | if (isUndefined(suiteView)) { | ||
231 | return; | ||
232 | } | ||
233 | suiteView.refresh(); | ||
234 | }; | ||
235 | |||
236 | this.refresh = function() { | ||
237 | |||
238 | if (isUndefined(this.resultsMenu)) { | ||
239 | this.createResultsMenu(); | ||
240 | } | ||
241 | |||
242 | // currently running UI | ||
243 | if (isUndefined(this.runningAlert)) { | ||
244 | this.runningAlert = this.createDom('a', {href: "?", className: "runningAlert bar"}); | ||
245 | dom.alert.appendChild(this.runningAlert); | ||
246 | } | ||
247 | this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount); | ||
248 | |||
249 | // skipped specs UI | ||
250 | if (isUndefined(this.skippedAlert)) { | ||
251 | this.skippedAlert = this.createDom('a', {href: "?", className: "skippedAlert bar"}); | ||
252 | } | ||
253 | |||
254 | this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all"; | ||
255 | |||
256 | if (this.skippedCount === 1 && isDefined(dom.alert)) { | ||
257 | dom.alert.appendChild(this.skippedAlert); | ||
258 | } | ||
259 | |||
260 | // passing specs UI | ||
261 | if (isUndefined(this.passedAlert)) { | ||
262 | this.passedAlert = this.createDom('span', {href: "?", className: "passingAlert bar"}); | ||
263 | } | ||
264 | this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount); | ||
265 | |||
266 | // failing specs UI | ||
267 | if (isUndefined(this.failedAlert)) { | ||
268 | this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"}); | ||
269 | } | ||
270 | this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount); | ||
271 | |||
272 | if (this.failedCount === 1 && isDefined(dom.alert)) { | ||
273 | dom.alert.appendChild(this.failedAlert); | ||
274 | dom.alert.appendChild(this.resultsMenu); | ||
275 | } | ||
276 | |||
277 | // summary info | ||
278 | this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount); | ||
279 | this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing"; | ||
280 | }; | ||
281 | |||
282 | this.complete = function() { | ||
283 | dom.alert.removeChild(this.runningAlert); | ||
284 | |||
285 | this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all"; | ||
286 | |||
287 | if (this.failedCount === 0) { | ||
288 | dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount))); | ||
289 | } else { | ||
290 | showDetails(); | ||
291 | } | ||
292 | |||
293 | dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s")); | ||
294 | }; | ||
295 | |||
296 | return this; | ||
297 | |||
298 | function showDetails() { | ||
299 | if (dom.reporter.className.search(/showDetails/) === -1) { | ||
300 | dom.reporter.className += " showDetails"; | ||
301 | } | ||
302 | } | ||
303 | |||
304 | function isUndefined(obj) { | ||
305 | return typeof obj === 'undefined'; | ||
306 | } | ||
307 | |||
308 | function isDefined(obj) { | ||
309 | return !isUndefined(obj); | ||
310 | } | ||
311 | |||
312 | function specPluralizedFor(count) { | ||
313 | var str = count + " spec"; | ||
314 | if (count > 1) { | ||
315 | str += "s" | ||
316 | } | ||
317 | return str; | ||
318 | } | ||
319 | |||
320 | }; | ||
321 | |||
322 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView); | ||
323 | |||
324 | |||
325 | jasmine.HtmlReporter.SpecView = function(spec, dom, views) { | ||
326 | this.spec = spec; | ||
327 | this.dom = dom; | ||
328 | this.views = views; | ||
329 | |||
330 | this.symbol = this.createDom('li', { className: 'pending' }); | ||
331 | this.dom.symbolSummary.appendChild(this.symbol); | ||
332 | |||
333 | this.summary = this.createDom('div', { className: 'specSummary' }, | ||
334 | this.createDom('a', { | ||
335 | className: 'description', | ||
336 | href: '?spec=' + encodeURIComponent(this.spec.getFullName()), | ||
337 | title: this.spec.getFullName() | ||
338 | }, this.spec.description) | ||
339 | ); | ||
340 | |||
341 | this.detail = this.createDom('div', { className: 'specDetail' }, | ||
342 | this.createDom('a', { | ||
343 | className: 'description', | ||
344 | href: '?spec=' + encodeURIComponent(this.spec.getFullName()), | ||
345 | title: this.spec.getFullName() | ||
346 | }, this.spec.getFullName()) | ||
347 | ); | ||
348 | }; | ||
349 | |||
350 | jasmine.HtmlReporter.SpecView.prototype.status = function() { | ||
351 | return this.getSpecStatus(this.spec); | ||
352 | }; | ||
353 | |||
354 | jasmine.HtmlReporter.SpecView.prototype.refresh = function() { | ||
355 | this.symbol.className = this.status(); | ||
356 | |||
357 | switch (this.status()) { | ||
358 | case 'skipped': | ||
359 | break; | ||
360 | |||
361 | case 'passed': | ||
362 | this.appendSummaryToSuiteDiv(); | ||
363 | break; | ||
364 | |||
365 | case 'failed': | ||
366 | this.appendSummaryToSuiteDiv(); | ||
367 | this.appendFailureDetail(); | ||
368 | break; | ||
369 | } | ||
370 | }; | ||
371 | |||
372 | jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() { | ||
373 | this.summary.className += ' ' + this.status(); | ||
374 | this.appendToSummary(this.spec, this.summary); | ||
375 | }; | ||
376 | |||
377 | jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() { | ||
378 | this.detail.className += ' ' + this.status(); | ||
379 | |||
380 | var resultItems = this.spec.results().getItems(); | ||
381 | var messagesDiv = this.createDom('div', { className: 'messages' }); | ||
382 | |||
383 | for (var i = 0; i < resultItems.length; i++) { | ||
384 | var result = resultItems[i]; | ||
385 | |||
386 | if (result.type == 'log') { | ||
387 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); | ||
388 | } else if (result.type == 'expect' && result.passed && !result.passed()) { | ||
389 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); | ||
390 | |||
391 | if (result.trace.stack) { | ||
392 | messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); | ||
393 | } | ||
394 | } | ||
395 | } | ||
396 | |||
397 | if (messagesDiv.childNodes.length > 0) { | ||
398 | this.detail.appendChild(messagesDiv); | ||
399 | this.dom.details.appendChild(this.detail); | ||
400 | } | ||
401 | }; | ||
402 | |||
403 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) { | ||
404 | this.suite = suite; | ||
405 | this.dom = dom; | ||
406 | this.views = views; | ||
407 | |||
408 | this.element = this.createDom('div', { className: 'suite' }, | ||
409 | this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description) | ||
410 | ); | ||
411 | |||
412 | this.appendToSummary(this.suite, this.element); | ||
413 | }; | ||
414 | |||
415 | jasmine.HtmlReporter.SuiteView.prototype.status = function() { | ||
416 | return this.getSpecStatus(this.suite); | ||
417 | }; | ||
418 | |||
419 | jasmine.HtmlReporter.SuiteView.prototype.refresh = function() { | ||
420 | this.element.className += " " + this.status(); | ||
421 | }; | ||
422 | |||
423 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView); | ||
424 | |||
425 | /* @deprecated Use jasmine.HtmlReporter instead | ||
426 | */ | ||
427 | jasmine.TrivialReporter = function(doc) { | ||
428 | this.document = doc || document; | ||
429 | this.suiteDivs = {}; | ||
430 | this.logRunningSpecs = false; | ||
431 | }; | ||
432 | |||
433 | jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) { | ||
434 | var el = document.createElement(type); | ||
435 | |||
436 | for (var i = 2; i < arguments.length; i++) { | ||
437 | var child = arguments[i]; | ||
438 | |||
439 | if (typeof child === 'string') { | ||
440 | el.appendChild(document.createTextNode(child)); | ||
441 | } else { | ||
442 | if (child) { el.appendChild(child); } | ||
443 | } | ||
444 | } | ||
445 | |||
446 | for (var attr in attrs) { | ||
447 | if (attr == "className") { | ||
448 | el[attr] = attrs[attr]; | ||
449 | } else { | ||
450 | el.setAttribute(attr, attrs[attr]); | ||
451 | } | ||
452 | } | ||
453 | |||
454 | return el; | ||
455 | }; | ||
456 | |||
457 | jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) { | ||
458 | var showPassed, showSkipped; | ||
459 | |||
460 | this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' }, | ||
461 | this.createDom('div', { className: 'banner' }, | ||
462 | this.createDom('div', { className: 'logo' }, | ||
463 | this.createDom('span', { className: 'title' }, "Jasmine"), | ||
464 | this.createDom('span', { className: 'version' }, runner.env.versionString())), | ||
465 | this.createDom('div', { className: 'options' }, | ||
466 | "Show ", | ||
467 | showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }), | ||
468 | this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "), | ||
469 | showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }), | ||
470 | this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped") | ||
471 | ) | ||
472 | ), | ||
473 | |||
474 | this.runnerDiv = this.createDom('div', { className: 'runner running' }, | ||
475 | this.createDom('a', { className: 'run_spec', href: '?' }, "run all"), | ||
476 | this.runnerMessageSpan = this.createDom('span', {}, "Running..."), | ||
477 | this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, "")) | ||
478 | ); | ||
479 | |||
480 | this.document.body.appendChild(this.outerDiv); | ||
481 | |||
482 | var suites = runner.suites(); | ||
483 | for (var i = 0; i < suites.length; i++) { | ||
484 | var suite = suites[i]; | ||
485 | var suiteDiv = this.createDom('div', { className: 'suite' }, | ||
486 | this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"), | ||
487 | this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description)); | ||
488 | this.suiteDivs[suite.id] = suiteDiv; | ||
489 | var parentDiv = this.outerDiv; | ||
490 | if (suite.parentSuite) { | ||
491 | parentDiv = this.suiteDivs[suite.parentSuite.id]; | ||
492 | } | ||
493 | parentDiv.appendChild(suiteDiv); | ||
494 | } | ||
495 | |||
496 | this.startedAt = new Date(); | ||
497 | |||
498 | var self = this; | ||
499 | showPassed.onclick = function(evt) { | ||
500 | if (showPassed.checked) { | ||
501 | self.outerDiv.className += ' show-passed'; | ||
502 | } else { | ||
503 | self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, ''); | ||
504 | } | ||
505 | }; | ||
506 | |||
507 | showSkipped.onclick = function(evt) { | ||
508 | if (showSkipped.checked) { | ||
509 | self.outerDiv.className += ' show-skipped'; | ||
510 | } else { | ||
511 | self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, ''); | ||
512 | } | ||
513 | }; | ||
514 | }; | ||
515 | |||
516 | jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) { | ||
517 | var results = runner.results(); | ||
518 | var className = (results.failedCount > 0) ? "runner failed" : "runner passed"; | ||
519 | this.runnerDiv.setAttribute("class", className); | ||
520 | //do it twice for IE | ||
521 | this.runnerDiv.setAttribute("className", className); | ||
522 | var specs = runner.specs(); | ||
523 | var specCount = 0; | ||
524 | for (var i = 0; i < specs.length; i++) { | ||
525 | if (this.specFilter(specs[i])) { | ||
526 | specCount++; | ||
527 | } | ||
528 | } | ||
529 | var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s"); | ||
530 | message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"; | ||
531 | this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild); | ||
532 | |||
533 | this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString())); | ||
534 | }; | ||
535 | |||
536 | jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) { | ||
537 | var results = suite.results(); | ||
538 | var status = results.passed() ? 'passed' : 'failed'; | ||
539 | if (results.totalCount === 0) { // todo: change this to check results.skipped | ||
540 | status = 'skipped'; | ||
541 | } | ||
542 | this.suiteDivs[suite.id].className += " " + status; | ||
543 | }; | ||
544 | |||
545 | jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) { | ||
546 | if (this.logRunningSpecs) { | ||
547 | this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); | ||
548 | } | ||
549 | }; | ||
550 | |||
551 | jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { | ||
552 | var results = spec.results(); | ||
553 | var status = results.passed() ? 'passed' : 'failed'; | ||
554 | if (results.skipped) { | ||
555 | status = 'skipped'; | ||
556 | } | ||
557 | var specDiv = this.createDom('div', { className: 'spec ' + status }, | ||
558 | this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"), | ||
559 | this.createDom('a', { | ||
560 | className: 'description', | ||
561 | href: '?spec=' + encodeURIComponent(spec.getFullName()), | ||
562 | title: spec.getFullName() | ||
563 | }, spec.description)); | ||
564 | |||
565 | |||
566 | var resultItems = results.getItems(); | ||
567 | var messagesDiv = this.createDom('div', { className: 'messages' }); | ||
568 | for (var i = 0; i < resultItems.length; i++) { | ||
569 | var result = resultItems[i]; | ||
570 | |||
571 | if (result.type == 'log') { | ||
572 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); | ||
573 | } else if (result.type == 'expect' && result.passed && !result.passed()) { | ||
574 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); | ||
575 | |||
576 | if (result.trace.stack) { | ||
577 | messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); | ||
578 | } | ||
579 | } | ||
580 | } | ||
581 | |||
582 | if (messagesDiv.childNodes.length > 0) { | ||
583 | specDiv.appendChild(messagesDiv); | ||
584 | } | ||
585 | |||
586 | this.suiteDivs[spec.suite.id].appendChild(specDiv); | ||
587 | }; | ||
588 | |||
589 | jasmine.TrivialReporter.prototype.log = function() { | ||
590 | var console = jasmine.getGlobal().console; | ||
591 | if (console && console.log) { | ||
592 | if (console.log.apply) { | ||
593 | console.log.apply(console, arguments); | ||
594 | } else { | ||
595 | console.log(arguments); // ie fix: console.log.apply doesn't exist on ie | ||
596 | } | ||
597 | } | ||
598 | }; | ||
599 | |||
600 | jasmine.TrivialReporter.prototype.getLocation = function() { | ||
601 | return this.document.location; | ||
602 | }; | ||
603 | |||
604 | jasmine.TrivialReporter.prototype.specFilter = function(spec) { | ||
605 | var paramMap = {}; | ||
606 | var params = this.getLocation().search.substring(1).split('&'); | ||
607 | for (var i = 0; i < params.length; i++) { | ||
608 | var p = params[i].split('='); | ||
609 | paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); | ||
610 | } | ||
611 | |||
612 | if (!paramMap.spec) { | ||
613 | return true; | ||
614 | } | ||
615 | return spec.getFullName().indexOf(paramMap.spec) === 0; | ||
616 | }; |
lib/jasmine-1.2.0/jasmine.css
0 → 100644
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; } |
lib/jasmine-1.2.0/jasmine.js
0 → 100644
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, '&') | ||
685 | .replace(/</g, '<') | ||
686 | .replace(/>/g, '>'); | ||
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": 1337005947 | ||
2529 | }; |
spec/mock.data.js
0 → 100644
1 | function Data(attributes) { | ||
2 | this.attributes = attributes || {}; | ||
3 | this.change = {} | ||
4 | } | ||
5 | |||
6 | Data.prototype.on = function(key, callback) { | ||
7 | this.change[key][callback] = true; | ||
8 | } | ||
9 | |||
10 | Data.prototype.off = function(key, callback) { | ||
11 | delete this.change[key][callback]; | ||
12 | } | ||
13 | |||
14 | Data.prototype.set = function(attributes) { | ||
15 | var old, key; | ||
16 | |||
17 | for(key in attributes) { | ||
18 | old = this.attributes[key]; | ||
19 | this.attributes[key] = attributes[key]; | ||
20 | if(this.get(key) !== old) | ||
21 | this.alertCallbacks(key); | ||
22 | } | ||
23 | } | ||
24 | |||
25 | Data.prototype.get = function(key) { | ||
26 | this.attributes[key]; | ||
27 | } | ||
28 | |||
29 | Data.prototype.alertCallbacks = function(key) { | ||
30 | if(!this.change[key]) | ||
31 | return; | ||
32 | |||
33 | for(callback in this.change[key]) | ||
34 | callback(this.get(key)); | ||
35 | } | ||
36 | |||
37 | window.Data = Data; |
spec/rivets.js
0 → 100644
1 | rivets.configure({ | ||
2 | adapter: { | ||
3 | subscribe: function(obj, keypath, callback) { | ||
4 | obj.on(keypath, callback); | ||
5 | }, | ||
6 | read: function(obj, keypath) { | ||
7 | obj.get(keypath); | ||
8 | }, | ||
9 | publish: function(obj, keypath, value) { | ||
10 | attributes = {}; | ||
11 | attributes[keypath] = value; | ||
12 | obj.set(attributes); | ||
13 | } | ||
14 | } | ||
15 | }); | ||
16 | |||
17 | |||
18 | describe('Rivets: ', function() { | ||
19 | var data; | ||
20 | |||
21 | beforeEach(function() { | ||
22 | data = new Data(); | ||
23 | }); | ||
24 | |||
25 | describe('Stuff', function() { | ||
26 | it('should work', function() { | ||
27 | expect(data.get('foo')).toBe(undefined); | ||
28 | expect(data.get('bar')).toBe('not undefined'); | ||
29 | }); | ||
30 | }); | ||
31 | }); |
test.html
0 → 100644
1 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" | ||
2 | "http://www.w3.org/TR/html4/loose.dtd"> | ||
3 | <html> | ||
4 | <head> | ||
5 | <title>Rivets test suite</title> | ||
6 | |||
7 | <link rel="shortcut icon" type="image/png" href="lib/jasmine-1.2.0/jasmine_favicon.png"> | ||
8 | <link rel="stylesheet" type="text/css" href="lib/jasmine-1.2.0/jasmine.css"> | ||
9 | <script type="text/javascript" src="lib/jasmine-1.2.0/jasmine.js"></script> | ||
10 | <script type="text/javascript" src="lib/jasmine-1.2.0/jasmine-html.js"></script> | ||
11 | |||
12 | <script type="text/javascript" src="build/rivets.js"></script> | ||
13 | |||
14 | <script type="text/javascript" src="spec/mock.data.js"></script> | ||
15 | <script type="text/javascript" src="spec/rivets.js"></script> | ||
16 | |||
17 | <script type="text/javascript"> | ||
18 | (function() { | ||
19 | var jasmineEnv = jasmine.getEnv(); | ||
20 | jasmineEnv.updateInterval = 250; | ||
21 | |||
22 | var htmlReporter = new jasmine.HtmlReporter(); | ||
23 | |||
24 | jasmineEnv.addReporter(htmlReporter); | ||
25 | |||
26 | jasmineEnv.specFilter = function(spec) { | ||
27 | return htmlReporter.specFilter(spec); | ||
28 | }; | ||
29 | |||
30 | var currentWindowOnload = window.onload; | ||
31 | |||
32 | window.onload = function() { | ||
33 | if (currentWindowOnload) { | ||
34 | currentWindowOnload(); | ||
35 | } | ||
36 | execJasmine(); | ||
37 | }; | ||
38 | |||
39 | function execJasmine() { | ||
40 | jasmineEnv.execute(); | ||
41 | } | ||
42 | |||
43 | })(); | ||
44 | </script> | ||
45 | |||
46 | </head> | ||
47 | |||
48 | <body> | ||
49 | </body> | ||
50 | </html> |
-
Please register or sign in to post a comment