1 /** 2 * Environment for Jasmine 3 * 4 * @constructor 5 */ 6 jasmine.Env = function() { 7 this.currentSpec = null; 8 this.currentSuite = null; 9 this.currentRunner_ = new jasmine.Runner(this); 10 11 this.reporter = new jasmine.MultiReporter(); 12 13 this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL; 14 this.lastUpdate = 0; 15 this.specFilter = function() { 16 return true; 17 }; 18 19 this.nextSpecId_ = 0; 20 this.nextSuiteId_ = 0; 21 this.equalityTesters_ = []; 22 23 // wrap matchers 24 this.matchersClass = function() { 25 jasmine.Matchers.apply(this, arguments); 26 }; 27 jasmine.util.inherit(this.matchersClass, jasmine.Matchers); 28 29 jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass); 30 }; 31 32 33 jasmine.Env.prototype.setTimeout = jasmine.setTimeout; 34 jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; 35 jasmine.Env.prototype.setInterval = jasmine.setInterval; 36 jasmine.Env.prototype.clearInterval = jasmine.clearInterval; 37 38 /** 39 * @returns an object containing jasmine version build info, if set. 40 */ 41 jasmine.Env.prototype.version = function () { 42 if (jasmine.version_) { 43 return jasmine.version_; 44 } else { 45 throw new Error('Version not set'); 46 } 47 }; 48 49 /** 50 * @returns string containing jasmine version build info, if set. 51 */ 52 jasmine.Env.prototype.versionString = function() { 53 if (jasmine.version_) { 54 var version = this.version(); 55 return version.major + "." + version.minor + "." + version.build + " revision " + version.revision; 56 } else { 57 return "version unknown"; 58 } 59 }; 60 61 /** 62 * @returns a sequential integer starting at 0 63 */ 64 jasmine.Env.prototype.nextSpecId = function () { 65 return this.nextSpecId_++; 66 }; 67 68 /** 69 * @returns a sequential integer starting at 0 70 */ 71 jasmine.Env.prototype.nextSuiteId = function () { 72 return this.nextSuiteId_++; 73 }; 74 75 /** 76 * Register a reporter to receive status updates from Jasmine. 77 * @param {jasmine.Reporter} reporter An object which will receive status updates. 78 */ 79 jasmine.Env.prototype.addReporter = function(reporter) { 80 this.reporter.addReporter(reporter); 81 }; 82 83 jasmine.Env.prototype.execute = function() { 84 this.currentRunner_.execute(); 85 }; 86 87 jasmine.Env.prototype.describe = function(description, specDefinitions) { 88 var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite); 89 90 var parentSuite = this.currentSuite; 91 if (parentSuite) { 92 parentSuite.add(suite); 93 } else { 94 this.currentRunner_.add(suite); 95 } 96 97 this.currentSuite = suite; 98 99 var declarationError = null; 100 try { 101 specDefinitions.call(suite); 102 } catch(e) { 103 declarationError = e; 104 } 105 106 this.currentSuite = parentSuite; 107 108 if (declarationError) { 109 this.it("encountered a declaration exception", function() { 110 throw declarationError; 111 }); 112 } 113 114 return suite; 115 }; 116 117 jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { 118 if (this.currentSuite) { 119 this.currentSuite.beforeEach(beforeEachFunction); 120 } else { 121 this.currentRunner_.beforeEach(beforeEachFunction); 122 } 123 }; 124 125 jasmine.Env.prototype.currentRunner = function () { 126 return this.currentRunner_; 127 }; 128 129 jasmine.Env.prototype.afterEach = function(afterEachFunction) { 130 if (this.currentSuite) { 131 this.currentSuite.afterEach(afterEachFunction); 132 } else { 133 this.currentRunner_.afterEach(afterEachFunction); 134 } 135 136 }; 137 138 jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { 139 return { 140 execute: function() { 141 } 142 }; 143 }; 144 145 jasmine.Env.prototype.it = function(description, func) { 146 var spec = new jasmine.Spec(this, this.currentSuite, description); 147 this.currentSuite.add(spec); 148 this.currentSpec = spec; 149 150 if (func) { 151 spec.runs(func); 152 } 153 154 return spec; 155 }; 156 157 jasmine.Env.prototype.xit = function(desc, func) { 158 return { 159 id: this.nextSpecId(), 160 runs: function() { 161 } 162 }; 163 }; 164 165 jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) { 166 if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) { 167 return true; 168 } 169 170 a.__Jasmine_been_here_before__ = b; 171 b.__Jasmine_been_here_before__ = a; 172 173 var hasKey = function(obj, keyName) { 174 return obj != null && obj[keyName] !== jasmine.undefined; 175 }; 176 177 for (var property in b) { 178 if (!hasKey(a, property) && hasKey(b, property)) { 179 mismatchKeys.push("expected has key '" + property + "', but missing from actual."); 180 } 181 } 182 for (property in a) { 183 if (!hasKey(b, property) && hasKey(a, property)) { 184 mismatchKeys.push("expected missing key '" + property + "', but present in actual."); 185 } 186 } 187 for (property in b) { 188 if (property == '__Jasmine_been_here_before__') continue; 189 if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) { 190 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."); 191 } 192 } 193 194 if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) { 195 mismatchValues.push("arrays were not the same length"); 196 } 197 198 delete a.__Jasmine_been_here_before__; 199 delete b.__Jasmine_been_here_before__; 200 return (mismatchKeys.length == 0 && mismatchValues.length == 0); 201 }; 202 203 jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) { 204 mismatchKeys = mismatchKeys || []; 205 mismatchValues = mismatchValues || []; 206 207 for (var i = 0; i < this.equalityTesters_.length; i++) { 208 var equalityTester = this.equalityTesters_[i]; 209 var result = equalityTester(a, b, this, mismatchKeys, mismatchValues); 210 if (result !== jasmine.undefined) return result; 211 } 212 213 if (a === b) return true; 214 215 if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) { 216 return (a == jasmine.undefined && b == jasmine.undefined); 217 } 218 219 if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) { 220 return a === b; 221 } 222 223 if (a instanceof Date && b instanceof Date) { 224 return a.getTime() == b.getTime(); 225 } 226 227 if (a instanceof jasmine.Matchers.Any) { 228 return a.matches(b); 229 } 230 231 if (b instanceof jasmine.Matchers.Any) { 232 return b.matches(a); 233 } 234 235 if (jasmine.isString_(a) && jasmine.isString_(b)) { 236 return (a == b); 237 } 238 239 if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) { 240 return (a == b); 241 } 242 243 if (typeof a === "object" && typeof b === "object") { 244 return this.compareObjects_(a, b, mismatchKeys, mismatchValues); 245 } 246 247 //Straight check 248 return (a === b); 249 }; 250 251 jasmine.Env.prototype.contains_ = function(haystack, needle) { 252 if (jasmine.isArray_(haystack)) { 253 for (var i = 0; i < haystack.length; i++) { 254 if (this.equals_(haystack[i], needle)) return true; 255 } 256 return false; 257 } 258 return haystack.indexOf(needle) >= 0; 259 }; 260 261 jasmine.Env.prototype.addEqualityTester = function(equalityTester) { 262 this.equalityTesters_.push(equalityTester); 263 }; 264