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 undefined. 117 */ 118 jasmine.Matchers.prototype.toBeDefined = function() { 119 return (this.actual !== undefined); 120 }; 121 122 /** 123 * Matcher that compares the actual to undefined. 124 */ 125 jasmine.Matchers.prototype.toBeUndefined = function() { 126 return (this.actual === 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 return "Expected spy to have been called with " + jasmine.pp(arguments) + " but was called with " + jasmine.pp(this.actual.argsForCall); 202 }; 203 204 return this.env.contains_(this.actual.argsForCall, jasmine.util.argsToArray(arguments)); 205 }; 206 207 /** 208 * Matcher that checks that the expected item is an element in the actual Array. 209 * 210 * @param {Object} item 211 */ 212 jasmine.Matchers.prototype.toContain = function(expected) { 213 return this.env.contains_(this.actual, expected); 214 }; 215 216 /** 217 * Matcher that checks that the expected item is NOT an element in the actual Array. 218 * 219 * @param {Object} item 220 */ 221 jasmine.Matchers.prototype.toNotContain = function(expected) { 222 return !this.env.contains_(this.actual, expected); 223 }; 224 225 jasmine.Matchers.prototype.toBeLessThan = function(expected) { 226 return this.actual < expected; 227 }; 228 229 jasmine.Matchers.prototype.toBeGreaterThan = function(expected) { 230 return this.actual > expected; 231 }; 232 233 /** 234 * Matcher that checks that the expected exception was thrown by the actual. 235 * 236 * @param {String} expectedException 237 */ 238 jasmine.Matchers.prototype.toThrow = function(expected) { 239 function getException_(actual, expected) { 240 var exception; 241 if (typeof actual != 'function') { 242 throw new Error('Actual is not a function'); 243 } 244 try { 245 actual(); 246 } catch (e) { 247 exception = e; 248 } 249 return exception; 250 } 251 252 var result = false; 253 var exception = getException_(this.actual, expected); 254 if (exception) { 255 result = (expected === undefined || this.env.equals_(exception.message || exception, expected.message || expected)); 256 } 257 258 this.message = function(expected) { 259 var exception = getException_(this.actual, expected); 260 if (exception && (expected === undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) { 261 return ["Expected function to throw", expected.message || expected, ", but it threw", exception.message || exception ].join(' '); 262 } else { 263 return "Expected function to throw an exception."; 264 } 265 }; 266 267 return result; 268 }; 269 270 jasmine.Matchers.Any = function(expectedClass) { 271 this.expectedClass = expectedClass; 272 }; 273 274 jasmine.Matchers.Any.prototype.matches = function(other) { 275 if (this.expectedClass == String) { 276 return typeof other == 'string' || other instanceof String; 277 } 278 279 if (this.expectedClass == Number) { 280 return typeof other == 'number' || other instanceof Number; 281 } 282 283 if (this.expectedClass == Function) { 284 return typeof other == 'function' || other instanceof Function; 285 } 286 287 if (this.expectedClass == Object) { 288 return typeof other == 'object'; 289 } 290 291 return other instanceof this.expectedClass; 292 }; 293 294 jasmine.Matchers.Any.prototype.toString = function() { 295 return '<jasmine.any(' + this.expectedClass + ')>'; 296 }; 297 298