Ruby scripting with Excel:-
First of all:
require 'win32ole'
Opening spreadsheets, accessing workbooks and worksheets
excel = WIN32OLE::new('excel.Application')
workbook = excel.Workbooks.Open('c:\examples\spreadsheet.xls')
worksheet = workbook.Worksheets(1) #get hold of the first worksheet
worksheet.Select #bring it to the front -need sometimes to run macros,
# not for working with a worksheet from ruby
excel['Visible'] = true #make visible, set to false to make invisible
# again. Don't need it to be visible for script to work
reading data from spreadsheet
worksheet.Range('a12')['Value'] #get value of single cell
data = worksheet.Range('a1:c12')['Value'] #read into 2D array
finding the first empty row (using empty column A)
line = '1'
while worksheet.Range("a#{line}")['Value']
line.succ!
end #line now holds row number of first empty row
or to read as you go
line = '1'
data = []
while worksheet.Range("a#{line}")['Value']
data << worksheet.Range("a#{line}:d#{line}")['Value']
line.succ!
end
writing data into spreadsheet, example
worksheet.Range('e2')['Value'] = Time.now.strftime
'%d/%m/%Y' #single value
worksheet.Range('a5:c5')['Value'] = ['Test', '25', 'result']
loading all Excel constants into a class
class ExcelConst
end
WIN32OLE.const_load(excel, ExcelConst)
Now the constant xlDown is accessible as
ExcelConst::XlDown
To find out what constants to use you can use this script. You run it by passing in a string which is matched against the constant names.
require 'win32ole'
module ExcelConsts
end
excel = WIN32OLE.new("Excel.Application")
WIN32OLE.const_load(excel, ExcelConsts)
excel.quit()
puts 'Matches for: ' + ARGV[0]
ExcelConsts.constants.each {|const|
match = const.match(/#{ARGV[0]}/)
value = eval("ExcelConsts::#{const}")
puts ' '*4 + const + ' => ' + value.to_s unless match.nil?
}
An example would be looking for the constant to center text. I ran
ruby search_excel_consts.rb Center
and the following results came up:
XlCenterAcrossSelection => 7
XlVAlignCenter => -4108
XlCenter => -4108
XlLabelPositionCenter => -4108
XlPhoneticAlignCenter => 2
XlHAlignCetner => -4108
XlHAlignCenterAcrossSelection => 7
calling macros
excel.Run('SortByNumber')
Setting background colour
worksheet.Range('a3:f5').Interior['ColorIndex'] = 36 #pale yellow
# Set background color back to uncoloured (rnicz)
worksheet.Range('a3:f5').Interior['ColorIndex'] = -4142 # XlColorIndexNone constant
# or use Excel constant to set background color back to uncoloured
worksheet.Range('a3:f5').Interior['ColorIndex'] = ExcelConst::XlColorIndexNone
Adding Formulae
emptyRow = 15
worksheet.Range("t#{emptyRow}")['Formula'] = "=(Q#{emptyRow}+L#{emptyRow}+I#{emptyRow}+S#{emptyRow})"
saving changes
workbook.Close(1)
# or
workbook.SaveAs 'myfile.xls'
# default path is the system defined My Documents folder
ending session
excel.Quit
If you're experimenting from within irb and are having problems with processes hanging around after you've called excel.Quit - try deleting the reference to excel and invoking the garbage collector.
excel.Quit
excel = nil
GC.start
Hopefully this is of some use. Please add anything else you have discovered.
Some further stuff that I learned so far...
It partly overlaps with what ChrisMorris already wrote, maybe we can merge it later on. -- BernhardLeicher
Start Excel, create new workbook and save it:
require 'win32ole'
excel = WIN32OLE.new("excel.application")
excel.visible = true # in case you want to see what happens
workbook = excel.workbooks.add
workbook.saveas('c:\examples\spreadsheet1.xls')
workbook.close
Or, suppose Excel is already started and a few Excel files are opened (=workbooks in Excel jargon): Connect to the running instance of Excel, activate one of the workbooks and write something.
This also shows that Excel collections can be iterated very handy with "each", and that collections can sometimes be indexed by number or by name:
excel = WIN32OLE.connect("excel.application")
excel.workbooks.each{|wb|puts wb.name} # loop through workbooks and display names
excel.workbooks(1).activate # activate by number
excel.workbooks("Mappe1").activate # or by name
excel.range("b5").value="soso" # write something to cell B5
Connecting to Excel is particularly good fun when done interactively from irb: You instantly see what happens!
irb(main):001:0> require 'win32ole'
true
irb(main):002:0> excel=WIN32OLE.connect('excel.application')
#
irb(main):003:0> excel.workbooks.each{|wb|puts wb.name}
PERSONL.XLS
Mappe1
Mappe2
Mappe3
nil
irb(main):004:0> excel.workbooks(1).name
"PERSONL.XLS"
irb(main):005:0> excel.workbooks("Mappe1").activate
true
irb(main):006:0> excel.range("b5").value="soso"
nil
Excel => workbook => worksheet => range(cell)
What always bugged me when browsing through examples were the various ways of referring to a particular cell on a particular worksheet in a particular workbook. When Excel is started and "Mappe1" is the currently active workbook and "Tabelle1" is the currently active worksheet, all following statements do the same thing:
excel.workbooks("Mappe1").worksheets("Tabelle1").range("a1").value
excel.worksheets("Tabelle1").range("a1").value
excel.activeworkbook.activesheet.range("a1").value
excel.activesheet.range("a1").value
excel.range("a1").value
My confusion was probably caused by the fact that a lot of properties/methods can be called on "excel" directly and then default to the currently active workbook/worksheet. It's more a matter of taste to specify "activesheet" and "activeworkbook" or not.
And regarding the hierarchy, it seems to be as simple as: When Excel is up and running, it contains 0 (no file opened) or more workbooks (Workbook? Just Excel jargon for an Excel file!), with each workbook/file containing 1 or more worksheets.
Various methods for addressing a cell or range of cells
In the Excel object model there isn't something like a cell object, it's all covered by the "Range" object. A range can represent only one cell or a whole bunch of them (a column, a row, a rectangular block of cells, ....).
Let's assume for the following examples, that "sheet" contains a reference to an Excel worksheet, obtained e.g. by:
require 'win32ole'
excel = WIN32OLE.connect('excel.application') # connect to running instance of Excel
sheet = excel.activesheet
sheet.range(cellname/cell[, cellname/cell])
A range can be obtained by using the worksheet's Range property. A range with only one cell:
sheet.range("a1")
Or a rectangular block of cells (A1 to C3):
sheet.range("a1", "c3")
Same with one argument:
sheet.range("a1:c3")
Whole Column A:
sheet.range("a:a")
Whole Row 3:
sheet.range("3:3")
A range itself has a range property, thus allowing to write:
sheet.range("c3").range("a1").address # >> "$C$3"
Doesn't make much sense, one might note that the second range's address becomes relative to the first range.
sheet.cells(rowindex, columnindex)
This is all wonderful, but shouldn't there be a way of addressing cells by row and column number? The worksheet's Cells property does that: It gets you a range with one cell by specifying the row and column number. The indices are counted from 1, so Cells(1,1) gives you cell A1:
sheet.cells(3,1).address # >> "$C$3"
Combined with range to get range A1:C3:
sheet.range(sheet.cells(1,1), sheet.cells(3,3))
And when applied to another range, row and column index become relative to the first range:
sheet.range("b2").cells(2,2).address # >> "$C$3"
The index can be negative:
sheet.range("c3").cells(-1,-1).address # >> "$A$1"
range.offset(rowoffset, columnoffset)
If you have a range, this can be used to return another range that is y rows and x columns away (or offset) from this one. This time the offsets count from 0:
sheet.range("a1").offset(0,0).address # >> "$A$1"
sheet.range("b5").offset(1,1).address # >> "$C$6"
While offset somehow reminds of the cells function, this might make a difference: If range contains a block of cells, an offset block of cells is returned too:
sheet.range("a1:c3").offset(0,2).address # >> "$C$1:$E$3"
Negative offsets can be specified too:
sheet.range("b2").offset(-1,-1).address # >> "$A$1"
Getting cell values
There isn't only one method for obtaining a cell's value, but at least three of them: text, value, value2. So which should one use, what is the difference between them?
Sidenote:
An Excel cell's content is somewhat relative, what you see isn't necessarily what is actually inside the cell, because a cell's content is displayed according to a specified format. A cell might contain "0.12345", but is displayed as "0.12" or "0.12 DM" or whatever. It might be good to know, that internally a cell's content is either a text or a floating point number. That's it, nothing else.
Just for curiosity:
Dates are represented internally as floating point values too (more details at Chip Pearson's site: HTTP://www.cpearson.com/excel/datetime.htm):³59³ "Excel stores dates and times as a number representing the number of days since 1900-Jan-0, plus a fractional portion of a 24 hour day: ddddd.tttttt . This is called a serial date, or serial date-time."
So if the content is 37936.0 and its format is "date", it's displayed as "11.11.03" or "Nov 2003".
For the following examples let's assume a content of:
A1 => 10.12345 => formatted with 2 decimal digits => 10.12
B1 => 10.12345 => formatted as currency => 10,00 DM
C1 => 11.11.03 => date => 11.11.03
range.text
Text property retrieves the value as it is displayed, as a string. It's readonly, so only for getting values. Because my country settings are "German", floats are displayed with a comma.
sheet.range("a1").text # >> "10,12"
sheet.range("b1").text # >> "10,12 DM"
sheet.range("c1").text # >> "11.11.03"
range.value
This is the result when retrieved with value:
sheet.range("a1").value # >> 10.12345
sheet.range("b1").value # >> "10,1235"
sheet.range("c1").value # >> "2003/11/11 00:00:00"
Retrieves the "internal" value (A1 becomes a float), whereby currency and date are still returned as strings albeit somewhat different than before.
range.value2
According to the Excel documentation value2 behaves just like value, but additionally retrieves currency and dates as doubles (the actual internal content):
sheet.range("a1").value2 # >> 10.12345
sheet.range("b1").value2 # >> 10.12345
sheet.range("c1").value2 # >> 37936.0
Yes, seems to work as advertised.
Setting values
Seems that only "value" is useful here. An integer or float arrives as expected as number in Excel:
sheet.range("a1").value = 1.2345
sheet.range("a1").value = 2
For strings Excel does the same processing that it does when something is interactively entered. It thus depends on how Excel interprets the string:
sheet.range("a1").value = "10.11.2003" # becomes a date
sheet.range("a1").value = "1,2345" # becomes a number (at least with German country settings)
Iterating ranges...
...with each
Ranges can be iterated with each:
sheet.range("a1:a10").each{|cell|puts cell.value}
If the range is a block of cells the iteration goes from left to right, then down one line, and so on:
sheet.range("a1:b5").each{|cell|puts cell.value}
Iterating block of cells by row and output the first cell of each row:
sheet.range("b3:c7").rows.each{|r|puts r.cells(1,1).value}
and by column:
sheet.range("b3:c7").columns.each{|c|puts c.cells(1,1).value}
Result of row.value is an array within an array:
sheet.range("b3:c7").rows.each{|r|puts r.value.inspect} # >> [1.0, 10.0]?
...with activecell
Like moving around an Excel sheet with the cursor. Moving down one cell:
sheet.activecell.offset(1,0).activate
Walking down from the active cell until an empty cell is encountered:
sheet.activecell.offset(1,0).activate while excel.activecell.value
...with an index
range = sheet.range("b3:c7")
noofrows = range.rows.count
(1..noofrows).each{|i|puts range.cells(i,1).value}
Named Ranges
Named ranges make Excel spreadsheets more usable for the end user. To create a named range "myRange":
sheet.names.Add( { 'Name' => 'myRange', 'RefersTo' => 'A2:A216' } )
One problem! This doesn't work. Use a Range object for RefersTo?, not a String:
myRange = sheet.Range( 'A2:A216' )
sheet.names.Add( { 'Name' => 'myRange', 'RefersTo' => myRange } )
How do you use named ranges in ruby? Named ranges are kept in the worksheet as well as the workbook. You may need to check both locations.
Something like the following works for named ranges manually defined by the user:
rangeString = workbook.names( 'Sheet1!myRange' ).Value
1. Remove "=" prefix (e.g. "=Sheet1!$A$2:$A$4")
rangeString = rangeString.slice( 1, rangeString.length - 1 ) if ( rangeString =~ /^=/ ) worksheet.range( rangeString ).value = 'testing...'
Finding Data Regions...
Data don't always start in row 1, column A, the number of columns might not be fixed, and the number of rows is most often variable. There are two handy methods that can help to find that "block of data".
Let's assume, that B3:C7 contain data.
...with CurrentRegion
Given any cell inside the "data block", CurrentRegion?() finds the surrounding contiguous data region and returns its range:
sheet.range("b5").currentregion.address # >> "$B$3:$C$7"
...by "jumping around"
There's a shortcut key in Excel "+", that allows you to jump to the end/start of regions with content. With our example and the cursor in B3, pressing + would jump the cursor to cell B7, pressing that shortcut again would move the cursor to the last line of the spreadsheet to B65536. There's an equivalent method: "End()".
Finding the last row with data:
sheet.range("b3").end(-4121).address # >> "$B$7"
The parameter indicates the direction, the Excel constants are:
xlDown = -4121
xlToLeft = -4159
xlToRight = -4161
xlUp = -4162
Saving to CSV (or other formats)
Note that Excel can show quite a lot of warnings / confirm request. To supress these:
excel.DisplayAlerts = false
Then:
workbook.SaveAs 'myfile.csv', xlCSV
where xlCSV = 6.
Here are some common file formats:
xlCSV=6
xlCSVMac=22
xlCSVMSDOS=24
xlCSVWindows=23
xlCurrentPlatformText=-4158
xlExcel9795=43
xlTextMSDOS=21
xlTextPrinter=36
xlTextWindows=20
See also: ScriptingOutlook, ScriptingAccess
- How about OpenOffice and Ruby scripting? Anything in this area? The examples all seem to rely on
require 'win32ole'
This will help you for Automation Software Testing with Watir Tool(Ruby)
Friday, June 3, 2011
Web Application Testing in Ruby: Web Application Testing in Ruby: Ruby scripting with Excel
Web Application Testing in Ruby: Web Application Testing in Ruby: Ruby scripting with Excel
reading data from spreadsheet
worksheet.Range('a12')['Value'] #get value of single cell
data = worksheet.Range('a1:c12')['Value'] #read into 2D array
reading data from spreadsheet
worksheet.Range('a12')['Value'] #get value of single cell
data = worksheet.Range('a1:c12')['Value'] #read into 2D array
Web Application Testing in Ruby: Ruby scripting with Excel
Web Application Testing in Ruby: Ruby scripting with Excel
Opening spreadsheets, accessing workbooks and worksheets
excel = WIN32OLE::new('excel.Application')
workbook = excel.Workbooks.Open('c:\examples\spreadsheet.xls')
worksheet = workbook.Worksheets(1) #get hold of the first worksheet
worksheet.Select #bring it to the front -need sometimes to run macros,
# not for working with a worksheet from ruby
excel['Visible'] = true #make visible, set to false to make invisible
# again. Don't need it to be visible for script to work
Opening spreadsheets, accessing workbooks and worksheets
excel = WIN32OLE::new('excel.Application')
workbook = excel.Workbooks.Open('c:\examples\spreadsheet.xls')
worksheet = workbook.Worksheets(1) #get hold of the first worksheet
worksheet.Select #bring it to the front -need sometimes to run macros,
# not for working with a worksheet from ruby
excel['Visible'] = true #make visible, set to false to make invisible
# again. Don't need it to be visible for script to work
Saturday, May 14, 2011
Nested frames
Web Application Testing in Ruby
Nested Frames
Sometimes a web page that is referenced by the tag is also a page that contains a tag. This is a nested frame. To deal with this, simply access the nested frame like this:
ie.rame(:name, "rame").rame(:name, "nested_frame")
Nested Frames
Sometimes a web page that is referenced by the
ie.rame(:name, "rame").rame(:name, "nested_frame")
Web Application Testing in Ruby
Web Application Testing in Ruby
IFrames
Firewatir (and maybe Watir and Watir-webdriver too) is somewhat stateful when interacting with iframes. Calling frame.locate switches Firewatir's internal context into the frame. Once Firewatir's internal context is switched to the iframe code can interact with that frame's elements. However, interacting with those elements resets Firewatir's context back to the root document. So repeated calls to locate can be used to establish the right internal context before subsequent element interactions. Related bug. Here is a code snippet used to interact with an AJAX button in an iframe that does not respond to click events, but rather responds to a sequence of mousedown/mouseup events.
browser.frame(:index, 1).locate
browser.div(:id, "somebutton").fire_event("onmousedown")
browser.frame(:index, 1).locate
browser.div(:id, "somebutton").fire_event("onmouseup")
IFrames
Firewatir (and maybe Watir and Watir-webdriver too) is somewhat stateful when interacting with iframes. Calling frame.locate switches Firewatir's internal context into the frame. Once Firewatir's internal context is switched to the iframe code can interact with that frame's elements. However, interacting with those elements resets Firewatir's context back to the root document. So repeated calls to locate can be used to establish the right internal context before subsequent element interactions. Related bug. Here is a code snippet used to interact with an AJAX button in an iframe that does not respond to click events, but rather responds to a sequence of mousedown/mouseup events.
browser.frame(:index, 1).locate
browser.div(:id, "somebutton").fire_event("onmousedown")
browser.frame(:index, 1).locate
browser.div(:id, "somebutton").fire_event("onmouseup")
Web Application Testing in Ruby
Web Application Testing in Ruby
Why do I get an access denied error when trying to access a frame?
This error message is due to Internet Explorer's attempt to prevent cross-window domain scripting (also known as cross-site scripting, or XSS). For security reasons, IE prevents embedded code in one frame from accessing another if the frame contents come from different domains. Watir runs into the same barriers when you attempt to navigate from a page hosted from one site to a frame hosted by another.
You may try one or more of the following methods to resolve this issue:
Navigate directly to the subframe (and the server that hosts it). That is, instead of having your script click on the link, use ie.goto("http://www.thenewsite.com/framecontents.html").
Add the particular host to the Internet Explorer Trusted Sites list. From IE's menu bar, choose Tools / Internet Options; click on the Security tab; click on the Trusted Sites icon; click on the Sites... button; type the name of the site into the field labelled "Add this Web site to the zone:". You may need to uncheck the box labelled "Require server verification ( https: ) for all sites in this zone." Click OK to finish the process.
Create an alias in the hosts file. This text file is typically in the folder c:\windows\system32\drivers\etc. Add a line in the form
192.168.10.32 foosystem
Replace 192.168.10.32 with the IP address of the host that is serving up the frame contents. Then access the frame using https://foosystem/testsystem.
Set Internet Explorer to its lowest possible security setting. From IE's menu bar, choose Tools / Internet Options; click on the Security tab; click on the Default Level button, and slide the slider to the Low setting; then click on OK to finish the process.
Watir 1.4 If none of these work, and you are still getting annoying error messages about Access Denied when your scripts run, you can turn off these warnings.
ie.logger.level = Logger::ERROR
Why do I get an access denied error when trying to access a frame?
This error message is due to Internet Explorer's attempt to prevent cross-window domain scripting (also known as cross-site scripting, or XSS). For security reasons, IE prevents embedded code in one frame from accessing another if the frame contents come from different domains. Watir runs into the same barriers when you attempt to navigate from a page hosted from one site to a frame hosted by another.
You may try one or more of the following methods to resolve this issue:
Navigate directly to the subframe (and the server that hosts it). That is, instead of having your script click on the link, use ie.goto("http://www.thenewsite.com/framecontents.html").
Add the particular host to the Internet Explorer Trusted Sites list. From IE's menu bar, choose Tools / Internet Options; click on the Security tab; click on the Trusted Sites icon; click on the Sites... button; type the name of the site into the field labelled "Add this Web site to the zone:". You may need to uncheck the box labelled "Require server verification ( https: ) for all sites in this zone." Click OK to finish the process.
Create an alias in the hosts file. This text file is typically in the folder c:\windows\system32\drivers\etc. Add a line in the form
192.168.10.32 foosystem
Replace 192.168.10.32 with the IP address of the host that is serving up the frame contents. Then access the frame using https://foosystem/testsystem.
Set Internet Explorer to its lowest possible security setting. From IE's menu bar, choose Tools / Internet Options; click on the Security tab; click on the Default Level button, and slide the slider to the Low setting; then click on OK to finish the process.
Watir 1.4 If none of these work, and you are still getting annoying error messages about Access Denied when your scripts run, you can turn off these warnings.
ie.logger.level = Logger::ERROR
How do I use OpenOffice.org Calc with Watir for data-driven tests?
Similar to Excel and the rest of Microsoft Office, OpenOffice.org is enabled for automation using a COM/OLE-like interface called UNO. So here's a brief example of how to access your Excel or OpenOffice.org spreadsheet using UNO, the Ruby Windows OLE interface, and OpenOffice.org.
require "win32ole"
noArgs = []
file_uri = "file:///c:/test.ods"
serviceManager = WIN32OLE.new("com.sun.star.ServiceManager")
coreReflection = serviceManager.createInstance("com.sun.star.reflection.CoreReflection")
desktop = serviceManager.creatInstance("com.sun.star.frame.Desktop")
spreadsheet = desktop.loadComponentFromURL (file_uri, "_blank", 0, noArgs)
sheetsCollection = spreadsheet.Sheets
sheet1 = sheetsCollection.getByIndex(0)
cellA1Formula = sheet1.getCellByPosition(0, 0).Formula # Gets text or number or whatever is in the cell
cellA1NumericValue = sheet1.getCellByPosition(0, 0).Value # Gets numerical value of the cell
cell1A = sheet1.getCellByPosition(0, 0) # Gets cell 1A
cell1A.Formula = "Nathan Lane" # Sets the formula for cell 1A to "Nathan Lane"
require "win32ole"
noArgs = []
file_uri = "file:///c:/test.ods"
serviceManager = WIN32OLE.new("com.sun.star.ServiceManager")
coreReflection = serviceManager.createInstance("com.sun.star.reflection.CoreReflection")
desktop = serviceManager.creatInstance("com.sun.star.frame.Desktop")
spreadsheet = desktop.loadComponentFromURL (file_uri, "_blank", 0, noArgs)
sheetsCollection = spreadsheet.Sheets
sheet1 = sheetsCollection.getByIndex(0)
cellA1Formula = sheet1.getCellByPosition(0, 0).Formula # Gets text or number or whatever is in the cell
cellA1NumericValue = sheet1.getCellByPosition(0, 0).Value # Gets numerical value of the cell
cell1A = sheet1.getCellByPosition(0, 0) # Gets cell 1A
cell1A.Formula = "Nathan Lane" # Sets the formula for cell 1A to "Nathan Lane"
What is Data-Driven Tests in Watir ? How do I use Excel with Watir for data-driven tests?
Data-Driven Tests
How do I use Excel with Watir for data-driven tests?
require 'win32ole'
excel = WIN32OLE::new("excel.Application")
workbook = excel.Workbooks.Open("c:\\examples\\example_sheet.xls")
worksheet = workbook.WorkSheets(1) # get first workbook
worksheet.Select # just to make sure macros are executed, if your sheet doesn't have macros you can skip this step.
value = worksheet.Range("a12").Value # get the value at cell a12 in worksheet.
data = worksheet.Range("a1:c12").Value # returns 2D array with values starting from cell a1 to cell c12
How do I use Excel with Watir for data-driven tests?
require 'win32ole'
excel = WIN32OLE::new("excel.Application")
workbook = excel.Workbooks.Open("c:\\examples\\example_sheet.xls")
worksheet = workbook.WorkSheets(1) # get first workbook
worksheet.Select # just to make sure macros are executed, if your sheet doesn't have macros you can skip this step.
value = worksheet.Range("a12").Value # get the value at cell a12 in worksheet.
data = worksheet.Range("a1:c12").Value # returns 2D array with values starting from cell a1 to cell c12
Latest Interview questions and answers on Ruby scripting
What is a class?
A text-book answer: classes are a blue-print for constructing computer models for real or virtual objects… boring.
In reality: classes hold data, have methods that interact with that data, and are used to instantiate objects.
Like this.
class WhatAreClasses
def initialize
@data = "I'm instance data of this object. Hello."
end
def method
puts @data.gsub("instance", "altered")
end
end
object = WhatAreClasses.new
object.method
#=> I'm altered data of this object. Hello.
What is an object?
An instance of a class.
To some, it’s also the root class in ruby (Object).
Classes themselves descend from the Object root class. (Kudos to Ezra)
What is a module? Can you tell me the difference between classes and modules?
Modules serve as a mechanism for namespaces.
module ANamespace
class AClass
def initialize
puts "Another object, coming right up!"
end
end
end
ANamespace::AClass.new
#=> Another object, coming right up!
Also, modules provide as a mechanism for multiple inheritance via mix-ins and cannot be instantiated like classes can.
module AMixIn
def who_am_i?
puts "An existentialist, that's who."
end
end
# String is already the parent class
class DeepString < String # extend adds instance methods from AMixIn as class methods extend AMixIn end DeepString.who_am_i? #=> An existentialist, that's who.
AMixIn.new
#=> NoMethodError: undefined method ‘new’ for AMixIn:Module
Can you tell me the three levels of method access control for classes and modules? What do they imply about the method?
All methods, no matter the access control, can be accessed within the class. But what about outside callers?
Public methods enforce no access control — they can be called in any scope.
Protected methods are only accessible to other objects of the same class.
Private methods are only accessible within the context of the current object.
class AccessLevel
def something_interesting
another = AccessLevel.new
another.public_method
another.protected_method
another.private_method
end
def public_method
puts "Public method. Nice to meet you."
end
protected
def protected_method
puts "Protected method. Sweet!"
end
private
def private_method
puts "Incoming exception!"
end
end
AccessLevel.new.something_interesting
#=> Public method. Nice to meet you.
#=> Protected method. Sweet!
#=> NoMethodError: private method ‘private_method’ called for
#=> #
There are three ways to invoke a method in ruby. Can you give me at least two?
Here, I’m looking for the dot operator (or period operator), the Object#send method, or method(:foo).call
object = Object.new
puts object.object_id
#=> 282660
puts object.send(:object_id)
#=> 282660
puts object.method(:object_id).call # (Kudos to Ezra)
#=> 282660
Separating the professional from the hobbyist
Senior programmers should be able to give competent answers for all questions. Junior programmers should answer some correct, but usually won’t know them all.
Explain this ruby idiom: a ||= b
A common idiom that strong ruby developers use all the time.
# a = b when a == false
# otherwise a remains unchanged
a || a = b # (Kudos to Markus Prinz)
a = 1
b = 2
a ||= b #=> a = 1
a = nil
b = 2
a ||= b #=> a = 2
a = false
b = 2
a ||= b #=> a = 2
What does self mean?
self always refers to the current object. But this question is more difficult than it seems because Classes are also objects in ruby. (Kudos to Stephen)
class WhatIsSelf
def test
puts "At the instance level, self is #{self}"
end
def self.test
puts "At the class level, self is #{self}"
end
end
WhatIsSelf.test
#=> At the class level, self is WhatIsSelf
WhatIsSelf.new.test
#=> At the instance level, self is #
This short snippet indicates two things:
at the class level, self is the class, in this case WhatIsSelf.
at the instance level, self is the instance in context, in this case the instance of WhatIsSelf at memory location 0×28190.
What is a Proc?
Everyone usually confuses procs with blocks, but the strongest rubyist can grok the true meaning of the question.
Essentially, Procs are anonymous methods (or nameless functions) containing code. They can be placed inside a variable and passed around like any other object or scalar value. They are created by Proc.new, lambda, and blocks (invoked by the yield keyword).
Note: Procs and lambdas do have subtle, but important, differences in ruby v1.8.6. However, I wouldn’t expect a candidate talk about these nitty-gritty details during an interview. (Kudos to Noah Thorp)
# wants a proc, a lambda, AND a block
def three_ways(proc, lambda, &block)
proc.call
lambda.call
yield # like block.call
puts "#{proc.inspect} #{lambda.inspect} #{block.inspect}"
end
anonymous = Proc.new { puts "I'm a Proc for sure." }
nameless = lambda { puts "But what about me?" }
three_ways(anonymous, nameless) do
puts "I'm a block, but could it be???"
end
#=> I'm a Proc for sure.
#=> But what about me?
#=> I'm a block, but could it be???
#=> # # #
What is unit testing (in classical terms)? What is the primary technique when writing a test?
The strongest candidates should be quite comfortable with test or behavior driven development.
Unit testing, simply put, is testing methods — the smallest unit in object-oriented programming. Strong candidates will argue that it allows a developer to flesh out their API before it’s consumed by other systems in the application.
The primary way to achieve this is to assert that the actual result of the method matches an expected result.
require "test/unit"
class Brokened
def uh_oh
"I needs fixing"
end
end
class BrokenedTest < Test::Unit::TestCase def test_uh_oh actual = Brokened.new assert_equal("I'm all better!", actual.uh_oh) end end #=> Started
#=> F
#=> Finished in 0.663831 seconds.
#=>
#=> 1) Failure:
#=> test_uh_oh:11
#=> <"I'm all better!"> expected but was
#=> <"I needs fixing">.
#=>
#=> 1 tests, 1 assertions, 1 failures, 0 errors
Show me the money!
Variable typing is one of those topics that everyone sort of understands it, but is hard to put it into words. I’ve iterated and improved the next series of questions to really test a senior level candidate’s knowledge of static and dynamic typing. This is my best attempt so far.
What is the primary difference in these two code snippets?
// Java
public boolean isEmpty(String s) {
return s.length() == 0;
}
# ruby
def empty?(s)
return s.size == 0
end
The Java method only accepts Strings as arguments and only returns a boolean while…
The ruby method accepts any Object and could return anything, but in this case will return a boolean if executed without exceptions.
What does this say about the advantages of ruby’s dynamic (duck) typed system?
That ruby program use less code and are more flexible.
What are some disadvantages (real and potential)?
Developers cannot be 100% certain that all arguments sent this empty? method will have a size method that is publicly accessible. Also, ruby is an interpreted language and it may take longer to run than compiled programs, such as Java, that are programmed similarly.
What could a developer do to address these disadvantages?
She could write unit tests or specs to ensure her application behaves as intended. She could also profile her application with tools like the unix time command, the ruby Benchmark class, and the ruby library called ruby-prof.
A cunning programmer would also argue that these two techniques ought to be used for both static and dynamic languages when developing complex systems.
Wrapping things up
To finish up with, I like to lob in some easy ones again. Plus I’m like to scratch my own curiosity about a candidates relationship with the ruby community.
What are rubygems? Any favorites not including rails? Any that you’ve worked on personally?
rubygems is package manager software for ruby libraries (i.e. gems). The package manager has basic CRUD operations, dependency trees, and supports asynchronous communication between multiple gem servers.
A text-book answer: classes are a blue-print for constructing computer models for real or virtual objects… boring.
In reality: classes hold data, have methods that interact with that data, and are used to instantiate objects.
Like this.
class WhatAreClasses
def initialize
@data = "I'm instance data of this object. Hello."
end
def method
puts @data.gsub("instance", "altered")
end
end
object = WhatAreClasses.new
object.method
#=> I'm altered data of this object. Hello.
What is an object?
An instance of a class.
To some, it’s also the root class in ruby (Object).
Classes themselves descend from the Object root class. (Kudos to Ezra)
What is a module? Can you tell me the difference between classes and modules?
Modules serve as a mechanism for namespaces.
module ANamespace
class AClass
def initialize
puts "Another object, coming right up!"
end
end
end
ANamespace::AClass.new
#=> Another object, coming right up!
Also, modules provide as a mechanism for multiple inheritance via mix-ins and cannot be instantiated like classes can.
module AMixIn
def who_am_i?
puts "An existentialist, that's who."
end
end
# String is already the parent class
class DeepString < String # extend adds instance methods from AMixIn as class methods extend AMixIn end DeepString.who_am_i? #=> An existentialist, that's who.
AMixIn.new
#=> NoMethodError: undefined method ‘new’ for AMixIn:Module
Can you tell me the three levels of method access control for classes and modules? What do they imply about the method?
All methods, no matter the access control, can be accessed within the class. But what about outside callers?
Public methods enforce no access control — they can be called in any scope.
Protected methods are only accessible to other objects of the same class.
Private methods are only accessible within the context of the current object.
class AccessLevel
def something_interesting
another = AccessLevel.new
another.public_method
another.protected_method
another.private_method
end
def public_method
puts "Public method. Nice to meet you."
end
protected
def protected_method
puts "Protected method. Sweet!"
end
private
def private_method
puts "Incoming exception!"
end
end
AccessLevel.new.something_interesting
#=> Public method. Nice to meet you.
#=> Protected method. Sweet!
#=> NoMethodError: private method ‘private_method’ called for
#=> #
There are three ways to invoke a method in ruby. Can you give me at least two?
Here, I’m looking for the dot operator (or period operator), the Object#send method, or method(:foo).call
object = Object.new
puts object.object_id
#=> 282660
puts object.send(:object_id)
#=> 282660
puts object.method(:object_id).call # (Kudos to Ezra)
#=> 282660
Separating the professional from the hobbyist
Senior programmers should be able to give competent answers for all questions. Junior programmers should answer some correct, but usually won’t know them all.
Explain this ruby idiom: a ||= b
A common idiom that strong ruby developers use all the time.
# a = b when a == false
# otherwise a remains unchanged
a || a = b # (Kudos to Markus Prinz)
a = 1
b = 2
a ||= b #=> a = 1
a = nil
b = 2
a ||= b #=> a = 2
a = false
b = 2
a ||= b #=> a = 2
What does self mean?
self always refers to the current object. But this question is more difficult than it seems because Classes are also objects in ruby. (Kudos to Stephen)
class WhatIsSelf
def test
puts "At the instance level, self is #{self}"
end
def self.test
puts "At the class level, self is #{self}"
end
end
WhatIsSelf.test
#=> At the class level, self is WhatIsSelf
WhatIsSelf.new.test
#=> At the instance level, self is #
This short snippet indicates two things:
at the class level, self is the class, in this case WhatIsSelf.
at the instance level, self is the instance in context, in this case the instance of WhatIsSelf at memory location 0×28190.
What is a Proc?
Everyone usually confuses procs with blocks, but the strongest rubyist can grok the true meaning of the question.
Essentially, Procs are anonymous methods (or nameless functions) containing code. They can be placed inside a variable and passed around like any other object or scalar value. They are created by Proc.new, lambda, and blocks (invoked by the yield keyword).
Note: Procs and lambdas do have subtle, but important, differences in ruby v1.8.6. However, I wouldn’t expect a candidate talk about these nitty-gritty details during an interview. (Kudos to Noah Thorp)
# wants a proc, a lambda, AND a block
def three_ways(proc, lambda, &block)
proc.call
lambda.call
yield # like block.call
puts "#{proc.inspect} #{lambda.inspect} #{block.inspect}"
end
anonymous = Proc.new { puts "I'm a Proc for sure." }
nameless = lambda { puts "But what about me?" }
three_ways(anonymous, nameless) do
puts "I'm a block, but could it be???"
end
#=> I'm a Proc for sure.
#=> But what about me?
#=> I'm a block, but could it be???
#=> #
What is unit testing (in classical terms)? What is the primary technique when writing a test?
The strongest candidates should be quite comfortable with test or behavior driven development.
Unit testing, simply put, is testing methods — the smallest unit in object-oriented programming. Strong candidates will argue that it allows a developer to flesh out their API before it’s consumed by other systems in the application.
The primary way to achieve this is to assert that the actual result of the method matches an expected result.
require "test/unit"
class Brokened
def uh_oh
"I needs fixing"
end
end
class BrokenedTest < Test::Unit::TestCase def test_uh_oh actual = Brokened.new assert_equal("I'm all better!", actual.uh_oh) end end #=> Started
#=> F
#=> Finished in 0.663831 seconds.
#=>
#=> 1) Failure:
#=> test_uh_oh:11
#=> <"I'm all better!"> expected but was
#=> <"I needs fixing">.
#=>
#=> 1 tests, 1 assertions, 1 failures, 0 errors
Show me the money!
Variable typing is one of those topics that everyone sort of understands it, but is hard to put it into words. I’ve iterated and improved the next series of questions to really test a senior level candidate’s knowledge of static and dynamic typing. This is my best attempt so far.
What is the primary difference in these two code snippets?
// Java
public boolean isEmpty(String s) {
return s.length() == 0;
}
# ruby
def empty?(s)
return s.size == 0
end
The Java method only accepts Strings as arguments and only returns a boolean while…
The ruby method accepts any Object and could return anything, but in this case will return a boolean if executed without exceptions.
What does this say about the advantages of ruby’s dynamic (duck) typed system?
That ruby program use less code and are more flexible.
What are some disadvantages (real and potential)?
Developers cannot be 100% certain that all arguments sent this empty? method will have a size method that is publicly accessible. Also, ruby is an interpreted language and it may take longer to run than compiled programs, such as Java, that are programmed similarly.
What could a developer do to address these disadvantages?
She could write unit tests or specs to ensure her application behaves as intended. She could also profile her application with tools like the unix time command, the ruby Benchmark class, and the ruby library called ruby-prof.
A cunning programmer would also argue that these two techniques ought to be used for both static and dynamic languages when developing complex systems.
Wrapping things up
To finish up with, I like to lob in some easy ones again. Plus I’m like to scratch my own curiosity about a candidates relationship with the ruby community.
What are rubygems? Any favorites not including rails? Any that you’ve worked on personally?
rubygems is package manager software for ruby libraries (i.e. gems). The package manager has basic CRUD operations, dependency trees, and supports asynchronous communication between multiple gem servers.
Friday, April 15, 2011
Services
Services
We have done several projects on Ruby Watir testing and QTP Automation testing.To discuss how we can help you, please contact us on Services@watirtesting.com.
Key Points
Team of 15+ dedicated WATIR script developers and QTP Experts.
Regularly updated on enhancements made to WATIR.
4+ years of experience in WATIR and QTP Automated Test Development.
Clients satisfied with a cheaper and effective automation effort.
Online Training (WATIR/QTP,Ruby Scripting/VB Scripting).
Online Training (WATIR Frameworks/QTP Frameworks).
Online Training (Ruby Scripting/VB Scripting).
selling WATIR Frameworks/Ruby Frameworks.
Setup of Testing Environment for Automation Testing.
Providing candidates for Automation Testing.
Project work for Automation Testing Testing.
Project Work on contract Basis.
Other Services Like Load Testing, Performance Testing, Manual Testing and web development.
Please mail me
sales@hlworldtech.com
We have done several projects on Ruby Watir testing and QTP Automation testing.To discuss how we can help you, please contact us on Services@watirtesting.com.
Key Points
Team of 15+ dedicated WATIR script developers and QTP Experts.
Regularly updated on enhancements made to WATIR.
4+ years of experience in WATIR and QTP Automated Test Development.
Clients satisfied with a cheaper and effective automation effort.
Online Training (WATIR/QTP,Ruby Scripting/VB Scripting).
Online Training (WATIR Frameworks/QTP Frameworks).
Online Training (Ruby Scripting/VB Scripting).
selling WATIR Frameworks/Ruby Frameworks.
Setup of Testing Environment for Automation Testing.
Providing candidates for Automation Testing.
Project work for Automation Testing Testing.
Project Work on contract Basis.
Other Services Like Load Testing, Performance Testing, Manual Testing and web development.
Please mail me
sales@hlworldtech.com
Tuesday, February 22, 2011
What is TRM?
Web Application Testing in Ruby: What is stub?
TRM means Test Responsibility Matrix.
TRM: --- It indicates mapping between test factors and development stages...
Test factors like:
Ease of use, reliability, portability, authorization, access control, audit trail, ease of operates, maintainable... Like dat...
Development stages...
Requirement gathering, Analysis, design, coding, testing, and maintenance
TRM means Test Responsibility Matrix.
TRM: --- It indicates mapping between test factors and development stages...
Test factors like:
Ease of use, reliability, portability, authorization, access control, audit trail, ease of operates, maintainable... Like dat...
Development stages...
Requirement gathering, Analysis, design, coding, testing, and maintenance
Monday, February 21, 2011
What is release notes?
Web Application Testing in Ruby: What is stub?
It's a document released along with the product which explains about the product. It also contains about the bugs that are in deferred status.
It's a document released along with the product which explains about the product. It also contains about the bugs that are in deferred status.
What is internationalization Testing?
Web Application Testing in Ruby: What is stub?
Software Internationalization is process of developing software products independent from cultural norms, language or other specific attributes of a market
Software Internationalization is process of developing software products independent from cultural norms, language or other specific attributes of a market
What is stub?
Web Application Testing in Ruby: What is bidirectional traceability?
Stub is a dummy program or component, the code is not ready for testing, it's used for testing...that means, in a project if there are 4 modules and last is remaining and there is no time then we will use dummy program to complete that fourth module and we will run whole 4 modules also. The dummy program is also known as stub
Stub is a dummy program or component, the code is not ready for testing, it's used for testing...that means, in a project if there are 4 modules and last is remaining and there is no time then we will use dummy program to complete that fourth module and we will run whole 4 modules also. The dummy program is also known as stub
What is bidirectional traceability?
Web Application Testing in Ruby: What is agile testing?
What is bidirectional traceability?
Bidirectional traceability needs to be implemented both forward and backward (i.e., from requirements to end products and from end product back to requirements).
When the requirements are managed well, traceability can be established from the source requirement to its lower level requirements and from the lower level requirements back to their source. Such bidirectional traceability helps determine that all source requirements have been completely addressed and that all lower level requirements can be traced to a valid source.
What is bidirectional traceability?
Bidirectional traceability needs to be implemented both forward and backward (i.e., from requirements to end products and from end product back to requirements).
When the requirements are managed well, traceability can be established from the source requirement to its lower level requirements and from the lower level requirements back to their source. Such bidirectional traceability helps determine that all source requirements have been completely addressed and that all lower level requirements can be traced to a valid source.
What is agile testing?
Web Application Testing in Ruby: What is Recovery testing?
What is agile testing?
What is agile testing?
Agile testing is used whenever customer requirements are changing dynamically
If we have no SRS, BRS but we have test cases does you execute the test cases blindly or do you follow any other process.
Test case would have detail steps of what the application is supposed to do.
1) Functionality of application.
2) In addition you can refer to Backend, is mean look into the Database. To gain more knowledge of the application.
What is agile testing?
What is agile testing?
Agile testing is used whenever customer requirements are changing dynamically
If we have no SRS, BRS but we have test cases does you execute the test cases blindly or do you follow any other process.
Test case would have detail steps of what the application is supposed to do.
1) Functionality of application.
2) In addition you can refer to Backend, is mean look into the Database. To gain more knowledge of the application.
What is Recovery testing?
Web Application Testing in Ruby: What is Recovery testing?
Recovery Testing is the testing which is used to find how
well the application will get recover from crashes.
Recovery Testing is the testing which is used to find how
well the application will get recover from crashes.
What is Recovery testing?
Evaluates the contigency features are built in the
application for handling interruptions and to return to
specific check points. This test also assures that disaster
recovery if possible.
application for handling interruptions and to return to
specific check points. This test also assures that disaster
recovery if possible.
Wednesday, February 9, 2011
Excel Interface Class
Summary
This ruby class provides simple methods for reading and writing data records to and from Excel spreadsheets. This data can then be easily used to create data-driven Watir tests. This class hides the complexities of directly using ruby's win32ole library to interface with Excel.
Features
Excel Data can be identified/located on any sheet using and either a "Range" (e.g. "A1:C20") or dynamically by searching for a specific text label above a data range
Excel Data formated as rows of records or as columns of records can easily be read
Data can be read in as an Array of Hashes (using headers as keys), a plain 2D Array, or a simple Hash of key-value pairs.
If the excel data file is already open, this class will simply attach to the open workbook and read its data instead of trying to re-open the file.
[6/22/07] Support adding and removing excel worksheets
[6/22/07] Support for ordered hashes, and writing them back to an excel file.
[6/25/07] Uploaded the RDOC documentation for the XLS class see XLS_doc.zip
[7/11/07] Made all get methods more flexible in how the range is specified (they now accept a string representing a literal range,a Named Range in the workbook, or a text label above a contiguous range of cells with data). This allowed me to simplify/shorten method names and to remove Redundant methods.
This ruby class provides simple methods for reading and writing data records to and from Excel spreadsheets. This data can then be easily used to create data-driven Watir tests. This class hides the complexities of directly using ruby's win32ole library to interface with Excel.
Features
Excel Data can be identified/located on any sheet using and either a "Range" (e.g. "A1:C20") or dynamically by searching for a specific text label above a data range
Excel Data formated as rows of records or as columns of records can easily be read
Data can be read in as an Array of Hashes (using headers as keys), a plain 2D Array, or a simple Hash of key-value pairs.
If the excel data file is already open, this class will simply attach to the open workbook and read its data instead of trying to re-open the file.
[6/22/07] Support adding and removing excel worksheets
[6/22/07] Support for ordered hashes, and writing them back to an excel file.
[6/25/07] Uploaded the RDOC documentation for the XLS class see XLS_doc.zip
[7/11/07] Made all get methods more flexible in how the range is specified (they now accept a string representing a literal range,a Named Range in the workbook, or a text label above a contiguous range of cells with data). This allowed me to simplify/shorten method names and to remove Redundant methods.
Web Application Testing in Ruby: How to wait in Watir?
Web Application Testing in Ruby: How to wait in Watir?
1 - New Windows
Navigating to a new page with the existing IE window will not require you to define any special behavior. However, if you perform an action that brings up a secondary page (pop-up) you will need to define some code to wait on it's existence. Luckily, if you can deal with pop-ups with the "attach" method, there is already an implicit wait in the attach method. If you have a modal dialog box or other windows related dialog box (Security Alert Box, Login, File Download, etc.) you will need to create your own wait methods. See this section for more info.
2 - Objects that depend on Javascript to show up
Sometimes IE thinks it's done before everything is loaded. Unfortunately, IE#wait doesn't always work here because it exits whenever IE thinks it's done. So, if this is your problem, you will need to tell Watir to wait. There are several ways to solve this, here are two.
If you want to wait forever, consider the following:
sleep 1 until ie.text.include? "new results are loaded"
This code will keep sleeping until the text "new results are loaded" appears on the page. However, you may not want to wait forever. Using the following code will wait; for the text "new results are loaded" to appear on the page OR 60 seconds, whichever comes first.
wait_until {ie.text.include? "new results are loaded"}
Sometimes you need to wait for something to happen in the Application under test before you interact with it. Sleep statements are hardcoded and lock you down into a certain number of seconds before moving through your test. To avoid that, we've written a polling mechanism in the latest versions of Watir - the wait_until method.
An example might be that you're loading the Google home page and for some reason it's taking time to load. Here's a basic contrived script with a sleep statement.
require 'watir'
browser = Watir::Browser.start('http://www.google.com')
sleep 5 # we need to wait for the page to load and on a subjective basis I've chosen 5 seconds which works on my machine
browser.text_field(:name, 'q').set('ruby poignant')
....
Unfortunately the sleep is hardcoded and doesn't work for anyone else on my team who have slower network connections, my connection has gotten faster, but it still waits for 5 seconds before setting the text field.
Watir has a Watir::Waiter class with a wait_until method that can poll for a certain condition to return true before continuing on or erroring out. By default it checks the condition every half second up until 60 seconds. So I rewrite my code to look like this:
require 'watir'
browser = Watir::Browser.start('http://www.google.com')
# In this case all I care about is the text field existing, you could
# check title, text, anything you're expecting before continuing
Watir::Waiter::wait_until { browser.text_field(:name, 'q').exists? }
browser.text_field(:name, 'q').set('ruby poignant')
...
It now works for me with a half second delay, but also works for the other members of my team who have network delays up to a minute. If you're considering using sleep, use wait_until instead. It will make your test code more resilient to timing issues in those cases where you really need to use it.
3 - Handling asynchronous javascript / AJAX
if you include asynchronous JS in your definition of done, you'll need to code around that specifically. There's an open feature request to have Watir's wait method track XHRs and timers that are launched when the page is loaded, and wait for them as well. That may be tricky to do though, and with an all-volunteer project, it really depends on someone making the time to do it.
In lieu of that, one option is having the application keep track if XHRs and timers that it kicks off, and setting the some value to true when they are all complete. For example:
def wait_until_loaded(timeout = 30)
start_time = Time.now
until (however_your_application_reports_its_loaded == 'true') do
sleep 0.1
if Time.now - start_time> timeout
raise RuntimeError, "Timed out after #{timeout} seconds"
end
end
end
A simpler option is:
tries = 0
until browser.link(:text, /link_to_wait_for/).exists? do
sleep 0.5
tries += 1
end
browser.link(:text, /link_to_wait_for/).click
end
Another option is to retry until timeout or no exception is raised.
def rescue_wait_retry(exception = Watir::Exception::UnknownObjectException, times = 10, seconds = 2, &block)
begin
return yield
rescue exception => e
puts "Caught #{exception}: #{e}. Sleeping #{seconds} seconds." if $DEBUG
sleep(seconds)
@ie.wait
if (times -= 1)> 0
puts "Retrying... #{times} times left" if $DEBUG
retry
end
end
yield
end
@ie.link(:url, %r|confirmdelete\.action\?educationId|).click #This starts some ajax stuff
rescue_wait_retry { @ie.button(:id, 'form_0').click }
Not sure about this one but this is a good introduction to the problem.
Also, from the thread "[wtr-general] SUMMARY: Enable/disable JS support in IE"
Q - How to check from watir code whether web page was reloaded or it was updated dynamically withJS.
A - Not so easy to implement for HCOM application due to a lot of ajax stuff. The following code should work when JS is disabled, plus we can pass additional condition to check here (e.g. waiter for object appearance on the page). Note: $ie is global IE instance in our framework. Also I think that we need to use something like click_no_wait method to reload the page, otherwise IE.wait() method won't let us do the check until page is ready. What I was asking here is how to check that page is reloading rather than just some elements on the page are updated with JS.
class Page
def loading?(additionalCondition = false)
if $ie.ie.busy || ($ie.ie.readyState != 4) || additionalCondition
true
else
false
end
end
end
4 - Yourself while you watch a script execute
Maybe you are watching the script execute and you just want to slow things down for troubleshooting reasons. Of course, there is always the venerable (and oft overused) "sleep" method. Using "sleep( x )" will cause the script to pause for x seconds.
If, however, you are annoyed by the slowness of your script, you can always make it faster:
ie = Watir::IE.new
ie.speed = :fast
or
ie = Watir::IE.new
ie.speed = :zippy
See this for more information.
click_no_wait
Information here about what this method is all about.
Continuing testing if IE refuses to load a page
When IE.attach does not find a window it throws a NoMatchingWindowFoundException. You can catch the exception instead of letting watir exit your tests. At this point you can build some 'recovery' if you need it or simply continue or exit your test explicitly after logging some test data.
require "watir"
begin
@ie = Watir::IE.attach(:url , /Webpage Dialog/) #let's say the window does not exist on the desktop
rescue Watir::Exception::NoMatchingWindowFoundException => e
puts "Failed to find new pop up window! #{e}"
# you can now recover or exit or continue
end
When IE.goto is invoked it implicitly waits for the page to load and runs any registered @error_checkers. If you don't have them added to browser then you can explicitly call check_for_http_errors. On HTTP errors encountered the Exception will be thrown. You can rescue the exception and continue with your test and recover or just exit after logging some test data.
require 'watir'
@ie = Watir::IE.new #start new browser window
@ie.goto 'http://asdf asdf.com' #navigation to this page will load Can Not Find Server page #notice the space in url string
begin
@ie.check_for_http_error # will throw Exception
rescue Watir::Exception::NavigationException => e #catch the Exception
puts "Page did not load: #{e}" # => 'Cannot find server or DNS Error'
# you can now recover or exit or just continue
end
# OR you can register error_checker which will be called when goto is invoked
require 'watir/contrib/page_checker'
@ie.add_checker(PageCheckers::NAVIGATION_CHECKER)
begin
@ie.goto "http://marekj.com/asdfasdfasdfa"
rescue Watir::Exception::NavigationException => e #catch the Exception
puts "Page did not load: #{e}" # => 'HTTP 404 - File not found'
# you can now recover or exit or just continue
end
1 - New Windows
Navigating to a new page with the existing IE window will not require you to define any special behavior. However, if you perform an action that brings up a secondary page (pop-up) you will need to define some code to wait on it's existence. Luckily, if you can deal with pop-ups with the "attach" method, there is already an implicit wait in the attach method. If you have a modal dialog box or other windows related dialog box (Security Alert Box, Login, File Download, etc.) you will need to create your own wait methods. See this section for more info.
2 - Objects that depend on Javascript to show up
Sometimes IE thinks it's done before everything is loaded. Unfortunately, IE#wait doesn't always work here because it exits whenever IE thinks it's done. So, if this is your problem, you will need to tell Watir to wait. There are several ways to solve this, here are two.
If you want to wait forever, consider the following:
sleep 1 until ie.text.include? "new results are loaded"
This code will keep sleeping until the text "new results are loaded" appears on the page. However, you may not want to wait forever. Using the following code will wait; for the text "new results are loaded" to appear on the page OR 60 seconds, whichever comes first.
wait_until {ie.text.include? "new results are loaded"}
Sometimes you need to wait for something to happen in the Application under test before you interact with it. Sleep statements are hardcoded and lock you down into a certain number of seconds before moving through your test. To avoid that, we've written a polling mechanism in the latest versions of Watir - the wait_until method.
An example might be that you're loading the Google home page and for some reason it's taking time to load. Here's a basic contrived script with a sleep statement.
require 'watir'
browser = Watir::Browser.start('http://www.google.com')
sleep 5 # we need to wait for the page to load and on a subjective basis I've chosen 5 seconds which works on my machine
browser.text_field(:name, 'q').set('ruby poignant')
....
Unfortunately the sleep is hardcoded and doesn't work for anyone else on my team who have slower network connections, my connection has gotten faster, but it still waits for 5 seconds before setting the text field.
Watir has a Watir::Waiter class with a wait_until method that can poll for a certain condition to return true before continuing on or erroring out. By default it checks the condition every half second up until 60 seconds. So I rewrite my code to look like this:
require 'watir'
browser = Watir::Browser.start('http://www.google.com')
# In this case all I care about is the text field existing, you could
# check title, text, anything you're expecting before continuing
Watir::Waiter::wait_until { browser.text_field(:name, 'q').exists? }
browser.text_field(:name, 'q').set('ruby poignant')
...
It now works for me with a half second delay, but also works for the other members of my team who have network delays up to a minute. If you're considering using sleep, use wait_until instead. It will make your test code more resilient to timing issues in those cases where you really need to use it.
3 - Handling asynchronous javascript / AJAX
if you include asynchronous JS in your definition of done, you'll need to code around that specifically. There's an open feature request to have Watir's wait method track XHRs and timers that are launched when the page is loaded, and wait for them as well. That may be tricky to do though, and with an all-volunteer project, it really depends on someone making the time to do it.
In lieu of that, one option is having the application keep track if XHRs and timers that it kicks off, and setting the some value to true when they are all complete. For example:
def wait_until_loaded(timeout = 30)
start_time = Time.now
until (however_your_application_reports_its_loaded == 'true') do
sleep 0.1
if Time.now - start_time> timeout
raise RuntimeError, "Timed out after #{timeout} seconds"
end
end
end
A simpler option is:
tries = 0
until browser.link(:text, /link_to_wait_for/).exists? do
sleep 0.5
tries += 1
end
browser.link(:text, /link_to_wait_for/).click
end
Another option is to retry until timeout or no exception is raised.
def rescue_wait_retry(exception = Watir::Exception::UnknownObjectException, times = 10, seconds = 2, &block)
begin
return yield
rescue exception => e
puts "Caught #{exception}: #{e}. Sleeping #{seconds} seconds." if $DEBUG
sleep(seconds)
@ie.wait
if (times -= 1)> 0
puts "Retrying... #{times} times left" if $DEBUG
retry
end
end
yield
end
@ie.link(:url, %r|confirmdelete\.action\?educationId|).click #This starts some ajax stuff
rescue_wait_retry { @ie.button(:id, 'form_0').click }
Not sure about this one but this is a good introduction to the problem.
Also, from the thread "[wtr-general] SUMMARY: Enable/disable JS support in IE"
Q - How to check from watir code whether web page was reloaded or it was updated dynamically withJS.
A - Not so easy to implement for HCOM application due to a lot of ajax stuff. The following code should work when JS is disabled, plus we can pass additional condition to check here (e.g. waiter for object appearance on the page). Note: $ie is global IE instance in our framework. Also I think that we need to use something like click_no_wait method to reload the page, otherwise IE.wait() method won't let us do the check until page is ready. What I was asking here is how to check that page is reloading rather than just some elements on the page are updated with JS.
class Page
def loading?(additionalCondition = false)
if $ie.ie.busy || ($ie.ie.readyState != 4) || additionalCondition
true
else
false
end
end
end
4 - Yourself while you watch a script execute
Maybe you are watching the script execute and you just want to slow things down for troubleshooting reasons. Of course, there is always the venerable (and oft overused) "sleep" method. Using "sleep( x )" will cause the script to pause for x seconds.
If, however, you are annoyed by the slowness of your script, you can always make it faster:
ie = Watir::IE.new
ie.speed = :fast
or
ie = Watir::IE.new
ie.speed = :zippy
See this for more information.
click_no_wait
Information here about what this method is all about.
Continuing testing if IE refuses to load a page
When IE.attach does not find a window it throws a NoMatchingWindowFoundException. You can catch the exception instead of letting watir exit your tests. At this point you can build some 'recovery' if you need it or simply continue or exit your test explicitly after logging some test data.
require "watir"
begin
@ie = Watir::IE.attach(:url , /Webpage Dialog/) #let's say the window does not exist on the desktop
rescue Watir::Exception::NoMatchingWindowFoundException => e
puts "Failed to find new pop up window! #{e}"
# you can now recover or exit or continue
end
When IE.goto is invoked it implicitly waits for the page to load and runs any registered @error_checkers. If you don't have them added to browser then you can explicitly call check_for_http_errors. On HTTP errors encountered the Exception will be thrown. You can rescue the exception and continue with your test and recover or just exit after logging some test data.
require 'watir'
@ie = Watir::IE.new #start new browser window
@ie.goto 'http://asdf asdf.com' #navigation to this page will load Can Not Find Server page #notice the space in url string
begin
@ie.check_for_http_error # will throw Exception
rescue Watir::Exception::NavigationException => e #catch the Exception
puts "Page did not load: #{e}" # => 'Cannot find server or DNS Error'
# you can now recover or exit or just continue
end
# OR you can register error_checker which will be called when goto is invoked
require 'watir/contrib/page_checker'
@ie.add_checker(PageCheckers::NAVIGATION_CHECKER)
begin
@ie.goto "http://marekj.com/asdfasdfasdfa"
rescue Watir::Exception::NavigationException => e #catch the Exception
puts "Page did not load: #{e}" # => 'HTTP 404 - File not found'
# you can now recover or exit or just continue
end
How to wait in Watir?
Watir does not wait for new page to load, except:
when you "attach" to an existing
window
use the "click" method
"set" or "clear" radio buttons or checkboxes
when you select an item in a select list
when you clear a text field
when you "goto" a new page
when you "submit" a form
when you "back", "forward" or "refresh" the browser
when you "fire_event" on any element
ie = Watir::IE.attach(:title, 'My Window')
# no need to wait, ie.wait called implicitly
ie.link(:id, 'mylink').click
# no need to wait, ie.wait called implicitly
assert(ie.link(:id, 'mynewlink).exists?)
"Watir is deterministic. Watir does not wait X seconds. It waits until the page is loaded. Period."
when you "attach" to an existing
window
use the "click" method
"set" or "clear" radio buttons or checkboxes
when you select an item in a select list
when you clear a text field
when you "goto" a new page
when you "submit" a form
when you "back", "forward" or "refresh" the browser
when you "fire_event" on any element
ie = Watir::IE.attach(:title, 'My Window')
# no need to wait, ie.wait called implicitly
ie.link(:id, 'mylink').click
# no need to wait, ie.wait called implicitly
assert(ie.link(:id, 'mynewlink).exists?)
"Watir is deterministic. Watir does not wait X seconds. It waits until the page is loaded. Period."
How do I use Ruby for shell scripting?
Dir['*.rb'] #basic globs
Dir['**/*.rb'] #** == any depth of directory, including current dir.
#=> array of relative names
File.expand_path('~/file.txt') #=> "/User/mat/file.txt"
File.dirname('dir/file.txt') #=> 'dir'
File.basename('dir/file.txt') #=> 'file.txt'
File.join('a', 'bunch', 'of', 'strings') #=> 'a/bunch/of/strings'
__FILE__ #=> the name of the current file
Also useful from the stdlib is FileUtils
require 'fileutils' #I know, no underscore is not ruby-like
include FileUtils
# Gives you access (without prepending by 'FileUtils.') to
cd(dir, options)
cd(dir, options) {|dir| .... }
pwd()
mkdir(dir, options)
mkdir(list, options)
mkdir_p(dir, options)
mkdir_p(list, options)
rmdir(dir, options)
rmdir(list, options)
ln(old, new, options)
ln(list, destdir, options)
ln_s(old, new, options)
ln_s(list, destdir, options)
ln_sf(src, dest, options)
cp(src, dest, options)
cp(list, dir, options)
cp_r(src, dest, options)
cp_r(list, dir, options)
mv(src, dest, options)
mv(list, dir, options)
rm(list, options)
rm_r(list, options)
rm_rf(list, options)
install(src, dest, mode =, options)
chmod(mode, list, options)
chmod_R(mode, list, options)
chown(user, group, list, options)
chown_R(user, group, list, options)
touch(list, options)
Dir['**/*.rb'] #** == any depth of directory, including current dir.
#=> array of relative names
File.expand_path('~/file.txt') #=> "/User/mat/file.txt"
File.dirname('dir/file.txt') #=> 'dir'
File.basename('dir/file.txt') #=> 'file.txt'
File.join('a', 'bunch', 'of', 'strings') #=> 'a/bunch/of/strings'
__FILE__ #=> the name of the current file
Also useful from the stdlib is FileUtils
require 'fileutils' #I know, no underscore is not ruby-like
include FileUtils
# Gives you access (without prepending by 'FileUtils.') to
cd(dir, options)
cd(dir, options) {|dir| .... }
pwd()
mkdir(dir, options)
mkdir(list, options)
mkdir_p(dir, options)
mkdir_p(list, options)
rmdir(dir, options)
rmdir(list, options)
ln(old, new, options)
ln(list, destdir, options)
ln_s(old, new, options)
ln_s(list, destdir, options)
ln_sf(src, dest, options)
cp(src, dest, options)
cp(list, dir, options)
cp_r(src, dest, options)
cp_r(list, dir, options)
mv(src, dest, options)
mv(list, dir, options)
rm(list, options)
rm_r(list, options)
rm_rf(list, options)
install(src, dest, mode =
chmod(mode, list, options)
chmod_R(mode, list, options)
chown(user, group, list, options)
chown_R(user, group, list, options)
touch(list, options)
Friday, February 4, 2011
Watir-WebDriver in three browsers
These three browsers seem to work very similarly, but obviously Internet Explorer will only run on Microsoft Windows.
view sourceprint?01 require "rubygems"
02 require "watir-webdriver"
03 require "watir-webdriver/extensions/wait"
04 b = Watir::Browser.new :chrome
05 b.goto "www.google.com"
06 b.text_field(:name => "q").set "Watir-WebDriver"
07 b.button(:name => "btnG").click
08 b.div(:id => "resultStats").wait_until_present
09 puts "Displaying page: '#{b.title}' with results: '#{b.div(:id => "resultStats").text}'"
10 b.close
view sourceprint?01 require "rubygems"
02 require "watir-webdriver"
03 require "watir-webdriver/extensions/wait"
04 b = Watir::Browser.new :chrome
05 b.goto "www.google.com"
06 b.text_field(:name => "q").set "Watir-WebDriver"
07 b.button(:name => "btnG").click
08 b.div(:id => "resultStats").wait_until_present
09 puts "Displaying page: '#{b.title}' with results: '#{b.div(:id => "resultStats").text}'"
10 b.close
Watir Framework
A Watir framework that object models your AUT and uses Rspec Story Runner aidy dot lewis at googlemail dot com
gem install rspec
Run example from:
watirFramework\runner\gmail.rb
(you will need to sign out of gmail)
watirFramework.zip you want this mail me...or comment on this post
The rspecReports zip contains js and css to colour your HTML reports
Red is a fail
Green a pass
Yellow means pending
eg.
cd watirFramework\runner
ruby gmail.rb -fh: > "C:\rspec_reports\gmail.htm"
rspecReports.zip
you want this mail me...or comment on this post
Labels parameters
Labels
gem install rspec
Run example from:
watirFramework\runner\gmail.rb
(you will need to sign out of gmail)
watirFramework.zip you want this mail me...or comment on this post
The rspecReports zip contains js and css to colour your HTML reports
Red is a fail
Green a pass
Yellow means pending
eg.
cd watirFramework\runner
ruby gmail.rb -fh: > "C:\rspec_reports\gmail.htm"
rspecReports.zip
you want this mail me...or comment on this post
Labels parameters
Labels
Is Ruby is a Scripting Language or Compiled Language?
In general, programming languages fall into one of two
categories: they're either compiled languages or scripting
languages. Let's explore what each of those terms means, and
understand the differences between them.
Compiled Languages: The language in which you write an
application is not actually something that your computer
understands. Your code needs to be translated into bits and
bytes that can be executed by your computer. This process of
translation is called compilation, and any language that
requires compilation is referred to as a compiled language.
Examples of compiled languages include C, C#, and Java.
For a compiled language, the actual compilation is the final
step in the development process. You invoke a compiler --
the software program that translates your final
hand-written, human-readable code into machine-readable code
-- and the compiler creates an executable file. This final
product is then able to execute independently of the
original source code.
Thus, if you make changes to your code, and you want those
changes to be incorporated into the application, you must
stop the running application, recompile it, then start the
application again.
Scripting Languages: On the other hand, a scripting language
such as Ruby, PHP, or Python, relies upon an application's
source code all of the time. Scripting languages don't have
a compiler or a compilation phase per se; instead, they use
an interpreter -- a program that runs on the web server --
to translate hand-written code into machine-executable code
on the fly. The link between the running application and
your hand-crafted code is never severed, because that
scripting code is translated every time it is invoked -- in
other words, for every web page that your application renders.
As you might have gathered from the name, the use of an
interpreter rather than a compiler is the major difference
between a scripting language and a compiled language.
The Great Performance Debate: If you've come from a
compiled-language background, you might be concerned by all
this talk of translating code on the fly -- how does it
affect the application's performance?
These concerns are valid -- translating code on the web
server every time it's needed is certainly more expensive,
performance-wise, than executing pre-compiled code, as it
requires more effort on the part of your machine's
processor. The good news is that there are ways to speed up
scripted languages, including techniques such as code
caching and persistent interpreters. However, both topics
are beyond the scope of this book.
There's also an upside to scripted languages in terms of
performance -- namely, your performance while developing an
application.
Imagine that you've just compiled a shiny new Java
application, and launched it for the first time ... and then
you notice a typo on the welcome screen. To fix it, you have
to stop your application, go back to the source code, fix
the typo, wait for the code to recompile, and restart your
application to confirm that it is fixed. And if you find
another typo, you'll need to repeat that process again.
Lather, rinse, repeat.
In a scripting language, you can fix the typo and just
reload the page in your browser -- no restart, no recompile,
no nothing. It's as simple as that.
categories: they're either compiled languages or scripting
languages. Let's explore what each of those terms means, and
understand the differences between them.
Compiled Languages: The language in which you write an
application is not actually something that your computer
understands. Your code needs to be translated into bits and
bytes that can be executed by your computer. This process of
translation is called compilation, and any language that
requires compilation is referred to as a compiled language.
Examples of compiled languages include C, C#, and Java.
For a compiled language, the actual compilation is the final
step in the development process. You invoke a compiler --
the software program that translates your final
hand-written, human-readable code into machine-readable code
-- and the compiler creates an executable file. This final
product is then able to execute independently of the
original source code.
Thus, if you make changes to your code, and you want those
changes to be incorporated into the application, you must
stop the running application, recompile it, then start the
application again.
Scripting Languages: On the other hand, a scripting language
such as Ruby, PHP, or Python, relies upon an application's
source code all of the time. Scripting languages don't have
a compiler or a compilation phase per se; instead, they use
an interpreter -- a program that runs on the web server --
to translate hand-written code into machine-executable code
on the fly. The link between the running application and
your hand-crafted code is never severed, because that
scripting code is translated every time it is invoked -- in
other words, for every web page that your application renders.
As you might have gathered from the name, the use of an
interpreter rather than a compiler is the major difference
between a scripting language and a compiled language.
The Great Performance Debate: If you've come from a
compiled-language background, you might be concerned by all
this talk of translating code on the fly -- how does it
affect the application's performance?
These concerns are valid -- translating code on the web
server every time it's needed is certainly more expensive,
performance-wise, than executing pre-compiled code, as it
requires more effort on the part of your machine's
processor. The good news is that there are ways to speed up
scripted languages, including techniques such as code
caching and persistent interpreters. However, both topics
are beyond the scope of this book.
There's also an upside to scripted languages in terms of
performance -- namely, your performance while developing an
application.
Imagine that you've just compiled a shiny new Java
application, and launched it for the first time ... and then
you notice a typo on the welcome screen. To fix it, you have
to stop your application, go back to the source code, fix
the typo, wait for the code to recompile, and restart your
application to confirm that it is fixed. And if you find
another typo, you'll need to repeat that process again.
Lather, rinse, repeat.
In a scripting language, you can fix the typo and just
reload the page in your browser -- no restart, no recompile,
no nothing. It's as simple as that.
Tuesday, February 1, 2011
How to Create watir Frame work : Admin Module.rb
Web Application Testing in Ruby: How to Create watir Frame work : Customer Module.rb
require 'test/unit'
02 include Test::Unit::Assertions
03
04 module Admin
05 TITLE = 'ADMINISTER Pragprog Books Online Store'
06 URL = 'http://localhost:3000/admin/'
07
08 def Admin.log_on(browser, username, password)
09 browser.goto(URL)
10 if browser.link(:text,'Log out').exist? then #if already logged in
11 browser.link(:text,'Log out').click
12 end
13 browser.text_field(:id, 'user_name').set username
14 browser.text_field(:id, 'user_password').set password
15 browser.button(:value, ' LOGIN ').click
16 if browser.div(:id, 'notice').exist? then
17 return false,browser.div(:id, 'notice').text
18 else
19 return true,''
20 end
21 end
22
23 def Admin.ship_items(browser, name)
24 browser.goto(URL)
25 browser.link(:text, 'Shipping').click
26 num_orders = 0
27 index = 0
28 browser.form(:action,'/admin/ship').divs.each do |div|
29 if div.class_name == "olname"
30 index+=1
31 if div.text == name then
32 browser.form(:action,'/admin/ship').checkbox(:index, index).set
33 num_orders+=1
34 end
35 end
36 end
37
38 browser.button(:value, ' SHIP CHECKED ITEMS ').click
39
40 if num_orders == 1 then
41 assert_equal(browser.div(:id,"notice").text, "One order marked as shipped","Correct notice")
42 elsif num_orders > 1 then
43 assert_equal(browser.div(:id,"notice").text, "#{num_orders} orders marked as shipped","Correct notice")
44 end
45 return true, num_orders.to_s
46 end
47
48 end
require 'test/unit'
02 include Test::Unit::Assertions
03
04 module Admin
05 TITLE = 'ADMINISTER Pragprog Books Online Store'
06 URL = 'http://localhost:3000/admin/'
07
08 def Admin.log_on(browser, username, password)
09 browser.goto(URL)
10 if browser.link(:text,'Log out').exist? then #if already logged in
11 browser.link(:text,'Log out').click
12 end
13 browser.text_field(:id, 'user_name').set username
14 browser.text_field(:id, 'user_password').set password
15 browser.button(:value, ' LOGIN ').click
16 if browser.div(:id, 'notice').exist? then
17 return false,browser.div(:id, 'notice').text
18 else
19 return true,''
20 end
21 end
22
23 def Admin.ship_items(browser, name)
24 browser.goto(URL)
25 browser.link(:text, 'Shipping').click
26 num_orders = 0
27 index = 0
28 browser.form(:action,'/admin/ship').divs.each do |div|
29 if div.class_name == "olname"
30 index+=1
31 if div.text == name then
32 browser.form(:action,'/admin/ship').checkbox(:index, index).set
33 num_orders+=1
34 end
35 end
36 end
37
38 browser.button(:value, ' SHIP CHECKED ITEMS ').click
39
40 if num_orders == 1 then
41 assert_equal(browser.div(:id,"notice").text, "One order marked as shipped","Correct notice")
42 elsif num_orders > 1 then
43 assert_equal(browser.div(:id,"notice").text, "#{num_orders} orders marked as shipped","Correct notice")
44 end
45 return true, num_orders.to_s
46 end
47
48 end
Labels:
General Testing,
Watir Framework,
Watir testing
How to Create watir Frame work : Customer Module.rb
Web Application Testing in Ruby: How to Create watir Frame work : Test Driver tc_main.rb
require 'test/unit'
002 include Test::Unit::Assertions
003
004 module Customer
005
006 TITLE = 'Pragprog Books Online Store'
007 URL = 'http://localhost:3000/store/'
008
009 # Description:: Adds a book named 'book_title' to cart
010 def Customer.add_book(browser, book_title)
011 browser.goto(URL)
012 # Check if title is already in cart - so we can check it was added correctly
013 browser.link(:text,'Show my cart').click
014 prev_cart_count = 0
015 prev_cart_total = 0.00
016 if not browser.div(:text,'Your cart is currently empty').exist? then
017 # We have a non-empty cart
018 for row in browser.table(:index,1)
019 if row[2].text == book_title then
020 prev_cart_count = row[1].text.to_i
021 break
022 end
023 end
024 prev_cart_total = browser.cell(:id, 'totalcell').text[1..-1].to_f #remove $ sign
025 browser.link(:text, 'Continue shopping').click
026 end
027
028 found = false
029 book_price = 0.00
030 1.upto(browser.divs.length) do |index|
031 if (browser.div(:index,index).attribute_value('className') == 'catalogentry') and (browser.div(:index,index).h3(:text,book_title).exists?) then
032 book_price = browser.div(:index,index).span(:class, 'catalogprice').text[1..-1].to_f #remove $ sign
033 browser.div(:index,index).link(:class,'addtocart').click
034 found = true
035 break
036 end
037 end
038 if not found then
039 return false,'Could not locate title in store'
040 end
041
042 new_cart_count = 0
043 for row in browser.table(:index,1)
044 if row[2].text == book_title then
045 new_cart_count = row[1].text.to_i
046 break
047 end
048 end
049 new_cart_total = browser.cell(:id, 'totalcell').text[1..-1].to_f # remove $ sign
050 assert_equal(new_cart_count,(prev_cart_count+1), "Ensure that new quantity is now one greater than previously")
051 assert_equal(new_cart_total,(prev_cart_total + book_price), "Ensure that new cart total is old cart total plus book price")
052 browser.link(:text, 'Continue shopping').click
053 return true,new_cart_total
054 end
055
056 def Customer.check_out(browser, customerName, customerEmail, customerAddress, customerPaymentMethod)
057 browser.goto(URL)
058 browser.link(:text,'Show my cart').click
059 if browser.div(:text,'Your cart is currently empty').exist? then
060 return false,'Your cart is currently empty'
061 end
062 browser.link(:text,"Checkout").click
063 browser.text_field(:id, 'order_name').set(customerName)
064 browser.text_field(:id, 'order_email').set(customerEmail)
065 browser.text_field(:id, 'order_address').set(customerAddress)
066 begin
067 browser.select_list(:id, 'order_pay_type').select(customerPaymentMethod)
068 rescue Watir::Exception::NoValueFoundException
069 flunk('Could not locate customer payment method in drop down list: '+customerPaymentMethod)
070 end
071 browser.button(:name, 'commit').click
072 if browser.div(:id,'errorExplanation').exist? then
073 error = ''
074 1.upto(browser.div(:id,'errorExplanation').lis.length) do |index|
075 error << (browser.div(:id,'errorExplanation').li(:index,index).text + ",")
076 end
077 browser.link(:text,'Continue shopping').click
078 return false, error
079 end
080 assert_equal(browser.div(:id,'notice').text, 'Thank you for your order.',"Thank you for your order should appear.")
081 return true,''
082 end
083
084 def Customer.empty_cart(browser)
085 browser.goto(URL)
086 browser.link(:text,"Show my cart").click
087 if browser.div(:text,"Your cart is currently empty").exist? then
088 assert('Cart was never empty')
089 else
090 browser.link(:text,'Empty cart').click
091 assert_equal(browser.div(:id, 'notice').text,'Your cart is now empty')
092 end
093 return true,''
094 end
095
096 def Customer.check_cart_total(browser, exp_total)
097 browser.goto(URL)
098 browser.link(:text,'Show my cart').click
099 if browser.div(:text,'Your cart is currently empty').exist? then
100 return false,'Your cart is currently empty'
101 end
102 act_total = browser.cell(:id, 'totalcell').text[1..-1].to_f
103 assert_equal(act_total,exp_total.to_f,"Check that cart total is as expected.")
104 return true,act_total
105 end
106 end
require 'test/unit'
002 include Test::Unit::Assertions
003
004 module Customer
005
006 TITLE = 'Pragprog Books Online Store'
007 URL = 'http://localhost:3000/store/'
008
009 # Description:: Adds a book named 'book_title' to cart
010 def Customer.add_book(browser, book_title)
011 browser.goto(URL)
012 # Check if title is already in cart - so we can check it was added correctly
013 browser.link(:text,'Show my cart').click
014 prev_cart_count = 0
015 prev_cart_total = 0.00
016 if not browser.div(:text,'Your cart is currently empty').exist? then
017 # We have a non-empty cart
018 for row in browser.table(:index,1)
019 if row[2].text == book_title then
020 prev_cart_count = row[1].text.to_i
021 break
022 end
023 end
024 prev_cart_total = browser.cell(:id, 'totalcell').text[1..-1].to_f #remove $ sign
025 browser.link(:text, 'Continue shopping').click
026 end
027
028 found = false
029 book_price = 0.00
030 1.upto(browser.divs.length) do |index|
031 if (browser.div(:index,index).attribute_value('className') == 'catalogentry') and (browser.div(:index,index).h3(:text,book_title).exists?) then
032 book_price = browser.div(:index,index).span(:class, 'catalogprice').text[1..-1].to_f #remove $ sign
033 browser.div(:index,index).link(:class,'addtocart').click
034 found = true
035 break
036 end
037 end
038 if not found then
039 return false,'Could not locate title in store'
040 end
041
042 new_cart_count = 0
043 for row in browser.table(:index,1)
044 if row[2].text == book_title then
045 new_cart_count = row[1].text.to_i
046 break
047 end
048 end
049 new_cart_total = browser.cell(:id, 'totalcell').text[1..-1].to_f # remove $ sign
050 assert_equal(new_cart_count,(prev_cart_count+1), "Ensure that new quantity is now one greater than previously")
051 assert_equal(new_cart_total,(prev_cart_total + book_price), "Ensure that new cart total is old cart total plus book price")
052 browser.link(:text, 'Continue shopping').click
053 return true,new_cart_total
054 end
055
056 def Customer.check_out(browser, customerName, customerEmail, customerAddress, customerPaymentMethod)
057 browser.goto(URL)
058 browser.link(:text,'Show my cart').click
059 if browser.div(:text,'Your cart is currently empty').exist? then
060 return false,'Your cart is currently empty'
061 end
062 browser.link(:text,"Checkout").click
063 browser.text_field(:id, 'order_name').set(customerName)
064 browser.text_field(:id, 'order_email').set(customerEmail)
065 browser.text_field(:id, 'order_address').set(customerAddress)
066 begin
067 browser.select_list(:id, 'order_pay_type').select(customerPaymentMethod)
068 rescue Watir::Exception::NoValueFoundException
069 flunk('Could not locate customer payment method in drop down list: '+customerPaymentMethod)
070 end
071 browser.button(:name, 'commit').click
072 if browser.div(:id,'errorExplanation').exist? then
073 error = ''
074 1.upto(browser.div(:id,'errorExplanation').lis.length) do |index|
075 error << (browser.div(:id,'errorExplanation').li(:index,index).text + ",")
076 end
077 browser.link(:text,'Continue shopping').click
078 return false, error
079 end
080 assert_equal(browser.div(:id,'notice').text, 'Thank you for your order.',"Thank you for your order should appear.")
081 return true,''
082 end
083
084 def Customer.empty_cart(browser)
085 browser.goto(URL)
086 browser.link(:text,"Show my cart").click
087 if browser.div(:text,"Your cart is currently empty").exist? then
088 assert('Cart was never empty')
089 else
090 browser.link(:text,'Empty cart').click
091 assert_equal(browser.div(:id, 'notice').text,'Your cart is now empty')
092 end
093 return true,''
094 end
095
096 def Customer.check_cart_total(browser, exp_total)
097 browser.goto(URL)
098 browser.link(:text,'Show my cart').click
099 if browser.div(:text,'Your cart is currently empty').exist? then
100 return false,'Your cart is currently empty'
101 end
102 act_total = browser.cell(:id, 'totalcell').text[1..-1].to_f
103 assert_equal(act_total,exp_total.to_f,"Check that cart total is as expected.")
104 return true,act_total
105 end
106 end
Labels:
General Testing,
Watir Framework,
Watir testing
How to Create watir Frame work : Test Driver tc_main.rb
Web Application Testing in Ruby: How to Create watir Frame work ?
$:.unshift File.join(File.dirname(__FILE__), ".", "lib")
002 require 'watir'
003 require 'roo'
004 require 'test/unit'
005 require 'customer'
006 require 'admin'
007 $stdout = File.new('log.txt',File::WRONLY|File::APPEND|File::CREAT)
008 $stderr = File.new('log.txt',File::WRONLY|File::APPEND|File::CREAT)
009
010 class TC_WatirMelon < Test::Unit::TestCase
011 @@colmap = {:module_name=>0, :method_name=>1, :comments=>2, :exp_outcome=>3, :exp_error=>4, :first_param=>5}
012 @@ss_format = ARGV[0]
013 @@specified_browser = ARGV[1]
014
015 def setup
016 puts "[Starting at #{Time.now}]\n"
017 case @@ss_format
018 when "excel"
019 @ss = Excel.new("watirmelon.xls")
020 when "wiki"
021 @ss = Excel.new("http://localhost:8080/download/attachments/2097153/watirmelon.xls")
022 when "gdocs"
023 @ss = Google.new("0AtL3mPY2rEqmdEY3XzRqUlZKSmM5Z3EtM21UdFdqb1E")
024 else
025 @ss = Openoffice.new("watirmelon.ods")
026 end
027 @ss.default_sheet = @ss.sheets.first
028 case @@specified_browser
029 when "firefox"
030 Watir::Browser.default = 'firefox'
031 @browser = Watir::Browser.new
032 else
033 Watir::Browser.default = 'ie'
034 @browser = Watir::Browser.new
035 @browser.speed = :zippy
036 @browser.visible = true
037 end
038 end
039
040 def test_run_sheet()
041 @ss.first_row.upto(@ss.last_row) do |row|
042 #Read row into array
043 line = Array.new
044 @ss.first_column.upto(@ss.last_column) do |column|
045 line << @ss.cell(row, column).to_s.strip
046 end
047
048 module_name = line[@@colmap[:module_name]]
049 if module_name != "Function" then #if not a header
050 method_name = line[@@colmap[:method_name]].downcase.gsub(' ','_') #automatically determine ruby method name based upon data sheet
051 exp_outcome = line[@@colmap[:exp_outcome]]
052 exp_error = line[@@colmap[:exp_error]]
053 first_param = @@colmap[:first_param]
054 required_module = Kernel.const_get(module_name)
055 required_method = required_module.method(method_name)
056 arity = required_method.arity() # this is how many arguments the method requires, it is negative if a 'catch all' is supplied.
057 arity = ((arity * -1) - 1) if arity < 0 # arity is negative when there is a 'catch all'
058 arity = arity-1 # Ignore the first browser parameter
059 unless arity == 0
060 parameters = line[first_param..first_param+(arity-1)]
061 else
062 parameters = []
063 end
064 begin
065 act_outcome, act_output = required_method.call(@browser, *parameters)
066 rescue Test::Unit::AssertionFailedError => e
067 self.send(:add_failure, e.message, e.backtrace)
068 act_outcome = false
069 act_output = e.message
070 end
071 if (exp_outcome == 'Success') and act_outcome then
072 assert(true, "Expected outcome and actual outcome are the same")
073 result = 'PASS'
074 elsif (exp_outcome == 'Error') and (not act_outcome) and (exp_error.strip! == act_output.strip!)
075 assert(true, "Expected outcome and actual outcome are the same, and error messages match")
076 result = 'PASS'
077 else
078 result = 'FAIL'
079 begin
080 assert(false,"Row: #{row}: Expected outcome and actual outcome for #{method_name} for #{module_name} do not match, or error messages do not match.")
081 rescue Test::Unit::AssertionFailedError => e
082 self.send(:add_failure, e.message, e.backtrace)
083 end
084 end
085 puts "###########################################"
086 puts "[Running: #{module_name}.#{method_name}]"
087 puts "[Expected Outcome: #{exp_outcome}]"
088 puts "[Expected Error: #{exp_error}]"
089 puts "[Actual Outcome: Success]" if act_outcome
090 puts "[Actual Outcome: Error]" if not act_outcome
091 puts "[Actual Output: #{act_output}]"
092 puts "[RESULT: #{result}]"
093 puts "###########################################"
094 end
095 end
096 end
097
098 def teardown
099 @browser.close
100 puts "[Finishing at #{Time.now}]\n\n"
101 end
102
103 end
$:.unshift File.join(File.dirname(__FILE__), ".", "lib")
002 require 'watir'
003 require 'roo'
004 require 'test/unit'
005 require 'customer'
006 require 'admin'
007 $stdout = File.new('log.txt',File::WRONLY|File::APPEND|File::CREAT)
008 $stderr = File.new('log.txt',File::WRONLY|File::APPEND|File::CREAT)
009
010 class TC_WatirMelon < Test::Unit::TestCase
011 @@colmap = {:module_name=>0, :method_name=>1, :comments=>2, :exp_outcome=>3, :exp_error=>4, :first_param=>5}
012 @@ss_format = ARGV[0]
013 @@specified_browser = ARGV[1]
014
015 def setup
016 puts "[Starting at #{Time.now}]\n"
017 case @@ss_format
018 when "excel"
019 @ss = Excel.new("watirmelon.xls")
020 when "wiki"
021 @ss = Excel.new("http://localhost:8080/download/attachments/2097153/watirmelon.xls")
022 when "gdocs"
023 @ss = Google.new("0AtL3mPY2rEqmdEY3XzRqUlZKSmM5Z3EtM21UdFdqb1E")
024 else
025 @ss = Openoffice.new("watirmelon.ods")
026 end
027 @ss.default_sheet = @ss.sheets.first
028 case @@specified_browser
029 when "firefox"
030 Watir::Browser.default = 'firefox'
031 @browser = Watir::Browser.new
032 else
033 Watir::Browser.default = 'ie'
034 @browser = Watir::Browser.new
035 @browser.speed = :zippy
036 @browser.visible = true
037 end
038 end
039
040 def test_run_sheet()
041 @ss.first_row.upto(@ss.last_row) do |row|
042 #Read row into array
043 line = Array.new
044 @ss.first_column.upto(@ss.last_column) do |column|
045 line << @ss.cell(row, column).to_s.strip
046 end
047
048 module_name = line[@@colmap[:module_name]]
049 if module_name != "Function" then #if not a header
050 method_name = line[@@colmap[:method_name]].downcase.gsub(' ','_') #automatically determine ruby method name based upon data sheet
051 exp_outcome = line[@@colmap[:exp_outcome]]
052 exp_error = line[@@colmap[:exp_error]]
053 first_param = @@colmap[:first_param]
054 required_module = Kernel.const_get(module_name)
055 required_method = required_module.method(method_name)
056 arity = required_method.arity() # this is how many arguments the method requires, it is negative if a 'catch all' is supplied.
057 arity = ((arity * -1) - 1) if arity < 0 # arity is negative when there is a 'catch all'
058 arity = arity-1 # Ignore the first browser parameter
059 unless arity == 0
060 parameters = line[first_param..first_param+(arity-1)]
061 else
062 parameters = []
063 end
064 begin
065 act_outcome, act_output = required_method.call(@browser, *parameters)
066 rescue Test::Unit::AssertionFailedError => e
067 self.send(:add_failure, e.message, e.backtrace)
068 act_outcome = false
069 act_output = e.message
070 end
071 if (exp_outcome == 'Success') and act_outcome then
072 assert(true, "Expected outcome and actual outcome are the same")
073 result = 'PASS'
074 elsif (exp_outcome == 'Error') and (not act_outcome) and (exp_error.strip! == act_output.strip!)
075 assert(true, "Expected outcome and actual outcome are the same, and error messages match")
076 result = 'PASS'
077 else
078 result = 'FAIL'
079 begin
080 assert(false,"Row: #{row}: Expected outcome and actual outcome for #{method_name} for #{module_name} do not match, or error messages do not match.")
081 rescue Test::Unit::AssertionFailedError => e
082 self.send(:add_failure, e.message, e.backtrace)
083 end
084 end
085 puts "###########################################"
086 puts "[Running: #{module_name}.#{method_name}]"
087 puts "[Expected Outcome: #{exp_outcome}]"
088 puts "[Expected Error: #{exp_error}]"
089 puts "[Actual Outcome: Success]" if act_outcome
090 puts "[Actual Outcome: Error]" if not act_outcome
091 puts "[Actual Output: #{act_output}]"
092 puts "[RESULT: #{result}]"
093 puts "###########################################"
094 end
095 end
096 end
097
098 def teardown
099 @browser.close
100 puts "[Finishing at #{Time.now}]\n\n"
101 end
102
103 end
Labels:
General Testing,
Watir Framework,
Watir testing
How to Create watir Frame work ?
One common challenge I see over and over again is people figuring out how to design a logical and maintainable automated testing framework. I have designed quite a few frameworks for various projects, but one thing that has consistently been a win for me is purposely separating test case and test execution design.
It’s therefore logical that the design of my Watir framework deliberately separates test case design and test execution design so that:
■test case design is done visually in spreadsheets; and
■test execution design is done in ruby methods, because code is the most efficient and maintainable way.
Since I last published details about my framework on this blog, I have started doing assertions using the Test::Unit ruby library. The reasons I chose Test::Unit are:
■it is easy to ‘mix-in’ Test::Unit assertions into modules of ruby code using include Test::Unit::Assertions;
■it is included with ruby;
■ruby scripts with Test::Unit::TestCase are instantly executable, in my case, from SciTE;
■its assertions are easy to understand and use.
I have also made some other improvements to my framework code, including:
■the ability to specify browser types, and spreadsheet sources, as command line arguments (with defaults);
■logging test output to a file;
■no longer attaching to an open browser, the same browser instance is used completely for all tests (and elegantly closed at the end).
The main design has been kept the same, in that a spreadsheet (either excel, openoffice or Google Docs) contains tests grouped by functional area, which call a method in a particular module.
The great thing about my framework is that adding a new test is a matter of designing the test case, and then writing the ruby method: as the methods are called dynamically from the spreadsheet, no extra glue is needed!
Enough talk, here’s the code. The Google spreadsheet is here. You can find a .zip file of all the required files to run it here. It runs on the depot app, which you get here. You will need two gems: Watir (oh duh), and Roo.
It’s therefore logical that the design of my Watir framework deliberately separates test case design and test execution design so that:
■test case design is done visually in spreadsheets; and
■test execution design is done in ruby methods, because code is the most efficient and maintainable way.
Since I last published details about my framework on this blog, I have started doing assertions using the Test::Unit ruby library. The reasons I chose Test::Unit are:
■it is easy to ‘mix-in’ Test::Unit assertions into modules of ruby code using include Test::Unit::Assertions;
■it is included with ruby;
■ruby scripts with Test::Unit::TestCase are instantly executable, in my case, from SciTE;
■its assertions are easy to understand and use.
I have also made some other improvements to my framework code, including:
■the ability to specify browser types, and spreadsheet sources, as command line arguments (with defaults);
■logging test output to a file;
■no longer attaching to an open browser, the same browser instance is used completely for all tests (and elegantly closed at the end).
The main design has been kept the same, in that a spreadsheet (either excel, openoffice or Google Docs) contains tests grouped by functional area, which call a method in a particular module.
The great thing about my framework is that adding a new test is a matter of designing the test case, and then writing the ruby method: as the methods are called dynamically from the spreadsheet, no extra glue is needed!
Enough talk, here’s the code. The Google spreadsheet is here. You can find a .zip file of all the required files to run it here. It runs on the depot app, which you get here. You will need two gems: Watir (oh duh), and Roo.
Labels:
General Testing,
Watir Framework,
Watir testing
Monday, January 31, 2011
How to Dowload Ruby for windows?
For windows you can download Ruby
from
http://rubyforge.org/frs/?group_id=167
from
http://rubyforge.org/frs/?group_id=167
How to Dowload Ruby for Linux?
For windows you can download Ruby
from
http://rubyforge.org/frs/?group_id=167
for Linux try
http://www.rpmfind.net.
from
http://rubyforge.org/frs/?group_id=167
for Linux try
http://www.rpmfind.net.
Saturday, January 29, 2011
Ruby scripting for beginners
Ruby Scripting for beginner
variables:-
We'll deal with variables in much more depth when we talk about classes and objects. For now, let's just say your basic local variable names should start with either a lower case letter or an underscore, and should contain upper or lower case letters, numbers, and underscore characters. Global variables start with a $.
Program flow:-
Ruby includes a pretty standard set of looping and branching constructs: if, while and case
For example, here's if in action:
a = 10 * rand
if a < 5 puts "#{a} less than 5" elsif a > 7
puts "#{a} greater than 7"
else
puts "Cheese sandwich!"
end
[As in other languages, the rand function generates a random number between 0 and 1]
There will be plenty more time to discuss conditional statements in later chapters. The above example should be pretty clear.
Ruby also includes a negated form of if called unless which goes something like
unless a > 5
puts "a is less than or equal to 5"
else
puts "a is greater than 5"
end
Generally speaking, Ruby keeps an if statement straight as long as the conditional (if ...) and the associated code block are on separate lines. If you have to smash everything together on one line, you'll need to place the then keyword after the conditional
if a < 5 then puts "#{a} less than 5" end if a < 5 then puts "#{a} less than 5" else puts "#{a} greater than 5" end Note that the if statement is also an expression; its value is the last line of the block executed. Therefore, the line above could also have been written as puts(if a < 5 then "#{a} less than 5" else "#{a} greater than 5" end) Ruby has also adopted the syntax from Perl where if and unless statements can be used as conditional modifiers after a statement. For example puts "#{a} less than 5" if a < 5 puts "Cheese sandwich" unless a == 4 while behaves as it does in other languages -- the code block that follows is run zero or more times, as long as the conditional is true while a > 5
a = 10*rand
end
And like if, there is also a negated version of while called until which runs the code block until the condition is true.
Finally there is the case statement which we'll just include here with a brief example. case is actually a very powerful super version of the if ... elsif... system
a = (10*rand).round
#a = rand(11) would do the same
case a
when 0..5
puts "#{a}: Low"
when 6
puts "#{a}: Six"
else
puts "#{a}: Cheese toast!"
end
There are some other interesting things going on in this example, but here the case statement is the center of attention.
functions:-
In keeping with Ruby's all-object-oriented-all-the-time design, functions are typically referred to as methods. No difference. We'll cover methods in much more detail when we get to objects and classes. For now, basic method writing looks something like this:
# Demonstrate a method with func1.rb
def my_function( a )
puts "Hello, #{a}"
return a.length
end
len = my_function( "Giraffe" )
puts "My secret word is #{len} long"
$ func1.rb
Hello, Giraffe
My secret word is 7 long
Methods are defined with the def keyword, followed by the function name. As with variables, local and class methods should start with a lower case letter.
In this example, the function takes one argument (a) and returns a value. Note that the input arguments aren't typed (i.e. a need not be a string) ... this allows for great flexibility but can also cause a lot of trouble. The function also returns a single value with the return keyword. Technically this isn't necessary -- the value of the last line executed in the function is used as the return value -- but more often than not using return explicitly makes things clearer.
As with other languages, Ruby supports both default values for arguments and variable-length argument lists, both of which will be covered in due time. There's also support for code blocks, as discussed below.
Blocks:-
One very important concept in Ruby is the code block. It's actually not a particularly revolutionary concept -- any time you've written if ... { ... } in C or Perl you've defined a code block, but in Ruby a code block has some hidden secret powers...
Code blocks in Ruby are defined either with the keywords do..end or the curly brackets {..}
do
print "I like "
print "code blocks!"
end
{
print "Me too!"
}
One very powerful usage of code blocks is that methods can take one as a parameter and execute it along the way.
[ed note: the Pragmatic Programmers actually want to point out that it's not very useful to describe it this way. Instead, the block of code behaves like a 'partner' to which the function occasionally hands over control]
The concept can be hard to get the first time it's explained to you. Here's an example:
$ irb --simple-prompt
>> 3.times { puts "Hi!" }
Hi!
Hi!
Hi!
=> 3
Surprise! You always thought 3 was just a number, but it's actually an object (of type Fixnum) As its an object, it has a member function times which takes a block as a parameter. The function runs the block 3 times.
Blocks can actually receive parameters, using a special notation |..|. In this case, a quick check of the documentation for times shows it will pass a single parameter into the block, indicating which loop it's on:
$ irb --simple-prompt
>> 4.times { |x| puts "Loop number #{x}" }
Loop number 0
Loop number 1
Loop number 2
Loop number 3
=> 4
The times function passes a number into the block. The block gets that number in the variable x (as set by the |x|), then prints out the result.
Functions interact with blocks through the yield. Every time the function invokes yield control passes to the block. It only comes back to the function when the block finishes. Here's a simple example:
# Script block2.rb
def simpleFunction
yield
yield
end
simpleFunction { puts "Hello!" }
$ block2.rb
Hello!
Hello!
The simpleFunction simply yields to the block twice -- so the block is run twice and we get two times the output. Here's an example where the function passes a parameter to the block:
# Script block1.rb
def animals
yield "Tiger"
yield "Giraffe"
end
animals { |x| puts "Hello, #{x}" }
$ block1.rb
Hello, Tiger
Hello, Giraffe
It might take a couple of reads through to figure out what's going on here. We've defined the function "animals" -- it expects a code block. When executed, the function calls the code block twice, first with the parameter "Tiger" then again with the parameter "Giraffe". In this example, we've written a simple code block which just prints out a greeting to the animals. We could write a different block, for example:
animals { |x| puts "It's #{x.length} characters long!" }
which would give:
It's 5 characters long!
It's 7 characters long!
Two completely different results from running the same function with two different blocks.
There are many powerful uses of blocks. One of the first you'll come across is the each function for arrays -- it runs a code block once for each element in the array -- it's great for iterating over lists.
variables:-
We'll deal with variables in much more depth when we talk about classes and objects. For now, let's just say your basic local variable names should start with either a lower case letter or an underscore, and should contain upper or lower case letters, numbers, and underscore characters. Global variables start with a $.
Program flow:-
Ruby includes a pretty standard set of looping and branching constructs: if, while and case
For example, here's if in action:
a = 10 * rand
if a < 5 puts "#{a} less than 5" elsif a > 7
puts "#{a} greater than 7"
else
puts "Cheese sandwich!"
end
[As in other languages, the rand function generates a random number between 0 and 1]
There will be plenty more time to discuss conditional statements in later chapters. The above example should be pretty clear.
Ruby also includes a negated form of if called unless which goes something like
unless a > 5
puts "a is less than or equal to 5"
else
puts "a is greater than 5"
end
Generally speaking, Ruby keeps an if statement straight as long as the conditional (if ...) and the associated code block are on separate lines. If you have to smash everything together on one line, you'll need to place the then keyword after the conditional
if a < 5 then puts "#{a} less than 5" end if a < 5 then puts "#{a} less than 5" else puts "#{a} greater than 5" end Note that the if statement is also an expression; its value is the last line of the block executed. Therefore, the line above could also have been written as puts(if a < 5 then "#{a} less than 5" else "#{a} greater than 5" end) Ruby has also adopted the syntax from Perl where if and unless statements can be used as conditional modifiers after a statement. For example puts "#{a} less than 5" if a < 5 puts "Cheese sandwich" unless a == 4 while behaves as it does in other languages -- the code block that follows is run zero or more times, as long as the conditional is true while a > 5
a = 10*rand
end
And like if, there is also a negated version of while called until which runs the code block until the condition is true.
Finally there is the case statement which we'll just include here with a brief example. case is actually a very powerful super version of the if ... elsif... system
a = (10*rand).round
#a = rand(11) would do the same
case a
when 0..5
puts "#{a}: Low"
when 6
puts "#{a}: Six"
else
puts "#{a}: Cheese toast!"
end
There are some other interesting things going on in this example, but here the case statement is the center of attention.
functions:-
In keeping with Ruby's all-object-oriented-all-the-time design, functions are typically referred to as methods. No difference. We'll cover methods in much more detail when we get to objects and classes. For now, basic method writing looks something like this:
# Demonstrate a method with func1.rb
def my_function( a )
puts "Hello, #{a}"
return a.length
end
len = my_function( "Giraffe" )
puts "My secret word is #{len} long"
$ func1.rb
Hello, Giraffe
My secret word is 7 long
Methods are defined with the def keyword, followed by the function name. As with variables, local and class methods should start with a lower case letter.
In this example, the function takes one argument (a) and returns a value. Note that the input arguments aren't typed (i.e. a need not be a string) ... this allows for great flexibility but can also cause a lot of trouble. The function also returns a single value with the return keyword. Technically this isn't necessary -- the value of the last line executed in the function is used as the return value -- but more often than not using return explicitly makes things clearer.
As with other languages, Ruby supports both default values for arguments and variable-length argument lists, both of which will be covered in due time. There's also support for code blocks, as discussed below.
Blocks:-
One very important concept in Ruby is the code block. It's actually not a particularly revolutionary concept -- any time you've written if ... { ... } in C or Perl you've defined a code block, but in Ruby a code block has some hidden secret powers...
Code blocks in Ruby are defined either with the keywords do..end or the curly brackets {..}
do
print "I like "
print "code blocks!"
end
{
print "Me too!"
}
One very powerful usage of code blocks is that methods can take one as a parameter and execute it along the way.
[ed note: the Pragmatic Programmers actually want to point out that it's not very useful to describe it this way. Instead, the block of code behaves like a 'partner' to which the function occasionally hands over control]
The concept can be hard to get the first time it's explained to you. Here's an example:
$ irb --simple-prompt
>> 3.times { puts "Hi!" }
Hi!
Hi!
Hi!
=> 3
Surprise! You always thought 3 was just a number, but it's actually an object (of type Fixnum) As its an object, it has a member function times which takes a block as a parameter. The function runs the block 3 times.
Blocks can actually receive parameters, using a special notation |..|. In this case, a quick check of the documentation for times shows it will pass a single parameter into the block, indicating which loop it's on:
$ irb --simple-prompt
>> 4.times { |x| puts "Loop number #{x}" }
Loop number 0
Loop number 1
Loop number 2
Loop number 3
=> 4
The times function passes a number into the block. The block gets that number in the variable x (as set by the |x|), then prints out the result.
Functions interact with blocks through the yield. Every time the function invokes yield control passes to the block. It only comes back to the function when the block finishes. Here's a simple example:
# Script block2.rb
def simpleFunction
yield
yield
end
simpleFunction { puts "Hello!" }
$ block2.rb
Hello!
Hello!
The simpleFunction simply yields to the block twice -- so the block is run twice and we get two times the output. Here's an example where the function passes a parameter to the block:
# Script block1.rb
def animals
yield "Tiger"
yield "Giraffe"
end
animals { |x| puts "Hello, #{x}" }
$ block1.rb
Hello, Tiger
Hello, Giraffe
It might take a couple of reads through to figure out what's going on here. We've defined the function "animals" -- it expects a code block. When executed, the function calls the code block twice, first with the parameter "Tiger" then again with the parameter "Giraffe". In this example, we've written a simple code block which just prints out a greeting to the animals. We could write a different block, for example:
animals { |x| puts "It's #{x.length} characters long!" }
which would give:
It's 5 characters long!
It's 7 characters long!
Two completely different results from running the same function with two different blocks.
There are many powerful uses of blocks. One of the first you'll come across is the each function for arrays -- it runs a code block once for each element in the array -- it's great for iterating over lists.
How Ruby XPath to find attribute ?
What Ruby library can be used to select attribute using XPath, and to use it as the starting point for other XPath queries.
Example:
Desired code:
get_pair "//*/@key", "../@value"
get_pair "//*/@foo", "../@bar"
Expected output:
"A" "B"
"C" "D"
"E" "F"
Pseudo implementation:
def get_pair(key, value)
xml_doc.select[key].each do |a|
puts [a, a.select[value]]
end
end
Example:
Desired code:
get_pair "//*/@key", "../@value"
get_pair "//*/@foo", "../@bar"
Expected output:
"A" "B"
"C" "D"
"E" "F"
Pseudo implementation:
def get_pair(key, value)
xml_doc.select[key].each do |a|
puts [a, a.select[value]]
end
end
Friday, January 28, 2011
How to deal with Java scripts and frame?
I came across this difficulty when I was trying to automate a webpage that was primarily built in Javascript; this webpage also always had the same href (or web address) and also was built with many frames. The problem that I ran into was that I could find the links with the IE developer toolbar to get their ids, but whenever I tried to access them, I could not, I was given an error message saying that they did not exist. At this point in time I thought the issue I had was with javascript, but I was incorrect!
A lot of hunting on the interwebs led me, ironically, back to the watir main documentation, where I discovered that my issue was really with frames! When a website has frames, you need to specify what frame the link is in to actually access it, for example:
ie.frame(“main”).link(:id,”UW_CO_JOBTITLE_HL$”).click
Or in general terms:
ie.frame(“FRAMENAME”).link(:id, “LINKID”).click
And there we have, you can now access links that are in frames, hopefully this saves someone all of the hunting that I had to do! This is also a really good example of how difficult it is to find a solution to something when you are not sure what the problem was; I thought the problem was with JavaScript, so I was searching for that, but it was in fact as stated above with the frames!
A lot of hunting on the interwebs led me, ironically, back to the watir main documentation, where I discovered that my issue was really with frames! When a website has frames, you need to specify what frame the link is in to actually access it, for example:
ie.frame(“main”).link(:id,”UW_CO_JOBTITLE_HL$”).click
Or in general terms:
ie.frame(“FRAMENAME”).link(:id, “LINKID”).click
And there we have, you can now access links that are in frames, hopefully this saves someone all of the hunting that I had to do! This is also a really good example of how difficult it is to find a solution to something when you are not sure what the problem was; I thought the problem was with JavaScript, so I was searching for that, but it was in fact as stated above with the frames!
IE Automation testing with Ruby: How to catch popup windows?
Firstly I need to define what I mean my pop-up Windows. The pop-up windows that cause trouble are not internet explorer based windows, they are actually ‘Windows’ windows, (sorry if thats confusing). The ones that I am referring to are the ones that come up when, for example, you click on a download link. These are inherently a pain because of the fact that they are not IE windows. Luckily there is a pretty simple work around that i have come up with.
Ruby has access to the WIN32OLE library , which is basically like an API for windows applications. What you can do is use this library to catch these pop up windows. Below is the code that you’ll need to run in a Ruby script:
require ‘win32ole’ #Loads the win32ole library
wsh = WIN32OLE.new(Wscript.Shell) #For more info click here
wsh.AppActivate(‘Connect’) #Focuses on a given application based on its Title
At this point you can manipulate the window, for example, with a SendKeys command:
wsh.SendKeys(“%{F4}”) #This would close the program with Alt-F4
This clearly has it’s limitations because during this time you cannot be doing things on your computer, because the AppActivate would fail. I am still looking for a lower level at which I can address this problem.
Now everyone likes to see code at work, so I have written a quick script that goes to the Notepad++ downloads page, clicks the download link, and then closes the pop-up download window. As a quick side note, if you do not already use notepad++ I highly recommend it!
require ‘win32ole’
require ‘watir’
wsh = WIN32OLE.new(‘Wscript.Shell’)
ie= Watir::IE.new
ie.goto(“http://notepad-plus.sourceforge.net/uk/site.htm”)
ie.frame(:name, “index”).link(:text, “Download”).click #Good example of how to execute a link in a Frame
ie.frame(:name, “index”).link(:text, “Download Notepad++ executable files”).click
sleep 20 #need to wait for source forge to load it is slow
ie1 = Watir::IE.attach(:title, /Source/)
ie1.link(:id, “showfiles_download_file_pkg0_1rel0_2″).click
wsh.AppActivate(“File Download – Security Warning”) #Focuses on the pop up window
wsh.SendKeys(“%{F4}”) #Sends the alt-F4 command to the window to close it
Watir::IE.close_all #Closes all open IE windows
Ruby has access to the WIN32OLE library , which is basically like an API for windows applications. What you can do is use this library to catch these pop up windows. Below is the code that you’ll need to run in a Ruby script:
require ‘win32ole’ #Loads the win32ole library
wsh = WIN32OLE.new(Wscript.Shell) #For more info click here
wsh.AppActivate(‘Connect’) #Focuses on a given application based on its Title
At this point you can manipulate the window, for example, with a SendKeys command:
wsh.SendKeys(“%{F4}”) #This would close the program with Alt-F4
This clearly has it’s limitations because during this time you cannot be doing things on your computer, because the AppActivate would fail. I am still looking for a lower level at which I can address this problem.
Now everyone likes to see code at work, so I have written a quick script that goes to the Notepad++ downloads page, clicks the download link, and then closes the pop-up download window. As a quick side note, if you do not already use notepad++ I highly recommend it!
require ‘win32ole’
require ‘watir’
wsh = WIN32OLE.new(‘Wscript.Shell’)
ie= Watir::IE.new
ie.goto(“http://notepad-plus.sourceforge.net/uk/site.htm”)
ie.frame(:name, “index”).link(:text, “Download”).click #Good example of how to execute a link in a Frame
ie.frame(:name, “index”).link(:text, “Download Notepad++ executable files”).click
sleep 20 #need to wait for source forge to load it is slow
ie1 = Watir::IE.attach(:title, /Source/)
ie1.link(:id, “showfiles_download_file_pkg0_1rel0_2″).click
wsh.AppActivate(“File Download – Security Warning”) #Focuses on the pop up window
wsh.SendKeys(“%{F4}”) #Sends the alt-F4 command to the window to close it
Watir::IE.close_all #Closes all open IE windows
How to catch Popup windows?
The pop-up windows that cause trouble are not internet explorer based windows, they are actually ‘Windows’ windows, (sorry if thats confusing). The ones that I am referring to are the ones that come up when, for example, you click on a download link. These are inherently a pain because of the fact that they are not IE windows. Luckily there is a pretty simple work around that i have come up with.
Ruby has access to the WIN32OLE library , which is basically like an API for windows applications. What you can do is use this library to catch these pop up windows. Below is the code that you’ll need to run in a Ruby script:
require ‘win32ole’ #Loads the win32ole library
wsh = WIN32OLE.new(Wscript.Shell) #For more info click here
wsh.AppActivate(‘Connect’) #Focuses on a given application based on its Title
At this point you can manipulate the window, for example, with a SendKeys command:
wsh.SendKeys(“%{F4}”) #This would close the program with Alt-F4
This clearly has it’s limitations because during this time you cannot be doing things on your computer, because the AppActivate would fail. I am still looking for a lower level at which I can address this problem.
Now everyone likes to see code at work, so I have written a quick script that goes to the Notepad++ downloads page, clicks the download link, and then closes the pop-up download window. As a quick side note, if you do not already use notepad++ I highly recommend it!
require ‘win32ole’
require ‘watir’
wsh = WIN32OLE.new(‘Wscript.Shell’)
ie= Watir::IE.new
ie.goto(“http://notepad-plus.sourceforge.net/uk/site.htm”)
ie.frame(:name, “index”).link(:text, “Download”).click #Good example of how to execute a link in a Frame
ie.frame(:name, “index”).link(:text, “Download Notepad++ executable files”).click
sleep 20 #need to wait for source forge to load it is slow
ie1 = Watir::IE.attach(:title, /Source/)
ie1.link(:id, “showfiles_download_file_pkg0_1rel0_2″).click
wsh.AppActivate(“File Download – Security Warning”) #Focuses on the pop up window
wsh.SendKeys(“%{F4}”) #Sends the alt-F4 command to the window to close it
Watir::IE.close_all #Closes all open IE windows
Ruby has access to the WIN32OLE library , which is basically like an API for windows applications. What you can do is use this library to catch these pop up windows. Below is the code that you’ll need to run in a Ruby script:
require ‘win32ole’ #Loads the win32ole library
wsh = WIN32OLE.new(Wscript.Shell) #For more info click here
wsh.AppActivate(‘Connect’) #Focuses on a given application based on its Title
At this point you can manipulate the window, for example, with a SendKeys command:
wsh.SendKeys(“%{F4}”) #This would close the program with Alt-F4
This clearly has it’s limitations because during this time you cannot be doing things on your computer, because the AppActivate would fail. I am still looking for a lower level at which I can address this problem.
Now everyone likes to see code at work, so I have written a quick script that goes to the Notepad++ downloads page, clicks the download link, and then closes the pop-up download window. As a quick side note, if you do not already use notepad++ I highly recommend it!
require ‘win32ole’
require ‘watir’
wsh = WIN32OLE.new(‘Wscript.Shell’)
ie= Watir::IE.new
ie.goto(“http://notepad-plus.sourceforge.net/uk/site.htm”)
ie.frame(:name, “index”).link(:text, “Download”).click #Good example of how to execute a link in a Frame
ie.frame(:name, “index”).link(:text, “Download Notepad++ executable files”).click
sleep 20 #need to wait for source forge to load it is slow
ie1 = Watir::IE.attach(:title, /Source/)
ie1.link(:id, “showfiles_download_file_pkg0_1rel0_2″).click
wsh.AppActivate(“File Download – Security Warning”) #Focuses on the pop up window
wsh.SendKeys(“%{F4}”) #Sends the alt-F4 command to the window to close it
Watir::IE.close_all #Closes all open IE windows
How to handle JavaScripts popups?
These JavaScript popups cause trouble as they interrupt the page from fully loading, causing Watir to wait (as the page is waiting), which means the next command in your script will never be reached. Previous work arounds to this were to use watirs built in click_no_wait, but I have that to be extremely temperamental and did not always work depending on which element the click was being performed on.
The new and improved method is to have a completely separate process that runs in the background and is continually checking for JavaScript pop ups. AutoIt commands are used to first locate the pop-up and then depending on what text or title is present in the pop up and different action can be performed on it. Unfortunately the same code cannot be used for both IE and FF due to the fact that the AutoIt controls cannot perform the same actions on IE pop-ups as it can on FF pop-ups. I have included the code for both below:
clickPopupsIE.rb
require 'win32ole'
begin
autoit WIN32OLE.new('AutoItX3.Control')
loop do
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')
sleep 1
end
rescue Exception > e
puts e
end
clickPopupsFF.rb
require 'win32ole'
websiteName = "w3schools.com"
begin
autoit = WIN32OLE.new('AutoItX3.Control')
loop do
autoit.winActivate("The page at http://#{websiteName} says:")
autoit.Send("{ENTER}") if(autoit.WinWait("The page at http://#{websiteName} says:",'',2) == 1)
end
rescue Exception => e
puts e
end
These two scripts can then be called from any of your other Watir scripts using the following two functions scripts:
require 'win32/process'
def callPopupKillerFF
$pid = Process.create(:app_name => 'ruby clickPopupsFF.rb', :creation_flags => Process::DETACHED_PROCESS).process_id
end
def callPopupKillerIE
$pid = Process.create(:app_name => 'ruby clickPopupsIE.rb', :creation_flags => Process::DETACHED_PROCESS).process_id
end
def killPopupKiller
Process.kill(9,$pid)
end
As you can see above you do need to require one more ruby gem, ‘win32/process’, this is used to run the popup clicker as a separate process that runs in the background. Once you have those functions in place you can simply call:
callPopupKillerIE #Starts the IE popup killer
#Some watir code that results in a popup#
killPopupKiller #Kills the popup killer process, so that you do not end up with 5 of them running!
The new and improved method is to have a completely separate process that runs in the background and is continually checking for JavaScript pop ups. AutoIt commands are used to first locate the pop-up and then depending on what text or title is present in the pop up and different action can be performed on it. Unfortunately the same code cannot be used for both IE and FF due to the fact that the AutoIt controls cannot perform the same actions on IE pop-ups as it can on FF pop-ups. I have included the code for both below:
clickPopupsIE.rb
require 'win32ole'
begin
autoit WIN32OLE.new('AutoItX3.Control')
loop do
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')
sleep 1
end
rescue Exception > e
puts e
end
clickPopupsFF.rb
require 'win32ole'
websiteName = "w3schools.com"
begin
autoit = WIN32OLE.new('AutoItX3.Control')
loop do
autoit.winActivate("The page at http://#{websiteName} says:")
autoit.Send("{ENTER}") if(autoit.WinWait("The page at http://#{websiteName} says:",'',2) == 1)
end
rescue Exception => e
puts e
end
These two scripts can then be called from any of your other Watir scripts using the following two functions scripts:
require 'win32/process'
def callPopupKillerFF
$pid = Process.create(:app_name => 'ruby clickPopupsFF.rb', :creation_flags => Process::DETACHED_PROCESS).process_id
end
def callPopupKillerIE
$pid = Process.create(:app_name => 'ruby clickPopupsIE.rb', :creation_flags => Process::DETACHED_PROCESS).process_id
end
def killPopupKiller
Process.kill(9,$pid)
end
As you can see above you do need to require one more ruby gem, ‘win32/process’, this is used to run the popup clicker as a separate process that runs in the background. Once you have those functions in place you can simply call:
callPopupKillerIE #Starts the IE popup killer
#Some watir code that results in a popup#
killPopupKiller #Kills the popup killer process, so that you do not end up with 5 of them running!
Ubuntu 8.10 With Firewatir
Some kind Ruby Enthusiasts built a tool called Watir (Web Application Testing in Ruby) which basically allows you to programmatically control a web browser (Specifically Microsoft Internet Explorer). From a Software Quality Assurance standpoint this allows the developers to automate much of what is typically a manual process.
However, IE is not the only browser in the world (and if I had my way it would be eliminated from the face of the earth), and thus has has grown related projects Such as FireWatir which runs Firefox instead of IE.
Last summer's google summer of code involved some refactoring of the Watir code to work more uniformely with FireWatir (and I believe the safari equivalent as well -- although I haven't used that so I can't confirm). Anyways, the process of using watir/firewatir is pretty simple. First, setup your requires/includes
view sourceprint?
1 #may not need rubygems if your system is setup right
2 require 'rubygems'
3 require 'watir'
4 require 'firewatir'
5
6 include FireWatir
Then you do
view sourceprint?
1 browser = Watir::Browser.new
2 #instead of browser = Watir::IE.new
For more information on Watir::Browser check this page:
http://wiki.openqa.org/display/WTR/Browser.new
Unfortunately it doesn't appear the RDocs have been updated to include Watir::Browser
This all works great on windows (who would have guessed), but I've been having trouble setting up Firefox to work with Firewatir in Ubuntu 8.10 linux. I've used several different JSSH extensions that are supposedly compatible with FF on linux (and they appear to install just fine). Those extensions can be found here:
http://wiki.openqa.org/display/WTR/FireWatir+Installation
and here:
http://www.valibuk.net/2008/11/jssh-firefox-30-with-optional-port-number/
Neither seem to work though. I've tried just about everything I can think of, but I can never get telnet to connect to port 9997 after I've loaded the extension into firefox (and restarted, and setup firefox preferences according to tutorials found
here
and
here
and several others. But nothing, I always get the following error when attempting to do either Firefox.new or Watir::Browser.new :
Watir::Exception::UnableToStartJSShException:
Unable to connect to machine : 127.0.0.1 on port 9997.
Make sure that JSSh is properly installed and Firefox
is running with '-jssh' option
I have yet to come up with a working solution, however I'm in the process of building firefox from source and enabling jssh in the build (which should solve the problem).
The build process I've essentially stolen from the firefox build process documentation and utilized from:
http://ubuntu-snippets.blogspot.com/2008/07/build-firefox-3-web-browser-...
and
https://developer.mozilla.org/En/Simple_build
Basically, I pull the source code with hg (mercurial), and use the newer build process documented on the mozilla site, while creating a .mozconfig file as noted in the other tutorial. The one change I had to make to the .mozconfig was I removed the webservices extension since it doesn't seem to be avaiable anymore (I was getting an error when I left it).
Anyways, if anyone has got JSSH working with ubuntu 8.10 I'd love to know how you did it.
Check back often as I shall report with news of whether or not this is working fairly soon.
--- Follow Up --3/22/2009
After finding out that selenium can now be used without using server side javascript code directly I switched to that. I'm now using that with cucumber and have come up with some cool ways of automating tests in multiple browsers. Check back soon, I should have a blog with some details on my setup.
--- Follow Up --4/30/2009
However, IE is not the only browser in the world (and if I had my way it would be eliminated from the face of the earth), and thus has has grown related projects Such as FireWatir which runs Firefox instead of IE.
Last summer's google summer of code involved some refactoring of the Watir code to work more uniformely with FireWatir (and I believe the safari equivalent as well -- although I haven't used that so I can't confirm). Anyways, the process of using watir/firewatir is pretty simple. First, setup your requires/includes
view sourceprint?
1 #may not need rubygems if your system is setup right
2 require 'rubygems'
3 require 'watir'
4 require 'firewatir'
5
6 include FireWatir
Then you do
view sourceprint?
1 browser = Watir::Browser.new
2 #instead of browser = Watir::IE.new
For more information on Watir::Browser check this page:
http://wiki.openqa.org/display/WTR/Browser.new
Unfortunately it doesn't appear the RDocs have been updated to include Watir::Browser
This all works great on windows (who would have guessed), but I've been having trouble setting up Firefox to work with Firewatir in Ubuntu 8.10 linux. I've used several different JSSH extensions that are supposedly compatible with FF on linux (and they appear to install just fine). Those extensions can be found here:
http://wiki.openqa.org/display/WTR/FireWatir+Installation
and here:
http://www.valibuk.net/2008/11/jssh-firefox-30-with-optional-port-number/
Neither seem to work though. I've tried just about everything I can think of, but I can never get telnet to connect to port 9997 after I've loaded the extension into firefox (and restarted, and setup firefox preferences according to tutorials found
here
and
here
and several others. But nothing, I always get the following error when attempting to do either Firefox.new or Watir::Browser.new :
Watir::Exception::UnableToStartJSShException:
Unable to connect to machine : 127.0.0.1 on port 9997.
Make sure that JSSh is properly installed and Firefox
is running with '-jssh' option
I have yet to come up with a working solution, however I'm in the process of building firefox from source and enabling jssh in the build (which should solve the problem).
The build process I've essentially stolen from the firefox build process documentation and utilized from:
http://ubuntu-snippets.blogspot.com/2008/07/build-firefox-3-web-browser-...
and
https://developer.mozilla.org/En/Simple_build
Basically, I pull the source code with hg (mercurial), and use the newer build process documented on the mozilla site, while creating a .mozconfig file as noted in the other tutorial. The one change I had to make to the .mozconfig was I removed the webservices extension since it doesn't seem to be avaiable anymore (I was getting an error when I left it).
Anyways, if anyone has got JSSH working with ubuntu 8.10 I'd love to know how you did it.
Check back often as I shall report with news of whether or not this is working fairly soon.
--- Follow Up --3/22/2009
After finding out that selenium can now be used without using server side javascript code directly I switched to that. I'm now using that with cucumber and have come up with some cool ways of automating tests in multiple browsers. Check back soon, I should have a blog with some details on my setup.
--- Follow Up --4/30/2009
Friday, January 21, 2011
Ruby Scripting
variables:-
We'll deal with variables in much more depth when we talk about classes and objects. For now, let's just say your basic local variable names should start with either a lower case letter or an underscore, and should contain upper or lower case letters, numbers, and underscore characters. Global variables start with a $.
Program flow:-
Ruby includes a pretty standard set of looping and branching constructs: if, while and case
For example, here's if in action:
a = 10 * rand
if a < 5 puts "#{a} less than 5" elsif a > 7
puts "#{a} greater than 7"
else
puts "Cheese sandwich!"
end
[As in other languages, the rand function generates a random number between 0 and 1]
There will be plenty more time to discuss conditional statements in later chapters. The above example should be pretty clear.
Ruby also includes a negated form of if called unless which goes something like
unless a > 5
puts "a is less than or equal to 5"
else
puts "a is greater than 5"
end
Generally speaking, Ruby keeps an if statement straight as long as the conditional (if ...) and the associated code block are on separate lines. If you have to smash everything together on one line, you'll need to place the then keyword after the conditional
if a < 5 then puts "#{a} less than 5" end if a < 5 then puts "#{a} less than 5" else puts "#{a} greater than 5" end Note that the if statement is also an expression; its value is the last line of the block executed. Therefore, the line above could also have been written as puts(if a < 5 then "#{a} less than 5" else "#{a} greater than 5" end) Ruby has also adopted the syntax from Perl where if and unless statements can be used as conditional modifiers after a statement. For example puts "#{a} less than 5" if a < 5 puts "Cheese sandwich" unless a == 4 while behaves as it does in other languages -- the code block that follows is run zero or more times, as long as the conditional is true while a > 5
a = 10*rand
end
And like if, there is also a negated version of while called until which runs the code block until the condition is true.
Finally there is the case statement which we'll just include here with a brief example. case is actually a very powerful super version of the if ... elsif... system
a = (10*rand).round
#a = rand(11) would do the same
case a
when 0..5
puts "#{a}: Low"
when 6
puts "#{a}: Six"
else
puts "#{a}: Cheese toast!"
end
There are some other interesting things going on in this example, but here the case statement is the center of attention.
functions:-
In keeping with Ruby's all-object-oriented-all-the-time design, functions are typically referred to as methods. No difference. We'll cover methods in much more detail when we get to objects and classes. For now, basic method writing looks something like this:
# Demonstrate a method with func1.rb
def my_function( a )
puts "Hello, #{a}"
return a.length
end
len = my_function( "Giraffe" )
puts "My secret word is #{len} long"
$ func1.rb
Hello, Giraffe
My secret word is 7 long
Methods are defined with the def keyword, followed by the function name. As with variables, local and class methods should start with a lower case letter.
In this example, the function takes one argument (a) and returns a value. Note that the input arguments aren't typed (i.e. a need not be a string) ... this allows for great flexibility but can also cause a lot of trouble. The function also returns a single value with the return keyword. Technically this isn't necessary -- the value of the last line executed in the function is used as the return value -- but more often than not using return explicitly makes things clearer.
As with other languages, Ruby supports both default values for arguments and variable-length argument lists, both of which will be covered in due time. There's also support for code blocks, as discussed below.
Blocks:-
One very important concept in Ruby is the code block. It's actually not a particularly revolutionary concept -- any time you've written if ... { ... } in C or Perl you've defined a code block, but in Ruby a code block has some hidden secret powers...
Code blocks in Ruby are defined either with the keywords do..end or the curly brackets {..}
do
print "I like "
print "code blocks!"
end
{
print "Me too!"
}
One very powerful usage of code blocks is that methods can take one as a parameter and execute it along the way.
[ed note: the Pragmatic Programmers actually want to point out that it's not very useful to describe it this way. Instead, the block of code behaves like a 'partner' to which the function occasionally hands over control]
The concept can be hard to get the first time it's explained to you. Here's an example:
$ irb --simple-prompt
>> 3.times { puts "Hi!" }
Hi!
Hi!
Hi!
=> 3
Surprise! You always thought 3 was just a number, but it's actually an object (of type Fixnum) As its an object, it has a member function times which takes a block as a parameter. The function runs the block 3 times.
Blocks can actually receive parameters, using a special notation |..|. In this case, a quick check of the documentation for times shows it will pass a single parameter into the block, indicating which loop it's on:
$ irb --simple-prompt
>> 4.times { |x| puts "Loop number #{x}" }
Loop number 0
Loop number 1
Loop number 2
Loop number 3
=> 4
The times function passes a number into the block. The block gets that number in the variable x (as set by the |x|), then prints out the result.
Functions interact with blocks through the yield. Every time the function invokes yield control passes to the block. It only comes back to the function when the block finishes. Here's a simple example:
# Script block2.rb
def simpleFunction
yield
yield
end
simpleFunction { puts "Hello!" }
$ block2.rb
Hello!
Hello!
The simpleFunction simply yields to the block twice -- so the block is run twice and we get two times the output. Here's an example where the function passes a parameter to the block:
# Script block1.rb
def animals
yield "Tiger"
yield "Giraffe"
end
animals { |x| puts "Hello, #{x}" }
$ block1.rb
Hello, Tiger
Hello, Giraffe
It might take a couple of reads through to figure out what's going on here. We've defined the function "animals" -- it expects a code block. When executed, the function calls the code block twice, first with the parameter "Tiger" then again with the parameter "Giraffe". In this example, we've written a simple code block which just prints out a greeting to the animals. We could write a different block, for example:
animals { |x| puts "It's #{x.length} characters long!" }
which would give:
It's 5 characters long!
It's 7 characters long!
Two completely different results from running the same function with two different blocks.
There are many powerful uses of blocks. One of the first you'll come across is the each function for arrays -- it runs a code block once for each element in the array -- it's great for iterating over lists.
We'll deal with variables in much more depth when we talk about classes and objects. For now, let's just say your basic local variable names should start with either a lower case letter or an underscore, and should contain upper or lower case letters, numbers, and underscore characters. Global variables start with a $.
Program flow:-
Ruby includes a pretty standard set of looping and branching constructs: if, while and case
For example, here's if in action:
a = 10 * rand
if a < 5 puts "#{a} less than 5" elsif a > 7
puts "#{a} greater than 7"
else
puts "Cheese sandwich!"
end
[As in other languages, the rand function generates a random number between 0 and 1]
There will be plenty more time to discuss conditional statements in later chapters. The above example should be pretty clear.
Ruby also includes a negated form of if called unless which goes something like
unless a > 5
puts "a is less than or equal to 5"
else
puts "a is greater than 5"
end
Generally speaking, Ruby keeps an if statement straight as long as the conditional (if ...) and the associated code block are on separate lines. If you have to smash everything together on one line, you'll need to place the then keyword after the conditional
if a < 5 then puts "#{a} less than 5" end if a < 5 then puts "#{a} less than 5" else puts "#{a} greater than 5" end Note that the if statement is also an expression; its value is the last line of the block executed. Therefore, the line above could also have been written as puts(if a < 5 then "#{a} less than 5" else "#{a} greater than 5" end) Ruby has also adopted the syntax from Perl where if and unless statements can be used as conditional modifiers after a statement. For example puts "#{a} less than 5" if a < 5 puts "Cheese sandwich" unless a == 4 while behaves as it does in other languages -- the code block that follows is run zero or more times, as long as the conditional is true while a > 5
a = 10*rand
end
And like if, there is also a negated version of while called until which runs the code block until the condition is true.
Finally there is the case statement which we'll just include here with a brief example. case is actually a very powerful super version of the if ... elsif... system
a = (10*rand).round
#a = rand(11) would do the same
case a
when 0..5
puts "#{a}: Low"
when 6
puts "#{a}: Six"
else
puts "#{a}: Cheese toast!"
end
There are some other interesting things going on in this example, but here the case statement is the center of attention.
functions:-
In keeping with Ruby's all-object-oriented-all-the-time design, functions are typically referred to as methods. No difference. We'll cover methods in much more detail when we get to objects and classes. For now, basic method writing looks something like this:
# Demonstrate a method with func1.rb
def my_function( a )
puts "Hello, #{a}"
return a.length
end
len = my_function( "Giraffe" )
puts "My secret word is #{len} long"
$ func1.rb
Hello, Giraffe
My secret word is 7 long
Methods are defined with the def keyword, followed by the function name. As with variables, local and class methods should start with a lower case letter.
In this example, the function takes one argument (a) and returns a value. Note that the input arguments aren't typed (i.e. a need not be a string) ... this allows for great flexibility but can also cause a lot of trouble. The function also returns a single value with the return keyword. Technically this isn't necessary -- the value of the last line executed in the function is used as the return value -- but more often than not using return explicitly makes things clearer.
As with other languages, Ruby supports both default values for arguments and variable-length argument lists, both of which will be covered in due time. There's also support for code blocks, as discussed below.
Blocks:-
One very important concept in Ruby is the code block. It's actually not a particularly revolutionary concept -- any time you've written if ... { ... } in C or Perl you've defined a code block, but in Ruby a code block has some hidden secret powers...
Code blocks in Ruby are defined either with the keywords do..end or the curly brackets {..}
do
print "I like "
print "code blocks!"
end
{
print "Me too!"
}
One very powerful usage of code blocks is that methods can take one as a parameter and execute it along the way.
[ed note: the Pragmatic Programmers actually want to point out that it's not very useful to describe it this way. Instead, the block of code behaves like a 'partner' to which the function occasionally hands over control]
The concept can be hard to get the first time it's explained to you. Here's an example:
$ irb --simple-prompt
>> 3.times { puts "Hi!" }
Hi!
Hi!
Hi!
=> 3
Surprise! You always thought 3 was just a number, but it's actually an object (of type Fixnum) As its an object, it has a member function times which takes a block as a parameter. The function runs the block 3 times.
Blocks can actually receive parameters, using a special notation |..|. In this case, a quick check of the documentation for times shows it will pass a single parameter into the block, indicating which loop it's on:
$ irb --simple-prompt
>> 4.times { |x| puts "Loop number #{x}" }
Loop number 0
Loop number 1
Loop number 2
Loop number 3
=> 4
The times function passes a number into the block. The block gets that number in the variable x (as set by the |x|), then prints out the result.
Functions interact with blocks through the yield. Every time the function invokes yield control passes to the block. It only comes back to the function when the block finishes. Here's a simple example:
# Script block2.rb
def simpleFunction
yield
yield
end
simpleFunction { puts "Hello!" }
$ block2.rb
Hello!
Hello!
The simpleFunction simply yields to the block twice -- so the block is run twice and we get two times the output. Here's an example where the function passes a parameter to the block:
# Script block1.rb
def animals
yield "Tiger"
yield "Giraffe"
end
animals { |x| puts "Hello, #{x}" }
$ block1.rb
Hello, Tiger
Hello, Giraffe
It might take a couple of reads through to figure out what's going on here. We've defined the function "animals" -- it expects a code block. When executed, the function calls the code block twice, first with the parameter "Tiger" then again with the parameter "Giraffe". In this example, we've written a simple code block which just prints out a greeting to the animals. We could write a different block, for example:
animals { |x| puts "It's #{x.length} characters long!" }
which would give:
It's 5 characters long!
It's 7 characters long!
Two completely different results from running the same function with two different blocks.
There are many powerful uses of blocks. One of the first you'll come across is the each function for arrays -- it runs a code block once for each element in the array -- it's great for iterating over lists.
Subscribe to:
Posts (Atom)