fixes #148 - broken utils.isWebPage()
Showing
6 changed files
with
334 additions
and
324 deletions
... | @@ -5,7 +5,8 @@ XXXX-XX-XX, v0.6.11 | ... | @@ -5,7 +5,8 @@ XXXX-XX-XX, v0.6.11 |
5 | ------------------- | 5 | ------------------- |
6 | 6 | ||
7 | - closed [#132](https://github.com/n1k0/casperjs/issues/132) - added ability to include js/coffee files using a dedicated option when using the `casper test` command | 7 | - closed [#132](https://github.com/n1k0/casperjs/issues/132) - added ability to include js/coffee files using a dedicated option when using the `casper test` command |
8 | - fixes [#140](https://github.com/n1k0/casperjs/issues/140) - `casper test` now resolves local paths urls | 8 | - fixed [#140](https://github.com/n1k0/casperjs/issues/140) - `casper test` now resolves local paths urls |
9 | - fixed [#148](https://github.com/n1k0/casperjs/issues/148) - `utils.isWebPage()` was broken | ||
9 | - closed [#144](https://github.com/n1k0/casperjs/issues/144) - added a `safeLogs` option to blur password values in debug logs. **This option is set to `true` by default.** | 10 | - closed [#144](https://github.com/n1k0/casperjs/issues/144) - added a `safeLogs` option to blur password values in debug logs. **This option is set to `true` by default.** |
10 | - added [`Casper.userAgent()`](http://casperjs.org/api.html#casper.userAgent) to ease a more dynamic setting of user-agent string | 11 | - added [`Casper.userAgent()`](http://casperjs.org/api.html#casper.userAgent) to ease a more dynamic setting of user-agent string |
11 | - added `Tester.assertTitleMatch()` method | 12 | - added `Tester.assertTitleMatch()` method | ... | ... |
... | @@ -400,6 +400,8 @@ Casper.prototype.die = function die(message, status) { | ... | @@ -400,6 +400,8 @@ Casper.prototype.die = function die(message, status) { |
400 | * | 400 | * |
401 | * @param String url The url of the resource to download | 401 | * @param String url The url of the resource to download |
402 | * @param String targetPath The destination file path | 402 | * @param String targetPath The destination file path |
403 | * @param String method The HTTP method to use (default: GET) | ||
404 | * @param String data Optional data to pass performing the request | ||
403 | * @return Casper | 405 | * @return Casper |
404 | */ | 406 | */ |
405 | Casper.prototype.download = function download(url, targetPath, method, data) { | 407 | Casper.prototype.download = function download(url, targetPath, method, data) { | ... | ... |
... | @@ -100,7 +100,7 @@ var Tester = function Tester(casper, options) { | ... | @@ -100,7 +100,7 @@ var Tester = function Tester(casper, options) { |
100 | if (failure.details) { | 100 | if (failure.details) { |
101 | this.comment(' details: ' + failure.details); | 101 | this.comment(' details: ' + failure.details); |
102 | } | 102 | } |
103 | if (failure.values && Object.keys(failure.values).length > 0) { | 103 | if (utils.isObject(failure.values) && Object.keys(failure.values).length > 0) { |
104 | for (var name in failure.values) { | 104 | for (var name in failure.values) { |
105 | this.comment(' ' + name + ': ' + utils.serialize(failure.values[name])); | 105 | this.comment(' ' + name + ': ' + utils.serialize(failure.values[name])); |
106 | } | 106 | } | ... | ... |
... | @@ -30,361 +30,341 @@ | ... | @@ -30,361 +30,341 @@ |
30 | 30 | ||
31 | /*global CasperError console exports phantom require*/ | 31 | /*global CasperError console exports phantom require*/ |
32 | 32 | ||
33 | /** | 33 | (function(exports) { |
34 | * Provides a better typeof operator equivalent, able to retrieve the array | ||
35 | * type. | ||
36 | * | ||
37 | * @param mixed input | ||
38 | * @return String | ||
39 | * @see http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/ | ||
40 | */ | ||
41 | function betterTypeOf(input) { | ||
42 | "use strict"; | ||
43 | try { | ||
44 | return Object.prototype.toString.call(input).match(/^\[object\s(.*)\]$/)[1].toLowerCase(); | ||
45 | } catch (e) { | ||
46 | return typeof input; | ||
47 | } | ||
48 | } | ||
49 | exports.betterTypeOf = betterTypeOf; | ||
50 | |||
51 | /** | ||
52 | * Dumps a JSON representation of passed value to the console. Used for | ||
53 | * debugging purpose only. | ||
54 | * | ||
55 | * @param Mixed value | ||
56 | */ | ||
57 | function dump(value) { | ||
58 | "use strict"; | 34 | "use strict"; |
59 | console.log(serialize(value)); | ||
60 | } | ||
61 | exports.dump = dump; | ||
62 | 35 | ||
63 | /** | 36 | /** |
64 | * Returns the file extension in lower case. | 37 | * Provides a better typeof operator equivalent, able to retrieve the array |
65 | * | 38 | * type. |
66 | * @param String file File path | 39 | * |
67 | * @return string | 40 | * @param mixed input |
68 | */ | 41 | * @return String |
69 | function fileExt(file) { | 42 | * @see http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/ |
70 | "use strict"; | 43 | */ |
71 | try { | 44 | function betterTypeOf(input) { |
72 | return file.split('.').pop().toLowerCase().trim(); | 45 | try { |
73 | } catch(e) { | 46 | return Object.prototype.toString.call(input).match(/^\[object\s(.*)\]$/)[1].toLowerCase(); |
74 | return ''; | 47 | } catch (e) { |
48 | return typeof input; | ||
49 | } | ||
75 | } | 50 | } |
76 | } | 51 | exports.betterTypeOf = betterTypeOf; |
77 | exports.fileExt = fileExt; | ||
78 | 52 | ||
79 | /** | 53 | /** |
80 | * Takes a string and append blanks until the pad value is reached. | 54 | * Dumps a JSON representation of passed value to the console. Used for |
81 | * | 55 | * debugging purpose only. |
82 | * @param String text | 56 | * |
83 | * @param Number pad Pad value (optional; default: 80) | 57 | * @param Mixed value |
84 | * @return String | 58 | */ |
85 | */ | 59 | function dump(value) { |
86 | function fillBlanks(text, pad) { | 60 | console.log(serialize(value)); |
87 | "use strict"; | ||
88 | pad = pad || 80; | ||
89 | if (text.length < pad) { | ||
90 | text += new Array(pad - text.length + 1).join(' '); | ||
91 | } | 61 | } |
92 | return text; | 62 | exports.dump = dump; |
93 | } | ||
94 | exports.fillBlanks = fillBlanks; | ||
95 | 63 | ||
96 | /** | 64 | /** |
97 | * Formats a string with passed parameters. Ported from nodejs `util.format()`. | 65 | * Returns the file extension in lower case. |
98 | * | 66 | * |
99 | * @return String | 67 | * @param String file File path |
100 | */ | 68 | * @return string |
101 | function format(f) { | 69 | */ |
102 | "use strict"; | 70 | function fileExt(file) { |
103 | var i = 1; | 71 | try { |
104 | var args = arguments; | 72 | return file.split('.').pop().toLowerCase().trim(); |
105 | var len = args.length; | 73 | } catch(e) { |
106 | var str = String(f).replace(/%[sdj%]/g, function _replace(x) { | 74 | return ''; |
107 | if (i >= len) return x; | ||
108 | switch (x) { | ||
109 | case '%s': | ||
110 | return String(args[i++]); | ||
111 | case '%d': | ||
112 | return Number(args[i++]); | ||
113 | case '%j': | ||
114 | return JSON.stringify(args[i++]); | ||
115 | case '%%': | ||
116 | return '%'; | ||
117 | default: | ||
118 | return x; | ||
119 | } | 75 | } |
120 | }); | 76 | } |
121 | for (var x = args[i]; i < len; x = args[++i]) { | 77 | exports.fileExt = fileExt; |
122 | if (x === null || typeof x !== 'object') { | 78 | |
123 | str += ' ' + x; | 79 | /** |
124 | } else { | 80 | * Takes a string and append blanks until the pad value is reached. |
125 | str += '[obj]'; | 81 | * |
82 | * @param String text | ||
83 | * @param Number pad Pad value (optional; default: 80) | ||
84 | * @return String | ||
85 | */ | ||
86 | function fillBlanks(text, pad) { | ||
87 | pad = pad || 80; | ||
88 | if (text.length < pad) { | ||
89 | text += new Array(pad - text.length + 1).join(' '); | ||
126 | } | 90 | } |
91 | return text; | ||
127 | } | 92 | } |
128 | return str; | 93 | exports.fillBlanks = fillBlanks; |
129 | } | ||
130 | exports.format = format; | ||
131 | 94 | ||
132 | /** | 95 | /** |
133 | * Inherit the prototype methods from one constructor into another. | 96 | * Formats a string with passed parameters. Ported from nodejs `util.format()`. |
134 | * | 97 | * |
135 | * @param {function} ctor Constructor function which needs to inherit the | 98 | * @return String |
136 | * prototype. | 99 | */ |
137 | * @param {function} superCtor Constructor function to inherit prototype from. | 100 | function format(f) { |
138 | */ | 101 | var i = 1; |
139 | function inherits(ctor, superCtor) { | 102 | var args = arguments; |
140 | "use strict"; | 103 | var len = args.length; |
141 | ctor.super_ = ctor.__super__ = superCtor; | 104 | var str = String(f).replace(/%[sdj%]/g, function _replace(x) { |
142 | ctor.prototype = Object.create(superCtor.prototype, { | 105 | if (i >= len) return x; |
143 | constructor: { | 106 | switch (x) { |
144 | value: ctor, | 107 | case '%s': |
145 | enumerable: false, | 108 | return String(args[i++]); |
146 | writable: true, | 109 | case '%d': |
147 | configurable: true | 110 | return Number(args[i++]); |
111 | case '%j': | ||
112 | return JSON.stringify(args[i++]); | ||
113 | case '%%': | ||
114 | return '%'; | ||
115 | default: | ||
116 | return x; | ||
117 | } | ||
118 | }); | ||
119 | for (var x = args[i]; i < len; x = args[++i]) { | ||
120 | if (x === null || typeof x !== 'object') { | ||
121 | str += ' ' + x; | ||
122 | } else { | ||
123 | str += '[obj]'; | ||
124 | } | ||
148 | } | 125 | } |
149 | }); | 126 | return str; |
150 | } | 127 | } |
151 | exports.inherits = inherits; | 128 | exports.format = format; |
152 | 129 | ||
153 | /** | 130 | /** |
154 | * Checks if value is a javascript Array | 131 | * Inherit the prototype methods from one constructor into another. |
155 | * | 132 | * |
156 | * @param mixed value | 133 | * @param {function} ctor Constructor function which needs to inherit the |
157 | * @return Boolean | 134 | * prototype. |
158 | */ | 135 | * @param {function} superCtor Constructor function to inherit prototype from. |
159 | function isArray(value) { | 136 | */ |
160 | "use strict"; | 137 | function inherits(ctor, superCtor) { |
161 | return Array.isArray(value) || isType(value, "array"); | 138 | ctor.super_ = ctor.__super__ = superCtor; |
162 | } | 139 | ctor.prototype = Object.create(superCtor.prototype, { |
163 | exports.isArray = isArray; | 140 | constructor: { |
141 | value: ctor, | ||
142 | enumerable: false, | ||
143 | writable: true, | ||
144 | configurable: true | ||
145 | } | ||
146 | }); | ||
147 | } | ||
148 | exports.inherits = inherits; | ||
164 | 149 | ||
165 | /** | 150 | /** |
166 | * Checks if passed argument is an instance of Capser object. | 151 | * Checks if value is a javascript Array |
167 | * | 152 | * |
168 | * @param mixed value | 153 | * @param mixed value |
169 | * @return Boolean | 154 | * @return Boolean |
170 | */ | 155 | */ |
171 | function isCasperObject(value) { | 156 | function isArray(value) { |
172 | "use strict"; | 157 | return Array.isArray(value) || isType(value, "array"); |
173 | return value instanceof require('casper').Casper; | 158 | } |
174 | } | 159 | exports.isArray = isArray; |
175 | exports.isCasperObject = isCasperObject; | ||
176 | 160 | ||
177 | /** | 161 | /** |
178 | * Checks if value is a phantomjs clipRect-compatible object | 162 | * Checks if passed argument is an instance of Capser object. |
179 | * | 163 | * |
180 | * @param mixed value | 164 | * @param mixed value |
181 | * @return Boolean | 165 | * @return Boolean |
182 | */ | 166 | */ |
183 | function isClipRect(value) { | 167 | function isCasperObject(value) { |
184 | "use strict"; | 168 | return value instanceof require('casper').Casper; |
185 | return isType(value, "cliprect") || ( | 169 | } |
186 | isObject(value) && | 170 | exports.isCasperObject = isCasperObject; |
187 | isNumber(value.top) && isNumber(value.left) && | ||
188 | isNumber(value.width) && isNumber(value.height) | ||
189 | ); | ||
190 | } | ||
191 | exports.isClipRect = isClipRect; | ||
192 | 171 | ||
193 | /** | 172 | /** |
194 | * Checks if value is a javascript Function | 173 | * Checks if value is a phantomjs clipRect-compatible object |
195 | * | 174 | * |
196 | * @param mixed value | 175 | * @param mixed value |
197 | * @return Boolean | 176 | * @return Boolean |
198 | */ | 177 | */ |
199 | function isFunction(value) { | 178 | function isClipRect(value) { |
200 | "use strict"; | 179 | return isType(value, "cliprect") || ( |
201 | return isType(value, "function"); | 180 | isObject(value) && |
202 | } | 181 | isNumber(value.top) && isNumber(value.left) && |
203 | exports.isFunction = isFunction; | 182 | isNumber(value.width) && isNumber(value.height) |
183 | ); | ||
184 | } | ||
185 | exports.isClipRect = isClipRect; | ||
204 | 186 | ||
205 | /** | 187 | /** |
206 | * Checks if a file is apparently javascript compatible (.js or .coffee). | 188 | * Checks if value is a javascript Function |
207 | * | 189 | * |
208 | * @param String file Path to the file to test | 190 | * @param mixed value |
209 | * @return Boolean | 191 | * @return Boolean |
210 | */ | 192 | */ |
211 | function isJsFile(file) { | 193 | function isFunction(value) { |
212 | "use strict"; | 194 | return isType(value, "function"); |
213 | var ext = fileExt(file); | 195 | } |
214 | return isString(ext, "string") && ['js', 'coffee'].indexOf(ext) !== -1; | 196 | exports.isFunction = isFunction; |
215 | } | ||
216 | exports.isJsFile = isJsFile; | ||
217 | 197 | ||
218 | /** | 198 | /** |
219 | * Checks if the provided value is null | 199 | * Checks if a file is apparently javascript compatible (.js or .coffee). |
220 | * | 200 | * |
221 | * @return Boolean | 201 | * @param String file Path to the file to test |
222 | */ | 202 | * @return Boolean |
223 | function isNull(value) { | 203 | */ |
224 | "use strict"; | 204 | function isJsFile(file) { |
225 | return isType(value, "null"); | 205 | var ext = fileExt(file); |
226 | } | 206 | return isString(ext, "string") && ['js', 'coffee'].indexOf(ext) !== -1; |
227 | exports.isNull = isNull; | 207 | } |
208 | exports.isJsFile = isJsFile; | ||
228 | 209 | ||
229 | /** | 210 | /** |
230 | * Checks if value is a javascript Number | 211 | * Checks if the provided value is null |
231 | * | 212 | * |
232 | * @param mixed value | 213 | * @return Boolean |
233 | * @return Boolean | 214 | */ |
234 | */ | 215 | function isNull(value) { |
235 | function isNumber(value) { | 216 | return isType(value, "null"); |
236 | "use strict"; | 217 | } |
237 | return isType(value, "number"); | 218 | exports.isNull = isNull; |
238 | } | ||
239 | exports.isNumber = isNumber; | ||
240 | 219 | ||
241 | /** | 220 | /** |
242 | * Checks if value is a javascript Object | 221 | * Checks if value is a javascript Number |
243 | * | 222 | * |
244 | * @param mixed value | 223 | * @param mixed value |
245 | * @return Boolean | 224 | * @return Boolean |
246 | */ | 225 | */ |
247 | function isObject(value) { | 226 | function isNumber(value) { |
248 | "use strict"; | 227 | return isType(value, "number"); |
249 | return isType(value, "object"); | 228 | } |
250 | } | 229 | exports.isNumber = isNumber; |
251 | exports.isObject = isObject; | ||
252 | 230 | ||
253 | /** | 231 | /** |
254 | * Checks if value is a javascript String | 232 | * Checks if value is a javascript Object |
255 | * | 233 | * |
256 | * @param mixed value | 234 | * @param mixed value |
257 | * @return Boolean | 235 | * @return Boolean |
258 | */ | 236 | */ |
259 | function isString(value) { | 237 | function isObject(value) { |
260 | "use strict"; | 238 | var objectTypes = ["array", "object", "qtruntimeobject"]; |
261 | return isType(value, "string"); | 239 | return objectTypes.indexOf(betterTypeOf(value)) >= 0; |
262 | } | 240 | } |
263 | exports.isString = isString; | 241 | exports.isObject = isObject; |
264 | 242 | ||
265 | /** | 243 | /** |
266 | * Shorthands for checking if a value is of the given type. Can check for | 244 | * Checks if value is a javascript String |
267 | * arrays. | 245 | * |
268 | * | 246 | * @param mixed value |
269 | * @param mixed what The value to check | 247 | * @return Boolean |
270 | * @param String typeName The type name ("string", "number", "function", etc.) | 248 | */ |
271 | * @return Boolean | 249 | function isString(value) { |
272 | */ | 250 | return isType(value, "string"); |
273 | function isType(what, typeName) { | ||
274 | "use strict"; | ||
275 | if (typeof typeName !== "string" || !typeName) { | ||
276 | throw new CasperError("You must pass isType() a typeName string"); | ||
277 | } | 251 | } |
278 | return betterTypeOf(what).toLowerCase() === typeName.toLowerCase(); | 252 | exports.isString = isString; |
279 | } | ||
280 | exports.isType = isType; | ||
281 | 253 | ||
282 | /** | 254 | /** |
283 | * Checks if the provided value is undefined | 255 | * Shorthands for checking if a value is of the given type. Can check for |
284 | * | 256 | * arrays. |
285 | * @return Boolean | 257 | * |
286 | */ | 258 | * @param mixed what The value to check |
287 | function isUndefined(value) { | 259 | * @param String typeName The type name ("string", "number", "function", etc.) |
288 | "use strict"; | 260 | * @return Boolean |
289 | return isType(value, "undefined"); | 261 | */ |
290 | } | 262 | function isType(what, typeName) { |
291 | exports.isUndefined = isUndefined; | 263 | if (typeof typeName !== "string" || !typeName) { |
264 | throw new CasperError("You must pass isType() a typeName string"); | ||
265 | } | ||
266 | return betterTypeOf(what).toLowerCase() === typeName.toLowerCase(); | ||
267 | } | ||
268 | exports.isType = isType; | ||
292 | 269 | ||
293 | /** | 270 | /** |
294 | * Checks if the provided var is a WebPage instance | 271 | * Checks if the provided value is undefined |
295 | * | 272 | * |
296 | * @param mixed what | 273 | * @return Boolean |
297 | * @return Boolean | 274 | */ |
298 | */ | 275 | function isUndefined(value) { |
299 | function isWebPage(what) { | 276 | return isType(value, "undefined"); |
300 | "use strict"; | ||
301 | if (!what || !isObject(what)) { | ||
302 | return false; | ||
303 | } | 277 | } |
304 | return what.toString().indexOf('WebPage(') === 0; | 278 | exports.isUndefined = isUndefined; |
305 | } | ||
306 | exports.isWebPage = isWebPage; | ||
307 | 279 | ||
308 | /** | 280 | /** |
309 | * Object recursive merging utility. | 281 | * Checks if the provided var is a WebPage instance |
310 | * | 282 | * |
311 | * @param Object origin the origin object | 283 | * @param mixed what |
312 | * @param Object add the object to merge data into origin | 284 | * @return Boolean |
313 | * @return Object | 285 | */ |
314 | */ | 286 | function isWebPage(what) { |
315 | function mergeObjects(origin, add) { | 287 | return betterTypeOf(what) === "qtruntimeobject" && what.objectName === 'WebPage'; |
316 | "use strict"; | 288 | } |
317 | for (var p in add) { | 289 | exports.isWebPage = isWebPage; |
318 | try { | 290 | |
319 | if (add[p].constructor === Object) { | 291 | /** |
320 | origin[p] = mergeObjects(origin[p], add[p]); | 292 | * Object recursive merging utility. |
321 | } else { | 293 | * |
322 | origin[p] = add[p]; | 294 | * @param Object origin the origin object |
295 | * @param Object add the object to merge data into origin | ||
296 | * @return Object | ||
297 | */ | ||
298 | function mergeObjects(origin, add) { | ||
299 | for (var p in add) { | ||
300 | try { | ||
301 | if (add[p].constructor === Object) { | ||
302 | origin[p] = mergeObjects(origin[p], add[p]); | ||
303 | } else { | ||
304 | origin[p] = add[p]; | ||
305 | } | ||
306 | } catch(e) { | ||
307 | origin[p] = add[p]; | ||
323 | } | 308 | } |
324 | } catch(e) { | ||
325 | origin[p] = add[p]; | ||
326 | } | 309 | } |
310 | return origin; | ||
327 | } | 311 | } |
328 | return origin; | 312 | exports.mergeObjects = mergeObjects; |
329 | } | ||
330 | exports.mergeObjects = mergeObjects; | ||
331 | 313 | ||
332 | /** | 314 | /** |
333 | * Creates an (SG|X)ML node element. | 315 | * Creates an (SG|X)ML node element. |
334 | * | 316 | * |
335 | * @param String name The node name | 317 | * @param String name The node name |
336 | * @param Object attributes Optional attributes | 318 | * @param Object attributes Optional attributes |
337 | * @return HTMLElement | 319 | * @return HTMLElement |
338 | */ | 320 | */ |
339 | function node(name, attributes) { | 321 | function node(name, attributes) { |
340 | "use strict"; | 322 | var _node = document.createElement(name); |
341 | var _node = document.createElement(name); | 323 | for (var attrName in attributes) { |
342 | for (var attrName in attributes) { | 324 | var value = attributes[attrName]; |
343 | var value = attributes[attrName]; | 325 | if (attributes.hasOwnProperty(attrName) && isString(attrName)) { |
344 | if (attributes.hasOwnProperty(attrName) && isString(attrName)) { | 326 | _node.setAttribute(attrName, value); |
345 | _node.setAttribute(attrName, value); | 327 | } |
346 | } | 328 | } |
329 | return _node; | ||
347 | } | 330 | } |
348 | return _node; | 331 | exports.node = node; |
349 | } | ||
350 | exports.node = node; | ||
351 | 332 | ||
352 | /** | 333 | /** |
353 | * Serializes a value using JSON. | 334 | * Serializes a value using JSON. |
354 | * | 335 | * |
355 | * @param Mixed value | 336 | * @param Mixed value |
356 | * @return String | 337 | * @return String |
357 | */ | 338 | */ |
358 | function serialize(value) { | 339 | function serialize(value) { |
359 | "use strict"; | 340 | if (isArray(value)) { |
360 | if (isArray(value)) { | 341 | value = value.map(function _map(prop) { |
361 | value = value.map(function _map(prop) { | 342 | return isFunction(prop) ? prop.toString().replace(/\s{2,}/, '') : prop; |
362 | return isFunction(prop) ? prop.toString().replace(/\s{2,}/, '') : prop; | 343 | }); |
363 | }); | 344 | } |
345 | return JSON.stringify(value, null, 4); | ||
364 | } | 346 | } |
365 | return JSON.stringify(value, null, 4); | 347 | exports.serialize = serialize; |
366 | } | ||
367 | exports.serialize = serialize; | ||
368 | 348 | ||
369 | /** | 349 | /** |
370 | * Returns unique values from an array. | 350 | * Returns unique values from an array. |
371 | * | 351 | * |
372 | * Note: ugly code is ugly, but efficient: http://jsperf.com/array-unique2/8 | 352 | * Note: ugly code is ugly, but efficient: http://jsperf.com/array-unique2/8 |
373 | * | 353 | * |
374 | * @param Array array | 354 | * @param Array array |
375 | * @return Array | 355 | * @return Array |
376 | */ | 356 | */ |
377 | function unique(array) { | 357 | function unique(array) { |
378 | "use strict"; | 358 | var o = {}, |
379 | var o = {}, | 359 | r = []; |
380 | r = []; | 360 | for (var i = 0, len = array.length; i !== len; i++) { |
381 | for (var i = 0, len = array.length; i !== len; i++) { | 361 | var d = array[i]; |
382 | var d = array[i]; | 362 | if (o[d] !== 1) { |
383 | if (o[d] !== 1) { | 363 | o[d] = 1; |
384 | o[d] = 1; | 364 | r[r.length] = d; |
385 | r[r.length] = d; | 365 | } |
386 | } | 366 | } |
367 | return r; | ||
387 | } | 368 | } |
388 | return r; | 369 | exports.unique = unique; |
389 | } | 370 | })(exports); |
390 | exports.unique = unique; | ... | ... |
... | @@ -29,6 +29,13 @@ t.comment('fillBlanks()'); | ... | @@ -29,6 +29,13 @@ t.comment('fillBlanks()'); |
29 | } | 29 | } |
30 | })(); | 30 | })(); |
31 | 31 | ||
32 | t.comment('isArray()'); | ||
33 | (function() { | ||
34 | t.assertEquals(utils.isArray([]), true, 'isArray() checks for an Array'); | ||
35 | t.assertEquals(utils.isArray({}), false, 'isArray() checks for an Array'); | ||
36 | t.assertEquals(utils.isArray("foo"), false, 'isArray() checks for an Array'); | ||
37 | })(); | ||
38 | |||
32 | t.comment('isClipRect()'); | 39 | t.comment('isClipRect()'); |
33 | (function() { | 40 | (function() { |
34 | testCases = [ | 41 | testCases = [ |
... | @@ -44,6 +51,26 @@ t.comment('isClipRect()'); | ... | @@ -44,6 +51,26 @@ t.comment('isClipRect()'); |
44 | }); | 51 | }); |
45 | })(); | 52 | })(); |
46 | 53 | ||
54 | t.comment('isObject()'); | ||
55 | (function() { | ||
56 | t.assertEquals(utils.isObject({}), true, 'isObject() checks for an Object'); | ||
57 | t.assertEquals(utils.isObject([]), true, 'isObject() checks for an Object'); | ||
58 | t.assertEquals(utils.isObject(1), false, 'isObject() checks for an Object'); | ||
59 | t.assertEquals(utils.isObject("1"), false, 'isObject() checks for an Object'); | ||
60 | t.assertEquals(utils.isObject(function(){}), false, 'isObject() checks for an Object'); | ||
61 | t.assertEquals(utils.isObject(new Function('return {};')()), true, 'isObject() checks for an Object'); | ||
62 | t.assertEquals(utils.isObject(require('webpage').create()), true, 'isObject() checks for an Object'); | ||
63 | t.assertEquals(utils.isObject(null), false, 'isObject() checks for an Object'); | ||
64 | })(); | ||
65 | |||
66 | t.comment('isWebPage()'); | ||
67 | (function() { | ||
68 | var pageModule = require('webpage'); | ||
69 | t.assertEquals(utils.isWebPage(pageModule), false, 'isWebPage() checks for a WebPage instance'); | ||
70 | t.assertEquals(utils.isWebPage(pageModule.create()), true, 'isWebPage() checks for a WebPage instance'); | ||
71 | t.assertEquals(utils.isWebPage(null), false, 'isWebPage() checks for a WebPage instance'); | ||
72 | })(); | ||
73 | |||
47 | t.comment('isJsFile()'); | 74 | t.comment('isJsFile()'); |
48 | (function() { | 75 | (function() { |
49 | testCases = { | 76 | testCases = { | ... | ... |
-
Please register or sign in to post a comment