Wednesday, May 18, 2011

Running Watir tests in parallell

If you want to speed up running your Watir tests, one easy way is to use PsExec. With this utility you can start browsers using different users.

To run a Ruby script using PsExec:

psexec.exe -w . -i -d -u <uname> -p <pwd> "myrubyscript.rb" 

Iframes

For testing pages with iframes, I would suggest using watir-webdriver. It has better support for iframes than Watir.

To access an element in an iframe:

$ie.frame(:id, 'iframe').text_field(:id, 'mytextfield').when_present.set "hello"

Watir-webdriver driver has some good methods for waiting:

.when_present.set - do something when element is present
.wait_until_present - wait until element is present
.wait_while_present - wait until element disappears

To change focus back to main page from an iframe:

$ie.frame(:index, 0).locate

If you are using Google Chrome, you might have problems with text fields. To enter a value in a text field, try:

$ie.frame(:id, 'iframe').text_field(:id, 'mytextfield').set "abcdef"
$ie.frame(:id, 'iframe').text_field(:id, 'mytextfield').set("abcdef")

Friday, May 6, 2011

Some text parsing examples

If a page contains e.g. user information in a format:

Name: John
Gender: Male
...

an easy way to get the name is:

$name = $ie.text.slice(Regexp.new('Name: .*?$')).sub("Name: ","")

Another way is to:

$firstarray = $ie.html.split("Name: ")
$secondarray = $firstarray[1].split(/<br>/)
$name = $secondarray[0]

Wednesday, May 4, 2011

UTF-8 characters in input fields

I haven't been able to write utf-8 characters to input fields using Watir. If anybody has, please comment!

For testing UTF-8 characters in input fields, I've created a small PHP script that:

1. Gets the web page.
2. Inserts UTF-8 string to input field value.
3. Displays the page.

Here is an example of the PHP script:

# proxy / url parameters
$proxyName = "proxy.com";
$proxyPort = "8080";
$requestURL = "http://mysite.com"
   
# create a new cURL resource
$ch = curl_init();
   
# set URL and other options
curl_setopt($ch, CURLOPT_PROXY, $proxyName);
curl_setopt($ch, CURLOPT_PROXYPORT, $proxyPort);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($ch, CURLOPT_URL, $requestUrl);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);

# pass request
$htmlSource = curl_exec($ch);

# close cURL resource, and free up system resources
curl_close($ch);
   
# e.g. add / replace input field value with utf-8 string
$htmlSource = ereg_replace($replacethis,$replacewith,$htmlSource);
   
echo $htmlSource

Checking for UTF-8 characters / texts

If you need to check for texts containing UTF-8 characters using Watir. You need to include following lines to your test script:

require "win32ole"
WIN32OLE.codepage = WIN32OLE::CP_UTF8

... and your script file should be UTF-8 encoded without BOM.

Check for javascript pop-ups

Pop-up handling is not very good in Watir. Here is just one example that checks if a javascript pop-up exist, and if it exists, it closes the browser and pop-up:

# check if javascript pop-up was found
require 'watir\ie'
require 'watir\contrib\enabled_popup'

$popup = $ie.enabled_popup(1);

# if pop-up was found, close browser and pop-ups
if ($popup)
  $u = ENV['USERNAME']
  system("taskkill /T /F /IM iexplore.exe /FI \"USERNAME eq "+$u+"\"")
end

How to make sure that all browser windows are closed ...

$u = ENV['USERNAME']
system("taskkill /T /F /IM iexplore.exe /FI \"USERNAME eq "+$u+"\"")
system("taskkill /T /F /IM firefox.exe /FI \"USERNAME eq "+$u+"\"")
system("taskkill /T /F /IM chrome.exe /FI \"USERNAME eq "+$u+"\"")

Using parameters in regular expressions

Here is an example on how to use parameters in a regular expression:

