Commit 55103a57 55103a57e0560d4687d049ec38701be1f02e6d41 by Nicolas Perriault

fixes #148 - broken utils.isWebPage()

1 parent 0245dcfb
...@@ -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
......
1 Subproject commit ed91017f48fd77e8c3a268ecdbb78adac7bce0b5 1 Subproject commit 76cc32f262a3ef924a67f33bb17432e3a5c33e03
......
...@@ -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 = {
......