refs #307 - add fillNames and fillSelectors functionality
Showing
3 changed files
with
137 additions
and
18 deletions
... | @@ -746,21 +746,24 @@ Casper.prototype.fetchText = function fetchText(selector) { | ... | @@ -746,21 +746,24 @@ Casper.prototype.fetchText = function fetchText(selector) { |
746 | /** | 746 | /** |
747 | * Fills a form with provided field values. | 747 | * Fills a form with provided field values. |
748 | * | 748 | * |
749 | * @param Casper casper A Casper instance | ||
749 | * @param String selector A DOM CSS3/XPath selector to the target form to fill | 750 | * @param String selector A DOM CSS3/XPath selector to the target form to fill |
750 | * @param Object vals Field values | 751 | * @param Object vals Field values |
751 | * @param Boolean submit Submit the form? | 752 | * @param Object options The fill settings (optional) |
752 | */ | 753 | */ |
753 | Casper.prototype.fill = function fill(selector, vals, submit) { | 754 | function fillForm (casper, selector, vals, options) { |
754 | "use strict"; | 755 | "use strict"; |
755 | this.checkStarted(); | 756 | var submit, selectorFunction; |
756 | submit = submit === true ? submit : false; | 757 | casper.checkStarted(); |
757 | if (!utils.isObject(vals)) { | 758 | |
758 | throw new CasperError("Form values must be provided as an object"); | 759 | selectorFunction = options.selectorFunction; |
759 | } | 760 | submit = options.submit === true ? options.submit : false; |
760 | this.emit('fill', selector, vals, submit); | 761 | |
761 | var fillResults = this.evaluate(function _evaluate(selector, values) { | 762 | casper.emit('fill', selector, vals, options); |
762 | return __utils__.fill(selector, values); | 763 | |
763 | }, selector, vals); | 764 | var fillResults = casper.evaluate(function _evaluate(selector, vals, selectorFunction) { |
765 | return __utils__.fill(selector, vals, selectorFunction); | ||
766 | }, selector, vals, selectorFunction); | ||
764 | if (!fillResults) { | 767 | if (!fillResults) { |
765 | throw new CasperError("Unable to fill form"); | 768 | throw new CasperError("Unable to fill form"); |
766 | } else if (fillResults.errors.length > 0) { | 769 | } else if (fillResults.errors.length > 0) { |
... | @@ -770,7 +773,7 @@ Casper.prototype.fill = function fill(selector, vals, submit) { | ... | @@ -770,7 +773,7 @@ Casper.prototype.fill = function fill(selector, vals, submit) { |
770 | // File uploads | 773 | // File uploads |
771 | if (fillResults.files && fillResults.files.length > 0) { | 774 | if (fillResults.files && fillResults.files.length > 0) { |
772 | if (utils.isObject(selector) && selector.type === 'xpath') { | 775 | if (utils.isObject(selector) && selector.type === 'xpath') { |
773 | this.warn('Filling file upload fields is currently not supported using ' + | 776 | casper.warn('Filling file upload fields is currently not supported using ' + |
774 | 'XPath selectors; Please use a CSS selector instead.'); | 777 | 'XPath selectors; Please use a CSS selector instead.'); |
775 | } else { | 778 | } else { |
776 | (function _each(self) { | 779 | (function _each(self) { |
... | @@ -781,15 +784,15 @@ Casper.prototype.fill = function fill(selector, vals, submit) { | ... | @@ -781,15 +784,15 @@ Casper.prototype.fill = function fill(selector, vals, submit) { |
781 | if (!fs.exists(file.path)) { | 784 | if (!fs.exists(file.path)) { |
782 | throw new CasperError('Cannot upload nonexistent file: ' + file.path); | 785 | throw new CasperError('Cannot upload nonexistent file: ' + file.path); |
783 | } | 786 | } |
784 | var fileFieldSelector = [selector, 'input[name="' + file.name + '"]'].join(' '); | 787 | var fileFieldSelector = selectorFunction(self, file.name, selector).fullSelector; |
785 | self.page.uploadFile(fileFieldSelector, file.path); | 788 | self.page.uploadFile(fileFieldSelector, file.path); |
786 | }); | 789 | }); |
787 | })(this); | 790 | })(casper); |
788 | } | 791 | } |
789 | } | 792 | } |
790 | // Form submission? | 793 | // Form submission? |
791 | if (submit) { | 794 | if (submit) { |
792 | this.evaluate(function _evaluate(selector) { | 795 | casper.evaluate(function _evaluate(selector) { |
793 | var form = __utils__.findOne(selector); | 796 | var form = __utils__.findOne(selector); |
794 | var method = (form.getAttribute('method') || "GET").toUpperCase(); | 797 | var method = (form.getAttribute('method') || "GET").toUpperCase(); |
795 | var action = form.getAttribute('action') || "unknown"; | 798 | var action = form.getAttribute('action') || "unknown"; |
... | @@ -808,6 +811,55 @@ Casper.prototype.fill = function fill(selector, vals, submit) { | ... | @@ -808,6 +811,55 @@ Casper.prototype.fill = function fill(selector, vals, submit) { |
808 | } | 811 | } |
809 | }, selector); | 812 | }, selector); |
810 | } | 813 | } |
814 | } | ||
815 | |||
816 | /** | ||
817 | * Fills a form with provided field values using the Name attribute. | ||
818 | * | ||
819 | * @param String formSelector A DOM CSS3/XPath selector to the target form to fill | ||
820 | * @param Object vals Field values | ||
821 | * @param Boolean submit Submit the form? | ||
822 | */ | ||
823 | Casper.prototype.fillNames = function fillNames(formSelector, vals, submit) { | ||
824 | "use strict"; | ||
825 | return fillForm(this, formSelector, vals, { | ||
826 | submit: submit, | ||
827 | selectorFunction: function (self, selector, form) { | ||
828 | return { | ||
829 | fullSelector: [form, '[name="' + selector + '"]'].join(' '), | ||
830 | elts: (self.findAll ? self.findAll('[name="' + selector + '"]', form) : null) | ||
831 | }; | ||
832 | } | ||
833 | }); | ||
834 | }; | ||
835 | |||
836 | /** | ||
837 | * Fills a form with provided field values using the Name attribute. | ||
838 | * | ||
839 | * @param String formSelector A DOM CSS3/XPath selector to the target form to fill | ||
840 | * @param Object vals Field values | ||
841 | * @param Boolean submit Submit the form? | ||
842 | */ | ||
843 | Casper.prototype.fill = Casper.prototype.fillNames | ||
844 | |||
845 | /** | ||
846 | * Fills a form with provided field values using CSS3 selectors. | ||
847 | * | ||
848 | * @param String formSelector A DOM CSS3/XPath selector to the target form to fill | ||
849 | * @param Object vals Field values | ||
850 | * @param Boolean submit Submit the form? | ||
851 | */ | ||
852 | Casper.prototype.fillSelectors = function fillSelectors(formSelector, vals, submit) { | ||
853 | "use strict"; | ||
854 | return fillForm(this, formSelector, vals, { | ||
855 | submit: submit, | ||
856 | selectorFunction: function (self, selector, form) { | ||
857 | return { | ||
858 | fullSelector: [form, selector].join(' '), | ||
859 | elts: (self.findAll ? self.findAll(selector, form) : null) | ||
860 | }; | ||
861 | } | ||
862 | }); | ||
811 | }; | 863 | }; |
812 | 864 | ||
813 | /** | 865 | /** | ... | ... |
... | @@ -194,19 +194,28 @@ | ... | @@ -194,19 +194,28 @@ |
194 | }; | 194 | }; |
195 | 195 | ||
196 | /** | 196 | /** |
197 | * Fills a form with provided field values, and optionnaly 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 | * @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 |
202 | */ | 203 | */ |
203 | this.fill = function fill(form, vals) { | 204 | this.fill = function fill(form, vals, findFunction) { |
204 | /*jshint maxcomplexity:8*/ | 205 | /*jshint maxcomplexity:8*/ |
205 | var out = { | 206 | var out = { |
206 | errors: [], | 207 | errors: [], |
207 | fields: [], | 208 | fields: [], |
208 | files: [] | 209 | files: [] |
209 | }; | 210 | }; |
211 | |||
212 | findFunction = findFunction || function(self, name, form) { | ||
213 | return { | ||
214 | fullSelector: [form, '[name="' + name + '"]'].join(' '), | ||
215 | elts: self.findAll('[name="' + name + '"]', form) | ||
216 | }; | ||
217 | }; | ||
218 | |||
210 | if (!(form instanceof HTMLElement) || typeof form === "string") { | 219 | if (!(form instanceof HTMLElement) || typeof form === "string") { |
211 | this.log("attempting to fetch form element from selector: '" + form + "'", "info"); | 220 | this.log("attempting to fetch form element from selector: '" + form + "'", "info"); |
212 | try { | 221 | try { |
... | @@ -226,7 +235,7 @@ | ... | @@ -226,7 +235,7 @@ |
226 | if (!vals.hasOwnProperty(name)) { | 235 | if (!vals.hasOwnProperty(name)) { |
227 | continue; | 236 | continue; |
228 | } | 237 | } |
229 | var field = this.findAll('[name="' + name + '"]', form) || this.findAll('#' + name, form); | 238 | var field = findFunction(this, name, form).elts; |
230 | var value = vals[name]; | 239 | var value = vals[name]; |
231 | if (!field || field.length === 0) { | 240 | if (!field || field.length === 0) { |
232 | out.errors.push('no field named "' + name + '" in form'); | 241 | out.errors.push('no field named "' + name + '" in form'); | ... | ... |
... | @@ -59,6 +59,64 @@ casper.test.begin('fill() tests', 15, function(test) { | ... | @@ -59,6 +59,64 @@ casper.test.begin('fill() tests', 15, function(test) { |
59 | }); | 59 | }); |
60 | }); | 60 | }); |
61 | 61 | ||
62 | casper.test.begin('fillSelector() tests', 15, function(test) { | ||
63 | var fpath = fs.pathJoin(phantom.casperPath, 'README.md'); | ||
64 | |||
65 | casper.start('tests/site/form.html', function() { | ||
66 | this.fillSelectors('form[action="result.html"]', { | ||
67 | "input[name='email']": 'chuck@norris.com', | ||
68 | "input[name='password']": 'chuck', | ||
69 | "textarea[name='content']": 'Am watching thou', | ||
70 | "input[name='check']": true, | ||
71 | "input[name='choice']": 'no', | ||
72 | "select[name='topic']": 'bar', | ||
73 | "input[name='file']": fpath, | ||
74 | "input[name='checklist[]']": ['1', '3'] | ||
75 | } | ||
76 | ); | ||
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() { | ||
99 | return __utils__.findOne('input[name="file"]').files.length === 1; | ||
100 | }, true, 'Casper.fill() can select a file to upload'); | ||
101 | test.assertEvalEquals(function() { | ||
102 | return (__utils__.findOne('input[name="checklist[]"][value="1"]').checked && | ||
103 | !__utils__.findOne('input[name="checklist[]"][value="2"]').checked && | ||
104 | __utils__.findOne('input[name="checklist[]"][value="3"]').checked); | ||
105 | }, true, 'Casper.fill() can fill a list of checkboxes'); | ||
106 | }); | ||
107 | casper.thenClick('input[type="submit"]', function() { | ||
108 | test.assertUrlMatch(/email=chuck@norris.com/, 'Casper.fill() input[type=email] field was submitted'); | ||
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 | }); | ||
115 | casper.run(function() { | ||
116 | test.done(); | ||
117 | }); | ||
118 | }); | ||
119 | |||
62 | casper.test.begin('nonexistent fields', 1, function(test) { | 120 | casper.test.begin('nonexistent fields', 1, function(test) { |
63 | casper.start('tests/site/form.html', function() { | 121 | casper.start('tests/site/form.html', function() { |
64 | test.assertRaises(this.fill, ['form[action="result.html"]', { | 122 | test.assertRaises(this.fill, ['form[action="result.html"]', { | ... | ... |
-
Please register or sign in to post a comment