1 /** 2 * @constructor 3 * @param {jasmine.Env} env 4 * @param actual 5 * @param {jasmine.Spec} spec 6 */ 7 jasmine.Matchers = function(env, actual, spec) { 8 this.env = env; 9 this.actual = actual; 10 this.spec = spec; 11 }; 12 13 jasmine.Matchers.pp = function(str) { 14 return jasmine.util.htmlEscape(jasmine.pp(str)); 15 }; 16 17 jasmine.Matchers.prototype.report = function(result, failing_message, details) { 18 var expectationResult = new jasmine.ExpectationResult({ 19 passed: result, 20 message: failing_message, 21 details: details 22 }); 23 this.spec.addMatcherResult(expectationResult); 24 return result; 25 }; 26 27 jasmine.Matchers.matcherFn_ = function(matcherName, options) { 28 return function () { 29 jasmine.util.extend(this, options); 30 var matcherArgs = jasmine.util.argsToArray(arguments); 31 var args = [this.actual].concat(matcherArgs); 32 var result = options.test.apply(this, args); 33 var message; 34 if (!result) { 35 message = options.message.apply(this, args); 36 } 37 var expectationResult = new jasmine.ExpectationResult({ 38 matcherName: matcherName, 39 passed: result, 40 expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0], 41 actual: this.actual, 42 message: message 43 }); 44 this.spec.addMatcherResult(expectationResult); 45 return result; 46 }; 47 }; 48 49 50 51 52 /** 53 * toBe: compares the actual to the expected using === 54 * @param expected 55 */ 56 57 jasmine.Matchers.prototype.toBe = jasmine.Matchers.matcherFn_('toBe', { 58 test: function (actual, expected) { 59 return actual === expected; 60 }, 61 message: function(actual, expected) { 62 return "Expected " + jasmine.pp(actual) + " to be " + jasmine.pp(expected); 63 } 64 }); 65 66 /** 67 * toNotBe: compares the actual to the expected using !== 68 * @param expected 69 */ 70 jasmine.Matchers.prototype.toNotBe = jasmine.Matchers.matcherFn_('toNotBe', { 71 test: function (actual, expected) { 72 return actual !== expected; 73 }, 74 message: function(actual, expected) { 75 return "Expected " + jasmine.pp(actual) + " to not be " + jasmine.pp(expected); 76 } 77 }); 78 79 /** 80 * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc. 81 * 82 * @param expected 83 */ 84 85 jasmine.Matchers.prototype.toEqual = jasmine.Matchers.matcherFn_('toEqual', { 86 test: function (actual, expected) { 87 return this.env.equals_(actual, expected); 88 }, 89 message: function(actual, expected) { 90 return "Expected " + jasmine.pp(actual) + " to equal " + jasmine.pp(expected); 91 } 92 }); 93 94 /** 95 * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual 96 * @param expected 97 */ 98 jasmine.Matchers.prototype.toNotEqual = jasmine.Matchers.matcherFn_('toNotEqual', { 99 test: function (actual, expected) { 100 return !this.env.equals_(actual, expected); 101 }, 102 message: function(actual, expected) { 103 return "Expected " + jasmine.pp(actual) + " to not equal " + jasmine.pp(expected); 104 } 105 }); 106 107 /** 108 * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes 109 * a pattern or a String. 110 * 111 * @param reg_exp 112 */ 113 jasmine.Matchers.prototype.toMatch = jasmine.Matchers.matcherFn_('toMatch', { 114 test: function(actual, expected) { 115 return new RegExp(expected).test(actual); 116 }, 117 message: function(actual, expected) { 118 return jasmine.pp(actual) + " does not match the regular expression " + new RegExp(expected).toString(); 119 } 120 }); 121 122 /** 123 * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch 124 * @param reg_exp 125 */ 126 127 jasmine.Matchers.prototype.toNotMatch = jasmine.Matchers.matcherFn_('toNotMatch', { 128 test: function(actual, expected) { 129 return !(new RegExp(expected).test(actual)); 130 }, 131 message: function(actual, expected) { 132 return jasmine.pp(actual) + " should not match " + new RegExp(expected).toString(); 133 } 134 }); 135 136 /** 137 * Matcher that compares the acutal to undefined. 138 */ 139 140 jasmine.Matchers.prototype.toBeDefined = jasmine.Matchers.matcherFn_('toBeDefined', { 141 test: function(actual) { 142 return (actual !== undefined); 143 }, 144 message: function() { 145 return 'Expected actual to not be undefined.'; 146 } 147 }); 148 149 /** 150 * Matcher that compares the acutal to undefined. 151 */ 152 153 jasmine.Matchers.prototype.toBeUndefined = jasmine.Matchers.matcherFn_('toBeUndefined', { 154 test: function(actual) { 155 return (actual === undefined); 156 }, 157 message: function(actual) { 158 return 'Expected ' + jasmine.pp(actual) + ' to be undefined.'; 159 } 160 }); 161 162 /** 163 * Matcher that compares the actual to null. 164 * 165 */ 166 jasmine.Matchers.prototype.toBeNull = jasmine.Matchers.matcherFn_('toBeNull', { 167 test: function(actual) { 168 return (actual === null); 169 }, 170 message: function(actual) { 171 return 'Expected ' + jasmine.pp(actual) + ' to be null.'; 172 } 173 }); 174 175 /** 176 * Matcher that boolean not-nots the actual. 177 */ 178 jasmine.Matchers.prototype.toBeTruthy = jasmine.Matchers.matcherFn_('toBeTruthy', { 179 test: function(actual) { 180 return !!actual; 181 }, 182 message: function() { 183 return 'Expected actual to be truthy'; 184 } 185 }); 186 187 188 /** 189 * Matcher that boolean nots the actual. 190 */ 191 jasmine.Matchers.prototype.toBeFalsy = jasmine.Matchers.matcherFn_('toBeFalsy', { 192 test: function(actual) { 193 return !actual; 194 }, 195 message: function(actual) { 196 return 'Expected ' + jasmine.pp(actual) + ' to be falsy'; 197 } 198 }); 199 200 /** 201 * Matcher that checks to see if the acutal, a Jasmine spy, was called. 202 */ 203 204 jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.matcherFn_('wasCalled', { 205 getActual_: function() { 206 var args = jasmine.util.argsToArray(arguments); 207 if (args.length > 1) { 208 throw(new Error('wasCalled does not take arguments, use wasCalledWith')); 209 } 210 return args.splice(0, 1)[0]; 211 }, 212 test: function() { 213 var actual = this.getActual_.apply(this, arguments); 214 if (!actual || !actual.isSpy) { 215 return false; 216 } 217 return actual.wasCalled; 218 }, 219 message: function() { 220 var actual = this.getActual_.apply(this, arguments); 221 if (!actual || !actual.isSpy) { 222 return 'Actual is not a spy.'; 223 } 224 return "Expected spy " + actual.identity + " to have been called."; 225 } 226 }); 227 228 /** 229 * Matcher that checks to see if the acutal, a Jasmine spy, was not called. 230 */ 231 jasmine.Matchers.prototype.wasNotCalled = jasmine.Matchers.matcherFn_('wasNotCalled', { 232 getActual_: function() { 233 var args = jasmine.util.argsToArray(arguments); 234 return args.splice(0, 1)[0]; 235 }, 236 test: function() { 237 var actual = this.getActual_.apply(this, arguments); 238 if (!actual || !actual.isSpy) { 239 return false; 240 } 241 return !actual.wasCalled; 242 }, 243 message: function() { 244 var actual = this.getActual_.apply(this, arguments); 245 if (!actual || !actual.isSpy) { 246 return 'Actual is not a spy.'; 247 } 248 return "Expected spy " + actual.identity + " to not have been called."; 249 } 250 }); 251 252 jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.matcherFn_('wasCalledWith', { 253 test: function() { 254 var args = jasmine.util.argsToArray(arguments); 255 var actual = args.splice(0, 1)[0]; 256 if (!actual || !actual.isSpy) { 257 return false; 258 } 259 return this.env.contains_(actual.argsForCall, args); 260 }, 261 message: function() { 262 var args = jasmine.util.argsToArray(arguments); 263 var actual = args.splice(0, 1)[0]; 264 var message; 265 if (!actual || !actual.isSpy) { 266 message = 'Actual is not a spy'; 267 } else { 268 message = "Expected spy to have been called with " + jasmine.pp(args) + " but was called with " + actual.argsForCall; 269 } 270 return message; 271 } 272 }); 273 274 /** 275 * Matcher that checks to see if the acutal, a Jasmine spy, was called with a set of parameters. 276 * 277 * @example 278 * 279 */ 280 281 /** 282 * Matcher that checks that the expected item is an element in the actual Array. 283 * 284 * @param {Object} item 285 */ 286 287 jasmine.Matchers.prototype.toContain = jasmine.Matchers.matcherFn_('toContain', { 288 test: function(actual, expected) { 289 return this.env.contains_(actual, expected); 290 }, 291 message: function(actual, expected) { 292 return 'Expected ' + jasmine.pp(actual) + ' to contain ' + jasmine.pp(expected); 293 } 294 }); 295 296 /** 297 * Matcher that checks that the expected item is NOT an element in the actual Array. 298 * 299 * @param {Object} item 300 */ 301 jasmine.Matchers.prototype.toNotContain = jasmine.Matchers.matcherFn_('toNotContain', { 302 test: function(actual, expected) { 303 return !this.env.contains_(actual, expected); 304 }, 305 message: function(actual, expected) { 306 return 'Expected ' + jasmine.pp(actual) + ' to not contain ' + jasmine.pp(expected); 307 } 308 }); 309 310 jasmine.Matchers.prototype.toBeLessThan = jasmine.Matchers.matcherFn_('toBeLessThan', { 311 test: function(actual, expected) { 312 return actual < expected; 313 }, 314 message: function(actual, expected) { 315 return 'Expected ' + jasmine.pp(actual) + ' to be less than ' + jasmine.pp(expected); 316 } 317 }); 318 319 jasmine.Matchers.prototype.toBeGreaterThan = jasmine.Matchers.matcherFn_('toBeGreaterThan', { 320 test: function(actual, expected) { 321 return actual > expected; 322 }, 323 message: function(actual, expected) { 324 return 'Expected ' + jasmine.pp(actual) + ' to be greater than ' + jasmine.pp(expected); 325 } 326 }); 327 328 /** 329 * Matcher that checks that the expected exception was thrown by the actual. 330 * 331 * @param {String} expectedException 332 */ 333 jasmine.Matchers.prototype.toThrow = jasmine.Matchers.matcherFn_('toThrow', { 334 getException_: function(actual, expected) { 335 var exception; 336 if (typeof actual != 'function') { 337 throw new Error('Actual is not a function'); 338 } 339 try { 340 actual(); 341 } catch (e) { 342 exception = e; 343 } 344 return exception; 345 }, 346 test: function(actual, expected) { 347 var result = false; 348 var exception = this.getException_(actual, expected); 349 if (exception) { 350 result = (expected === undefined || this.env.equals_(exception.message || exception, expected.message || expected)); 351 } 352 return result; 353 }, 354 message: function(actual, expected) { 355 var exception = this.getException_(actual, expected); 356 if (exception && (expected === undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) { 357 return ["Expected function to throw", expected.message || expected, ", but it threw", exception.message || exception ].join(' '); 358 } else { 359 return "Expected function to throw an exception."; 360 } 361 } 362 }); 363 364 jasmine.Matchers.Any = function(expectedClass) { 365 this.expectedClass = expectedClass; 366 }; 367 368 jasmine.Matchers.Any.prototype.matches = function(other) { 369 if (this.expectedClass == String) { 370 return typeof other == 'string' || other instanceof String; 371 } 372 373 if (this.expectedClass == Number) { 374 return typeof other == 'number' || other instanceof Number; 375 } 376 377 if (this.expectedClass == Function) { 378 return typeof other == 'function' || other instanceof Function; 379 } 380 381 if (this.expectedClass == Object) { 382 return typeof other == 'object'; 383 } 384 385 return other instanceof this.expectedClass; 386 }; 387 388 jasmine.Matchers.Any.prototype.toString = function() { 389 return '<jasmine.any(' + this.expectedClass + ')>'; 390 }; 391 392