Commit 9697410d 9697410dde3e5797591ee0593fed82d2b46cf370 by Nicolas Perriault

closes #150 - added Casper.captureBase64()

1 parent 86b650c0
...@@ -17,6 +17,7 @@ XXXX-XX-XX, v1.0 ...@@ -17,6 +17,7 @@ XXXX-XX-XX, v1.0
17 - added [`Casper.userAgent()`](http://casperjs.org/api.html#casper.userAgent) to ease a more dynamic setting of user-agent string 17 - added [`Casper.userAgent()`](http://casperjs.org/api.html#casper.userAgent) to ease a more dynamic setting of user-agent string
18 - added [`Tester.assertTitleMatch()`](http://casperjs.org/api.html#tester.assertTitleMatch) method 18 - added [`Tester.assertTitleMatch()`](http://casperjs.org/api.html#tester.assertTitleMatch) method
19 - added [`utils.getPropertyPath()`](http://casperjs.org/api.html#utils.getPropertyPath) 19 - added [`utils.getPropertyPath()`](http://casperjs.org/api.html#utils.getPropertyPath)
20 - added [`Casper.captureBase64()`](http://casperjs.org/api.html#casper.captureBase64) for rendering screen captures as base64 strings - closes [#150](https://github.com/n1k0/casperjs/issues/150)
20 - added [`Casper.reload()`](http://casperjs.org/api.html#casper.reload) 21 - added [`Casper.reload()`](http://casperjs.org/api.html#casper.reload)
21 - added experimental support of custom headers sending in outgoing request (refs [#137](https://github.com/n1k0/casperjs/issues/137) - PhantomJS 1.6 required) 22 - added experimental support of custom headers sending in outgoing request (refs [#137](https://github.com/n1k0/casperjs/issues/137) - PhantomJS 1.6 required)
22 - switched to more standard `.textContent` property to get a node text; this allows a better compatibility of the clientutils bookmarklet with non-webkit browsers 23 - switched to more standard `.textContent` property to get a node text; this allows a better compatibility of the clientutils bookmarklet with non-webkit browsers
......
...@@ -246,7 +246,47 @@ Casper.prototype.capture = function capture(targetFile, clipRect) { ...@@ -246,7 +246,47 @@ Casper.prototype.capture = function capture(targetFile, clipRect) {
246 }; 246 };
247 247
248 /** 248 /**
249 * Captures the page area containing the provided selector. 249 * Returns a Base64 representation of a binary image capture of the current
250 * page, or an area within the page, in a given format.
251 *
252 * Supported image formats are `bmp`, `jpg`, `jpeg`, `png`, `ppm`, `tiff`,
253 * `xbm` and `xpm`.
254 *
255 * @param String format The image format
256 * @param String|Object|undefined selector CSS3 selector or clipRect object (optional)
257 * @return Casper
258 */
259 Casper.prototype.captureBase64 = function captureBase64(format, area) {
260 "use strict";
261 var base64;
262 var previousClipRect;
263 var formats = ['bmp', 'jpg', 'jpeg', 'png', 'ppm', 'tiff', 'xbm', 'xpm'];
264 if (formats.indexOf(format.toLowerCase()) === -1) {
265 throw new CasperError(f('Unsupported format "%s"', format));
266 }
267 if (utils.isClipRect(area)) {
268 // if area is a clipRect object
269 this.log(f("Capturing base64 %s representation of %s", format, utils.serialize(area)), "debug");
270 previousClipRect = this.page.clipRect;
271 this.page.clipRect = area;
272 base64 = this.page.renderBase64(format);
273 } else if (utils.isValidSelector(area)) {
274 // if area is a selector string or object
275 this.log(f("Capturing base64 %s representation of %s", format, area), "debug");
276 base64 = this.captureBase64(format, this.getElementBounds(area));
277 } else {
278 // whole page capture
279 this.log(f("Capturing base64 %s representation of page", format), "debug");
280 base64 = this.page.renderBase64(format);
281 }
282 if (previousClipRect) {
283 this.page.clipRect = previousClipRect;
284 }
285 return base64;
286 };
287
288 /**
289 * Captures the page area matching the provided selector.
250 * 290 *
251 * @param String targetFile Target destination file path. 291 * @param String targetFile Target destination file path.
252 * @param String selector CSS3 selector 292 * @param String selector CSS3 selector
......
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
57 * @param Mixed value 57 * @param Mixed value
58 */ 58 */
59 function dump(value) { 59 function dump(value) {
60 console.log(serialize(value)); 60 console.log(serialize(value, 4));
61 } 61 }
62 exports.dump = dump; 62 exports.dump = dump;
63 63
...@@ -304,6 +304,39 @@ ...@@ -304,6 +304,39 @@
304 exports.isUndefined = isUndefined; 304 exports.isUndefined = isUndefined;
305 305
306 /** 306 /**
307 * Checks if value is a valid selector Object.
308 *
309 * @param mixed value
310 * @return Boolean
311 */
312 function isValidSelector(value) {
313 if (isString(value)) {
314 try {
315 // phantomjs env has a working document object, let's use it
316 document.querySelector(value);
317 } catch(e) {
318 if ('name' in e && e.name === 'SYNTAX_ERR') {
319 return false;
320 }
321 }
322 return true;
323 } else if (isObject(value)) {
324 if (!value.hasOwnProperty('type')) {
325 return false;
326 }
327 if (!value.hasOwnProperty('path')) {
328 return false;
329 }
330 if (['css', 'xpath'].indexOf(value.type) === -1) {
331 return false;
332 }
333 return true;
334 }
335 return false;
336 }
337 exports.isValidSelector = isValidSelector;
338
339 /**
307 * Checks if the provided var is a WebPage instance 340 * Checks if the provided var is a WebPage instance
308 * 341 *
309 * @param mixed what 342 * @param mixed what
...@@ -362,13 +395,13 @@ ...@@ -362,13 +395,13 @@
362 * @param Mixed value 395 * @param Mixed value
363 * @return String 396 * @return String
364 */ 397 */
365 function serialize(value) { 398 function serialize(value, indent) {
366 if (isArray(value)) { 399 if (isArray(value)) {
367 value = value.map(function _map(prop) { 400 value = value.map(function _map(prop) {
368 return isFunction(prop) ? prop.toString().replace(/\s{2,}/, '') : prop; 401 return isFunction(prop) ? prop.toString().replace(/\s{2,}/, '') : prop;
369 }); 402 });
370 } 403 }
371 return JSON.stringify(value, null, 4); 404 return JSON.stringify(value, null, indent);
372 } 405 }
373 exports.serialize = serialize; 406 exports.serialize = serialize;
374 407
......
...@@ -4,17 +4,26 @@ if (fs.exists(testFile) && fs.isFile(testFile)) { ...@@ -4,17 +4,26 @@ if (fs.exists(testFile) && fs.isFile(testFile)) {
4 fs.remove(testFile); 4 fs.remove(testFile);
5 } 5 }
6 6
7 casper.start('tests/site/index.html', function(self) { 7 casper.start('tests/site/index.html', function() {
8 self.viewport(300, 200); 8 this.viewport(300, 200);
9 this.test.comment('Casper.capture()'); 9 this.test.comment('Casper.capture()');
10 self.capture(testFile); 10 this.capture(testFile);
11 this.test.assert(fs.isFile(testFile), 'Casper.capture() captured a screenshot'); 11 this.test.assert(fs.isFile(testFile), 'Casper.capture() captured a screenshot');
12 }); 12 });
13 13
14 try { 14 casper.thenOpen('tests/site/index.html', function() {
15 fs.remove(testFile); 15 this.test.comment('Casper.captureBase64()');
16 } catch(e) {} 16 this.test.assert(this.captureBase64('png').length > 0,
17 'Casper.captureBase64() rendered a page capture as base64');
18 this.test.assert(this.captureBase64('png', 'ul').length > 0,
19 'Casper.captureBase64() rendered a capture from a selector as base64');
20 this.test.assert(this.captureBase64('png', {top: 0, left: 0, width: 30, height: 30}).length > 0,
21 'Casper.captureBase64() rendered a capture from a clipRect as base64');
22 });
17 23
18 casper.run(function(self) { 24 casper.run(function() {
25 try {
26 fs.remove(testFile);
27 } catch(e) {}
19 this.test.done(); 28 this.test.done();
20 }); 29 });
......
1 var utils = require('utils'), t = casper.test; 1 var utils = require('utils'), t = casper.test, x = require('casper').selectXPath;
2 2
3 t.comment('fileExt()'); 3 t.comment('fileExt()');
4 (function() { 4 (function() {
...@@ -100,6 +100,33 @@ t.comment('isObject()'); ...@@ -100,6 +100,33 @@ t.comment('isObject()');
100 t.assertEquals(utils.isObject(null), false, 'isObject() checks for an Object'); 100 t.assertEquals(utils.isObject(null), false, 'isObject() checks for an Object');
101 })(); 101 })();
102 102
103 t.comment('isValidSelector()');
104 (function() {
105 t.assertEquals(utils.isValidSelector({}), false, 'isValidSelector() checks for a valid selector');
106 t.assertEquals(utils.isValidSelector(""), false, 'isValidSelector() checks for a valid selector');
107 t.assertEquals(utils.isValidSelector("a"), true, 'isValidSelector() checks for a valid selector');
108 t.assertEquals(utils.isValidSelector('div#plop form[name="form"] input[type="submit"]'), true, 'isValidSelector() checks for a valid selector');
109 t.assertEquals(utils.isValidSelector(x('//a')), true, 'isValidSelector() checks for a valid selector');
110 t.assertEquals(utils.isValidSelector({
111 type: "css",
112 path: 'div#plop form[name="form"] input[type="submit"]'
113 }), true, 'isValidSelector() checks for a valid selector');
114 t.assertEquals(utils.isValidSelector({
115 type: "xpath",
116 path: '//a'
117 }), true, 'isValidSelector() checks for a valid selector');
118 t.assertEquals(utils.isValidSelector({
119 type: "css"
120 }), false, 'isValidSelector() checks for a valid selector');
121 t.assertEquals(utils.isValidSelector({
122 type: "xpath"
123 }), false, 'isValidSelector() checks for a valid selector');
124 t.assertEquals(utils.isValidSelector({
125 type: "css3",
126 path: "a"
127 }), false, 'isValidSelector() checks for a valid selector');
128 })();
129
103 t.comment('isWebPage()'); 130 t.comment('isWebPage()');
104 (function() { 131 (function() {
105 var pageModule = require('webpage'); 132 var pageModule = require('webpage');
......