/**
* Copyright (C) 2012-2014 Gist Labs, LLC. (http://gistlabs.com)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.gistlabs.mechanize.document.html.form;
import static com.gistlabs.mechanize.util.css.CSSHelper.*;
import static org.junit.Assert.*;
import java.io.File;
import org.junit.Test;
import com.gistlabs.mechanize.MechanizeTestCase;
import com.gistlabs.mechanize.Resource;
import com.gistlabs.mechanize.document.AbstractDocument;
import com.gistlabs.mechanize.document.html.form.Select.Option;
import com.gistlabs.mechanize.util.apache.ContentType;
/**
* @author Martin Kersten<Martin.Kersten.mk@gmail.com>
*/
public class FormTest extends MechanizeTestCase {
protected String contentType() {
return ContentType.TEXT_HTML.getMimeType();
}
protected String newHtml(final String title, final FormBuilder form) {
return "<html><head><title>" + title + "</title></head><body>" + form.toString() + "</body></html>";
}
protected FormBuilder newForm(final String action) {
return new FormBuilder(action);
}
protected FormBuilder newForm(final String action, final String method) {
return new FormBuilder(action, method);
}
public static class FormBuilder {
private final StringBuilder content = new StringBuilder();
private final String action;
private String id;
private String name;
private String method;
private String enctype;
public FormBuilder(final String action) {
this.action = action;
}
public FormBuilder(final String action, final String method) {
this(action);
method(method);
}
public String getAction() {
return this.action;
}
public FormBuilder method(final String method) {
this.method = method;
return this;
}
public String getMethod() {
return this.method;
}
public FormBuilder enctype(final String enctype) {
this.enctype = enctype;
return this;
}
public String getEnctype() {
return this.enctype;
}
public FormBuilder id(final String id) {
this.id = id;
return this;
}
public FormBuilder name(final String name) {
this.name = name;
return this;
}
public FormBuilder addInput(final String name, final String type, final String defaultValue) {
appendSimpleInput(type, name, defaultValue);
return this;
}
public FormBuilder addText(final String name, final String defaultValue) {
String type = "text";
appendSimpleInput(type, name, defaultValue);
return this;
}
public FormBuilder addText(final String name, final String defaultValue, final int maxLength) {
String type = "text";
appendSimpleInput(type, name, defaultValue, "maxlength='" + maxLength + "'");
return this;
}
public FormBuilder addRaw(final String htmlFragment) {
content.append(htmlFragment);
return this;
}
private void appendSimpleInput(final String type, final String name, final String value, final String...additionals) {
content.append("<input type='" + type + "'");
appendIfSet(content, "name", name);
appendIfSet(content, "value", value);
for(String toAdd : additionals)
content.append(" " + toAdd);
content.append("/>");
}
public FormBuilder addFileInput(final String name, final String value) {
appendSimpleInput("file", name, value);
return this;
}
public FormBuilder addTextArea(final String name, final String value) {
content.append("<textarea");
appendIfSet(content, "name", name);
content.append(">");
if(value != null)
content.append(value);
content.append("</textarea>");
return this;
}
public FormBuilder addPassword(final String name, final String defaultValue) {
appendSimpleInput("password", name, defaultValue);
return this;
}
public FormBuilder addHidden(final String name, final String value) {
appendSimpleInput("hidden", name, value);
return this;
}
public FormBuilder addSubmitButton(final String name, final String value) {
appendSimpleInput("submit", name, value);
return this;
}
public FormBuilder addSubmitImage(final String name, final String value) {
appendSimpleInput("image", name, value);
return this;
}
public FormBuilder addCheckbox(final String name, final String value) {
appendSimpleInput("checkbox", name, value);
return this;
}
public FormBuilder addCheckedCheckbox(final String name, final String value) {
appendSimpleInput("checkbox", name, value, "checked");
return this;
}
public FormBuilder addRadioButton(final String name, final String value) {
appendSimpleInput("radio", name, value);
return this;
}
public FormBuilder addCheckedRadioButton(final String name, final String value) {
appendSimpleInput("radio", name, value, "checked");
return this;
}
public SelectBuilder beginSelect(final String name) {
return new SelectBuilder(name, false);
}
public SelectBuilder beginMultiSelect(final String name) {
return new SelectBuilder(name, true);
}
@Override
public String toString() {
StringBuilder form = new StringBuilder();
form.append("<form");
appendIfSet(form, "action", action);
appendIfSet(form, "id", id);
appendIfSet(form, "name", name);
appendIfSet(form, "enctype", enctype);
appendIfSet(form, "method", method);
form.append(">");
form.append(content.toString());
form.append("</form>");
return form.toString();
}
private void appendIfSet(final StringBuilder builder, final String name, final String value) {
if(value != null)
builder.append(" " + name + "='" + value + "'");
}
public class SelectBuilder {
public SelectBuilder(final String name, final boolean isMultiple) {
content.append("<select name='" + name + "'" + (isMultiple ? " multiple" : "") + ">");
}
public SelectBuilder addOption(final String text) {
return addOption(text, text);
}
public SelectBuilder addOption(final String text, final String value) {
return addOption(text, value, false);
}
public SelectBuilder addOption(final String text, final String value, final boolean isSelected) {
content.append("<option");
if(text != value)
content.append(" value='" + value + "'");
if(isSelected)
content.append(" selected");
content.append(">");
content.append(text);
content.append("</option>");
return this;
}
public SelectBuilder addSelectedOption(final String text, final String value) {
return addOption(text, value, true);
}
public FormBuilder end() {
content.append("</select>");
return FormBuilder.this;
}
}
}
@Test
public void testEmptyFormWithGetMethod() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form")));
addPageRequest("http://test.com/form", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
Resource response = form.submit();
assertEquals("OK", response.getTitle());
assertFalse(form.isDoPost());
}
@Test
public void testEmptyFormWithPostMethod() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form", "post").id("form")));
addPageRequest("POST", "http://test.com/form", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
AbstractDocument response = form.submit();
assertEquals("OK", response.getTitle());
assertTrue(form.isDoPost());
}
@Test
public void testSimpleInputNoText() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").addText("text", null)));
addPageRequest("http://test.com/form?text=", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
AbstractDocument response = form.submit();
assertEquals("OK", response.getTitle());
}
@Test
public void testSimpleInputWithDefaultText() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").addText("text", "Text")));
addPageRequest("http://test.com/form?text=Text", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
AbstractDocument response = form.submit();
assertEquals("OK", response.getTitle());
}
@Test
public void testSimpleInputSettingValueToValueBiggerThanMaxLengthWillGetAutomaticallyTruncated() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").addText("text", null, 5)));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
form.find(byIdOrName("text")).set("123456789");
assertEquals("12345", form.get("text").get());
}
@Test
public void testEmailInputFieldWithNoText() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").addInput("mail", "email", null)));
addPageRequest("http://test.com/form?mail=", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
FormElement email = form.find(byIdOrName("mail"));
assertTrue(email instanceof Email);
assertSame(email, form.findEmail(byName("mail")));
assertSame(email, form.findAll(byName("mail"), Email.class).get(0));
AbstractDocument response = form.submit();
assertEquals("OK", response.getTitle());
}
@Test
public void testUnrecognizedInputFieldWithNoText() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").addInput("unknown", "unknownType", null)));
addPageRequest("http://test.com/form?unknown=test", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
FormElement unknown = form.find(byName("unknown"));
assertNotNull(unknown);
assertTrue(unknown instanceof FormElement);
unknown.setValue("test");
AbstractDocument response = form.submit();
assertEquals("OK", response.getTitle());
}
@Test
public void testInputTextWithName() {
String newHtml = newHtml("Test Page", newForm("form").id("form")
.addRaw("<input type=\"text\" class=\"txt\" name=\"login\" size=\"30\" onfocus=\"hlFF(this, true);\" onblur=\"hlFF(this);\">"));
addPageRequest("http://test.com",
newHtml);
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
FormElement login = form.find(byIdOrName("login"));
assertNotNull(login);
assertTrue(login instanceof FormElement);
login.setValue("test");
}
@Test
public void testTextAreaInputWithDefaultText() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").addTextArea("text", "Text")));
addPageRequest("http://test.com/form?text=Text", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
AbstractDocument response = form.submit();
assertEquals("OK", response.getTitle());
}
public void testTextAreaInputWithChangedValue() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").addTextArea("text", "Text")));
addPageRequest("http://test.com/form?text=differentText", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
form.findTextArea(byIdOrName("text")).setValue("differentText");
AbstractDocument response = form.submit();
assertEquals("OK", response.getTitle());
}
@Test
public void testHiddenInput() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").addHidden("hidden", "Text")));
addPageRequest("http://test.com/form?hidden=Text", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
AbstractDocument response = form.submit();
assertEquals("OK", response.getTitle());
}
@Test(expected = UnsupportedOperationException.class)
public void testSettingValueOfSubmitButtonFails() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").addSubmitButton("button", "Text")));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
form.find(byIdOrName("button")).setValue("shouldFail");
}
@Test
public void testSimpleLoginFormWithTextAndPasswordAndSubmitButtonSubmittingByButton() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").addText("user", null).addPassword("pass", null).addSubmitButton("submit", "pressed")));
addPageRequest("http://test.com/form?user=username&pass=password&submit=pressed", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
form.find(byIdOrName("user")).setValue("username");
form.find(byIdOrName("pass")).setValue("password");
AbstractDocument response = form.findSubmitButton(byIdOrName("submit")).submit();
assertEquals("OK", response.getTitle());
}
@Test
public void testSimpleLoginFormWithTextAndPasswordAndSubmitButtonSubmittingByPressingEnter() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").addText("user", null).addPassword("pass", null).addSubmitButton("submit", "pressed")));
addPageRequest("http://test.com/form?user=username&pass=password", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
form.find(byIdOrName("user")).setValue("username");
form.find(byIdOrName("pass")).setValue("password");
AbstractDocument response = form.submit();
assertEquals("OK", response.getTitle());
}
@Test
public void testCheckboxForm() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").addCheckbox("box", "value1").addCheckedCheckbox("box", "value2").addCheckedCheckbox("box", "value3")));
addPageRequest("http://test.com/form?box=value1&box=value3", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
assertFalse(form.findCheckbox(byIdOrName("box"), "value1").isChecked());
assertTrue(form.findCheckbox(byIdOrName("box"), "value2").isChecked());
assertTrue(form.findCheckbox(byIdOrName("box"), "value3").isChecked());
assertEquals(3, form.findAll(byIdOrName("box"), Checkbox.class).size());
form.findCheckbox(byIdOrName("box"), "value1").check();
form.findCheckbox(byIdOrName("box"), "value2").uncheck();
AbstractDocument response = form.submit();
assertEquals("OK", response.getTitle());
}
@Test(expected = UnsupportedOperationException.class)
public void testSettingValueOfCheckboxFails() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").addCheckbox("box", "value")));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
form.findCheckbox(byIdOrName("box")).setValue("shouldFail");
}
@Test
public void testRadioButtonForm() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").addRadioButton("button", "value1").
addCheckedRadioButton("button", "value2").addRadioButton("button", "value3")));
addPageRequest("http://test.com/form?button=value3", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
assertFalse(form.findRadioButton(byIdOrName("button"), "value1").isChecked());
assertTrue(form.findRadioButton(byIdOrName("button"), "value2").isChecked());
assertFalse(form.findRadioButton(byIdOrName("button"), "value3").isChecked());
assertEquals(3, form.findAll(byIdOrName("button"), RadioButton.class).size());
form.findRadioButton(byIdOrName("button"), "value3").check();
assertFalse(form.findRadioButton(byIdOrName("button"), "value1").isChecked());
assertFalse(form.findRadioButton(byIdOrName("button"), "value2").isChecked());
assertTrue(form.findRadioButton(byIdOrName("button"), "value3").isChecked());
AbstractDocument response = form.submit();
assertEquals("OK", response.getTitle());
}
@Test(expected = UnsupportedOperationException.class)
public void testSettingValueOfRadioButtonFails() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").addRadioButton("button", "value")));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
form.findRadioButton(byIdOrName("button")).setValue("shouldFail");
}
@Test
public void testSingleElementSelect() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").beginSelect("person").addOption("Peter", "1").addOption("John", "2").addSelectedOption("Susanna", "3").end()));
addPageRequest("http://test.com/form?person=1", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
Select select = form.findSelect(byIdOrName("person"));
assertFalse(select.isMultiple());
assertEquals(3, select.getOptions().size());
Option peter = select.getOption("Peter");
assertEquals("Peter", peter.getText());
assertEquals("1", peter.getValue());
assertFalse(peter.isSelected());
Option john = select.getOption("John");
assertEquals("John", john.getText());
assertEquals("2", john.getValue());
assertFalse(john.isSelected());
assertTrue(select.getOption("Susanna").isSelected());
peter.select();
assertTrue(peter.isSelected());
assertFalse(john.isSelected());
assertFalse(select.getOption("Susanna").isSelected());
AbstractDocument response = form.submit();
assertEquals("OK", response.getTitle());
}
@Test
public void testMultipleElementSelect() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").beginMultiSelect("person").addOption("Peter", "1").addSelectedOption("John", "2").addOption("Susanna", "3").end()));
addPageRequest("http://test.com/form?person=2&person=3", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
Select select = form.findSelect(byIdOrName("person"));
assertTrue(select.isMultiple());
assertFalse(select.getOption("Peter").isSelected());
assertTrue(select.getOption("John").isSelected());
assertFalse(select.getOption("Susanna").isSelected());
assertEquals(3, select.getOptions().size());
select.getOption("Peter").select();
assertTrue(select.getOption("Peter").isSelected());
assertTrue(select.getOption("John").isSelected());
assertFalse(select.getOption("Susanna").isSelected());
select.getOption("Susanna").select();
select.getOption("Peter").unselect();
assertFalse(select.getOption("Peter").isSelected());
assertTrue(select.getOption("John").isSelected());
assertTrue(select.getOption("Susanna").isSelected());
AbstractDocument response = form.submit();
assertEquals("OK", response.getTitle());
}
@Test(expected = UnsupportedOperationException.class)
public void testSettingValueOfSelectFails() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").beginSelect("person").addOption("Peter", "1").addOption("John", "2").addSelectedOption("Susanna", "3").end()));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
form.findSelect(byIdOrName("person")).setValue("shouldFail");
}
@Test
public void testImageToSubmitForm() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").addSubmitImage("submitImage", "value")));
addPageRequest("http://test.com/form?submitImage=value&submitImage.x=20&submitImage.y=10", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
AbstractDocument response = form.findSubmitImage(byIdOrName("submitImage")).submit(20, 10);
assertEquals("OK", response.getTitle());
}
@Test(expected = UnsupportedOperationException.class)
public void testSettingValueOfSubmitImageFails() {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").id("form").addSubmitImage("submitImage", "value")));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
form.findSubmitImage(byIdOrName("submitImage")).setValue("shouldFail");
}
@Test
public void testSimpleFileUpload() throws Exception {
File tmpFile = File.createTempFile("mechanize", "tmp");
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").method("post").id("form").enctype("multipart/form-data").addFileInput("fileUpload", "")));
addPageRequest("POST", "http://test.com/form", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
form.findUpload(byIdOrName("fileUpload")).setValue(tmpFile);
AbstractDocument response = form.submit();
assertEquals("OK", response.getTitle());
}
/**
*
* @throws Exception
*/
@Test
public void testFileUploadWithNoFile() throws Exception {
addPageRequest("http://test.com",
newHtml("Test Page", newForm("form").method("post").id("form").enctype("multipart/form-data").addFileInput("fileUpload", null)));
addPageRequest("POST", "http://test.com/form", newHtml("OK", ""));
AbstractDocument page = agent().get("http://test.com");
Form form = page.forms().find("#form");
AbstractDocument response = form.submit();
assertEquals("OK", response.getTitle());
}
//TODO Find a better test
// @Test
// public void testFileUploadingByUsingMegaFileUpload() {
// Mechanize agent = new Mechanize();
// Page page = agent.get("http://www.megafileupload.com/");
// Form form = page.forms().findByName("uploadform");
// Upload upload = form.getUpload("uploadfile_0");
// File file = new File(FormTest.class.getResource("test.html").getFile());
// upload.setValue(file);
// Page response = form.submit();
// assertTrue(response.getUri().startsWith("http://94.75.216.85/cgi-bin/upload.cgi"));
// }
}