|
| 1 | +/* |
| 2 | + * Copyright © 2012 Jamie Mason, @GotNoSugarBaby, https://github.com/JamieMason |
| 3 | + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
| 4 | + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. |
| 5 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 6 | + */ |
| 7 | + |
| 8 | +beforeEach(function() { |
| 9 | + |
| 10 | + /** |
| 11 | + * Assert subject is of type |
| 12 | + * @param {Mixed} subject |
| 13 | + * @param {String} type |
| 14 | + * @return {Boolean} |
| 15 | + */ |
| 16 | + function is(subject, type) { |
| 17 | + return Object.prototype.toString.call(subject) === '[object ' + type + ']'; |
| 18 | + } |
| 19 | + |
| 20 | + /** |
| 21 | + * Assert subject is an HTML Element with the given node type |
| 22 | + * @return {Boolean} |
| 23 | + */ |
| 24 | + function isHtmlElementOfType(subject, type) { |
| 25 | + return subject && subject.nodeType === type; |
| 26 | + } |
| 27 | + |
| 28 | + /* Arrays |
| 29 | + * ==================================================== */ |
| 30 | + |
| 31 | + /** |
| 32 | + * Assert subject is an Array from this document (Arrays from iframes etc won't match) |
| 33 | + * @return {Boolean} |
| 34 | + */ |
| 35 | + function toBeArray() { |
| 36 | + return this.actual instanceof Array; |
| 37 | + } |
| 38 | + |
| 39 | + /** |
| 40 | + * Assert subject is an Array with a defined number of members |
| 41 | + * @param {Number} size |
| 42 | + * @return {Boolean} |
| 43 | + */ |
| 44 | + function toBeArrayOfSize(size) { |
| 45 | + return toBeArray.call(this) && this.actual.length === size; |
| 46 | + } |
| 47 | + |
| 48 | + /** |
| 49 | + * Assert subject is an Array with at least one member |
| 50 | + * @return {Boolean} |
| 51 | + */ |
| 52 | + function toBeNonEmptyArray() { |
| 53 | + return toBeArray.call(this) && this.actual.length > 0; |
| 54 | + } |
| 55 | + |
| 56 | + /* Booleans |
| 57 | + * ==================================================== */ |
| 58 | + |
| 59 | + /** |
| 60 | + * Assert subject is not only truthy or falsy, but an actual Boolean |
| 61 | + * @return {Boolean} |
| 62 | + */ |
| 63 | + function toBeBoolean() { |
| 64 | + return toBeTrue.call(this) || toBeFalse.call(this); |
| 65 | + } |
| 66 | + |
| 67 | + /** |
| 68 | + * Assert subject is not only truthy, but an actual Boolean |
| 69 | + * @return {Boolean} |
| 70 | + */ |
| 71 | + function toBeTrue() { |
| 72 | + return this.actual === true; |
| 73 | + } |
| 74 | + |
| 75 | + /** |
| 76 | + * Assert subject is not only falsy, but an actual Boolean |
| 77 | + * @return {Boolean} |
| 78 | + */ |
| 79 | + function toBeFalse() { |
| 80 | + return this.actual === false; |
| 81 | + } |
| 82 | + |
| 83 | + /* Browser |
| 84 | + * ==================================================== */ |
| 85 | + |
| 86 | + /** |
| 87 | + * Assert subject is the window global |
| 88 | + * @return {Boolean} |
| 89 | + */ |
| 90 | + function toBeWindow() { |
| 91 | + return typeof window !== 'undefined' && this.actual === window; |
| 92 | + } |
| 93 | + |
| 94 | + /** |
| 95 | + * Assert subject is the document global |
| 96 | + * @return {Boolean} |
| 97 | + */ |
| 98 | + function toBeDocument() { |
| 99 | + return typeof document !== 'undefined' && this.actual === document; |
| 100 | + } |
| 101 | + |
| 102 | + /** |
| 103 | + * Assert subject is an HTML Element |
| 104 | + * @return {Boolean} |
| 105 | + */ |
| 106 | + function toBeHtmlNode() { |
| 107 | + return isHtmlElementOfType(this.actual, 1); |
| 108 | + } |
| 109 | + |
| 110 | + /** |
| 111 | + * Assert subject is an HTML Text Element |
| 112 | + * @return {Boolean} |
| 113 | + */ |
| 114 | + function toBeHtmlTextNode() { |
| 115 | + return isHtmlElementOfType(this.actual, 3); |
| 116 | + } |
| 117 | + |
| 118 | + /** |
| 119 | + * Assert subject is an HTML Text Element |
| 120 | + * @return {Boolean} |
| 121 | + */ |
| 122 | + function toBeHtmlCommentNode() { |
| 123 | + return isHtmlElementOfType(this.actual, 8); |
| 124 | + } |
| 125 | + |
| 126 | + /* Strings |
| 127 | + * ==================================================== */ |
| 128 | + |
| 129 | + /** |
| 130 | + * Assert subject is a String |
| 131 | + * @return {Boolean} |
| 132 | + */ |
| 133 | + function toBeString() { |
| 134 | + return is(this.actual, 'String'); |
| 135 | + } |
| 136 | + |
| 137 | + /** |
| 138 | + * @return {Boolean} |
| 139 | + */ |
| 140 | + function toBeEmptyString() { |
| 141 | + return this.actual === ''; |
| 142 | + } |
| 143 | + |
| 144 | + /** |
| 145 | + * @return {Boolean} |
| 146 | + */ |
| 147 | + function toBeNonEmptyString() { |
| 148 | + return toBeString.call(this) && this.actual.length > 0; |
| 149 | + } |
| 150 | + |
| 151 | + /** |
| 152 | + * Assert subject is string containing HTML Markup |
| 153 | + * @return {Boolean} |
| 154 | + */ |
| 155 | + function toBeHtmlString() { |
| 156 | + return toBeString.call(this) && this.actual.search(/<([a-z]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)/) !== -1; |
| 157 | + } |
| 158 | + |
| 159 | + /** |
| 160 | + * Assert subject is a String containing nothing but whitespace |
| 161 | + * @return {Boolean} |
| 162 | + */ |
| 163 | + function toBeWhitespace() { |
| 164 | + return is(this.actual, 'String') && this.actual.search(/\S/) === -1; |
| 165 | + } |
| 166 | + |
| 167 | + /* Numbers |
| 168 | + * ==================================================== */ |
| 169 | + |
| 170 | + /** |
| 171 | + * Assert subject is not only calculable, but an actual Number |
| 172 | + * @return {Boolean} |
| 173 | + */ |
| 174 | + function toBeNumber() { |
| 175 | + return !isNaN(parseFloat(this.actual)) && !is(this.actual, 'String'); |
| 176 | + } |
| 177 | + |
| 178 | + /** |
| 179 | + * Assert subject is an even Number |
| 180 | + * @return {Boolean} |
| 181 | + */ |
| 182 | + function toBeEvenNumber() { |
| 183 | + return toBeNumber.call(this) && this.actual % 2 === 0; |
| 184 | + } |
| 185 | + |
| 186 | + /** |
| 187 | + * Assert subject is an odd Number |
| 188 | + * @return {Boolean} |
| 189 | + */ |
| 190 | + function toBeOddNumber() { |
| 191 | + return toBeNumber.call(this) && this.actual % 2 !== 0; |
| 192 | + } |
| 193 | + |
| 194 | + /** |
| 195 | + * Assert subject can be used in Mathemetic calculations, despite not being an actual Number. |
| 196 | + * @example "1" * "2" === 2 (pass) |
| 197 | + * @example "wut?" * "2" === NaN (fail) |
| 198 | + * @return {Boolean} |
| 199 | + */ |
| 200 | + function toBeCalculable() { |
| 201 | + return !isNaN(this.actual * 2); |
| 202 | + } |
| 203 | + |
| 204 | + /* Objects |
| 205 | + * ==================================================== */ |
| 206 | + |
| 207 | + /** |
| 208 | + * Assert subject is an Object, and not null |
| 209 | + * @return {Boolean} |
| 210 | + */ |
| 211 | + function toBeObject() { |
| 212 | + return this.actual instanceof Object; |
| 213 | + } |
| 214 | + |
| 215 | + /** |
| 216 | + * Assert subject features the same public members as api. |
| 217 | + * @param {Object|Array} api |
| 218 | + * @return {Boolean} |
| 219 | + */ |
| 220 | + function toImplement(api) { |
| 221 | + if(!this.actual || !api) { |
| 222 | + return false; |
| 223 | + } |
| 224 | + for(var required in api) { |
| 225 | + if((required in this.actual) === false) { |
| 226 | + return false; |
| 227 | + } |
| 228 | + } |
| 229 | + return true; |
| 230 | + } |
| 231 | + |
| 232 | + /** |
| 233 | + * Assert subject is a function |
| 234 | + * @return {Boolean} |
| 235 | + */ |
| 236 | + function toBeFunction() { |
| 237 | + return this.actual instanceof Function; |
| 238 | + } |
| 239 | + |
| 240 | + /* Errors |
| 241 | + * ==================================================== */ |
| 242 | + |
| 243 | + /** |
| 244 | + * Asserts subject throws an Error of any type |
| 245 | + * @return {Boolean} |
| 246 | + */ |
| 247 | + function toThrowError() { |
| 248 | + var threwError = false; |
| 249 | + try { |
| 250 | + this.actual(); |
| 251 | + } catch(e) { |
| 252 | + threwError = true; |
| 253 | + } |
| 254 | + return threwError; |
| 255 | + } |
| 256 | + |
| 257 | + /** |
| 258 | + * Asserts subject throws an Error of a specific type, such as 'TypeError' |
| 259 | + * @param {String} type |
| 260 | + * @return {Boolean} |
| 261 | + */ |
| 262 | + function toThrowErrorOfType(type) { |
| 263 | + var threwErrorOfType = false; |
| 264 | + try { |
| 265 | + this.actual(); |
| 266 | + } catch(e) { |
| 267 | + threwErrorOfType = (e.name === type); |
| 268 | + } |
| 269 | + return threwErrorOfType; |
| 270 | + } |
| 271 | + |
| 272 | + /* Other |
| 273 | + * ==================================================== */ |
| 274 | + |
| 275 | + /** |
| 276 | + * Assert subject is a Date |
| 277 | + * @return {Boolean} |
| 278 | + */ |
| 279 | + function toBeDate() { |
| 280 | + return this.actual instanceof Date; |
| 281 | + } |
| 282 | + |
| 283 | + this.addMatchers({ |
| 284 | + toBeArray: toBeArray, |
| 285 | + toBeArrayOfSize: toBeArrayOfSize, |
| 286 | + toBeNonEmptyArray: toBeNonEmptyArray, |
| 287 | + toBeTrue: toBeTrue, |
| 288 | + toBeFalse: toBeFalse, |
| 289 | + toBeBoolean: toBeBoolean, |
| 290 | + toBeWindow: toBeWindow, |
| 291 | + toBeDocument: toBeDocument, |
| 292 | + toBeHtmlCommentNode: toBeHtmlCommentNode, |
| 293 | + toBeHtmlNode: toBeHtmlNode, |
| 294 | + toBeHtmlTextNode: toBeHtmlTextNode, |
| 295 | + toBeEmptyString: toBeEmptyString, |
| 296 | + toBeNonEmptyString: toBeNonEmptyString, |
| 297 | + toBeString: toBeString, |
| 298 | + toBeHtmlString: toBeHtmlString, |
| 299 | + toBeWhitespace: toBeWhitespace, |
| 300 | + toBeNumber: toBeNumber, |
| 301 | + toBeCalculable: toBeCalculable, |
| 302 | + toBeEvenNumber: toBeEvenNumber, |
| 303 | + toBeOddNumber: toBeOddNumber, |
| 304 | + toBeFunction: toBeFunction, |
| 305 | + toBeObject: toBeObject, |
| 306 | + toImplement: toImplement, |
| 307 | + toThrowError: toThrowError, |
| 308 | + toThrowErrorOfType: toThrowErrorOfType, |
| 309 | + toBeDate: toBeDate |
| 310 | + }); |
| 311 | +}); |
0 commit comments