They've added getAnchorByText and getOptionByText. This means I can remove some of the code from my ad hoc HtmlUnitUtils class. Of course, there are still more it'd be nice to see. I include here the whole of my utils class so that they may pick away at it for anything else they may want to incorporate.
Naturally I don't expect it all, or even most. But whatever they may add is awesome as it means less code for me to maintain!
package com.kennardconsulting.core.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import org.metawidget.util.CollectionUtils;
import org.metawidget.util.simple.StringUtils;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.WebWindow;
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlFileInput;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlOption;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlRadioButtonInput;
import com.gargoylesoftware.htmlunit.html.HtmlSelect;
import com.gargoylesoftware.htmlunit.html.HtmlTable;
import com.kennardconsulting.core.enumeration.FileFormat;
/**
* Utilities for working with HtmlUnit.
*/
public final class HtmlUnitUtils
{
//
// Public statics
//
public static HtmlAnchor getLink( HtmlPage response, String text )
{
List<HtmlAnchor> links = getLinks( response, text );
if ( links.isEmpty() )
throw new RuntimeException( "No such link with exact text of '" + text + "'" );
if ( links.size() > 1 )
throw new RuntimeException( "More than one link with exact text of '" + text + "'" );
return links.get( 0 );
}
public static List<HtmlAnchor> getLinks( HtmlPage response, String text )
{
return getLinks( response, text, false );
}
public static List<HtmlAnchor> getLinks( HtmlPage response, String text, boolean contains )
{
List<HtmlAnchor> anchors = CollectionUtils.newArrayList();
for ( HtmlAnchor anchor : response.getAnchors() )
{
String anchorText = anchor.asText();
anchorText = anchorText.replaceAll( "\r", "" );
if ( contains )
{
if ( !anchorText.contains( text ) )
continue;
}
else
{
if ( !anchorText.equals( text ) )
continue;
}
anchors.add( anchor );
}
return anchors;
}
@SuppressWarnings( "unchecked" )
public static <T extends HtmlElement> T getInputByNameEndingWith( HtmlForm form, String nameEndingWith )
{
for ( HtmlElement element : form.getHtmlElementsByTagName( "input" ) )
{
String elementName = element.getAttribute( "name" );
if ( elementName == null )
continue;
if ( elementName.endsWith( nameEndingWith ) )
return (T) element;
}
return null;
}
public static HtmlOption getSelectedOption( HtmlForm form, String selectName )
{
return getSelectedOption( form.getSelectByName( selectName ) );
}
public static HtmlOption getSelectedOption( HtmlSelect select )
{
List<HtmlOption> selectedOptions = select.getSelectedOptions();
if ( selectedOptions.isEmpty() )
return null;
if ( selectedOptions.size() > 1 )
throw new RuntimeException( "'" + select.getNameAttribute() + "' has more than one option selected" );
return selectedOptions.get( 0 );
}
public static String setSelectedOption( HtmlForm form, String selectName, String option )
{
return setSelectedOption( form.getSelectByName( selectName ), option );
}
public static String setSelectedOption( HtmlForm form, String selectName, String option, boolean allowOnlyOne )
{
return setSelectedOption( form.getSelectByName( selectName ), option, allowOnlyOne );
}
public static String setSelectedOption( HtmlSelect select, String option )
{
return setSelectedOption( select, option, true );
}
public static String setSelectedOption( HtmlSelect select, String option, boolean allowOnlyOne )
{
String selectedValue = null;
for ( HtmlOption htmlOption : select.getOptions() )
{
String htmlOptionText = htmlOption.asText();
// Special support for trimming off , which we use for indenting select options
htmlOptionText = htmlOptionText.trim();
if ( htmlOptionText.equals( option ) )
{
if ( selectedValue != null )
throw new RuntimeException( "Select '" + select.getNameAttribute() + "' has more than one '" + option + "'" );
selectedValue = htmlOption.getValueAttribute();
htmlOption.setSelected( true );
if ( !allowOnlyOne )
break;
}
}
if ( selectedValue == null )
throw new RuntimeException( "Select '" + select.getNameAttribute() + "' does not contain '" + option + "'" );
return selectedValue;
}
public static String setSelectedOptionValue( HtmlForm form, String selectName, String option )
{
return setSelectedOptionValue( form.getSelectByName( selectName ), option );
}
public static String setSelectedOptionValue( HtmlSelect select, String optionValue )
{
String selectedValue = null;
for ( HtmlOption htmlOption : select.getOptions() )
{
if ( htmlOption.getValueAttribute().equals( optionValue ) )
{
if ( selectedValue != null )
throw new RuntimeException( "Select '" + select.getNameAttribute() + "' has more than one '" + optionValue + "'" );
selectedValue = htmlOption.getValueAttribute();
htmlOption.setSelected( true );
}
}
if ( selectedValue == null )
throw new RuntimeException( "Select '" + select.getNameAttribute() + "' does not contain value '" + optionValue + "'" );
return selectedValue;
}
public static boolean hasOption( HtmlForm form, String selectName, boolean selected, String... options )
{
int found = 0;
for ( HtmlOption htmlOption : form.getSelectByName( selectName ).getOptions() )
{
for ( String option : options )
{
if ( htmlOption.asText().equals( option ) )
{
if ( selected && !htmlOption.isSelected() )
return false;
found++;
break;
}
}
}
return ( found == options.length );
}
public static boolean hasOptionValue( HtmlForm form, String selectName, boolean selected, String... options )
{
int found = 0;
for ( HtmlOption htmlOption : form.getSelectByName( selectName ).getOptions() )
{
for ( String option : options )
{
if ( htmlOption.getValueAttribute().equals( option ) )
{
if ( selected && !htmlOption.isSelected() )
return false;
found++;
break;
}
}
}
return ( found == options.length );
}
public static String getOptionValue( HtmlForm form, String selectName, String option )
{
for ( HtmlOption htmlOption : form.getSelectByName( selectName ).getOptions() )
{
if ( htmlOption.asText().equals( option ) )
return htmlOption.getValueAttribute();
}
throw new RuntimeException( "No option with text '" + option + "' found" );
}
public static void setSelectedRadio( HtmlForm form, String radioName, String value )
{
boolean selectedOne = false;
for ( HtmlRadioButtonInput htmlRadioButtonInput : form.getRadioButtonsByName( radioName ) )
{
if ( !htmlRadioButtonInput.getValueAttribute().trim().equals( value ) )
continue;
if ( selectedOne )
throw new RuntimeException( "Radio button group '" + radioName + "' has more than one '" + value + "'" );
selectedOne = true;
htmlRadioButtonInput.setChecked( true );
}
if ( !selectedOne )
throw new RuntimeException( "Radio button group '" + radioName + "' has no option '" + value + "'" );
}
public static boolean hasRadio( HtmlForm form, String radioName, String value )
{
for ( HtmlRadioButtonInput htmlRadioButtonInput : form.getRadioButtonsByName( radioName ) )
{
if ( htmlRadioButtonInput.getValueAttribute().trim().equals( value ) )
return true;
}
return false;
}
public static String getSelectedRadioValue( HtmlForm form, String radioName )
{
HtmlRadioButtonInput radioButtonInputSelected = null;
for ( HtmlRadioButtonInput htmlRadioButtonInput : form.getRadioButtonsByName( radioName ) )
{
if ( !htmlRadioButtonInput.isChecked() )
continue;
if ( radioButtonInputSelected != null )
throw new RuntimeException( "Radio button group '" + radioName + "' has more than one selected" );
radioButtonInputSelected = htmlRadioButtonInput;
}
if ( radioButtonInputSelected == null )
return null;
return radioButtonInputSelected.getValueAttribute();
}
@SuppressWarnings( "unchecked" )
public static <E extends HtmlElement> E getElementByAttribute( HtmlPage page, String elementName, String attributeName, String attributeValue )
{
return (E) getElementByAttribute( page.getDocumentElement(), elementName, attributeName, attributeValue );
}
public static <E extends HtmlElement> E getElementByAttribute( HtmlElement element, String elementName, String attributeName, String attributeValue )
{
List<E> elements = element.getElementsByAttribute( elementName, attributeName, attributeValue );
if ( elements.isEmpty() )
return null;
if ( elements.size() > 1 )
throw new RuntimeException( "More than one " + elementName + " with " + attributeName + " of '" + attributeValue + "'" );
return elements.get( 0 );
}
public static <E extends HtmlElement> E getElementByAttributeContaining( HtmlPage page, String elementName, String attributeName, String attributeValueContained )
{
List<E> elements = getElementsByAttributeContaining( page, elementName, attributeName, attributeValueContained );
if ( elements.isEmpty() )
return null;
if ( elements.size() > 1 )
throw new RuntimeException( "More than one " + elementName + " with " + attributeName + " containing '" + attributeValueContained + "': " + CollectionUtils.toString( elements ) );
return elements.get( 0 );
}
/**
* @return the elements, in the order they are declared in the HTML.
*/
@SuppressWarnings( "unchecked" )
public static <E extends HtmlElement> List<E> getElementsByAttributeContaining( HtmlPage page, String elementName, String attributeName, String attributeValueContained )
{
List<E> toReturn = CollectionUtils.newArrayList();
NodeList nodeList = page.getElementsByTagName( elementName );
for ( int loop = 0, length = nodeList.getLength(); loop < length; loop++ )
{
Node node = nodeList.item( loop );
Node nodeValue = node.getAttributes().getNamedItem( attributeName );
if ( nodeValue == null )
continue;
if ( nodeValue.getNodeValue().contains( attributeValueContained ) )
toReturn.add( (E) node );
}
return toReturn;
}
@SuppressWarnings("unchecked")
public static <T extends Page> T waitForAjax( T page )
{
WebWindow window = page.getEnclosingWindow();
window.getThreadManager().joinAll( 10000 );
return (T) window.getEnclosedPage();
}
public static void setUpload( HtmlForm form, String uploadName, String url )
{
setUpload( form, uploadName, CoreStringUtils.substringAfterLast( url, StringUtils.SEPARATOR_FORWARD_SLASH ), url );
}
public static void setUpload( HtmlForm form, String uploadName, String name, String url )
{
try
{
setUpload( form, uploadName, name, new URL( url ).openStream() );
}
catch ( IOException e )
{
throw new RuntimeException( e );
}
}
public static void setUpload( HtmlForm form, String uploadName, String name, InputStream streamIn )
{
HtmlFileInput fileInput = form.getInputByName( uploadName );
ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
try
{
IOUtils.streamBetween( streamIn, streamOut );
}
catch ( IOException e )
{
throw new RuntimeException( e );
}
fileInput.setValueAttribute( name );
fileInput.setData( streamOut.toByteArray() );
}
public static HtmlTable getTableStartingWith( HtmlPage page, String startingWith )
{
NodeList tables = page.getElementsByTagName( "table" );
for( int loop = 0, length = tables.getLength(); loop < length; loop++ )
{
HtmlTable table = (HtmlTable) tables.item( loop );
if ( table.asText().trim().startsWith( startingWith ))
return table;
}
throw new RuntimeException( "No table starting with '" + startingWith + "'" );
}
//
// Private constructor
//
private HtmlUnitUtils()
{
// Can never be called
}
}
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import org.metawidget.util.CollectionUtils;
import org.metawidget.util.simple.StringUtils;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.WebWindow;
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlFileInput;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlOption;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlRadioButtonInput;
import com.gargoylesoftware.htmlunit.html.HtmlSelect;
import com.gargoylesoftware.htmlunit.html.HtmlTable;
import com.kennardconsulting.core.enumeration.FileFormat;
/**
* Utilities for working with HtmlUnit.
*/
public final class HtmlUnitUtils
{
//
// Public statics
//
public static HtmlAnchor getLink( HtmlPage response, String text )
{
List<HtmlAnchor> links = getLinks( response, text );
if ( links.isEmpty() )
throw new RuntimeException( "No such link with exact text of '" + text + "'" );
if ( links.size() > 1 )
throw new RuntimeException( "More than one link with exact text of '" + text + "'" );
return links.get( 0 );
}
public static List<HtmlAnchor> getLinks( HtmlPage response, String text )
{
return getLinks( response, text, false );
}
public static List<HtmlAnchor> getLinks( HtmlPage response, String text, boolean contains )
{
List<HtmlAnchor> anchors = CollectionUtils.newArrayList();
for ( HtmlAnchor anchor : response.getAnchors() )
{
String anchorText = anchor.asText();
anchorText = anchorText.replaceAll( "\r", "" );
if ( contains )
{
if ( !anchorText.contains( text ) )
continue;
}
else
{
if ( !anchorText.equals( text ) )
continue;
}
anchors.add( anchor );
}
return anchors;
}
@SuppressWarnings( "unchecked" )
public static <T extends HtmlElement> T getInputByNameEndingWith( HtmlForm form, String nameEndingWith )
{
for ( HtmlElement element : form.getHtmlElementsByTagName( "input" ) )
{
String elementName = element.getAttribute( "name" );
if ( elementName == null )
continue;
if ( elementName.endsWith( nameEndingWith ) )
return (T) element;
}
return null;
}
public static HtmlOption getSelectedOption( HtmlForm form, String selectName )
{
return getSelectedOption( form.getSelectByName( selectName ) );
}
public static HtmlOption getSelectedOption( HtmlSelect select )
{
List<HtmlOption> selectedOptions = select.getSelectedOptions();
if ( selectedOptions.isEmpty() )
return null;
if ( selectedOptions.size() > 1 )
throw new RuntimeException( "'" + select.getNameAttribute() + "' has more than one option selected" );
return selectedOptions.get( 0 );
}
public static String setSelectedOption( HtmlForm form, String selectName, String option )
{
return setSelectedOption( form.getSelectByName( selectName ), option );
}
public static String setSelectedOption( HtmlForm form, String selectName, String option, boolean allowOnlyOne )
{
return setSelectedOption( form.getSelectByName( selectName ), option, allowOnlyOne );
}
public static String setSelectedOption( HtmlSelect select, String option )
{
return setSelectedOption( select, option, true );
}
public static String setSelectedOption( HtmlSelect select, String option, boolean allowOnlyOne )
{
String selectedValue = null;
for ( HtmlOption htmlOption : select.getOptions() )
{
String htmlOptionText = htmlOption.asText();
// Special support for trimming off , which we use for indenting select options
htmlOptionText = htmlOptionText.trim();
if ( htmlOptionText.equals( option ) )
{
if ( selectedValue != null )
throw new RuntimeException( "Select '" + select.getNameAttribute() + "' has more than one '" + option + "'" );
selectedValue = htmlOption.getValueAttribute();
htmlOption.setSelected( true );
if ( !allowOnlyOne )
break;
}
}
if ( selectedValue == null )
throw new RuntimeException( "Select '" + select.getNameAttribute() + "' does not contain '" + option + "'" );
return selectedValue;
}
public static String setSelectedOptionValue( HtmlForm form, String selectName, String option )
{
return setSelectedOptionValue( form.getSelectByName( selectName ), option );
}
public static String setSelectedOptionValue( HtmlSelect select, String optionValue )
{
String selectedValue = null;
for ( HtmlOption htmlOption : select.getOptions() )
{
if ( htmlOption.getValueAttribute().equals( optionValue ) )
{
if ( selectedValue != null )
throw new RuntimeException( "Select '" + select.getNameAttribute() + "' has more than one '" + optionValue + "'" );
selectedValue = htmlOption.getValueAttribute();
htmlOption.setSelected( true );
}
}
if ( selectedValue == null )
throw new RuntimeException( "Select '" + select.getNameAttribute() + "' does not contain value '" + optionValue + "'" );
return selectedValue;
}
public static boolean hasOption( HtmlForm form, String selectName, boolean selected, String... options )
{
int found = 0;
for ( HtmlOption htmlOption : form.getSelectByName( selectName ).getOptions() )
{
for ( String option : options )
{
if ( htmlOption.asText().equals( option ) )
{
if ( selected && !htmlOption.isSelected() )
return false;
found++;
break;
}
}
}
return ( found == options.length );
}
public static boolean hasOptionValue( HtmlForm form, String selectName, boolean selected, String... options )
{
int found = 0;
for ( HtmlOption htmlOption : form.getSelectByName( selectName ).getOptions() )
{
for ( String option : options )
{
if ( htmlOption.getValueAttribute().equals( option ) )
{
if ( selected && !htmlOption.isSelected() )
return false;
found++;
break;
}
}
}
return ( found == options.length );
}
public static String getOptionValue( HtmlForm form, String selectName, String option )
{
for ( HtmlOption htmlOption : form.getSelectByName( selectName ).getOptions() )
{
if ( htmlOption.asText().equals( option ) )
return htmlOption.getValueAttribute();
}
throw new RuntimeException( "No option with text '" + option + "' found" );
}
public static void setSelectedRadio( HtmlForm form, String radioName, String value )
{
boolean selectedOne = false;
for ( HtmlRadioButtonInput htmlRadioButtonInput : form.getRadioButtonsByName( radioName ) )
{
if ( !htmlRadioButtonInput.getValueAttribute().trim().equals( value ) )
continue;
if ( selectedOne )
throw new RuntimeException( "Radio button group '" + radioName + "' has more than one '" + value + "'" );
selectedOne = true;
htmlRadioButtonInput.setChecked( true );
}
if ( !selectedOne )
throw new RuntimeException( "Radio button group '" + radioName + "' has no option '" + value + "'" );
}
public static boolean hasRadio( HtmlForm form, String radioName, String value )
{
for ( HtmlRadioButtonInput htmlRadioButtonInput : form.getRadioButtonsByName( radioName ) )
{
if ( htmlRadioButtonInput.getValueAttribute().trim().equals( value ) )
return true;
}
return false;
}
public static String getSelectedRadioValue( HtmlForm form, String radioName )
{
HtmlRadioButtonInput radioButtonInputSelected = null;
for ( HtmlRadioButtonInput htmlRadioButtonInput : form.getRadioButtonsByName( radioName ) )
{
if ( !htmlRadioButtonInput.isChecked() )
continue;
if ( radioButtonInputSelected != null )
throw new RuntimeException( "Radio button group '" + radioName + "' has more than one selected" );
radioButtonInputSelected = htmlRadioButtonInput;
}
if ( radioButtonInputSelected == null )
return null;
return radioButtonInputSelected.getValueAttribute();
}
@SuppressWarnings( "unchecked" )
public static <E extends HtmlElement> E getElementByAttribute( HtmlPage page, String elementName, String attributeName, String attributeValue )
{
return (E) getElementByAttribute( page.getDocumentElement(), elementName, attributeName, attributeValue );
}
public static <E extends HtmlElement> E getElementByAttribute( HtmlElement element, String elementName, String attributeName, String attributeValue )
{
List<E> elements = element.getElementsByAttribute( elementName, attributeName, attributeValue );
if ( elements.isEmpty() )
return null;
if ( elements.size() > 1 )
throw new RuntimeException( "More than one " + elementName + " with " + attributeName + " of '" + attributeValue + "'" );
return elements.get( 0 );
}
public static <E extends HtmlElement> E getElementByAttributeContaining( HtmlPage page, String elementName, String attributeName, String attributeValueContained )
{
List<E> elements = getElementsByAttributeContaining( page, elementName, attributeName, attributeValueContained );
if ( elements.isEmpty() )
return null;
if ( elements.size() > 1 )
throw new RuntimeException( "More than one " + elementName + " with " + attributeName + " containing '" + attributeValueContained + "': " + CollectionUtils.toString( elements ) );
return elements.get( 0 );
}
/**
* @return the elements, in the order they are declared in the HTML.
*/
@SuppressWarnings( "unchecked" )
public static <E extends HtmlElement> List<E> getElementsByAttributeContaining( HtmlPage page, String elementName, String attributeName, String attributeValueContained )
{
List<E> toReturn = CollectionUtils.newArrayList();
NodeList nodeList = page.getElementsByTagName( elementName );
for ( int loop = 0, length = nodeList.getLength(); loop < length; loop++ )
{
Node node = nodeList.item( loop );
Node nodeValue = node.getAttributes().getNamedItem( attributeName );
if ( nodeValue == null )
continue;
if ( nodeValue.getNodeValue().contains( attributeValueContained ) )
toReturn.add( (E) node );
}
return toReturn;
}
@SuppressWarnings("unchecked")
public static <T extends Page> T waitForAjax( T page )
{
WebWindow window = page.getEnclosingWindow();
window.getThreadManager().joinAll( 10000 );
return (T) window.getEnclosedPage();
}
public static void setUpload( HtmlForm form, String uploadName, String url )
{
setUpload( form, uploadName, CoreStringUtils.substringAfterLast( url, StringUtils.SEPARATOR_FORWARD_SLASH ), url );
}
public static void setUpload( HtmlForm form, String uploadName, String name, String url )
{
try
{
setUpload( form, uploadName, name, new URL( url ).openStream() );
}
catch ( IOException e )
{
throw new RuntimeException( e );
}
}
public static void setUpload( HtmlForm form, String uploadName, String name, InputStream streamIn )
{
HtmlFileInput fileInput = form.getInputByName( uploadName );
ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
try
{
IOUtils.streamBetween( streamIn, streamOut );
}
catch ( IOException e )
{
throw new RuntimeException( e );
}
fileInput.setValueAttribute( name );
fileInput.setData( streamOut.toByteArray() );
}
public static HtmlTable getTableStartingWith( HtmlPage page, String startingWith )
{
NodeList tables = page.getElementsByTagName( "table" );
for( int loop = 0, length = tables.getLength(); loop < length; loop++ )
{
HtmlTable table = (HtmlTable) tables.item( loop );
if ( table.asText().trim().startsWith( startingWith ))
return table;
}
throw new RuntimeException( "No table starting with '" + startingWith + "'" );
}
//
// Private constructor
//
private HtmlUnitUtils()
{
// Can never be called
}
}
1 comments:
Thank you Kennard Consulting. The HtmlUnitUtils saved me some time.
Post a Comment