Package com.canoo.webtest.steps.form

Source Code of com.canoo.webtest.steps.form.AbstractSetFieldStep

// Copyright � 2002-2005 Canoo Engineering AG, Switzerland.
package com.canoo.webtest.steps.form;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.xml.sax.SAXException;

import com.canoo.webtest.engine.IStringVerifier;
import com.canoo.webtest.engine.StepFailedException;
import com.canoo.webtest.extension.StoreElementAttribute;
import com.canoo.webtest.steps.AbstractBrowserAction;
import com.canoo.webtest.steps.Step;
import com.canoo.webtest.util.ConversionUtil;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlLabel;
import com.gargoylesoftware.htmlunit.html.HtmlPage;

/**
* Abstract class for steps which update form fields.
* This class handles the attributes name/formName, htmlId or xpath.
*
* @author Marc Guillemot
* @author Paul King
* @author Denis N. Antonioli
*/
public abstract class AbstractSetFieldStep extends AbstractBrowserAction {
  private static final Logger LOG = Logger.getLogger(AbstractSetFieldStep.class);

  public static final String MESSAGE_ARGUMENT_MISSING = "One of 'forLabel', 'htmlId', 'name', or 'xpath' must be set!";
  public static final String MESSAGE_ARGUMENT_REDUNDANT = "Only one of 'forLabel', 'htmlId', 'name', and 'xpath' should be set!";

  private String fName;
    private String fXPath;
    private String fFormName;
    private String fFieldIndex;
    private String fHtmlId;
    private String fForLabel;

    /**
     * Set the name.
     * @param name
     * @webtest.parameter required="yes/no"
     * description="The name of the input field of interest.
     * One of <em>forLabel</em>, <em>htmlId</em>, <em>name</em>, or <em>xpath</em> is required."
     */
    public void setName(final String name) {
        fName = name;
    }

    public String getName() {
        return fName;
    }

    /**
     * Set the text of the label associated with the field to set.
     * @param text the label text
     * @webtest.parameter required="yes/no"
     * description="The text of the label field associated with the input field of interest.
     * One of <em>forLabel</em>, <em>htmlId</em>, <em>name</em>, or <em>xpath</em> is required."
     */
    public void setForLabel(final String text) {
        fForLabel = text;
    }

    public String getForLabel() {
        return fForLabel;
    }

    public String getXpath() {
        return fXPath;
    }

    /**
   * Set the xpath.
   *
   * @param xpath
   * @webtest.parameter required="yes/no"
   * description="The xpath of the input field of interest.
     * One of <em>forLabel</em>, <em>htmlId</em>, <em>name</em>, or <em>xpath</em> is required."
   */
  public void setXpath(final String xpath) {
    fXPath = xpath;
  }

    /**
     * Set the form name.
     * @param formName
     * @webtest.parameter required="no"
     * default="the last form selected using 'selectForm', otherwise searches all forms"
     * description="The name of the form containing the field of interest. Ignored if <em>htmlId</em> is used."
     */
    public void setFormName(final String formName) {
        fFormName = formName;
    }

    public String getFormName() {
        return fFormName;
    }

    public String getHtmlId() {
        return fHtmlId;
    }

    /**
   * Set the html id.
   *
   * @param htmlId
   * @webtest.parameter required="yes/no"
   * description="The id of the input field of interest.
     * One of <em>forLabel</em>, <em>htmlId</em>, <em>name</em>, or <em>xpath</em> is required."
   */
  public void setHtmlId(final String htmlId) {
    fHtmlId = htmlId;
  }

  /**
   * Set the index.
   *
   * @param index
   * @webtest.parameter required="no"
   * default="the first field found that matches criteria"
   * description="The index of the field of interest (starting at 0) if more than one field matches criteria. Ignored if <em>htmlId</em> or <em>xpath</em> is used."
   */
  public void setFieldIndex(final String index) {
    fFieldIndex = index;
  }

  public String getFieldIndex() {
    return fFieldIndex;
  }

  public void doExecute() throws SAXException, IOException {
    if (fName != null) {
      final HtmlForm form = findForm();
      if (form == null) {
        throw new StepFailedException("No suitable form found having field named \"" + getName() + "\"", this);
      }
      LOG.debug("Found matching form " + form);
      setField(selectField(trimFields(findFields(form)), getFieldIndex(), this));
    }
    else if (getForLabel() != null)
    {
      setField(findFieldByLabel(getContext().getCurrentHtmlResponse(this), getForLabel()));
    }
    else { // htmlId, xpath
      setField(StoreElementAttribute.findElement(getContext().getCurrentHtmlResponse(this), getHtmlId(), getXpath(), LOG, this));
    }
  }

