Commit 80669cda 80669cdab302946f8300af5d28c8719b3d0719d1 by Nicolas Perriault

added Casper#getCurrentUrl() & onLoadError callback option + tests

1 parent f8160f0d
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
33 * logLevel | String | "error" | Logging level (see logLevels for available values) 33 * logLevel | String | "error" | Logging level (see logLevels for available values)
34 * onDie | function | null | A function to be called when Casper#die() is called 34 * onDie | function | null | A function to be called when Casper#die() is called
35 * onError | function | null | A function to be called when an "error" level event occurs 35 * onError | function | null | A function to be called when an "error" level event occurs
36 * onLoadError | function | null | A function to be called when a requested resource cannot be loaded
36 * onPageInitialized | function | null | A function to be called after WebPage instance has been initialized 37 * onPageInitialized | function | null | A function to be called after WebPage instance has been initialized
37 * page | WebPage | null | An existing WebPage instance 38 * page | WebPage | null | An existing WebPage instance
38 * pageSettings | Object | {} | PhantomJS's WebPage settings object 39 * pageSettings | Object | {} | PhantomJS's WebPage settings object
...@@ -56,6 +57,7 @@ ...@@ -56,6 +57,7 @@
56 logLevel: "error", 57 logLevel: "error",
57 onDie: null, 58 onDie: null,
58 onError: null, 59 onError: null,
60 onLoadError: null,
59 onPageInitialized: null, 61 onPageInitialized: null,
60 page: null, 62 page: null,
61 pageSettings: { userAgent: DEFAULT_USER_AGENT }, 63 pageSettings: { userAgent: DEFAULT_USER_AGENT },
...@@ -64,6 +66,7 @@ ...@@ -64,6 +66,7 @@
64 }; 66 };
65 // local properties 67 // local properties
66 this.checker = null; 68 this.checker = null;
69 this.currentUrl = 'about:blank';
67 this.currentHTTPStatus = 200; 70 this.currentHTTPStatus = 200;
68 this.loadInProgress = false; 71 this.loadInProgress = false;
69 this.logLevels = ["debug", "info", "warning", "error"]; 72 this.logLevels = ["debug", "info", "warning", "error"];
...@@ -358,6 +361,17 @@ ...@@ -358,6 +361,17 @@
358 }, 361 },
359 362
360 /** 363 /**
364 * Retrieve current document url.
365 *
366 * @return String
367 */
368 getCurrentUrl: function() {
369 return decodeURIComponent(this.evaluate(function() {
370 return document.location.href;
371 }));
372 },
373
374 /**
361 * Logs a message. 375 * Logs a message.
362 * 376 *
363 * @param String message The message to log 377 * @param String message The message to log
...@@ -568,14 +582,8 @@ ...@@ -568,14 +582,8 @@
568 * @return Boolean 582 * @return Boolean
569 */ 583 */
570 this.click = function(selector) { 584 this.click = function(selector) {
571 try {
572 var elem = document.querySelector(selector); 585 var elem = document.querySelector(selector);
573 } catch (e) {
574 console.log('invalid selector: ' + selector);
575 return false;
576 }
577 if (!elem) { 586 if (!elem) {
578 console.log('selector "' + selector + '" did not find any matching element');
579 return false; 587 return false;
580 } 588 }
581 var evt = document.createEvent("MouseEvents"); 589 var evt = document.createEvent("MouseEvents");
...@@ -694,6 +702,34 @@ ...@@ -694,6 +702,34 @@
694 }; 702 };
695 703
696 /** 704 /**
705 * Finds all DOM elements matching by the provided selector.
706 *
707 * @param String selector CSS3 selector
708 * @return NodeList|undefined
709 */
710 this.findAll = function(selector) {
711 try {
712 return document.querySelectorAll(selector);
713 } catch (e) {
714 console.log('findAll(): invalid selector provided "' + selector + '":' + e);
715 }
716 };
717
718 /**
719 * Finds a DOM element by the provided selector.
720 *
721 * @param String selector CSS3 selector
722 * @return HTMLElement|undefined
723 */
724 this.findOne = function(selector) {
725 try {
726 return document.querySelector(selector);
727 } catch (e) {
728 console.log('findOne(): invalid selector provided "' + selector + '":' + e);
729 }
730 };
731
732 /**
697 * Downloads a resource behind an url and returns its base64-encoded 733 * Downloads a resource behind an url and returns its base64-encoded
698 * contents. 734 * contents.
699 * 735 *
...@@ -822,6 +858,9 @@ ...@@ -822,6 +858,9 @@
822 } 858 }
823 message += ': ' + casper.requestUrl; 859 message += ': ' + casper.requestUrl;
824 casper.log(message, "warning"); 860 casper.log(message, "warning");
861 if (typeof(casper.options.onLoadError) === "function") {
862 casper.options.onLoadError(casper, casper.requestUrl, status);
863 }
825 } 864 }
826 if (casper.options.clientScripts) { 865 if (casper.options.clientScripts) {
827 for (var i = 0; i < casper.options.clientScripts.length; i++) { 866 for (var i = 0; i < casper.options.clientScripts.length; i++) {
...@@ -842,15 +881,16 @@ ...@@ -842,15 +881,16 @@
842 utils: encodeURIComponent(phantom.Casper.ClientUtils.toString()) 881 utils: encodeURIComponent(phantom.Casper.ClientUtils.toString())
843 })); 882 }));
844 if (!injected) { 883 if (!injected) {
845 casper.log('Failed to inject Casper client-side utilities!', "warning"); 884 casper.log("Failed to inject Casper client-side utilities!", "warning");
846 } else { 885 } else {
847 casper.log('Successfully injected Casper client-side utilities', "debug"); 886 casper.log("Successfully injected Casper client-side utilities", "debug");
848 } 887 }
849 casper.loadInProgress = false; 888 casper.loadInProgress = false;
850 }; 889 };
851 page.onResourceReceived = function(resource) { 890 page.onResourceReceived = function(resource) {
852 if (resource.url === casper.requestUrl) { 891 if (resource.url === casper.requestUrl) {
853 casper.currentHTTPStatus = resource.status; 892 casper.currentHTTPStatus = resource.status;
893 casper.currentUrl = resource.url;
854 } 894 }
855 }; 895 };
856 return page; 896 return page;
......
...@@ -35,6 +35,20 @@ phantom.Casper.extend({ ...@@ -35,6 +35,20 @@ phantom.Casper.extend({
35 return this.assertEquals(this.evaluate(fn), expected, message); 35 return this.assertEquals(this.evaluate(fn), expected, message);
36 }, 36 },
37 37
38 assertMatch: function(subject, pattern, message) {
39 return this.assert(pattern.test(subject), message);
40 },
41
42 assertTitle: function(expected, message) {
43 return this.assertEvalEquals(function() {
44 return document.title;
45 }, expected, message);
46 },
47
48 assertUrlMatch: function(pattern, message) {
49 return this.assertMatch(this.getCurrentUrl(), pattern, message);
50 },
51
38 renderResults: function() { 52 renderResults: function() {
39 this.echo("=========================================="); 53 this.echo("==========================================");
40 var total = testResults.passed + testResults.failed, 54 var total = testResults.passed + testResults.failed,
......
...@@ -26,9 +26,7 @@ casper.options.verbose = true; ...@@ -26,9 +26,7 @@ casper.options.verbose = true;
26 26
27 // Casper#start() 27 // Casper#start()
28 casper.start('tests/site/index.html', function(self) { 28 casper.start('tests/site/index.html', function(self) {
29 self.assertEvalEquals(function() { 29 self.assertTitle('CasperJS test index', 'start() casper can start itself an open an url');
30 return document.title;
31 }, 'CasperJS test index', 'start() casper can start itself an open an url');
32 self.assertEval(function() { 30 self.assertEval(function() {
33 return typeof(__utils__) === "object"; 31 return typeof(__utils__) === "object";
34 }, 'start() injects ClientUtils instance within remote DOM'); 32 }, 'start() injects ClientUtils instance within remote DOM');
...@@ -41,9 +39,7 @@ casper.assert(casper.steps.length === 1, 'start() can add a new navigation step' ...@@ -41,9 +39,7 @@ casper.assert(casper.steps.length === 1, 'start() can add a new navigation step'
41 39
42 // Casper#then() 40 // Casper#then()
43 casper.then(function(self) { 41 casper.then(function(self) {
44 self.assertEvalEquals(function() { 42 self.assertTitle('CasperJS test target', 'click() casper can click on a text link and react when it is loaded 1/2');
45 return document.title;
46 }, 'CasperJS test target', 'click() casper can click on a text link and react when it is loaded 1/2');
47 self.click('a[href="form.html"]'); 43 self.click('a[href="form.html"]');
48 }); 44 });
49 45
...@@ -51,14 +47,13 @@ casper.assert(casper.steps.length === 2, 'then() adds a new navigation step'); ...@@ -51,14 +47,13 @@ casper.assert(casper.steps.length === 2, 'then() adds a new navigation step');
51 47
52 // Casper#fill() 48 // Casper#fill()
53 casper.then(function(self) { 49 casper.then(function(self) {
54 self.assertEvalEquals(function() { 50 self.assertTitle('CasperJS test form', 'click() casper can click on a text link and react when it is loaded 2/2');
55 return document.title; 51 self.fill('form[action="result.html"]', {
56 }, 'CasperJS test form', 'click() casper can click on a text link and react when it is loaded 2/2');
57 self.fill('form[action="form.html"]', {
58 email: 'chuck@norris.com', 52 email: 'chuck@norris.com',
59 content: 'Am watching thou', 53 content: 'Am watching thou',
60 check: true, 54 check: true,
61 choice: 'no', 55 choice: 'no',
56 topic: 'bar',
62 file: phantom.libraryPath + '/README.md' 57 file: phantom.libraryPath + '/README.md'
63 }); 58 });
64 self.assertEvalEquals(function() { 59 self.assertEvalEquals(function() {
...@@ -68,6 +63,9 @@ casper.then(function(self) { ...@@ -68,6 +63,9 @@ casper.then(function(self) {
68 return document.querySelector('textarea[name="content"]').value; 63 return document.querySelector('textarea[name="content"]').value;
69 }, 'Am watching thou', 'fill() can fill a textarea form field'); 64 }, 'Am watching thou', 'fill() can fill a textarea form field');
70 self.assertEvalEquals(function() { 65 self.assertEvalEquals(function() {
66 return document.querySelector('select[name="topic"]').value;
67 }, 'bar', 'fill() can pick a value from a select form field');
68 self.assertEvalEquals(function() {
71 return document.querySelector('input[name="check"]').checked; 69 return document.querySelector('input[name="check"]').checked;
72 }, true, 'fill() can check a form checkbox'); 70 }, true, 'fill() can check a form checkbox');
73 self.assertEvalEquals(function() { 71 self.assertEvalEquals(function() {
...@@ -79,9 +77,17 @@ casper.then(function(self) { ...@@ -79,9 +77,17 @@ casper.then(function(self) {
79 self.assertEvalEquals(function() { 77 self.assertEvalEquals(function() {
80 return document.querySelector('input[name="file"]').files.length === 1; 78 return document.querySelector('input[name="file"]').files.length === 1;
81 }, true, 'fill() can select a file to upload'); 79 }, true, 'fill() can select a file to upload');
82 self.evaluate(function() { 80 self.click('input[type="submit"]');
83 document.querySelector('form[action="form.html"]').submit(); 81 });
84 }) 82
83 // Casper#click()
84 casper.then(function(self) {
85 self.assertTitle('CasperJS test form result', 'click() casper can click on a submit button');
86 self.assertUrlMatch(/email=chuck@norris.com/, 'fill() input[type=email] field was submitted');
87 self.assertUrlMatch(/content=Am\+watching\+thou/, 'fill() textarea field was submitted');
88 self.assertUrlMatch(/check=on/, 'fill() input[type=checkbox] field was submitted');
89 self.assertUrlMatch(/choice=no/, 'fill() input[type=radio] field was submitted');
90 self.assertUrlMatch(/topic=bar/, 'fill() select field was submitted');
85 }); 91 });
86 92
87 casper.run(function(self) { 93 casper.run(function(self) {
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
5 <title>CasperJS test form</title> 5 <title>CasperJS test form</title>
6 </head> 6 </head>
7 <body> 7 <body>
8 <form action="form.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 <textarea name="content"></textarea> 10 <textarea name="content"></textarea>
11 <select name="topic"> 11 <select name="topic">
......