if not checkintext.match(/(#{checkfortxt})/)
  raise "Text '" + checkfortxt + "' not found!"
end

How to close browser pop-ups

Easiest way to close IE browser pop-ups (not javascript) is to use AutoIt. Here is an example:

autoit = WIN32OLE.new('AutoItX3.Control')
autoit.ControlClick("Windows Internet Explorer",'', 'OK')
autoit.ControlClick("Security Information",'', '&Yes')
autoit.ControlClick("Security Alert",'', '&Yes')
autoit.ControlClick("Security Warning",'', 'Yes')
autoit.ControlClick("Message from webpage",'', 'OK')

Sending HTTP requests and headers

Here is the first example on how to send extra HTTP headers in a HTTP request and then checking the response. In this example Cookie header is sent in a GET request:

require "net/http"
require "net/https"
require "uri"
  
# HTTP GET without proxy and SSL
res = Net::HTTP.start($host, 80) {|http|

  http.get2('/mysite/index.html',{'Cookie' => $cookie})
}
    

# HTTP GET with proxy, but without SSL
http = Net::HTTP::Proxy($proxyhost, $proxyport).new($host, 80)
res = http.get2('/mysite/index.html',{'Cookie' => $cookie})

# HTTP GET with proxy and SSL
http = Net::HTTP::Proxy($proxyhost, $proxyport).new($host, 443)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
res = http.get2('/mysite/index.html',{'Cookie' => $cookie})

# HTTP response body
$httpresponse = res.body

Here is the second example on how to send HTTP requests and checking the response:

response = sendHttpRequest $myurl,$mypostdata,{'Cookie' => 'xxx'}
puts "Response code:\n" + response[:code].to_s
puts "Response code description:\n" + response[:name].to_s
puts "Response body:\n" + response[:body].to_s
puts "Response headers:\n"+response[:headers].to_s

def sendHttpRequest requrl, postdata=nil, headers=nil

  proxyhost = "xxx"
  proxyport = "yyy"

  url = URI.parse(requrl)
  resheaders=""
  myurl = "/"
  if (not (url.path == nil or url.path == ""))
    myurl = url.path
  end
  if (not (url.query == nil or url.query == ""))
    myurl = myurl+"?"+url.query
  end
  if (not (url.fragment == nil or url.fragment == ""))
    myurl = myurl+"#"+url.fragment
  end

  ht = Net::HTTP.Proxy(proxyhost, proxyport).new(url.host, url.port) 
  if (requrl.to_s.include? "https")   
      ht.use_ssl = true
      ht.verify_mode = OpenSSL::SSL::VERIFY_NONE     
  else
      ht.use_ssl = false
  end
 
  begin
    ht.start
  rescue
    sleep 5
    ht.start
  end

  if (postdata.to_s == "nil" || postdata.to_s == "")
        if (headers.to_s == "nil") or (headers.to_s == "")
            res,datax = ht.request_get(myurl)
        else
            res,datax = ht.request_get(myurl,headers)
        end


        ht.finish     
        res.each_header() { |key,value| resheaders=resheaders+key+": "+value+"\n" }
        return {:name => res.class, :code => res.code, :body => datax, :headers => resheaders}
  end
 
  if (headers.to_s == "nil") or (headers.to_s == "")
        res,datax = ht.request_post(myurl, postdata)
  else
        res,datax = ht.request_post(myurl, postdata,headers)
  end
  ht.finish                 
     
  res.each_header() { |key,value| resheaders=resheaders+key+": "+value+"\n" }
  return {:name => res.class, :code => res.code, :body => datax, :headers => resheaders}


end 

Tuesday, May 3, 2011

Screenshots

Watir has some built in functions for taking screenshots, but they are not very good. The best way to take screenshots is by using SnagIt.

Here is an example function for taking screenshots by using SnagIt. This function is also capable of taking screenshots of invisible windows:

def screencapture fname
        snagit = WIN32OLE.new('Snagit.ImageCapture')
        visibilityState=$ie.getIE.Visible
        $ie.getIE.Visible = true
        $ie.bring_to_front
        $ie.maximize 
        snagit.Input = 1 #window
        snagit.Output = 2 #file
        snagit.InputWindowOptions.XPos = 350  
        # select XPosition for window ID
        snagit.InputWindowOptions.YPos = 350  
        # select YPosition for window ID
        snagit.InputWindowOptions.SelectionMethod = 3  
        # capture window under the X, Y point specified above.
        snagit.AutoScrollOptions.StartingPosition = 3  
        # set scroll to top and left
        snagit.OutputImageFile.FileType = 5 #:png
        snagit.OutputImageFile.FileNamingMethod = 1 # fixed
        tempStoragePath="c:\\screenshot\\"
        if (! File::exists?( tempStoragePath )) 
            tempStoragePath=Dir.pwd+"//screenshot//"
            if (! File::exists?( tempStoragePath )) 
                Dir.mkdir tempStoragePath
            end     
        end
        snagit.OutputImageFile.Directory = tempStoragePath
        snagit.OutputImageFile.Filename = fname
        snagit.AutoScrollOptions.AutoScrollMethod = 0
        snagit.Capture
        # wait for capture to complete
        until snagit.IsCaptureDone do
            sleep 0.5
        end
        $ie.getIE.Visible = visibilityState
end

If you don't have SnagIt installed, then another easy way to take screenshots is by using PHP.
For example, create following PHP file:

<?php

if(!isset($argv[1]))
{
    echo "Image not specified!";
    exit;
}
else
    $image = $argv[1];

$imagefile = "c://".$image.".png";
$im = imagegrabscreen();
imagepng($im, $imagefile);
imagedestroy($im);

?>

... and then, for example, following Ruby function:

def screencapture fname
    cmd = 'PHP.exe C:\\screenshot.php ' + fname
    puts %x{#{cmd}}
    sleep 8
end

Monday, May 2, 2011

Cookies

How to get all cookies for the current domain:

puts $ie.document.cookie

How to get value of a specific cookie:

$carray = $ie.document.cookie.split(';')
$carray.length.times do |i|   
    if /MyCookie/.match($carray[i])
       $cookieval = $carray[i]
       $cvalarray = $cookieval.split('=')
       $cookieval = $cvalarray[1]     
    end 
end
puts $cookieval

How to delete all cookies:

require "fileutils" 
cookieDir = "C:\\Documents and Settings\\#{ENV['USERNAME']}\\Cookies"
FileUtils.rm_rf cookieDir

NOTE! These examples only work for IE!

Check e.g. from here how to manage cookies in Firefox ...