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, matcherFunction) { 28 return function() { 29 var matcherArgs = jasmine.util.argsToArray(arguments); 30 var result = matcherFunction.apply(this, arguments); 31 var message; 32 if (!result) { 33 if (this.message) { 34 message = this.message.apply(this, arguments); 35 } else { 36 var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); }); 37 message = "Expected " + jasmine.pp(this.actual) + " " + englishyPredicate; 38 if (matcherArgs.length > 0) { 39 for (var i = 0; i < matcherArgs.length; i++) { 40 if (i > 0) message += ","; 41 message += " " + jasmine.pp(matcherArgs[i]); 42 } 43 } 44 message += "."; 45 } 46 } 47 var expectationResult = new jasmine.ExpectationResult({ 48 matcherName: matcherName, 49 passed: result, 50 expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0], 51 actual: this.actual, 52 message: message 53 }); 54 this.spec.addMatcherResult(expectationResult); 55 return result; 56 }; 57 }; 58 59 60 61 62 /** 63 * toBe: compares the actual to the expected using === 64 * @param expected 65 */ 66 67 jasmine.Matchers.prototype.toBe = function(expected) { 68 return this.actual === expected; 69 }; 70 71 /** 72 * toNotBe: compares the actual to the expected using !== 73 * @param expected 74 */ 75 jasmine.Matchers.prototype.toNotBe = function(expected) { 76 return this.actual !== expected; 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 = function(expected) { 86 return this.env.equals_(this.actual, expected); 87 }; 88 89 /** 90 * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual 91 * @param expected 92 */ 93 jasmine.Matchers.prototype.toNotEqual = function(expected) { 94 return !this.env.equals_(this.actual, expected); 95 }; 96 97 /** 98 * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes 99 * a pattern or a String. 100 * 101 * @param reg_exp 102 */ 103 jasmine.Matchers.prototype.toMatch = function(expected) { 104 return new RegExp(expected).test(this.actual); 105 }; 106 107 /** 108 * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch 109 * @param reg_exp 110 */ 111 jasmine.Matchers.prototype.toNotMatch = function(expected) { 112 return !(new RegExp(expected).test(this.actual)); 113 }; 114 115 /** 116 * Matcher that compares the actual to jasmine.undefined. 117 */ 118 jasmine.Matchers.prototype.toBeDefined = function() { 119 return (this.actual !== jasmine.undefined); 120 }; 121 122 /** 123 * Matcher that compares the actual to jasmine.undefined. 124 */ 125 jasmine.Matchers.prototype.toBeUndefined = function() { 126 return (this.actual === jasmine.undefined); 127 }; 128 129 /** 130 * Matcher that compares the actual to null. 131 */ 132 jasmine.Matchers.prototype.toBeNull = function() { 133 return (this.actual === null); 134 }; 135 136 /** 137 * Matcher that boolean not-nots the actual. 138 */ 139 jasmine.Matchers.prototype.toBeTruthy = function() { 140 return !!this.actual; 141 }; 142 143 144 /** 145 * Matcher that boolean nots the actual. 146 */ 147 jasmine.Matchers.prototype.toBeFalsy = function() { 148 return !this.actual; 149 }; 150 151 /** 152 * Matcher that checks to see if the actual, a Jasmine spy, was called. 153 */ 154 jasmine.Matchers.prototype.wasCalled = function() { 155 if (arguments.length > 0) { 156 throw new Error('wasCalled does not take arguments, use wasCalledWith'); 157 } 158 159 if (!jasmine.isSpy(this.actual)) { 160 throw new Error('Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); 161 } 162 163 this.message = function() { 164 return "Expected spy " + this.actual.identity + " to have been called."; 165 }; 166 167 return this.actual.wasCalled; 168 }; 169 170 /** 171 * Matcher that checks to see if the actual, a Jasmine spy, was not called. 172 */ 173 jasmine.Matchers.prototype.wasNotCalled = function() { 174 if (arguments.length > 0) { 175 throw new Error('wasNotCalled does not take arguments'); 176 } 177 178 if (!jasmine.isSpy(this.actual)) { 179 throw new Error('Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); 180 } 181 182 this.message = function() { 183 return "Expected spy " + this.actual.identity + " to not have been called."; 184 }; 185 186 return !this.actual.wasCalled; 187 }; 188 189 /** 190 * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters. 191 * 192 * @example 193 * 194 */ 195 jasmine.Matchers.prototype.wasCalledWith = function() { 196 if (!jasmine.isSpy(this.actual)) { 197 throw new Error('Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); 198 } 199 200 this.message = function() { 201 if (this.actual.callCount == 0) { 202 return "Expected spy to have been called with " + jasmine.pp(arguments) + " but it was never called."; 203 } else { 204 return "Expected spy to have been called with " + jasmine.pp(arguments) + " but was called with " + jasmine.pp(this.actual.argsForCall); 205 } 206 }; 207 208 return this.env.contains_(this.actual.argsForCall, jasmine.util.argsToArray(arguments)); 209 }; 210 211 jasmine.Matchers.prototype.wasNotCalledWith = function() { 212 if (!jasmine.isSpy(this.actual)) { 213 throw new Error('Expected a spy, but got ' + jasmine.Matchers.pp(this.actual) + '.'); 214 } 215 216 this.message = function() { 217 return "Expected spy not to have been called with " + jasmine.pp(arguments) + " but it was"; 218 }; 219 220 return !this.env.contains_(this.actual.argsForCall, jasmine.util.argsToArray(arguments)); 221 }; 222 223 /** 224 * Matcher that checks that the expected item is an element in the actual Array. 225 * 226 * @param {Object} item 227 */ 228 jasmine.Matchers.prototype.toContain = function(expected) { 229 return this.env.contains_(this.actual, expected); 230 }; 231 232 /** 233 * Matcher that checks that the expected item is NOT an element in the actual Array. 234 * 235 * @param {Object} item 236 */ 237 jasmine.Matchers.prototype.toNotContain = function(expected) { 238 return !this.env.contains_(this.actual, expected); 239 }; 240 241 jasmine.Matchers.prototype.toBeLessThan = function(expected) { 242 return this.actual < expected; 243 }; 244 245 jasmine.Matchers.prototype.toBeGreaterThan = function(expected) { 246 return this.actual > expected; 247 }; 248 249 /** 250 * Matcher that checks that the expected exception was thrown by the actual. 251 * 252 * @param {String} expectedException 253 */ 254 jasmine.Matchers.prototype.toThrow = function(expected) { 255 function getException_(actual, expected) { 256 var exception; 257 if (typeof actual != 'function') { 258 throw new Error('Actual is not a function'); 259 } 260 try { 261 actual(); 262 } catch (e) { 263 exception = e; 264 } 265 return exception; 266 } 267 268 var result = false; 269 var exception = getException_(this.actual, expected); 270 if (exception) { 271 result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected)); 272 } 273 274 this.message = function(expected) { 275 var exception = getException_(this.actual, expected); 276 if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) { 277 return ["Expected function to throw", expected.message || expected, ", but it threw", exception.message || exception ].join(' '); 278 } else { 279 return "Expected function to throw an exception."; 280 } 281 }; 282 283 return result; 284 }; 285 286 jasmine.Matchers.Any = function(expectedClass) { 287 this.expectedClass = expectedClass; 288 }; 289 290 jasmine.Matchers.Any.prototype.matches = function(other) { 291 if (this.expectedClass == String) { 292 return typeof other == 'string' || other instanceof String; 293 } 294 295 if (this.expectedClass == Number) { 296 return typeof other == 'number' || other instanceof Number; 297 } 298 299 if (this.expectedClass == Function) { 300 return typeof other == 'function' || other instanceof Function; 301 } 302 303 if (this.expectedClass == Object) { 304 return typeof other == 'object'; 305 } 306 307 return other instanceof this.expectedClass; 308 }; 309 310 jasmine.Matchers.Any.prototype.toString = function() { 311 return '<jasmine.any(' + this.expectedClass + ')>'; 312 }; 313 314