Saving Your Automatic Web Page Test Result

Objective

In the previous example, it was shown that we can built functional tests for our web code making sure it comply with the needed functionality or that it continues to work as expected after our modifications.

The next step is to permanently store the result  as proof that it was checked properly and that it is ready for acceptance tests from our clients.

Ruby Interface with a Database

In this example the result is stored in RTH database (Requirements and Testing Hub) -an open source system-. We’ll use a file (RTH_Verify.rb) that was posted in the original RTH forum page and unfortunatelly no longer available. There are four steps, first the initialization of the odbc interface,  creation of a test suite record and update that a test as beeing run, notification of the completed test and close of the connection.

First Part (RTH_Verify.rb)

[This code is from the original developers of RTH]
In this class they initialize the odbc interface to MySQL rth database in a initialize call.
For your instalation you will have to change: yourserver, rth (or your database), yourdbuser, yourdbpassword.

Class Verify
require 'dbi'
def initialize(projectID, testID, testSetID, testName,
 testDir, action, expectedResult, actualResult)
 @projectID = projectID
 @testID = testID
 @testSetID = testSetID
 @testName = testName
 @testDir = testDir
 @action = action
 @expectedResult = expectedResult
 @actualResult = actualResult
 @uniqueRunID = "0"

 #The connection string in your odbc string is:
  #connectionString = '{DSN=rth;DRIVER=MySQL;SERVER=yourserver;DATABASE=rth;UID=yourdbuser;PWD=yourdbpassword;PORT=3306;}'
  @dbh = DBI.connect("dbi:ODBC:rth","yourdbuser","yourdbpassword")
 end

The Second Part (RTH_Verify.rb)
It’s about setting variables: time, sql INSERT string (you can check the file for the complete syntax), sql UPDATE string for the status record. And excecuting the initial notifications of a test being run.

def testStarted
 projid = @projectID.to_s
 tsid = @testSetID.to_s
 tid = @testID.to_s
 tName = @testName.to_s
 tDir = @testDir.to_s
 timeStarted = DateTime.now
 @uniqueRunID = "S"+Time.now.tv_sec.to_s

 # First SQL
 sql = "INSERT INTO ..."  + "VALUES(...)"
 q = @dbh.prepare(sql)
 q.execute

 # Second SQL
 sql = "UPDATE testset_testsuite_assoc SET ... WHERE ..."
 q = @dbh.prepare(sql) 
 q.execute
end

The Thirdh Part (RTH_Verify.rb)
Is the notificaction that the test was compleated, in our watir code it means it was succesfull.

def testCompleted
tsid = @testSetID.to_s
ttid = @testID.to_s
timeFinished = DateTime.now
date=timeFinished.strftime("%Y")+"-"+timeFinished.strftime("%m")+ "-"+timeFinished.strftime("%d")+ " "
date=date+timeFinished.strftime("%H")+ ":"+timeFinished.strftime("%M")+":"+ timeFinished.strftime("%S")
# First SQL
sql = "UPDATE testsuiteresults SET ... WHERE ...";
q = @dbh.prepare(sql)
q.execute # Second SQL
sql="UPDATE testset_testsuite_assoc SET ... WHERE ..."
q = @dbh.prepare(sql)
q.execute
end

Fourth Part (RTH_Verify.rb)
And finally the end of the code to close and disconnect.

 def close
  @dbh.disconnect
 end
end

How It Is Used

This is how I use this code in my tests. You can see that the only change to our code is the requirement for dbi and the RTH_Verify.rb file

# Test with DB result stored
require 'watir'
require 'test/unit' 
require 'dbi' 
require 'RTH_Verify.rb'

class TC_recorded < Test::Unit::TestCase
 def test_toDB
  ie = Watir::IE.new
  ie.wait
 ie.bring_to_front
 ie.wait

Then the actual test is excecuted. I choose only to record a successfull test, so at the end the rutines are called.

  #Here goes the test
  ie.close

  #Variables
  testDir = Dir.getwd
  testName = File.basename(testDir)
  # This are RTH specific
  projectID = 2
  testID     = 4
  stepNum  = 1
  testSetID = 33

  db = Verify.new(projectID, testID, testSetID, testName, testDir, "", "", "")
  db.testStarted
  db.writeVerification(stepNum,
   "Test identification string","Detail test description string","Success Message String",
   "Pass","Module test string", "N/A", "N/A",  "#")
  db.testCompleted
  db.close
 end
end

