// Copyright � 2004-2007 ASERT. Released under the Canoo Webtest license.
package com.canoo.webtest.extension.dialogs;
import com.canoo.webtest.ant.WebtestTask;
import com.canoo.webtest.boundary.AntBoundary;
import com.canoo.webtest.engine.Context;
import com.canoo.webtest.engine.StepFailedException;
import com.canoo.webtest.steps.AbstractStepContainer;
import com.canoo.webtest.steps.Step;
import com.canoo.webtest.util.ConversionUtil;
import com.gargoylesoftware.htmlunit.*;
import org.apache.commons.lang.ClassUtils;
import org.apache.log4j.Logger;
import org.apache.tools.ant.Task;
import java.util.Iterator;
/**
* Saves away one or more JavaScript dialog expectations in preparation for subsequent automatic user response(s).<p>
*
* @author Paul King, ASERT
* @webtest.step category="Extension"
* name="expectDialogs"
* description="Provides the ability to set expectations in relation to user responses to <key>javascript</key> Dialog boxes (Alert, Confirm and Prompt dialogs). Supports nested dialog steps such as <stepref name='alert'/>, <stepref name='confirm'/> and <stepref name='prompt'/>. See also the <stepref name='verifyNoDialogs'/> step."
*/
public class ExpectDialogs extends AbstractStepContainer
{
private static final Logger LOG = Logger.getLogger(ExpectDialogs.class);
public void doExecute() {
final Context context = getContext();
DialogHelper.clearExpectedDialogs(context);
final WebClient wc = context.getWebClient();
for (final Iterator iter = getSteps().iterator(); iter.hasNext();) {
final Step step = (Step) iter.next();
DialogHelper.addExpectedDialog(context, (AbstractDialogStep) step);
executeContainedStep(step);
}
final CheckingDialogHandler handler = new CheckingDialogHandler(context, this);
wc.setAlertHandler(handler);
wc.setConfirmHandler(handler);
wc.setPromptHandler(handler);
LOG.debug("Dialog expectation saved - now expecting "
+ DialogHelper.getExpectedDialogsCount(context) + " dialog(s).");
}
public void addTask(final Task newTask) {
final Task task = AntBoundary.maybeConfigure(newTask);
if (task instanceof AbstractDialogStep) {
super.addTask(task);
} else {
throw new StepFailedException("Not a dialog step: " + task);
}
}
static class CheckingDialogHandler implements AlertHandler, ConfirmHandler, PromptHandler
{
private final Context fContext;
private final Step fOuter;
CheckingDialogHandler(final Context context, final Step outer) {
this.fContext = context;
this.fOuter = outer;
}
public void handleAlert(final Page page, final String message) {
checkContext();
checkDialog(message, "AlertDialog");
}
/**
* Checks that the context information is available for this thread
* indeed dialog handler may be called back from HtmlUnit in a different thread
*/
private void checkContext()
{
if (WebtestTask.getThreadContext() == null)
{
WebtestTask.setThreadContext(fContext);
}
}
public boolean handleConfirm(final Page page, final String message) {
checkContext();
final AbstractDialogStep thisDialog = checkDialog(message, "ConfirmDialog");
return ConversionUtil.convertToBoolean(thisDialog.getResponse(), true);
}
public String handlePrompt(final Page page, final String message) {
checkContext();
final AbstractDialogStep thisDialog = checkDialog(message, "PromptDialog");
return thisDialog.getResponse();
}
private AbstractDialogStep checkDialog(final String message, final String dialogType) {
checkExpectationsSet(fContext);
final AbstractDialogStep thisDialog = DialogHelper.getNextExpectedDialog(fContext);
saveResponse(thisDialog, message);
checkResponseType(thisDialog, dialogType);
thisDialog.verify(message);
return thisDialog;
}
private void checkExpectationsSet(final Context context) {
if (DialogHelper.getExpectedDialogsCount(context) == 0) {
throw new StepFailedException("Expected dialogs but none found!", fOuter);
}
}
private void saveResponse(final AbstractDialogStep thisDialog, final String message) {
if (thisDialog.getSaveProperty() != null) {
fOuter.setWebtestProperty(thisDialog.getSaveProperty(), message,
thisDialog.getSavePropertyType());
}
}
private void checkResponseType(final AbstractDialogStep thisDialog, final String dialogType) {
final String name = ClassUtils.getShortClassName(thisDialog.getClass());
final String prefix = name.substring(0, name.length() - 4);
if (!prefix.equals(dialogType)) {
throw new StepFailedException("Incorrect dialog type", dialogType, prefix, fOuter);
}
}
}
}