added a 'safeLogs' option to blur password value in debug logs
Showing
4 changed files
with
40 additions
and
23 deletions
... | @@ -80,6 +80,7 @@ var Casper = function Casper(options) { | ... | @@ -80,6 +80,7 @@ var Casper = function Casper(options) { |
80 | exitOnError: true, | 80 | exitOnError: true, |
81 | logLevel: "error", | 81 | logLevel: "error", |
82 | httpStatusHandlers: {}, | 82 | httpStatusHandlers: {}, |
83 | safeLogs: true, | ||
83 | onAlert: null, | 84 | onAlert: null, |
84 | onDie: null, | 85 | onDie: null, |
85 | onError: null, | 86 | onError: null, |
... | @@ -385,7 +386,7 @@ Casper.prototype.die = function die(message, status) { | ... | @@ -385,7 +386,7 @@ Casper.prototype.die = function die(message, status) { |
385 | * @return Casper | 386 | * @return Casper |
386 | */ | 387 | */ |
387 | Casper.prototype.download = function download(url, targetPath, method, data) { | 388 | Casper.prototype.download = function download(url, targetPath, method, data) { |
388 | var cu = require('clientutils').create(); | 389 | var cu = require('clientutils').create(this.options); |
389 | try { | 390 | try { |
390 | fs.write(targetPath, cu.decode(this.base64encode(url, method, data)), 'wb'); | 391 | fs.write(targetPath, cu.decode(this.base64encode(url, method, data)), 'wb'); |
391 | this.emit('downloaded.file', targetPath); | 392 | this.emit('downloaded.file', targetPath); |
... | @@ -700,8 +701,13 @@ Casper.prototype.injectClientUtils = function injectClientUtils() { | ... | @@ -700,8 +701,13 @@ Casper.prototype.injectClientUtils = function injectClientUtils() { |
700 | if (true === this.page.injectJs(clientUtilsPath)) { | 701 | if (true === this.page.injectJs(clientUtilsPath)) { |
701 | this.log("Successfully injected Casper client-side utilities", "debug"); | 702 | this.log("Successfully injected Casper client-side utilities", "debug"); |
702 | } else { | 703 | } else { |
703 | this.log("Failed to instantiate Casper client-side utilities!", "warning"); | 704 | this.warn("Failed to inject Casper client-side utilities"); |
704 | } | 705 | } |
706 | // ClientUtils and Casper shares the same options | ||
707 | // These are not the lines I'm the most proud of in my life, but it works. | ||
708 | this.page.evaluate(function() { | ||
709 | __utils__ = new ClientUtils(__options); | ||
710 | }.toString().replace('__options', JSON.stringify(this.options))); | ||
705 | }; | 711 | }; |
706 | 712 | ||
707 | /** | 713 | /** | ... | ... |
... | @@ -28,14 +28,15 @@ | ... | @@ -28,14 +28,15 @@ |
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | (function(exports) { | 30 | (function(exports) { |
31 | exports.create = function create() { | 31 | exports.create = function create(options) { |
32 | return new this.ClientUtils(); | 32 | return new this.ClientUtils(options); |
33 | }; | 33 | }; |
34 | 34 | ||
35 | /** | 35 | /** |
36 | * Casper client-side helpers. | 36 | * Casper client-side helpers. |
37 | */ | 37 | */ |
38 | exports.ClientUtils = function ClientUtils() { | 38 | exports.ClientUtils = function ClientUtils(options) { |
39 | // private members | ||
39 | var BASE64_ENCODE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | 40 | var BASE64_ENCODE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
40 | var BASE64_DECODE_CHARS = new Array( | 41 | var BASE64_DECODE_CHARS = new Array( |
41 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | 42 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
... | @@ -49,6 +50,9 @@ | ... | @@ -49,6 +50,9 @@ |
49 | ); | 50 | ); |
50 | var SUPPORTED_SELECTOR_TYPES = ['css', 'xpath']; | 51 | var SUPPORTED_SELECTOR_TYPES = ['css', 'xpath']; |
51 | 52 | ||
53 | // public members | ||
54 | this.options = options || {}; | ||
55 | |||
52 | /** | 56 | /** |
53 | * Clicks on the DOM element behind the provided selector. | 57 | * Clicks on the DOM element behind the provided selector. |
54 | * | 58 | * |
... | @@ -185,7 +189,7 @@ | ... | @@ -185,7 +189,7 @@ |
185 | files: [] | 189 | files: [] |
186 | }; | 190 | }; |
187 | if (!(form instanceof HTMLElement) || typeof form === "string") { | 191 | if (!(form instanceof HTMLElement) || typeof form === "string") { |
188 | __utils__.log("attempting to fetch form element from selector: '" + form + "'", "info"); | 192 | this.log("attempting to fetch form element from selector: '" + form + "'", "info"); |
189 | try { | 193 | try { |
190 | form = this.findOne(form); | 194 | form = this.findOne(form); |
191 | } catch (e) { | 195 | } catch (e) { |
... | @@ -463,7 +467,7 @@ | ... | @@ -463,7 +467,7 @@ |
463 | */ | 467 | */ |
464 | this.setField = function setField(field, value) { | 468 | this.setField = function setField(field, value) { |
465 | var fields, out; | 469 | var fields, out; |
466 | value = value || ""; | 470 | value = logValue = (value || ""); |
467 | if (field instanceof NodeList) { | 471 | if (field instanceof NodeList) { |
468 | fields = field; | 472 | fields = field; |
469 | field = fields[0]; | 473 | field = fields[0]; |
... | @@ -471,11 +475,15 @@ | ... | @@ -471,11 +475,15 @@ |
471 | if (!field instanceof HTMLElement) { | 475 | if (!field instanceof HTMLElement) { |
472 | this.log("Invalid field type; only HTMLElement and NodeList are supported", "error"); | 476 | this.log("Invalid field type; only HTMLElement and NodeList are supported", "error"); |
473 | } | 477 | } |
474 | this.log('Set "' + field.getAttribute('name') + '" field value to ' + value, "debug"); | 478 | if (this.options && this.options.safeLogs && field.getAttribute('type') === "password") { |
479 | // obfuscate password value | ||
480 | logValue = Array(value.length + 1).join("*"); | ||
481 | } | ||
482 | this.log('Set "' + field.getAttribute('name') + '" field value to ' + logValue, "debug"); | ||
475 | try { | 483 | try { |
476 | field.focus(); | 484 | field.focus(); |
477 | } catch (e) { | 485 | } catch (e) { |
478 | __utils__.log("Unable to focus() input field " + field.getAttribute('name') + ": " + e, "warning"); | 486 | this.log("Unable to focus() input field " + field.getAttribute('name') + ": " + e, "warning"); |
479 | } | 487 | } |
480 | var nodeName = field.nodeName.toLowerCase(); | 488 | var nodeName = field.nodeName.toLowerCase(); |
481 | switch (nodeName) { | 489 | switch (nodeName) { |
... | @@ -544,7 +552,7 @@ | ... | @@ -544,7 +552,7 @@ |
544 | try { | 552 | try { |
545 | field.blur(); | 553 | field.blur(); |
546 | } catch (err) { | 554 | } catch (err) { |
547 | __utils__.log("Unable to blur() input field " + field.getAttribute('name') + ": " + err, "warning"); | 555 | this.log("Unable to blur() input field " + field.getAttribute('name') + ": " + err, "warning"); |
548 | } | 556 | } |
549 | return out; | 557 | return out; |
550 | }; | 558 | }; |
... | @@ -570,7 +578,4 @@ | ... | @@ -570,7 +578,4 @@ |
570 | } | 578 | } |
571 | }; | 579 | }; |
572 | }; | 580 | }; |
573 | |||
574 | // silly "hack" to force having an instance available | ||
575 | exports.__utils__ = new exports.ClientUtils(); | ||
576 | })(typeof exports === "object" ? exports : window); | 581 | })(typeof exports === "object" ? exports : window); | ... | ... |
1 | <!DOCTYPE html> | 1 | <!DOCTYPE html> |
2 | <html> | 2 | <html> |
3 | <head> | 3 | <head> |
4 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | 4 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> |
5 | <title>CasperJS test form</title> | 5 | <title>CasperJS test form</title> |
6 | </head> | 6 | </head> |
7 | <body> | 7 | <body> |
8 | <form action="result.html" enctype="multipart/form-data"> | 8 | <form action="result.html" enctype="multipart/form-data"> |
9 | <input type="text" name="email" placeholder="email" /> | 9 | <input type="text" name="email" placeholder="email"> |
10 | <input type="password" name="password" placeholder="password"> | ||
10 | <textarea name="content"></textarea> | 11 | <textarea name="content"></textarea> |
11 | <select name="topic"> | 12 | <select name="topic"> |
12 | <option>foo</option> | 13 | <option>foo</option> |
13 | <option value="bar">baz</option> | 14 | <option value="bar">baz</option> |
14 | </select> | 15 | </select> |
15 | <input type="checkbox" name="check" /> | 16 | <input type="checkbox" name="check"> |
16 | <input type="radio" name="choice" value="yes"/> | 17 | <input type="radio" name="choice" value="yes"> |
17 | <input type="radio" name="choice" value="no"/> | 18 | <input type="radio" name="choice" value="no"> |
18 | <input type="file" name="file"/> | 19 | <input type="file" name="file"> |
19 | <input type="checkbox" name="checklist[]" value="1" /> | 20 | <input type="checkbox" name="checklist[]" value="1"> |
20 | <input type="checkbox" name="checklist[]" value="2" /> | 21 | <input type="checkbox" name="checklist[]" value="2"> |
21 | <input type="checkbox" name="checklist[]" value="3" /> | 22 | <input type="checkbox" name="checklist[]" value="3"> |
22 | <input type="submit" name="submit" value="submit" /> | 23 | <input type="submit" name="submit" value="submit"> |
23 | </form> | 24 | </form> |
24 | </body> | 25 | </body> |
25 | </html> | 26 | </html> | ... | ... |
... | @@ -2,6 +2,7 @@ casper.start('tests/site/form.html', function() { | ... | @@ -2,6 +2,7 @@ casper.start('tests/site/form.html', function() { |
2 | this.test.comment('Casper.fill()'); | 2 | this.test.comment('Casper.fill()'); |
3 | this.fill('form[action="result.html"]', { | 3 | this.fill('form[action="result.html"]', { |
4 | email: 'chuck@norris.com', | 4 | email: 'chuck@norris.com', |
5 | password: 'chuck', | ||
5 | content: 'Am watching thou', | 6 | content: 'Am watching thou', |
6 | check: true, | 7 | check: true, |
7 | choice: 'no', | 8 | choice: 'no', |
... | @@ -13,6 +14,9 @@ casper.start('tests/site/form.html', function() { | ... | @@ -13,6 +14,9 @@ casper.start('tests/site/form.html', function() { |
13 | return document.querySelector('input[name="email"]').value; | 14 | return document.querySelector('input[name="email"]').value; |
14 | }, 'chuck@norris.com', 'Casper.fill() can fill an input[type=text] form field'); | 15 | }, 'chuck@norris.com', 'Casper.fill() can fill an input[type=text] form field'); |
15 | this.test.assertEvalEquals(function() { | 16 | this.test.assertEvalEquals(function() { |
17 | return document.querySelector('input[name="password"]').value; | ||
18 | }, 'chuck', 'Casper.fill() can fill an input[type=password] form field'); | ||
19 | this.test.assertEvalEquals(function() { | ||
16 | return document.querySelector('textarea[name="content"]').value; | 20 | return document.querySelector('textarea[name="content"]').value; |
17 | }, 'Am watching thou', 'Casper.fill() can fill a textarea form field'); | 21 | }, 'Am watching thou', 'Casper.fill() can fill a textarea form field'); |
18 | this.test.assertEvalEquals(function() { | 22 | this.test.assertEvalEquals(function() { |
... | @@ -41,6 +45,7 @@ casper.start('tests/site/form.html', function() { | ... | @@ -41,6 +45,7 @@ casper.start('tests/site/form.html', function() { |
41 | casper.then(function() { | 45 | casper.then(function() { |
42 | this.test.comment('Form submitted'); | 46 | this.test.comment('Form submitted'); |
43 | this.test.assertUrlMatch(/email=chuck@norris.com/, 'Casper.fill() input[type=email] field was submitted'); | 47 | this.test.assertUrlMatch(/email=chuck@norris.com/, 'Casper.fill() input[type=email] field was submitted'); |
48 | this.test.assertUrlMatch(/password=chuck/, 'Casper.fill() input[type=password] field was submitted'); | ||
44 | this.test.assertUrlMatch(/content=Am\+watching\+thou/, 'Casper.fill() textarea field was submitted'); | 49 | this.test.assertUrlMatch(/content=Am\+watching\+thou/, 'Casper.fill() textarea field was submitted'); |
45 | this.test.assertUrlMatch(/check=on/, 'Casper.fill() input[type=checkbox] field was submitted'); | 50 | this.test.assertUrlMatch(/check=on/, 'Casper.fill() input[type=checkbox] field was submitted'); |
46 | this.test.assertUrlMatch(/choice=no/, 'Casper.fill() input[type=radio] field was submitted'); | 51 | this.test.assertUrlMatch(/choice=no/, 'Casper.fill() input[type=radio] field was submitted'); | ... | ... |
-
Please register or sign in to post a comment