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