Monday, September 19, 2011

Convert Unicode to UTF-8

Here is a simple function for changing \u3232 characters to UTF-8 characters in a given string:

def unicodeToUtf8(str)
    return str.gsub(/\\u([a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9])/) {|p| [$1.to_i(16)].pack("U")}   
end

Tuesday, September 6, 2011

Timeout ...

IE has some problems with e.g. javascripts, where it is loading a page forever without ever timing out. To prevent your test runs from hanging, e.g. create a function for opening URLs:

def openURL url
   begin
      Timeout::timeout(60) do
         $ie.goto url
      end
   rescue Timeout::Error
      puts "Timeout occured! Continuing ..."
   end 
end

Wait for page redirect

If you need to wait for a page redirect to happen, here is an example how to do so:

begin
   Watir::Waiter.wait_until(20) { $ie.text.include? "Redirected" }
   rescue Watir::Exception::TimeOutException
   begin
       raise "Redirect didn't happen!"
   end
end

This will wait for maximum 20 seconds for the text 'Redirected' to appear. If it doesn't appear within the timeframe, TimeOutException is raised.

URL parsing

Here is an example on how to easily parse an URL.

e.g. http://www.someurl.com?a=1&b=2&c=3

$baseurl = $ie.url.split("?")[0]
$aparam = $ie.url.split("a=")[1].split("&")[0]
$bparam = $ie.url.split("b=")[1].split("&")[0]
$cparam = $ie.url.split("c=")[1]

Thursday, June 23, 2011

Ruby constants and variables

foobar 
A variable whose name begins with a lowercase letter (a-z) or underscore (_) is a local variable.

@foobar
A variable whose name begins with '@' is an instance variable of self.

@@foobar
A class variable is shared by all instances of a class.

$foobar
A variable whose name begins with '$' has a global scope; meaning it can be accessed from anywhere within the program during runtime.

FOOBAR
A variable whose name begins with an uppercase letter (A-Z) is a constant. A constant can be reassigned a value after its initialization, but doing so will generate a warning,

More detailed information about Ruby constants and variables can be found from here:
http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Variables_and_Constants

Thursday, June 16, 2011

Browser version

How to get browser version e.g.

$browserversion = $ie.document.invoke('parentWindow').navigator.appVersion
            $tmp_str =/MSIE\s(.*?);/.match($browserversion)
            $browserversion = "MSIE " + $tmp_str[1] 
puts "Browser: " + $browserversion

Changing browser settings

 You can modify browser settings by using Windows Registry Editor e.g.
  
system("echo Windows Registry Editor Version 5.00 > useragent.reg") 
system("echo. >> useragent.reg")     
system("echo [HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\5.0\\User Agent] >> useragent.reg")
system("echo \"Compatible\"=\"Testclient\" >> useragent.reg")      system("regedit /s useragent.reg")   
system("del /f useragent.reg")

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 ...