  /**
   * Retrieves the (first) field associated with the label containing the provided text
   * @param page the page to search in
   * @param labelText the text of the label
   * @return the associated form field
   * @throws StepFailedException if no field is found
   */
  HtmlElement findFieldByLabel(final HtmlPage page, final String labelText)
  {
    LOG.debug("Searching label tag with text: " + labelText);
    final List labels = page.getDocumentElement().getHtmlElementsByTagName("label");
    LOG.debug(labels.size() + " found in the page");
   
    final IStringVerifier verifier = getVerifier(false);
    for (final Iterator iter=labels.iterator(); iter.hasNext();)
    {
      final HtmlLabel label = (HtmlLabel) iter.next();
      if (verifier.verifyStrings(labelText, label.asText()))
      {
        LOG.debug("Found label with matching text, examining the associated field: " + label);
        final HtmlElement target = label.getReferencedElement();
        if (keepField(target))
        {
          LOG.debug("Found field: " + target);
          return target;
        }
        else
        {
          LOG.debug("Target doesn't match: " + target);
        }
      }
    }
    throw new StepFailedException("No label found with text \"" + labelText + "\"", this);
  }

  /**
   * Sets a field according to the step.
   * It is up to the step's implementation to decide how to set the step.
   *
   * @param field The field to set.
   */
  protected abstract void setField(HtmlElement field) throws IOException;

  /**
   * Finds the relevant form.
   *
   * @return The found form.
   */
  protected abstract HtmlForm findForm();

  /**
   * Finds all possible input fields. This is a generic implementation, sub-classes may want to take advantage
   * of more specific functions.
   *
   * @param form The form to search.
   * @return A list of candidate fields.
   */
  protected List findFields(final HtmlForm form) {
    return form.getInputsByName(fName);
  }

  /**
   * Apply {@link #keepField(com.gargoylesoftware.htmlunit.html.HtmlElement)} to trim the list of fields found.
   *
   * @param fields All fields found.
   * @return A list of candidate fields.
   */
  protected List trimFields(final List fields) {
    for (final Iterator iter = fields.iterator(); iter.hasNext();) {
      final HtmlElement elt = (HtmlElement) iter.next();
      LOG.debug("Considering element " + elt);
      if (!keepField(elt)) {
        iter.remove();
      }
    }
    LOG.debug("Found " + fields.size() + " field(s)");
    return fields;
  }

  /**
   * Called by {@link #findFields(com.gargoylesoftware.htmlunit.html.HtmlForm)} to filter out elements
   * with the correct name but not matching some other selection criteria.
   * @param elt One of the elements with the correct name.
   * @return True if the element is accepted.
   */
  protected boolean keepField(HtmlElement elt) {
    return true;
  }

  /**
   * Finds the desired field by selecting either a specific field designated by
   * indexStr or the first one if indexStr is left blank
   *
   * @param fieldList A list of {@link HtmlElement fields}.
   * @param indexStr The index of the desired field.
   * @param step The calling step, for exception.
   * @return The selected field
   */
  public static HtmlElement selectField(final List fieldList, final String indexStr, final Step step) {
    if (fieldList.isEmpty()) {
      throw new StepFailedException("No suitable field(s) found", step);
    }

    int numFieldsFound = fieldList.size();
    int index;
    if (StringUtils.isEmpty(indexStr)) {
      LOG.info("Found " + numFieldsFound + " suitable fields, considering only the first one");
      index = 0;
    } else {
      index = ConversionUtil.convertToInt(indexStr, 0);
      if (index < 0 || index >= numFieldsFound) {
        throw new StepFailedException("Can't set field with index '" + index + "', valid range is 0.." + (numFieldsFound - 1), step);
      }
    }
    return (HtmlElement) fieldList.get(index);
  }

  protected void verifyParameters() {
    super.verifyParameters();

    nullResponseCheck();

    int count = 0;
    if (fXPath != null) {
      count++;
    }
    if (fName != null) {
      count++;
    }
    if (fHtmlId != null) {
      count++;
    }
    if (getForLabel() != null) {
      count++;
    }
    paramCheck(count == 0, MESSAGE_ARGUMENT_MISSING);
    paramCheck(count > 1, MESSAGE_ARGUMENT_REDUNDANT);
    if (fName == null) {
      paramCheck(fFieldIndex != null, "The attribute 'fieldIndex' is only valid with the attribute 'name'.");
    } else {
      optionalIntegerParamCheck(fFieldIndex, "fieldIndex", false);
    }
  }
}
TOP

Related Classes of com.canoo.webtest.steps.form.AbstractSetFieldStep

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.