Commit 02e4bbf7 02e4bbf7105886dc5efa135be8f34e908dca1f13 by Nicolas Perriault

decoupled form filling strategies from casper object

1 parent e042ce6d
...@@ -114,6 +114,7 @@ Last, all the casper test suites have been upgraded to use the new testing featu ...@@ -114,6 +114,7 @@ Last, all the casper test suites have been upgraded to use the new testing featu
114 - Added [`Casper#eachThen()`](http://docs.casperjs.org/en/latest/modules/casper.html#eachThen) 114 - Added [`Casper#eachThen()`](http://docs.casperjs.org/en/latest/modules/casper.html#eachThen)
115 - merged [#427](https://github.com/n1k0/casperjs/issues/427) - Added `keepFocus` option to `Casper#sendKeys()` 115 - merged [#427](https://github.com/n1k0/casperjs/issues/427) - Added `keepFocus` option to `Casper#sendKeys()`
116 - fixed [#441](https://github.com/n1k0/casperjs/issues/441) - added `--ssl-protocol` option support to the `casperjs` executable 116 - fixed [#441](https://github.com/n1k0/casperjs/issues/441) - added `--ssl-protocol` option support to the `casperjs` executable
117 - Added [`Casper#fillSelectors()`](http://docs.casperjs.org/en/latest/modules/casper.html#fillselectors) and [`Casper#fillXPath()`](http://docs.casperjs.org/en/latest/modules/casper.html#fillxpath)
117 - `cli`: Now dropping an arg or an option will be reflected in their *raw* equivalent 118 - `cli`: Now dropping an arg or an option will be reflected in their *raw* equivalent
118 - `cli.get()` now supports fallback values 119 - `cli.get()` now supports fallback values
119 120
......
...@@ -839,7 +839,10 @@ Logs a message with an optional level in an optional space. Available levels are ...@@ -839,7 +839,10 @@ Logs a message with an optional level in an optional space. Available levels are
839 839
840 **Signature:** ``fill(String selector, Object values[, Boolean submit])`` 840 **Signature:** ``fill(String selector, Object values[, Boolean submit])``
841 841
842 Fills the fields of a form with given values and optionally submits it. 842 Fills the fields of a form with given values and optionally submits it. Fields
843 are referenced by their ``name`` attribute.
844
845 .. versionchanged:: 1.1 To use :doc:`CSS3 or XPath selectors <../selectors>` instead, check the `fillSelectors()`_ and `fillXPath()`_ methods.
843 846
844 Example with this sample html form: 847 Example with this sample html form:
845 848
...@@ -883,9 +886,56 @@ A script to fill and submit this form:: ...@@ -883,9 +886,56 @@ A script to fill and submit this form::
883 886
884 .. warning:: 887 .. warning::
885 888
886 1. The ``fill()`` method currently can't fill **file fields using XPath selectors**; PhantomJS natively only allows the use of CSS3 selectors in its uploadFile method, hence this limitation. 889 1. The ``fill()`` method currently can't fill **file fields using XPath selectors**; PhantomJS natively only allows the use of CSS3 selectors in its ``uploadFile()`` method, hence this limitation.
887 2. Please Don't use CasperJS nor PhantomJS to send spam, or I'll be calling the Chuck. More seriously, please just don't. 890 2. Please Don't use CasperJS nor PhantomJS to send spam, or I'll be calling the Chuck. More seriously, please just don't.
888 891
892 ``fillSelectors()``
893 -------------------------------------------------------------------------------
894
895 **Signature:** ``fillSelectors(String selector, Object values[, Boolean submit])``
896
897 .. versionadded:: 1.1
898
899 Fills form fields with given values and optionally submits it. Fields
900 are referenced by ``CSS3`` selectors::
901
902 casper.start('http://some.tld/contact.form', function() {
903 this.fill('form#contact-form', {
904 'input[name="subject"]': 'I am watching you',
905 'input[name="content"]': 'So be careful.',
906 'input[name="civility"]': 'Mr',
907 'input[name="name"]': 'Chuck Norris',
908 'input[name="email"]': 'chuck@norris.com',
909 'input[name="cc"]': true,
910 'input[name="attachment"]': '/Users/chuck/roundhousekick.doc'
911 }, true);
912 });
913
914
915 ``fillXPath()``
916 -------------------------------------------------------------------------------
917
918 **Signature:** ``fillXPath(String selector, Object values[, Boolean submit])``
919
920 .. versionadded:: 1.1
921
922 Fills form fields with given values and optionally submits it. While the ``form`` element is always referenced by a CSS3 selector, fields are referenced by ``XPath`` selectors::
923
924 casper.start('http://some.tld/contact.form', function() {
925 this.fill('form#contact-form', {
926 '//input[@name="subject"]': 'I am watching you',
927 '//input[@name="content"]': 'So be careful.',
928 '//input[@name="civility"]': 'Mr',
929 '//input[@name="name"]': 'Chuck Norris',
930 '//input[@name="email"]': 'chuck@norris.com',
931 '//input[@name="cc"]': true,
932 }, true);
933 });
934
935 .. warning::
936
937 The ``fillXPath()`` method currently can't fill **file fields using XPath selectors**; PhantomJS natively only allows the use of CSS3 selectors in its ``uploadFile()`` method, hence this limitation.
938
889 .. index:: URL 939 .. index:: URL
890 940
891 ``getCurrentUrl()`` 941 ``getCurrentUrl()``
...@@ -1905,6 +1955,7 @@ is changed to a different value before processing the next step. Uses `waitFor() ...@@ -1905,6 +1955,7 @@ is changed to a different value before processing the next step. Uses `waitFor()
1905 ------------------------------------------------------------------------------- 1955 -------------------------------------------------------------------------------
1906 1956
1907 **Signature:** ``waitForText(String text[, Function then, Function onTimeout, Number timeout])`` 1957 **Signature:** ``waitForText(String text[, Function then, Function onTimeout, Number timeout])``
1958
1908 .. versionadded:: 1.0 1959 .. versionadded:: 1.0
1909 1960
1910 Waits until the passed text is present in the page contents before processing the immediate next step. Uses `waitFor()`_:: 1961 Waits until the passed text is present in the page contents before processing the immediate next step. Uses `waitFor()`_::
......
...@@ -752,41 +752,51 @@ Casper.prototype.fetchText = function fetchText(selector) { ...@@ -752,41 +752,51 @@ Casper.prototype.fetchText = function fetchText(selector) {
752 */ 752 */
753 Casper.prototype.fillForm = function fillForm(selector, vals, options) { 753 Casper.prototype.fillForm = function fillForm(selector, vals, options) {
754 "use strict"; 754 "use strict";
755 var submit, selectorFunction;
756 this.checkStarted(); 755 this.checkStarted();
757 756
758 selectorFunction = options && options.selectorFunction; 757 var selectorType = options && options.selectorType || "names",
759 submit = options.submit === true ? options.submit : false; 758 submit = !!(options && options.submit);
760 759
761 this.emit('fill', selector, vals, options); 760 this.emit('fill', selector, vals, options);
762 761
763 var fillResults = this.evaluate(function _evaluate(selector, vals, selectorFunction) { 762 var fillResults = this.evaluate(function _evaluate(selector, vals, selectorType) {
764 return __utils__.fill(selector, vals, selectorFunction); 763 try {
765 }, selector, vals, selectorFunction); 764 return __utils__.fill(selector, vals, selectorType);
765 } catch (exception) {
766 return {exception: exception.toString()};
767 }
768 }, selector, vals, selectorType);
769
766 if (!fillResults) { 770 if (!fillResults) {
767 throw new CasperError("Unable to fill form"); 771 throw new CasperError("Unable to fill form");
772 } else if (fillResults && fillResults.exception) {
773 throw new CasperError("Unable to fill form: " + fillResults.exception);
768 } else if (fillResults.errors.length > 0) { 774 } else if (fillResults.errors.length > 0) {
769 throw new CasperError(f('Errors encountered while filling form: %s', 775 throw new CasperError(f('Errors encountered while filling form: %s',
770 fillResults.errors.join('; '))); 776 fillResults.errors.join('; ')));
771 } 777 }
778
772 // File uploads 779 // File uploads
773 if (fillResults.files && fillResults.files.length > 0) { 780 if (fillResults.files && fillResults.files.length > 0) {
774 if (utils.isObject(selector) && selector.type === 'xpath') { 781 if (utils.isObject(selector) && selector.type === 'xpath') {
775 this.warn('Filling file upload fields is currently not supported using ' + 782 this.warn('Filling file upload fields is currently not supported using ' +
776 'XPath selectors; Please use a CSS selector instead.'); 783 'XPath selectors; Please use a CSS selector instead.');
777 } else { 784 } else {
778 (function _each(self) { 785 fillResults.files.forEach(function _forEach(file) {
779 fillResults.files.forEach(function _forEach(file) { 786 if (!file || !file.path) {
780 if (!file || !file.path) { 787 return;
781 return; 788 }
782 } 789 if (!fs.exists(file.path)) {
783 if (!fs.exists(file.path)) { 790 throw new CasperError('Cannot upload nonexistent file: ' + file.path);
784 throw new CasperError('Cannot upload nonexistent file: ' + file.path); 791 }
785 } 792 var fileFieldSelector;
786 var fileFieldSelector = selectorFunction.call(this, file.name, selector).fullSelector; 793 if (file.type === "names") {
787 self.page.uploadFile(fileFieldSelector, file.path); 794 fileFieldSelector = [selector, 'input[name="' + file.selector + '"]'].join(' ');
788 }); 795 } else if (file.type === "css") {
789 })(this); 796 fileFieldSelector = [selector, file.selector].join(' ');
797 }
798 this.page.uploadFile(fileFieldSelector, file.path);
799 }.bind(this));
790 } 800 }
791 } 801 }
792 // Form submission? 802 // Form submission?
...@@ -817,47 +827,52 @@ Casper.prototype.fillForm = function fillForm(selector, vals, options) { ...@@ -817,47 +827,52 @@ Casper.prototype.fillForm = function fillForm(selector, vals, options) {
817 * 827 *
818 * @param String formSelector A DOM CSS3/XPath selector to the target form to fill 828 * @param String formSelector A DOM CSS3/XPath selector to the target form to fill
819 * @param Object vals Field values 829 * @param Object vals Field values
820 * @param Boolean submit Submit the form? 830 * @param Boolean submit Submit the form?
821 */ 831 */
822 Casper.prototype.fillNames = function fillNames(formSelector, vals, submit) { 832 Casper.prototype.fillNames = function fillNames(formSelector, vals, submit) {
823 "use strict"; 833 "use strict";
824 return this.fillForm(formSelector, vals, { 834 return this.fillForm(formSelector, vals, {
825 submit: submit, 835 submit: submit,
826 selectorFunction: function _nameSelector(elementName, formSelector) { 836 selectorType: 'names'
827 return {
828 fullSelector: [formSelector, '[name="' + elementName + '"]'].join(' '),
829 elts: (this.findAll ? this.findAll('[name="' + elementName + '"]', formSelector) : null)
830 };
831 }
832 }); 837 });
833 }; 838 };
834 839
835 /** 840 /**
836 * Fills a form with provided field values using the Name attribute. 841 * Fills a form with provided field values using CSS3 selectors.
842 *
843 * @param String formSelector A DOM CSS3/XPath selector to the target form to fill
844 * @param Object vals Field values
845 * @param Boolean submit Submit the form?
846 */
847 Casper.prototype.fillSelectors = function fillSelectors(formSelector, vals, submit) {
848 "use strict";
849 return this.fillForm(formSelector, vals, {
850 submit: submit,
851 selectorType: 'css'
852 });
853 };
854
855 /**
856 * Fills a form with provided field values using the Name attribute by default.
837 * 857 *
838 * @param String formSelector A DOM CSS3/XPath selector to the target form to fill 858 * @param String formSelector A DOM CSS3/XPath selector to the target form to fill
839 * @param Object vals Field values 859 * @param Object vals Field values
840 * @param Boolean submit Submit the form? 860 * @param Boolean submit Submit the form?
841 */ 861 */
842 Casper.prototype.fill = Casper.prototype.fillNames 862 Casper.prototype.fill = Casper.prototype.fillNames;
843 863
844 /** 864 /**
845 * Fills a form with provided field values using CSS3 selectors. 865 * Fills a form with provided field values using XPath selectors.
846 * 866 *
847 * @param String formSelector A DOM CSS3/XPath selector to the target form to fill 867 * @param String formSelector A DOM CSS3/XPath selector to the target form to fill
848 * @param Object vals Field values 868 * @param Object vals Field values
849 * @param Boolean submit Submit the form? 869 * @param Boolean submit Submit the form?
850 */ 870 */
851 Casper.prototype.fillSelectors = function fillSelectors(formSelector, vals, submit) { 871 Casper.prototype.fillXPath = function fillXPath(formSelector, vals, submit) {
852 "use strict"; 872 "use strict";
853 return this.fillForm(formSelector, vals, { 873 return this.fillForm(formSelector, vals, {
854 submit: submit, 874 submit: submit,
855 selectorFunction: function _css3Selector(inputSelector, formSelector) { 875 selectorType: 'xpath'
856 return {
857 fullSelector: [formSelector, inputSelector].join(' '),
858 elts: (this.findAll ? this.findAll(inputSelector, formSelector) : null)
859 };
860 }
861 }); 876 });
862 }; 877 };
863 878
......
...@@ -196,12 +196,12 @@ ...@@ -196,12 +196,12 @@
196 /** 196 /**
197 * Fills a form with provided field values, and optionally submits it. 197 * Fills a form with provided field values, and optionally submits it.
198 * 198 *
199 * @param HTMLElement|String form A form element, or a CSS3 selector to a form element 199 * @param HTMLElement|String form A form element, or a CSS3 selector to a form element
200 * @param Object vals Field values 200 * @param Object vals Field values
201 * @param Function findFunction A function to be used for getting the selector for the element or a list of matching elements (optional) 201 * @param Function findType Element finder type (css, names, xpath)
202 * @return Object An object containing setting result for each field, including file uploads 202 * @return Object An object containing setting result for each field, including file uploads
203 */ 203 */
204 this.fill = function fill(form, vals, findFunction) { 204 this.fill = function fill(form, vals, findType) {
205 /*jshint maxcomplexity:8*/ 205 /*jshint maxcomplexity:8*/
206 var out = { 206 var out = {
207 errors: [], 207 errors: [],
...@@ -209,13 +209,6 @@ ...@@ -209,13 +209,6 @@
209 files: [] 209 files: []
210 }; 210 };
211 211
212 findFunction = findFunction || function _nameSelector(elementName, formSelector) {
213 return {
214 fullSelector: [formSelector, '[name="' + elementName + '"]'].join(' '),
215 elts: this.findAll('[name="' + elementName + '"]', formSelector)
216 };
217 };
218
219 if (!(form instanceof HTMLElement) || typeof form === "string") { 212 if (!(form instanceof HTMLElement) || typeof form === "string") {
220 this.log("attempting to fetch form element from selector: '" + form + "'", "info"); 213 this.log("attempting to fetch form element from selector: '" + form + "'", "info");
221 try { 214 try {
...@@ -227,30 +220,45 @@ ...@@ -227,30 +220,45 @@
227 } 220 }
228 } 221 }
229 } 222 }
223
230 if (!form) { 224 if (!form) {
231 out.errors.push("form not found"); 225 out.errors.push("form not found");
232 return out; 226 return out;
233 } 227 }
234 for (var name in vals) { 228
235 if (!vals.hasOwnProperty(name)) { 229 var finders = {
230 css: function(inputSelector, formSelector) {
231 return this.findAll(inputSelector, form);
232 },
233 names: function(elementName, formSelector) {
234 return this.findAll('[name="' + elementName + '"]', form);
235 },
236 xpath: function(xpath, formSelector) {
237 return this.findAll({type: "xpath", path: xpath}, form);
238 }
239 };
240
241 for (var fieldSelector in vals) {
242 if (!vals.hasOwnProperty(fieldSelector)) {
236 continue; 243 continue;
237 } 244 }
238 var field = findFunction.call(this, name, form).elts; 245 var field = finders[findType || "names"].call(this, fieldSelector, form),
239 var value = vals[name]; 246 value = vals[fieldSelector];
240 if (!field || field.length === 0) { 247 if (!field || field.length === 0) {
241 out.errors.push('no field named "' + name + '" in form'); 248 out.errors.push('no field matching ' + findType + ' selector "' + fieldSelector + '" in form');
242 continue; 249 continue;
243 } 250 }
244 try { 251 try {
245 out.fields[name] = this.setField(field, value); 252 out.fields[fieldSelector] = this.setField(field, value);
246 } catch (err) { 253 } catch (err) {
247 if (err.name === "FileUploadError") { 254 if (err.name === "FileUploadError") {
248 out.files.push({ 255 out.files.push({
249 name: name, 256 type: findType,
257 selector: fieldSelector,
250 path: err.path 258 path: err.path
251 }); 259 });
252 } else if(err.name === "FieldNotFound") { 260 } else if (err.name === "FieldNotFound") {
253 out.errors.push('Form field named "' + name + '" was not found.'); 261 out.errors.push('Unable to find field element in form: ' + err.toString());
254 } else { 262 } else {
255 out.errors.push(err.toString()); 263 out.errors.push(err.toString());
256 } 264 }
...@@ -680,26 +688,33 @@ ...@@ -680,26 +688,33 @@
680 /*jshint maxcomplexity:99 */ 688 /*jshint maxcomplexity:99 */
681 var logValue, fields, out; 689 var logValue, fields, out;
682 value = logValue = (value || ""); 690 value = logValue = (value || "");
683 if (field instanceof NodeList) { 691
692 if (field instanceof NodeList || field instanceof Array) {
684 fields = field; 693 fields = field;
685 field = fields[0]; 694 field = fields[0];
686 } 695 }
696
687 if (!(field instanceof HTMLElement)) { 697 if (!(field instanceof HTMLElement)) {
688 var error = new Error('Invalid field type; only HTMLElement and NodeList are supported'); 698 var error = new Error('Invalid field type; only HTMLElement and NodeList are supported');
689 error.name = 'FieldNotFound'; 699 error.name = 'FieldNotFound';
690 throw error; 700 throw error;
691 } 701 }
702
692 if (this.options && this.options.safeLogs && field.getAttribute('type') === "password") { 703 if (this.options && this.options.safeLogs && field.getAttribute('type') === "password") {
693 // obfuscate password value 704 // obfuscate password value
694 logValue = new Array(value.length + 1).join("*"); 705 logValue = new Array(value.length + 1).join("*");
695 } 706 }
707
696 this.log('Set "' + field.getAttribute('name') + '" field value to ' + logValue, "debug"); 708 this.log('Set "' + field.getAttribute('name') + '" field value to ' + logValue, "debug");
709
697 try { 710 try {
698 field.focus(); 711 field.focus();
699 } catch (e) { 712 } catch (e) {
700 this.log("Unable to focus() input field " + field.getAttribute('name') + ": " + e, "warning"); 713 this.log("Unable to focus() input field " + field.getAttribute('name') + ": " + e, "warning");
701 } 714 }
715
702 var nodeName = field.nodeName.toLowerCase(); 716 var nodeName = field.nodeName.toLowerCase();
717
703 switch (nodeName) { 718 switch (nodeName) {
704 case "input": 719 case "input":
705 var type = field.getAttribute('type') || "text"; 720 var type = field.getAttribute('type') || "text";
......
...@@ -2,7 +2,40 @@ ...@@ -2,7 +2,40 @@
2 /*jshint strict:false*/ 2 /*jshint strict:false*/
3 var fs = require('fs'); 3 var fs = require('fs');
4 4
5 casper.test.begin('fill() tests', 15, function(test) { 5 function testFormValues(test) {
6 test.assertField('email', 'chuck@norris.com',
7 'can fill an input[type=text] form field');
8 test.assertField('password', 'chuck',
9 'can fill an input[type=password] form field')
10 test.assertField('content', 'Am watching thou',
11 'can fill a textarea form field');
12 test.assertField('topic', 'bar',
13 'can pick a value from a select form field');
14 test.assertField('check', true,
15 'can check a form checkbox');
16 test.assertEvalEquals(function() {
17 return __utils__.findOne('input[name="choice"][value="no"]').checked;
18 }, true, 'can check a form radio button 1/2');
19 test.assertEvalEquals(function() {
20 return __utils__.findOne('input[name="choice"][value="yes"]').checked;
21 }, false, 'can check a form radio button 2/2');
22 test.assertEvalEquals(function() {
23 return (__utils__.findOne('input[name="checklist[]"][value="1"]').checked &&
24 !__utils__.findOne('input[name="checklist[]"][value="2"]').checked &&
25 __utils__.findOne('input[name="checklist[]"][value="3"]').checked);
26 }, true, 'can fill a list of checkboxes');
27 }
28
29 function testUrl(test) {
30 test.assertUrlMatch(/email=chuck@norris.com/, 'input[type=email] field was submitted');
31 test.assertUrlMatch(/password=chuck/, 'input[type=password] field was submitted');
32 test.assertUrlMatch(/content=Am\+watching\+thou/, 'textarea field was submitted');
33 test.assertUrlMatch(/check=on/, 'input[type=checkbox] field was submitted');
34 test.assertUrlMatch(/choice=no/, 'input[type=radio] field was submitted');
35 test.assertUrlMatch(/topic=bar/, 'select field was submitted');
36 }
37
38 casper.test.begin('fill() & fillNames() tests', 15, function(test) {
6 var fpath = fs.pathJoin(phantom.casperPath, 'README.md'); 39 var fpath = fs.pathJoin(phantom.casperPath, 'README.md');
7 40
8 casper.start('tests/site/form.html', function() { 41 casper.start('tests/site/form.html', function() {
...@@ -16,101 +49,62 @@ casper.test.begin('fill() tests', 15, function(test) { ...@@ -16,101 +49,62 @@ casper.test.begin('fill() tests', 15, function(test) {
16 file: fpath, 49 file: fpath,
17 'checklist[]': ['1', '3'] 50 'checklist[]': ['1', '3']
18 }); 51 });
19 test.assertEvalEquals(function() { 52 testFormValues(test);
20 return __utils__.findOne('input[name="email"]').value;
21 }, 'chuck@norris.com', 'Casper.fill() can fill an input[type=text] form field');
22 test.assertEvalEquals(function() {
23 return __utils__.findOne('input[name="password"]').value;
24 }, 'chuck', 'Casper.fill() can fill an input[type=password] form field');
25 test.assertEvalEquals(function() {
26 return __utils__.findOne('textarea[name="content"]').value;
27 }, 'Am watching thou', 'Casper.fill() can fill a textarea form field');
28 test.assertEvalEquals(function() {
29 return __utils__.findOne('select[name="topic"]').value;
30 }, 'bar', 'Casper.fill() can pick a value from a select form field');
31 test.assertEvalEquals(function() {
32 return __utils__.findOne('input[name="check"]').checked;
33 }, true, 'Casper.fill() can check a form checkbox');
34 test.assertEvalEquals(function() {
35 return __utils__.findOne('input[name="choice"][value="no"]').checked;
36 }, true, 'Casper.fill() can check a form radio button 1/2');
37 test.assertEvalEquals(function() {
38 return __utils__.findOne('input[name="choice"][value="yes"]').checked;
39 }, false, 'Casper.fill() can check a form radio button 2/2');
40 test.assertEvalEquals(function() { 53 test.assertEvalEquals(function() {
41 return __utils__.findOne('input[name="file"]').files.length === 1; 54 return __utils__.findOne('input[name="file"]').files.length === 1;
42 }, true, 'Casper.fill() can select a file to upload'); 55 }, true, 'can select a file to upload');
43 test.assertEvalEquals(function() {
44 return (__utils__.findOne('input[name="checklist[]"][value="1"]').checked &&
45 !__utils__.findOne('input[name="checklist[]"][value="2"]').checked &&
46 __utils__.findOne('input[name="checklist[]"][value="3"]').checked);
47 }, true, 'Casper.fill() can fill a list of checkboxes');
48 }); 56 });
49 casper.thenClick('input[type="submit"]', function() { 57 casper.thenClick('input[type="submit"]', function() {
50 test.assertUrlMatch(/email=chuck@norris.com/, 'Casper.fill() input[type=email] field was submitted'); 58 testUrl(test);
51 test.assertUrlMatch(/password=chuck/, 'Casper.fill() input[type=password] field was submitted');
52 test.assertUrlMatch(/content=Am\+watching\+thou/, 'Casper.fill() textarea field was submitted');
53 test.assertUrlMatch(/check=on/, 'Casper.fill() input[type=checkbox] field was submitted');
54 test.assertUrlMatch(/choice=no/, 'Casper.fill() input[type=radio] field was submitted');
55 test.assertUrlMatch(/topic=bar/, 'Casper.fill() select field was submitted');
56 }); 59 });
57 casper.run(function() { 60 casper.run(function() {
58 test.done(); 61 test.done();
59 }); 62 });
60 }); 63 });
61 64
62 casper.test.begin('fillSelector() tests', 15, function(test) { 65 casper.test.begin('fillSelectors() tests', 15, function(test) {
63 var fpath = fs.pathJoin(phantom.casperPath, 'README.md'); 66 var fpath = fs.pathJoin(phantom.casperPath, 'README.md');
64 67
65 casper.start('tests/site/form.html', function() { 68 casper.start('tests/site/form.html', function() {
66 this.fillSelectors('form[action="result.html"]', { 69 this.fillSelectors('form[action="result.html"]', {
67 "input[name='email']": 'chuck@norris.com', 70 "input[name='email']": 'chuck@norris.com',
68 "input[name='password']": 'chuck', 71 "input[name='password']": 'chuck',
69 "textarea[name='content']": 'Am watching thou', 72 "textarea[name='content']": 'Am watching thou',
70 "input[name='check']": true, 73 "input[name='check']": true,
71 "input[name='choice']": 'no', 74 "input[name='choice']": 'no',
72 "select[name='topic']": 'bar', 75 "select[name='topic']": 'bar',
73 "input[name='file']": fpath, 76 "input[name='file']": fpath,
74 "input[name='checklist[]']": ['1', '3'] 77 "input[name='checklist[]']": ['1', '3']
75 } 78 });
76 ); 79 testFormValues(test);
77 test.assertEvalEquals(function() {
78 return __utils__.findOne('input[name="email"]').value;
79 }, 'chuck@norris.com', 'Casper.fill() can fill an input[type=text] form field');
80 test.assertEvalEquals(function() {
81 return __utils__.findOne('input[name="password"]').value;
82 }, 'chuck', 'Casper.fill() can fill an input[type=password] form field');
83 test.assertEvalEquals(function() {
84 return __utils__.findOne('textarea[name="content"]').value;
85 }, 'Am watching thou', 'Casper.fill() can fill a textarea form field');
86 test.assertEvalEquals(function() {
87 return __utils__.findOne('select[name="topic"]').value;
88 }, 'bar', 'Casper.fill() can pick a value from a select form field');
89 test.assertEvalEquals(function() {
90 return __utils__.findOne('input[name="check"]').checked;
91 }, true, 'Casper.fill() can check a form checkbox');
92 test.assertEvalEquals(function() {
93 return __utils__.findOne('input[name="choice"][value="no"]').checked;
94 }, true, 'Casper.fill() can check a form radio button 1/2');
95 test.assertEvalEquals(function() {
96 return __utils__.findOne('input[name="choice"][value="yes"]').checked;
97 }, false, 'Casper.fill() can check a form radio button 2/2');
98 test.assertEvalEquals(function() { 80 test.assertEvalEquals(function() {
99 return __utils__.findOne('input[name="file"]').files.length === 1; 81 return __utils__.findOne('input[name="file"]').files.length === 1;
100 }, true, 'Casper.fill() can select a file to upload'); 82 }, true, 'can select a file to upload');
101 test.assertEvalEquals(function() { 83 });
102 return (__utils__.findOne('input[name="checklist[]"][value="1"]').checked && 84 casper.thenClick('input[type="submit"]', function() {
103 !__utils__.findOne('input[name="checklist[]"][value="2"]').checked && 85 testUrl(test);
104 __utils__.findOne('input[name="checklist[]"][value="3"]').checked); 86 });
105 }, true, 'Casper.fill() can fill a list of checkboxes'); 87 casper.run(function() {
88 test.done();
89 });
90 });
91
92 casper.test.begin('fillXPath() tests', 14, function(test) {
93 casper.start('tests/site/form.html', function() {
94 this.fillXPath('form[action="result.html"]', {
95 '//input[@name="email"]': 'chuck@norris.com',
96 '//input[@name="password"]': 'chuck',
97 '//textarea[@name="content"]': 'Am watching thou',
98 '//input[@name="check"]': true,
99 '//input[@name="choice"]': 'no',
100 '//select[@name="topic"]': 'bar',
101 '//input[@name="checklist[]"]': ['1', '3']
102 });
103 testFormValues(test);
104 // note: file inputs cannot be filled using XPath
106 }); 105 });
107 casper.thenClick('input[type="submit"]', function() { 106 casper.thenClick('input[type="submit"]', function() {
108 test.assertUrlMatch(/email=chuck@norris.com/, 'Casper.fill() input[type=email] field was submitted'); 107 testUrl(test);
109 test.assertUrlMatch(/password=chuck/, 'Casper.fill() input[type=password] field was submitted');
110 test.assertUrlMatch(/content=Am\+watching\+thou/, 'Casper.fill() textarea field was submitted');
111 test.assertUrlMatch(/check=on/, 'Casper.fill() input[type=checkbox] field was submitted');
112 test.assertUrlMatch(/choice=no/, 'Casper.fill() input[type=radio] field was submitted');
113 test.assertUrlMatch(/topic=bar/, 'Casper.fill() select field was submitted');
114 }); 108 });
115 casper.run(function() { 109 casper.run(function() {
116 test.done(); 110 test.done();
......