Commit 689e565d 689e565db7bc2a29d2e75b40c3c6fdb7276912f3 by Matt Bowman

refs #307 - add fillNames and fillSelectors functionality

1 parent 0c4adc21
......@@ -746,21 +746,24 @@ Casper.prototype.fetchText = function fetchText(selector) {
/**
* Fills a form with provided field values.
*
* @param String selector A DOM CSS3/XPath selector to the target form to fill
* @param Object vals Field values
* @param Boolean submit Submit the form?
* @param Casper casper A Casper instance
* @param String selector A DOM CSS3/XPath selector to the target form to fill
* @param Object vals Field values
* @param Object options The fill settings (optional)
*/
Casper.prototype.fill = function fill(selector, vals, submit) {
function fillForm (casper, selector, vals, options) {
"use strict";
this.checkStarted();
submit = submit === true ? submit : false;
if (!utils.isObject(vals)) {
throw new CasperError("Form values must be provided as an object");
}
this.emit('fill', selector, vals, submit);
var fillResults = this.evaluate(function _evaluate(selector, values) {
return __utils__.fill(selector, values);
}, selector, vals);
var submit, selectorFunction;
casper.checkStarted();
selectorFunction = options.selectorFunction;
submit = options.submit === true ? options.submit : false;
casper.emit('fill', selector, vals, options);
var fillResults = casper.evaluate(function _evaluate(selector, vals, selectorFunction) {
return __utils__.fill(selector, vals, selectorFunction);
}, selector, vals, selectorFunction);
if (!fillResults) {
throw new CasperError("Unable to fill form");
} else if (fillResults.errors.length > 0) {
......@@ -770,7 +773,7 @@ Casper.prototype.fill = function fill(selector, vals, submit) {
// File uploads
if (fillResults.files && fillResults.files.length > 0) {
if (utils.isObject(selector) && selector.type === 'xpath') {
this.warn('Filling file upload fields is currently not supported using ' +
casper.warn('Filling file upload fields is currently not supported using ' +
'XPath selectors; Please use a CSS selector instead.');
} else {
(function _each(self) {
......@@ -781,15 +784,15 @@ Casper.prototype.fill = function fill(selector, vals, submit) {
if (!fs.exists(file.path)) {
throw new CasperError('Cannot upload nonexistent file: ' + file.path);
}
var fileFieldSelector = [selector, 'input[name="' + file.name + '"]'].join(' ');
var fileFieldSelector = selectorFunction(self, file.name, selector).fullSelector;
self.page.uploadFile(fileFieldSelector, file.path);
});
})(this);
})(casper);
}
}
// Form submission?
if (submit) {
this.evaluate(function _evaluate(selector) {
casper.evaluate(function _evaluate(selector) {
var form = __utils__.findOne(selector);
var method = (form.getAttribute('method') || "GET").toUpperCase();
var action = form.getAttribute('action') || "unknown";
......@@ -808,6 +811,55 @@ Casper.prototype.fill = function fill(selector, vals, submit) {
}
}, selector);
}
}
/**
* Fills a form with provided field values using the Name attribute.
*
* @param String formSelector A DOM CSS3/XPath selector to the target form to fill
* @param Object vals Field values
* @param Boolean submit Submit the form?
*/
Casper.prototype.fillNames = function fillNames(formSelector, vals, submit) {
"use strict";
return fillForm(this, formSelector, vals, {
submit: submit,
selectorFunction: function (self, selector, form) {
return {
fullSelector: [form, '[name="' + selector + '"]'].join(' '),
elts: (self.findAll ? self.findAll('[name="' + selector + '"]', form) : null)
};
}
});
};
/**
* Fills a form with provided field values using the Name attribute.
*
* @param String formSelector A DOM CSS3/XPath selector to the target form to fill
* @param Object vals Field values
* @param Boolean submit Submit the form?
*/
Casper.prototype.fill = Casper.prototype.fillNames
/**
* Fills a form with provided field values using CSS3 selectors.
*
* @param String formSelector A DOM CSS3/XPath selector to the target form to fill
* @param Object vals Field values
* @param Boolean submit Submit the form?
*/
Casper.prototype.fillSelectors = function fillSelectors(formSelector, vals, submit) {
"use strict";
return fillForm(this, formSelector, vals, {
submit: submit,
selectorFunction: function (self, selector, form) {
return {
fullSelector: [form, selector].join(' '),
elts: (self.findAll ? self.findAll(selector, form) : null)
};
}
});
};
/**
......
......@@ -194,19 +194,28 @@
};
/**
* Fills a form with provided field values, and optionnaly submits it.
* Fills a form with provided field values, and optionally submits it.
*
* @param HTMLElement|String form A form element, or a CSS3 selector to a form element
* @param Object vals Field values
* @return Object An object containing setting result for each field, including file uploads
* @param HTMLElement|String form A form element, or a CSS3 selector to a form element
* @param Object vals Field values
* @param Function findFunction A function to be used for getting the selector for the element or a list of matching elements (optional)
* @return Object An object containing setting result for each field, including file uploads
*/
this.fill = function fill(form, vals) {
this.fill = function fill(form, vals, findFunction) {
/*jshint maxcomplexity:8*/
var out = {
errors: [],
fields: [],
files: []
};
findFunction = findFunction || function(self, name, form) {
return {
fullSelector: [form, '[name="' + name + '"]'].join(' '),
elts: self.findAll('[name="' + name + '"]', form)
};
};
if (!(form instanceof HTMLElement) || typeof form === "string") {
this.log("attempting to fetch form element from selector: '" + form + "'", "info");
try {
......@@ -226,7 +235,7 @@
if (!vals.hasOwnProperty(name)) {
continue;
}
var field = this.findAll('[name="' + name + '"]', form) || this.findAll('#' + name, form);
var field = findFunction(this, name, form).elts;
var value = vals[name];
if (!field || field.length === 0) {
out.errors.push('no field named "' + name + '" in form');
......
......@@ -59,6 +59,64 @@ casper.test.begin('fill() tests', 15, function(test) {
});
});
casper.test.begin('fillSelector() tests', 15, function(test) {
var fpath = fs.pathJoin(phantom.casperPath, 'README.md');
casper.start('tests/site/form.html', function() {
this.fillSelectors('form[action="result.html"]', {
"input[name='email']": 'chuck@norris.com',
"input[name='password']": 'chuck',
"textarea[name='content']": 'Am watching thou',
"input[name='check']": true,
"input[name='choice']": 'no',
"select[name='topic']": 'bar',
"input[name='file']": fpath,
"input[name='checklist[]']": ['1', '3']
}
);
test.assertEvalEquals(function() {
return __utils__.findOne('input[name="email"]').value;
}, 'chuck@norris.com', 'Casper.fill() can fill an input[type=text] form field');
test.assertEvalEquals(function() {
return __utils__.findOne('input[name="password"]').value;
}, 'chuck', 'Casper.fill() can fill an input[type=password] form field');
test.assertEvalEquals(function() {
return __utils__.findOne('textarea[name="content"]').value;
}, 'Am watching thou', 'Casper.fill() can fill a textarea form field');
test.assertEvalEquals(function() {
return __utils__.findOne('select[name="topic"]').value;
}, 'bar', 'Casper.fill() can pick a value from a select form field');
test.assertEvalEquals(function() {
return __utils__.findOne('input[name="check"]').checked;
}, true, 'Casper.fill() can check a form checkbox');
test.assertEvalEquals(function() {
return __utils__.findOne('input[name="choice"][value="no"]').checked;
}, true, 'Casper.fill() can check a form radio button 1/2');
test.assertEvalEquals(function() {
return __utils__.findOne('input[name="choice"][value="yes"]').checked;
}, false, 'Casper.fill() can check a form radio button 2/2');
test.assertEvalEquals(function() {
return __utils__.findOne('input[name="file"]').files.length === 1;
}, true, 'Casper.fill() can select a file to upload');
test.assertEvalEquals(function() {
return (__utils__.findOne('input[name="checklist[]"][value="1"]').checked &&
!__utils__.findOne('input[name="checklist[]"][value="2"]').checked &&
__utils__.findOne('input[name="checklist[]"][value="3"]').checked);
}, true, 'Casper.fill() can fill a list of checkboxes');
});
casper.thenClick('input[type="submit"]', function() {
test.assertUrlMatch(/email=chuck@norris.com/, 'Casper.fill() input[type=email] field was submitted');
test.assertUrlMatch(/password=chuck/, 'Casper.fill() input[type=password] field was submitted');
test.assertUrlMatch(/content=Am\+watching\+thou/, 'Casper.fill() textarea field was submitted');
test.assertUrlMatch(/check=on/, 'Casper.fill() input[type=checkbox] field was submitted');
test.assertUrlMatch(/choice=no/, 'Casper.fill() input[type=radio] field was submitted');
test.assertUrlMatch(/topic=bar/, 'Casper.fill() select field was submitted');
});
casper.run(function() {
test.done();
});
});
casper.test.begin('nonexistent fields', 1, function(test) {
casper.start('tests/site/form.html', function() {
test.assertRaises(this.fill, ['form[action="result.html"]', {
......