Extension Step expectDialog
Description
Provides the ability to set expectations in relation to user responses to JavaScript Dialog boxes (Alert, Confirm and Prompt dialogs).
This step is used prior to clicking on a link or button which invokes some JavaScript that uses dialogs (Alert, Confirm or Prompt dialogs). If you don't use this step, Canoo WebTest simply clicks 'OK' on every dialog silently. This is OK if you don't care about the Dialogs, but if you do care, you have no way of telling if anything was actually clicked or what messages were displayed in the dialogs.
You may be wondering why you need to set up expectations prior to clicking on a link or button. This is mostly due to implementation issues with the way Canoo WebTest works and the way it calls HtmlUnit . It turns out to be easier at the moment to create a list of dialog expectations. As interactions with your application cause JavaScript to invoke dialogs, we simply look at the next dialog expectation on the list, check that it meets expectations (or optionally save away the dialog message text) and then remove it from the list. For tricky JavaScript there may be multiple interactions from the user. We simply list all the expected dialog interactions in the order we expect them to occur by repeating this step as many times as required. (Alternatively, consider using the newer expectDialogs step which allows more concise expression of dialog sequences.)
Often you will use the verifyNoDialogs step in conjunction with this step to ensure that your expectations for dialogs were met. The verifyNoDialogs step is used after clicking on your link or button - it checks that the list of expected dialogs is now empty, i.e. by the time you have finished interacting with your application all the dialogs you were expecting to need clicking were actually clicked.
Parameters
- description
- Required? no
- The description of this test step.
- dialogType
- Required? no, default is alert
- One of "alert", "confirm" or "prompt".
- response
- Required? no, default is true
- simulate user response: ignored for alerts, converted to boolean for confirms - "OK" (true) or "Cancel" (false), contains typed text for prompts.
- saveProperty
- Required? no
- The name of the property in which to store the dialog text for later checking with "verifyProperty".
- savePropertyType
- Required? no, default is the "defaultPropertyType" as specified in the "config" element is used.
- The type of the property in which to store the dialog text for later checking. Either "ant" or "dynamic".
Details
Normally only one <expectDialog> step will be required but if you have complex JavaScript, it may require the user to respond to multiple dialogs associated with one form or link click. If this is the case (as in the complex example below) you should use multiple <expectDialog> steps in the same order that the user would respond to them in or consider using the enhanced expectDialogs step. If you want to check that no dialogs were in fact used, you must use the expectDialogs step. Only one verifyNoDialogs is ever required after the click event to check that everything worked as planned.
If you were expecting the JavaScript to invoke 2 dialog but only one was in fact invoked, the verifyNoDialogs step will fail with an appropriate error message. Similarly, if you expected only one dialog interaction but more occurred, the intervening click request step will fail.
Simple Example
Consider the following HTML form:
If the user leaves fields blank, we want to pop up an alert as follows:
The HTML might look something like:
<HEAD><TITLE>Simple Dialog Example</TITLE>
<SCRIPT LANGUAGE='JAVASCRIPT'>
function isEmpty(thefield) {
var re = /^\s{1,}$/g; //match white space i.e. space, tab, form-feed, etc.
if ((thefield.value.length==0) || (thefield.value==null)
|| ((thefield.value.search(re)) > -1)) {
return true;
}
return false;
}
function validate(theForm) {
var message="Validation errors in form:\n";
var errorFound = false;
if (isEmpty(theForm.name)) {
message += "Username field must not be blank!\n";
theForm.name.focus();
errorFound = true;
}
if (isEmpty(theForm.password)) {
message += "Password field must not be blank!\n";
if (!errorFound) {
theForm.password.focus();
errorFound = true;
}
}
if (errorFound) {
alert(message);
return false;
}
return true;
}
</SCRIPT>
</HEAD>
<BODY>
<FORM name='myForm' action='' method='post'>
Username: <INPUT type='text' NAME='name' value='' SIZE='30'><br>
Password: <INPUT type='password' NAME='password' value='' SIZE='30'><br>
<INPUT type='button' name='submit' value=' Login '
onClick='return validate(myForm);'>
<INPUT type='reset' name='reset' value=' Clear '>
</FORM>
</BODY>
</HTML>
The test might look something like:
<config .../>
<steps>
<invoke description="Load Page" url="/simpleDialogExample.html"/>
<verifyTitle description="Confirm page" text="Simple Dialog Example"/>
<-- try with both fields blank -->
<expectDialog dialogType="alert" saveProperty="simpleDialog" />
<clickButton description="Click Login button" name="submit" />
<verifyProperty name="simpleDialog" regex="true"
text=".*Username field must not be blank.*"/>
<verifyProperty name="simpleDialog" regex="true"
text=".*Password field must not be blank.*"/>
<verifyNoDialogs description="Check all dialogs were used" />
<-- try with just password field blank -->
<expectDialog dialogType="alert" saveProperty="simpleDialog" />
<setInputField name="name" value="some username" />
<clickButton description="Click Login button" name="submit" />
<not>
<verifyProperty name="simpleDialog" regex="true"
text=".*Username field must not be blank.*"/>
</not>
<verifyProperty name="simpleDialog" regex="true"
text=".*Password field must not be blank.*"/>
<verifyNoDialogs description="Check all dialogs were used" />
<-- try with just username field blank -->
<expectDialog dialogType="alert" saveProperty="simpleDialog" />
<setInputField name="name" value="" />
<setInputField name="password" value="some password" />
<clickButton description="Click Login button" name="submit" />
<verifyProperty name="simpleDialog" regex="true"
text=".*Username field must not be blank.*"/>
<not>
<verifyProperty name="simpleDialog" regex="true"
text=".*Password field must not be blank.*"/>
</not>
<verifyNoDialogs description="Check all dialogs were used" />
<-- try with valid fields -->
<setInputField name="name" value="some username" />
<clickButton description="Click Login button" name="submit" />
<-- would normally check we are on a new page here -->
</steps>
</webtest>
Complex Example
Consider an application which performs some disk administration (the samples below don't actual do anything but show the kind of JavaScript messages that such an application would need to use).
When the user clicks the clean button they receive a JavaScript confirm dialog:
If the user selects "Cancel" they receive the following alert:
If the user selects "OK" they receive the following prompt dialog as a precaution:
If the user then clicks "Cancel" or enters incorrect text, e.g. "No" in the prompt, they receive the following alert dialog:
If the user enters the correct "YES" text and clicks "OK", they receive the following alert dialog (NOTE: nothing happens despite the message - this is just a hypothetical demo):
Here is the relevant part of the build.xml:
<config .../>
<steps>
<invoke description="Load Initial Page" url="/diskadmin.jsp"/>
<verifytitle description="Should be disk admin page" text="Disk Admin Page"/>
<-- check for initial cancel -->
<expectDialog description="Save first JavaScript Response"
dialogType="confirm" response="false" saveProperty="initialDialog" />
<expectDialog description="Save second JavaScript Response"
dialogType="alert" saveProperty="resultDialog" />
<clickbutton description="Click Clean button" name="CleanButton" />
<verifyProperty description="Check text from first JavaScript Dialog"
property="initialDialog" text="Are you sure?" />
<verifyProperty description="Check text from second JavaScript Dialog"
property="resultDialog" text="Operation cancelled!" />
<verifyNoDialogs description="Check all dialogs were used" />
<-- check for initial OK but then cancel instead of confirm -->
<expectDialog description="Save first JavaScript Response"
dialogType="confirm" response="true" saveProperty="initialDialog" />
<expectDialog description="Save second JavaScript Response"
dialogType="prompt" response="false" saveProperty="confirmDialog" />
<expectDialog description="Save third JavaScript Response"
dialogType="alert" saveProperty="resultDialog" />
<clickbutton description="Click Clean button" name="CleanButton" />
<verifyProperty description="Check text from first JavaScript Dialog"
property="initialDialog" text="Are you sure?" />
<verifyProperty description="Check text from second JavaScript Dialog"
property="confirmDialog" regex="true" text=".*very sure.*YES.*" />
<verifyProperty description="Check text from third JavaScript Dialog"
property="resultDialog" text="Operation aborted!" />
<verifyNoDialogs description="Check all dialogs were used" />
<-- check for initial OK followed by confirm -->
<expectDialog description="Save first JavaScript Response"
dialogType="confirm" response="true" saveProperty="initialDialog" />
<expectDialog description="Save second JavaScript Response"
dialogType="prompt" response="YES" saveProperty="confirmDialog" />
<expectDialog description="Save third JavaScript Response"
dialogType="alert" saveProperty="resultDialog" />
<clickbutton description="Click Clean button" name="CleanButton" />
<verifyProperty description="Check text from first JavaScript Dialog"
property="initialDialog" text="Are you sure?" />
<verifyProperty description="Check text from second JavaScript Dialog"
property="confirmDialog" regex="true" text=".*very sure.*YES.*" />
<verifyProperty description="Check text from third JavaScript Dialog"
property="resultDialog" text="Hard disk erased!" />
<verifyNoDialogs description="Check all dialogs were used" />
</steps>
</webtest>
This assumes you have some HTML containing a form and some JavaScript something like the following:
<title>Disk Admin Page</title>
<body>
<script>
function doubleCheck() {
var x=confirm("Are you sure?")
if (x) {
var y=prompt("Are you very sure? Type 'YES' to confirm")
if (y=="YES")
alert("Hard disk erased!")
else
alert("Operation aborted!")
} else
alert("Operation cancelled!")
}
</script>
<h3>Clean Disk?</h3>
<form method="POST">
<p><input type="button" name="CleanButton" value="OK" onclick="doubleCheck()"></p>
</form>
</body>
</html>