If it the test terminates normally, the test is successfull, and the database has been modified so the ‘results page’ on the RTH system wi’ll show that an automated test exist and user or QA confirmation is needed to change status to ‘signed’.

You can modify this file for your particular system or try RTH which I recommend.

Web Page Testing in Windows-IE and Linux-FF

Objective
This post shows tree things:

  • Construction of a web page with Dojo Toolkit widgets.
  • The code to test that form in windows using the internet explorer browser with watir.
  • The code for testing in linux using firefox with firewatir.
    [Edit: this will only work up to firefox 3.6, check this post for firefox 4.0]

The Form

This is a form that is included with the dojo toolkit 1.5 SDK in the dijit/test subdirectory, simplified a bit.

The code for (Demo_Form.html) is:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
 <head>
  <title>Form unit test</title>
  <style type="text/css">
   @import "/dojo/dojo/resources/dojo.css";
  </style>
  <link id="themeStyles" rel="stylesheet" href="/dojo/dijit/themes/claro/claro.css">
  <script type="text/javascript" src="/dojo/dojo/dojo.js"
 djconfig="isDebug: true, parseOnLoad: true">
  </script>

That sets the form styles to dojo.css and claro.css.The path for the dojo.js is set as well as the flags to turn on the debug messages. Then dojo componets are required and a javascript rutine will be used to get the values of the form fields at the bottom of the page as a text result to test:

 <script type="text/javascript">
  dojo.require("dojo.date");
  dojo.require("dijit.dijit");
  dojo.require("dijit.form.Form");
  dojo.require("dijit.form.ComboBox");
  dojo.require("dijit.form.CheckBox");
  dojo.require("dijit.form.DateTextBox");
  dojo.require("dijit.form.Button");
  dojo.require("dijit.form.MultiSelect");
 function getValues(){
   var obj = dijit.byId('myForm').get('value');
   var strObj = dojo.toJson(obj, true);
   document.getElementById("result").innerHTML=
    "Form Fields Content:<br/>" + strObj.replace(/["]/g,"'");
  }
 </script>
</head>

The following html code is how the form and fields are defined in dojo. Notice the use of ids for reference and the digit.form.TYPE-OF-FIELD declaration:

<body>
 <br>
 <form dojotype="dijit.form.Form" id="myForm"
  enctype="multipart/form-data" action="../formAction.html"
  method="" target="_formSubmitIframe">
  <table style="border: 1px solid rgb(159, 159, 159);" cellspacing="10">
  <thead>
   <tr><th>Description</th><th>Widget</th>
   </tr>
  </thead>
  <tbody>
   <tr><td>DateTextBox</td><td>
    <input id="dtText" name="dtText" dojotype="dijit.form.DateTextBox"
     value="2010-08-31" type="text"></td>
   </tr>
   <tr><td>ComboBox</td><td>
    <select id="Combo1" name="Combo1" dojotype="dijit.form.ComboBox">
     <option value="one">one</option>
     <option value="two">two</option>
     <option value="three">three</option>
    </select></td>
   </tr>
   <tr><td>CheckBox widget</td><td>
    <input dojotype="dijit.form.CheckBox" id="cb2a" name="cb2"
     value="1" type="checkbox"> 1
    <input dojotype="dijit.form.CheckBox" id="cb2b" name="cb2"
     value="2" checked="checked" type="checkbox"> 2
    <input dojotype="dijit.form.CheckBox" id="cb2c" name="cb2"
     value="3" checked="checked" type="checkbox"> 3
    <input dojotype="dijit.form.CheckBox" id="cb2d" name="cb2"
     value="4" type="checkbox"> 4
    </td></tr>
   <tr><td>Radio widget</td><td id="radio-cells" name="radio-cells">
    <input dojotype="dijit.form.RadioButton" id="r2a" name="r2"
     value="1" type="radio"> 1
    <input dojotype="dijit.form.RadioButton" id="r2b" name="r2"
     value="2" checked="checked" type="radio"> 2
    <input dojotype="dijit.form.RadioButton" id="r2c" name="r2"
     value="3" type="radio"> 3
    <input dojotype="dijit.form.RadioButton" id="r2d" name="r2"
     value="4" type="radio"> 4
    </td></tr>
   <tr><td>multi-select</td><td>
    <select id="ms1" name="ms1" multiple="true" dojotype="dijit.form.MultiSelect"
     style="border: 5px solid rgb(237, 237, 237); height: 100px; width: 175px;">
     <option value="TN">Tennessee</option>
     <option value="VA" selected="true">Virginia</option>
     <option value="WA" selected="true">Washington</option>
     <option value="FL">Florida</option>
     <option value="CA">California</option>
    </select></td></tr>
  </tbody></table>
  <button dojotype="dijit.form.Button" name="bgetval" onclick="getValues();">
   Get Values from form!</button></form>
  <div id="result"></div>
 </body>
</html>

From the previous post you should have installed the Dojo Toolkit files at the same level that the form so you can see if everything’s all right by opening the form and using the calendar functionality.

Test in Windows and IE

The ruby code for this demo is demo_watir.rb. I use also a simple batch to test with a double click demo_watir.bat or you can just type ruby demo_watir.rb

The first lines require watir and the assertion libraries as well as defining the class.

# Demo for testing dojo.toolkit widgets @ Linux & Firefox #includes
require 'watir'
require 'test/unit'
 class TC_recorded < Test::Unit::TestCase
 def test_webpage

A browser is instantiated and opens the Demo form

 ie = Watir::IE.new
 ie.wait
 #:::::::::login page::::::::::::::::::
 ie.goto("http://localhost/Demo_Form.html")
 ie.wait
 ie.bring_to_front
 ie.wait

Lets see how the we fields in the form are changed.

The date field is a normal textbox and the name used is dtText. The combo field is really a text box. You can check this by open the form with firefox with firebug add-in and use the context menu (right click) and select inspect element.

The checkbox and radio option are normal elements and set and clear methods are used. The select list needs to be cleared and then the Tennesse element selected.

The button is rendered different and we need to use a span element by its text to trigger its click event.

 #:::::::::form page::::::::::::::::::   #date into text field
 ie.text_field( :id, "dtText").set("01/09/2010")
 #select the second option of combobox, tow values: display and option value
 ie.text_field( :id, "Combo1").set("two")
 #set first checkbox
 ie.checkbox( :id, "cb2b").clear
 #set radio to first option
 ie.radio( :id, "r2a").set
 #select first option of multiselect. First we clear all, then select only the first one
 ie.select_list( :id, "ms1").clearSelection
 ie.select_list( :id, "ms1").select("Tennessee")
 #and click de submit button, by text
 ie.span( :text, "Get Values from form!").click
 ie.wait
 sleep 1

The last part is the actual test, an assertion of expected text. If it is the expected one, the excecution will continue and the browser will be closed. Otherwise the excecution will be stoped and the error ‘Text not found’ will be shown.

 # check for de json output
 assert( ie.contains_text(
  "{ 'dtText': { }, 'Combo1': 'two', 'cb2': [ '3' ], 'r2': '1', 'ms1': [ 'TN' ], 'bgetval': '' }"),
   'ERROR: Text not found of form #1' )
  ie.close
 end
end

This should work.

Test in Linux and FF

For firefox the ruby code has a few diferences, check demo_firewatir.rb.

The first lines are for requiring firewatir and the assertion libraries as well as defining the class.

# Demo for testing dojo.toolkit widgets @ Linux & Firefox #includes
require 'rubygems'
require 'firewatir'
require 'test/unit'

class TC_recorded < Test::Unit::TestCase
 def test_webpage

A browser is instantiated and opens the Demo form

 ff = FireWatir::Firefox.new
 ff.wait
 #:::::::::login page::::::::::::::::::
 ff.goto("http://localhost/Demo_Form.html")
 ff.wait

The rest of the script is the same as the example above:

 #:::::::::form page::::::::::::::::::
 #date into text field
  ff.text_field( :id, "dtText").set("01/09/2010")
 #select the second option of combobox, tow values: display and option value
  ff.text_field( :id, "Combo1").set("two")
 #set first checkbox
  ff.checkbox( :id, "cb2b").clear
 #set radio to first option
  ff.radio( :id, "r2a").set
 #select first option of multiselect. First we clear all, then select only the first one
  ff.select_list( :id, "ms1").clearSelection
  ff.select_list( :id, "ms1").select("Tennessee")
 #and click de submit button, by text
  ff.span( :text, "Get Values from form!").click
  ff.wait
  sleep 1
 # check for de json output
 assert( ff.contains_text(
   "{ 'dtText': { }, 'Combo1': 'two', 'cb2': [ '3' ], 'r2': '1', 'ms1': [ 'TN' ], 'bgetval': '' }"),
   'ERROR: Text not found of form #1' )
  ff.close
 end
end

To run this test you can type ruby demo_firewatir.rb

Thats it.