diff --git a/.buildpath b/.buildpath index 69396a1..77b8bfd 100644 --- a/.buildpath +++ b/.buildpath @@ -1,5 +1,5 @@ - - - - - + + + + + diff --git a/.project b/.project index c0dd501..c0329e0 100644 --- a/.project +++ b/.project @@ -1,23 +1,23 @@ - - - selenium - - - - - - org.eclipse.dltk.core.scriptbuilder - - - - - org.rubypeople.rdt.core.rubybuilder - - - - - - org.rubypeople.rdt.core.rubynature - org.eclipse.dltk.ruby.core.nature - - + + + selenium + + + + + + org.eclipse.dltk.core.scriptbuilder + + + + + org.rubypeople.rdt.core.rubybuilder + + + + + + org.rubypeople.rdt.core.rubynature + org.eclipse.dltk.ruby.core.nature + + diff --git a/README b/README index df9099f..292dbee 100644 --- a/README +++ b/README @@ -1,17 +1,17 @@ -= Selenium Ruby[http://selenium.rubyforge.org] - Object-oriented testing with selenium - -Homepage:: http://selenium.rubyforge.org -Author:: Shane -Copyright:: (c) 2006 Selenium-Ruby on rubyforge -License:: Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0.txt) - -Selenium Ruby[http://selenium.rubyforge.org] is a project that wraps selenium-rc[http://www.openqa.org/selenium-rc/] -into an object-oriented way, and wraps it into a RubyGem. - -This rDoc is intended for you the check out the available methods on the objects. For a full -document of what Selenium can do for you, please check out the home page: -http://selenium.rubyforge.org - -For document on the Selenium project and its RC, see Selenium homepage: http://www.openqa.org/selenium - += Selenium Ruby[http://selenium.rubyforge.org] - Object-oriented testing with selenium + +Homepage:: http://selenium.rubyforge.org +Author:: Shane +Copyright:: (c) 2006 Selenium-Ruby on rubyforge +License:: Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0.txt) + +Selenium Ruby[http://selenium.rubyforge.org] is a project that wraps selenium-rc[http://www.openqa.org/selenium-rc/] +into an object-oriented way, and wraps it into a RubyGem. + +This rDoc is intended for you the check out the available methods on the objects. For a full +document of what Selenium can do for you, please check out the home page: +http://selenium.rubyforge.org + +For document on the Selenium project and its RC, see Selenium homepage: http://www.openqa.org/selenium + Please post your question at mailing-list. \ No newline at end of file diff --git a/bin/selenium b/bin/selenium index d61ea6e..c1cec8f 100644 --- a/bin/selenium +++ b/bin/selenium @@ -1,5 +1,5 @@ -#!/usr/bin/env ruby -$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib")) -require 'selenium' - +#!/usr/bin/env ruby +$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib")) +require 'selenium' + Selenium::SeleniumServer.run(ARGV) \ No newline at end of file diff --git a/lib/selenium/alert.rb b/lib/selenium/alert.rb index 86ce6c3..03da7a6 100644 --- a/lib/selenium/alert.rb +++ b/lib/selenium/alert.rb @@ -1,15 +1,15 @@ -module Selenium - class Alert - def initialize(webpage) - @webpage = webpage - end - - def present? - @webpage.alert_present? - end - - def message - @webpage.alert_message - end - end +module Selenium + class Alert + def initialize(webpage) + @webpage = webpage + end + + def present? + @webpage.alert_present? + end + + def message + @webpage.alert_message + end + end end \ No newline at end of file diff --git a/lib/selenium/auto_it.rb b/lib/selenium/auto_it.rb index 0aa22e9..c56cbec 100644 --- a/lib/selenium/auto_it.rb +++ b/lib/selenium/auto_it.rb @@ -1,4 +1,4 @@ -require 'win32ole' -require 'selenium/auto_it_driver' -require 'selenium/auto_it_window' -require 'selenium/file_upload' +require 'win32ole' +require 'selenium/auto_it_driver' +require 'selenium/auto_it_window' +require 'selenium/file_upload' diff --git a/lib/selenium/auto_it_driver.rb b/lib/selenium/auto_it_driver.rb index 7aab78c..9647d5c 100644 --- a/lib/selenium/auto_it_driver.rb +++ b/lib/selenium/auto_it_driver.rb @@ -1,45 +1,45 @@ -module Selenium - class AutoIt - @@autoit = nil - - def self.load - begin - @@autoit = load_instance - rescue WIN32OLERuntimeError - registerAutoItDll - @@autoit = load_instance - end - @@autoit - end - - def self.load_instance - @@autoit = WIN32OLE.new('AutoItX3.Control') unless @@autoit - @@autoit - end - - def self.reset - if @@autoit - @@autoit.ole_free - @@autoit =nil - system("regsvr32.exe /s /u #{dll}") - end - end - - def self.registerAutoItDll - system("regsvr32.exe /s #{dll}") - end - - def self.dll - File.join(File.dirname(__FILE__), 'autoit', 'AutoItX3.dll') - end - - def initialize - @autoit = AutoIt.load - end - - def on_window_active(title, text = nil) - @autoit.WinWaitActive(title, text, 30) - yield @@autoit - end - end +module Selenium + class AutoIt + @@autoit = nil + + def self.load + begin + @@autoit = load_instance + rescue WIN32OLERuntimeError + registerAutoItDll + @@autoit = load_instance + end + @@autoit + end + + def self.load_instance + @@autoit = WIN32OLE.new('AutoItX3.Control') unless @@autoit + @@autoit + end + + def self.reset + if @@autoit + @@autoit.ole_free + @@autoit =nil + system("regsvr32.exe /s /u #{dll}") + end + end + + def self.registerAutoItDll + system("regsvr32.exe /s #{dll}") + end + + def self.dll + File.join(File.dirname(__FILE__), 'autoit', 'AutoItX3.dll') + end + + def initialize + @autoit = AutoIt.load + end + + def on_window_active(title, text = nil) + @autoit.WinWaitActive(title, text, 30) + yield @@autoit + end + end end \ No newline at end of file diff --git a/lib/selenium/auto_it_window.rb b/lib/selenium/auto_it_window.rb index 175c05a..7741fc8 100644 --- a/lib/selenium/auto_it_window.rb +++ b/lib/selenium/auto_it_window.rb @@ -1,82 +1,82 @@ -class AutoItWindow - def initialize(autoit, title, text=nil) - @autoit = autoit - @title = title - @text = text - end - - def self.wait_for(autoit, title, text = nil) - window = self.new(autoit, title, text) - window.wait_for_appear - window - end - - def self.on_activation(autoit, title, text = nil) - window = wait_for(autoit, title, text) - yield window - end - - def wait_for_activation - @autoit.WinWaitActive(@title, @text, 30) - end - - def wait_for_appear - @autoit.WinWait(@title, @text, 30) - end - - def activate - @autoit.WinActivate(@title, @text) - end - - def active? - 1 == @autoit.WinActive(@title, @text) - end - - def state - AutoItWindowState.new(@autoit.WinGetState(@title, @text)) - end - - def send_keys(keys) - activate_if_needed - @autoit.Send(keys) - end - - def close - @autoit.WinClose(@title) - end - - def activate_if_needed - winstate = state - activate unless winstate.active? - end -end - -class AutoItWindowState - def initialize(state) - @state = state - end - - def exists? - @state & 1 > 0 - end - - def visible? - @state & 2 > 0 - end - - def enabled? - @state & 4 > 0 - end - - def active? - @state & 8 > 0 - end - - def minimized? - @state & 16 > 0 - end - - def maxmized? - @state & 32 > 0 - end -end +class AutoItWindow + def initialize(autoit, title, text=nil) + @autoit = autoit + @title = title + @text = text + end + + def self.wait_for(autoit, title, text = nil) + window = self.new(autoit, title, text) + window.wait_for_appear + window + end + + def self.on_activation(autoit, title, text = nil) + window = wait_for(autoit, title, text) + yield window + end + + def wait_for_activation + @autoit.WinWaitActive(@title, @text, 30) + end + + def wait_for_appear + @autoit.WinWait(@title, @text, 30) + end + + def activate + @autoit.WinActivate(@title, @text) + end + + def active? + 1 == @autoit.WinActive(@title, @text) + end + + def state + AutoItWindowState.new(@autoit.WinGetState(@title, @text)) + end + + def send_keys(keys) + activate_if_needed + @autoit.Send(keys) + end + + def close + @autoit.WinClose(@title) + end + + def activate_if_needed + winstate = state + activate unless winstate.active? + end +end + +class AutoItWindowState + def initialize(state) + @state = state + end + + def exists? + @state & 1 > 0 + end + + def visible? + @state & 2 > 0 + end + + def enabled? + @state & 4 > 0 + end + + def active? + @state & 8 > 0 + end + + def minimized? + @state & 16 > 0 + end + + def maxmized? + @state & 32 > 0 + end +end diff --git a/lib/selenium/file_upload.rb b/lib/selenium/file_upload.rb index 30458a4..4fdc226 100644 --- a/lib/selenium/file_upload.rb +++ b/lib/selenium/file_upload.rb @@ -1,12 +1,12 @@ -module Selenium - class FileUpload - def initialize(webpage, locator) - @webpage = webpage - @locator = locator - end - - def enter(file) - @webpage.upload(@locator, file) - end - end +module Selenium + class FileUpload + def initialize(webpage, locator) + @webpage = webpage + @locator = locator + end + + def enter(file) + @webpage.upload(@locator, file) + end + end end \ No newline at end of file diff --git a/lib/selenium/key.rb b/lib/selenium/key.rb index a814394..001d123 100644 --- a/lib/selenium/key.rb +++ b/lib/selenium/key.rb @@ -1,16 +1,16 @@ -module Selenium - class Key - def initialize(webpage, key) - @webpage = webpage - @key = key - end - - def up - @webpage.key_up(@key) - end - - def down - @webpage.key_down(@key) - end - end +module Selenium + class Key + def initialize(webpage, key) + @webpage = webpage + @key = key + end + + def up + @webpage.key_up(@key) + end + + def down + @webpage.key_down(@key) + end + end end \ No newline at end of file diff --git a/lib/selenium/locator.rb b/lib/selenium/locator.rb index 61b4fd9..70627b9 100644 --- a/lib/selenium/locator.rb +++ b/lib/selenium/locator.rb @@ -1,15 +1,15 @@ -module Selenium - module Locator - def by_name(name) - name - end - - def by_id(id) - "id=#{id}" - end - - def by_text(text) - "link=#{text}" - end - end +module Selenium + module Locator + def by_name(name) + name + end + + def by_id(id) + "id=#{id}" + end + + def by_text(text) + "link=#{text}" + end + end end \ No newline at end of file diff --git a/lib/selenium/openqa/README b/lib/selenium/openqa/README index 34c47d6..d01a8c4 100644 --- a/lib/selenium/openqa/README +++ b/lib/selenium/openqa/README @@ -1,5 +1,5 @@ -All the files in this foler are from the "Selenium" project on OpenQA (http://www.openqa.org/selenium-rc/), under the -Apache License (http://www.openqa.org/selenium-rc/license.action) - -The selenium-server.jar was renamed to have a txt extension because somehow ruby gem does not like jar extension (Installation +All the files in this foler are from the "Selenium" project on OpenQA (http://www.openqa.org/selenium-rc/), under the +Apache License (http://www.openqa.org/selenium-rc/license.action) + +The selenium-server.jar was renamed to have a txt extension because somehow ruby gem does not like jar extension (Installation will fail on buffer error. \ No newline at end of file diff --git a/lib/selenium/server.rb b/lib/selenium/server.rb index 5a89348..86a107f 100644 --- a/lib/selenium/server.rb +++ b/lib/selenium/server.rb @@ -1,120 +1,120 @@ -module Selenium -# The class that can manages the server driver classes. -# This class is originally copied from the BuildMaster project. -# You can setup your build task to start the server before -# the tests and shutdown when it is finished -# server = Selenium::Server.new() -# begin -# server.start -# tests.run # run your tests here -# ensure -# server.stop -# end -class Server - # The status of the server. Values are - # * stopped - # * starting - # * started - # * stopping - # * error - attr_reader :status - - # The timeout setting for selenium in seconds - attr_reader :timeout - - def Server::on_port(port) - Server.new(SeleniumServer.new(port)) - end - - # Create a selenium server that can be controlled directly - def initialize(port_number, timeout=60) - if port_number.is_a? SeleniumServer - # backward compatibility, to be removed in 2.0 - @server = port_number - else - @server = SeleniumServer.new(port_number, timeout) - end - @status = 'stopped' - end - - def print_log=(value) - @server.print_log = value - end - - # Starts the server, returns when the server is up and running - def start(*argv) - puts "starting selenium server..." - starting_server(*argv) - wait_for_condition {@server.running?} - puts "started selenium server" - @status = 'started' - end - - def driver(browser_start_command, browser_url) - SeleniumDriver.new('localhost', @server.port_number, browser_start_command, browser_url, @server.request_timeout * 1000) - end - - def open(browser_start_command, browser_url) - url = URI.parse(browser_url) - browser = driver(browser_start_command, URI::Generic::new(url.scheme, url.userinfo, url.host, url.port, nil, nil, nil, nil, nil)) - browser.start - browser.open(url.request_uri) - WebPage.new(browser) - end - - # Starts the server, does not return until the server shuts down - def run(*argv) - @server.start(*argv) - end - - # Stops the server, returns when the server is no longer running - def stop - puts "stopping selenium server..." - stopping_server - wait_for_condition {not @server.running?} - puts "stopped selenium server." - @status = 'stopped' - end - - private - def starting_server(*argv) - @status = 'starting' - ['INT', 'TERM'].each { |signal| - trap(signal){ @server.stop} - } - start_thread {run(*argv)} - end - - def stopping_server - @status = 'stopping' - start_thread {@server.stop} - end - - def start_thread - Thread.new do - begin - yield - rescue Exception => exception - @exception = exception - end - end - end - - def wait_for_condition - count = 0 - sleep 1 - while not (result = yield) - if (@exception) - error = @exception - @exception = nil - @status = 'error' - raise error - end - count = count + 1 - raise 'wait timed out' unless count < 10 - sleep 1 - end - end - -end +module Selenium +# The class that can manages the server driver classes. +# This class is originally copied from the BuildMaster project. +# You can setup your build task to start the server before +# the tests and shutdown when it is finished +# server = Selenium::Server.new() +# begin +# server.start +# tests.run # run your tests here +# ensure +# server.stop +# end +class Server + # The status of the server. Values are + # * stopped + # * starting + # * started + # * stopping + # * error + attr_reader :status + + # The timeout setting for selenium in seconds + attr_reader :timeout + + def Server::on_port(port) + Server.new(SeleniumServer.new(port)) + end + + # Create a selenium server that can be controlled directly + def initialize(port_number, timeout=60) + if port_number.is_a? SeleniumServer + # backward compatibility, to be removed in 2.0 + @server = port_number + else + @server = SeleniumServer.new(port_number, timeout) + end + @status = 'stopped' + end + + def print_log=(value) + @server.print_log = value + end + + # Starts the server, returns when the server is up and running + def start(*argv) + puts "starting selenium server..." + starting_server(*argv) + wait_for_condition {@server.running?} + puts "started selenium server" + @status = 'started' + end + + def driver(browser_start_command, browser_url) + SeleniumDriver.new('localhost', @server.port_number, browser_start_command, browser_url, @server.request_timeout * 1000) + end + + def open(browser_start_command, browser_url) + url = URI.parse(browser_url) + browser = driver(browser_start_command, URI::Generic::new(url.scheme, url.userinfo, url.host, url.port, nil, nil, nil, nil, nil)) + browser.start + browser.open(url.request_uri) + WebPage.new(browser) + end + + # Starts the server, does not return until the server shuts down + def run(*argv) + @server.start(*argv) + end + + # Stops the server, returns when the server is no longer running + def stop + puts "stopping selenium server..." + stopping_server + wait_for_condition {not @server.running?} + puts "stopped selenium server." + @status = 'stopped' + end + + private + def starting_server(*argv) + @status = 'starting' + ['INT', 'TERM'].each { |signal| + trap(signal){ @server.stop} + } + start_thread {run(*argv)} + end + + def stopping_server + @status = 'stopping' + start_thread {@server.stop} + end + + def start_thread + Thread.new do + begin + yield + rescue Exception => exception + @exception = exception + end + end + end + + def wait_for_condition + count = 0 + sleep 1 + while not (result = yield) + if (@exception) + error = @exception + @exception = nil + @status = 'error' + raise error + end + count = count + 1 + raise 'wait timed out' unless count < 10 + sleep 1 + end + end + +end end \ No newline at end of file diff --git a/lib/selenium/text_area.rb b/lib/selenium/text_area.rb index fe87fac..0f59f31 100644 --- a/lib/selenium/text_area.rb +++ b/lib/selenium/text_area.rb @@ -1,11 +1,11 @@ -module Selenium - class TextArea < HtmlElement - def enter(value) - @webpage.enter(@locator, value) - end - - def value - @webpage.value(@locator) - end - end +module Selenium + class TextArea < HtmlElement + def enter(value) + @webpage.enter(@locator, value) + end + + def value + @webpage.value(@locator) + end + end end \ No newline at end of file diff --git a/lib/selenium/web_page.rb b/lib/selenium/web_page.rb index 49c4f77..15cd93f 100644 --- a/lib/selenium/web_page.rb +++ b/lib/selenium/web_page.rb @@ -1,209 +1,209 @@ -module Selenium - # Error that is thrown when a key is not supported - class NoKeyError < NameError - def initialize(key) - super(key) - end - end - - # Class that models a web page with a title - class WebPage - attr_reader :browser - attr_accessor :timeout, :interval_millis - - def initialize(browser, expected_title = nil) - @browser = browser - @expected_title = expected_title - @timeout = 60 - @interval_millis = 100 - end - - def title - raise 'nil as browser' unless @browser - @browser.get_title - end - - def present? - title == @expected_title - end - - def ensure_present - title.should == @expected_title - end - - def html - @browser.get_html_source - end - - def speed=(value) - @browser.set_speed(value) - end - - def speed - @browser.get_speed.to_i - end - - def wait_for_load - @browser.wait_for_page_to_load - end - - def wait_until(message, &block) - Timeout::timeout(timeout, "Timeout waiting for : #{message}") do - while(not yield message) - sleep interval_millis / 1000.0 - end - end - end - - def alert - Alert.new(self) - end - - def link(how, what=nil) - if (how == :text) - locator = "link=#{what}" - elsif (how == :href) - locator = "xpath=//a[@href='#{what}']" - else - locator = element_locator(how, what) - end - Link.new(self, locator) - end - - def text_field(how, what=nil) - TextField.new(self, element_locator(how, what)) - end - - def text_area(how, what=nil) - TextArea.new(self, element_locator(how, what)) - end - - def element(how, what=nil) - HtmlElement.new(self, element_locator(how,what)) - end - - def element_locator(how, what=nil) - locator = how - if (not what.nil?) - if (how == :xpath or how == :name or how == :id) - locator = "#{how}=#{what}" - else - raise "couldn't understand how to build locator using #{how} with #{what}" - end - end - locator - end - - def file_upload(how, what) - FileUpload.new(self, element_locator(how, what)) - end - - def open_page(url) - @browser.open(url) - end - - def close - @browser.stop - end - - def click(locator) - @browser.click(locator) - end - - def text(locator) - @browser.get_text(locator) - end - - def button(how, what=nil) - Button.new(self, element_locator(how, what)) - end - - def key(key) - Key.new(self, key) - end - - def element_present?(locator) - @browser.is_element_present(locator) - end - - def alert_present? - @browser.is_alert_present - end - - def text_present?(text) - @browser.is_text_present(text) - end - - def double_click(locator) - @browser.double_click(locator) - end - - def click_wait(locator) - click(locator) - wait_for_load - end - - # enter the text to the element found by locator - def enter(locator, text) - @browser.type(locator, text) - end - - def value(locator) - @browser.get_value(locator) - end - - def alert_message - @browser.get_alert - end - - def context_menu(locator) - @browser.context_menu(locator) - end - - def fire_event(locator, event) - @browser.fire_event(locator, event) - end - - def key_down(key) - message = "#{key}_key_down" - raise NoKeyError.new(key.to_s) unless @browser.respond_to? message - @browser.send message - end - - def key_up(key) - message = "#{key}_key_up" - raise NoKeyError.new(key.to_s) unless @browser.respond_to? message - @browser.send message - end - - def key_press(locator, key) - @browser.key_press(locator, key) - end - - def focus(locator) - @browser.focus(locator) - end - - def upload(locator, file) -# @browser.attach_file(locator, file) - @browser.click(locator) - require 'auto_it' - autoit = AutoIt.load - window = AutoItWindow.wait_for(autoit, 'File Upload') - puts window - end - - def capture_page(file) - @browser.capture_entire_page_screenshot(file) - end - - def capture_screen(file) - @browser.capture_screenshot(file) - end - - def to_s - "#{self.class}('#{@expected_title}') - #{browser.to_s}" - end - - end +module Selenium + # Error that is thrown when a key is not supported + class NoKeyError < NameError + def initialize(key) + super(key) + end + end + + # Class that models a web page with a title + class WebPage + attr_reader :browser + attr_accessor :timeout, :interval_millis + + def initialize(browser, expected_title = nil) + @browser = browser + @expected_title = expected_title + @timeout = 60 + @interval_millis = 100 + end + + def title + raise 'nil as browser' unless @browser + @browser.get_title + end + + def present? + title == @expected_title + end + + def ensure_present + title.should == @expected_title + end + + def html + @browser.get_html_source + end + + def speed=(value) + @browser.set_speed(value) + end + + def speed + @browser.get_speed.to_i + end + + def wait_for_load + @browser.wait_for_page_to_load + end + + def wait_until(message, &block) + Timeout::timeout(timeout, "Timeout waiting for : #{message}") do + while(not yield message) + sleep interval_millis / 1000.0 + end + end + end + + def alert + Alert.new(self) + end + + def link(how, what=nil) + if (how == :text) + locator = "link=#{what}" + elsif (how == :href) + locator = "xpath=//a[@href='#{what}']" + else + locator = element_locator(how, what) + end + Link.new(self, locator) + end + + def text_field(how, what=nil) + TextField.new(self, element_locator(how, what)) + end + + def text_area(how, what=nil) + TextArea.new(self, element_locator(how, what)) + end + + def element(how, what=nil) + HtmlElement.new(self, element_locator(how,what)) + end + + def element_locator(how, what=nil) + locator = how + if (not what.nil?) + if (how == :xpath or how == :name or how == :id) + locator = "#{how}=#{what}" + else + raise "couldn't understand how to build locator using #{how} with #{what}" + end + end + locator + end + + def file_upload(how, what) + FileUpload.new(self, element_locator(how, what)) + end + + def open_page(url) + @browser.open(url) + end + + def close + @browser.stop + end + + def click(locator) + @browser.click(locator) + end + + def text(locator) + @browser.get_text(locator) + end + + def button(how, what=nil) + Button.new(self, element_locator(how, what)) + end + + def key(key) + Key.new(self, key) + end + + def element_present?(locator) + @browser.is_element_present(locator) + end + + def alert_present? + @browser.is_alert_present + end + + def text_present?(text) + @browser.is_text_present(text) + end + + def double_click(locator) + @browser.double_click(locator) + end + + def click_wait(locator) + click(locator) + wait_for_load + end + + # enter the text to the element found by locator + def enter(locator, text) + @browser.type(locator, text) + end + + def value(locator) + @browser.get_value(locator) + end + + def alert_message + @browser.get_alert + end + + def context_menu(locator) + @browser.context_menu(locator) + end + + def fire_event(locator, event) + @browser.fire_event(locator, event) + end + + def key_down(key) + message = "#{key}_key_down" + raise NoKeyError.new(key.to_s) unless @browser.respond_to? message + @browser.send message + end + + def key_up(key) + message = "#{key}_key_up" + raise NoKeyError.new(key.to_s) unless @browser.respond_to? message + @browser.send message + end + + def key_press(locator, key) + @browser.key_press(locator, key) + end + + def focus(locator) + @browser.focus(locator) + end + + def upload(locator, file) +# @browser.attach_file(locator, file) + @browser.click(locator) + require 'auto_it' + autoit = AutoIt.load + window = AutoItWindow.wait_for(autoit, 'File Upload') + puts window + end + + def capture_page(file) + @browser.capture_entire_page_screenshot(file) + end + + def capture_screen(file) + @browser.capture_screenshot(file) + end + + def to_s + "#{self.class}('#{@expected_title}') - #{browser.to_s}" + end + + end end \ No newline at end of file diff --git a/rakefile.rb b/rakefile.rb index 62a56c3..0abce9f 100644 --- a/rakefile.rb +++ b/rakefile.rb @@ -1,79 +1,79 @@ -$:.unshift File.dirname(__FILE__) - -require 'rubygems' -Gem::manage_gems -require 'rake' -require 'spec/rake/spectask' -require 'rake/gempackagetask' -require 'rake/rdoctask' -require 'rcov/rcovtask' -require 'specs' -require 'buildmaster/project/server_manager' -require 'lib/selenium' - -rcov_dir = SITE_SPEC.output_dir.dir('rcov') -rspec_dir = SITE_SPEC.output_dir.dir('rspec') - -task :init do - rcov_dir.mkdirs - rspec_dir.mkdirs -end - -#desc "Run all specifications" -Spec::Rake::SpecTask.new(:coverage) do |t| - t.spec_files = FileList['spec/**/tc_*.rb'] - t.rcov = true - t.rcov_dir = rcov_dir.path - t.spec_opts = ["--format", "html:#{rspec_dir.file('index.html').path}", "--diff"] - t.fail_on_error = true -end - -Rake::RDocTask.new(:rdoc) do |rdoc| - rdoc.main = "README" - rdoc.rdoc_files.include("README", "lib/**/*.rb") - rdoc.options << "--all" - rdoc.rdoc_dir = SITE_SPEC.output_dir.dir('rdoc').path.to_s -end - -task :default => [:coverage, :build_site, :rdoc, :package] -task :coverage => [:init] - -# ??? if we use the rakt gem task, it will somehow be built multiple times and fail??? -task :package do - Gem::manage_gems - Gem::Builder.new(SPEC).build -end - -task :local_install do - gem_file = SPEC.full_name + ".gem" - puts "Insalling #{gem_file}..." - Gem::Installer.new(gem_file).install -end - -task :build_site do - BuildMaster::Site.new(SITE_SPEC).build -end - -task :publish_site do - svn = BuildMaster::SvnDriver.from_path(BuildMaster::Cotta.new.file(__FILE__).parent) - output_dir = SITE_SPEC.output_dir - raise 'output dir needs to be called the same as the project name for one copy action to work' unless output_dir.name == 'selenium' - BuildMaster::PscpDriver.new("#{svn.user}@selenium.rubyforge.org").copy(output_dir.path, '/var/www/gforge-projects') -end - -task :test_site do - BuildMaster::Site.new(SITE_SPEC).test -end - -task :serve do - BuildMaster::Site.new(SITE_SPEC).server -end - -task :setup_site do - BuildMaster::Site.setup(SITE_SPEC) -end - -task :selenium do - server = Selenium::SeleniumServer.new(BuildMaster::Cotta.new, 4444) - server.start -end +$:.unshift File.dirname(__FILE__) + +require 'rubygems' +Gem::manage_gems +require 'rake' +require 'spec/rake/spectask' +require 'rake/gempackagetask' +require 'rake/rdoctask' +require 'rcov/rcovtask' +require 'specs' +require 'buildmaster/project/server_manager' +require 'lib/selenium' + +rcov_dir = SITE_SPEC.output_dir.dir('rcov') +rspec_dir = SITE_SPEC.output_dir.dir('rspec') + +task :init do + rcov_dir.mkdirs + rspec_dir.mkdirs +end + +#desc "Run all specifications" +Spec::Rake::SpecTask.new(:coverage) do |t| + t.spec_files = FileList['spec/**/tc_*.rb'] + t.rcov = true + t.rcov_dir = rcov_dir.path + t.spec_opts = ["--format", "html:#{rspec_dir.file('index.html').path}", "--diff"] + t.fail_on_error = true +end + +Rake::RDocTask.new(:rdoc) do |rdoc| + rdoc.main = "README" + rdoc.rdoc_files.include("README", "lib/**/*.rb") + rdoc.options << "--all" + rdoc.rdoc_dir = SITE_SPEC.output_dir.dir('rdoc').path.to_s +end + +task :default => [:coverage, :build_site, :rdoc, :package] +task :coverage => [:init] + +# ??? if we use the rakt gem task, it will somehow be built multiple times and fail??? +task :package do + Gem::manage_gems + Gem::Builder.new(SPEC).build +end + +task :local_install do + gem_file = SPEC.full_name + ".gem" + puts "Insalling #{gem_file}..." + Gem::Installer.new(gem_file).install +end + +task :build_site do + BuildMaster::Site.new(SITE_SPEC).build +end + +task :publish_site do + svn = BuildMaster::SvnDriver.from_path(BuildMaster::Cotta.new.file(__FILE__).parent) + output_dir = SITE_SPEC.output_dir + raise 'output dir needs to be called the same as the project name for one copy action to work' unless output_dir.name == 'selenium' + BuildMaster::PscpDriver.new("#{svn.user}@selenium.rubyforge.org").copy(output_dir.path, '/var/www/gforge-projects') +end + +task :test_site do + BuildMaster::Site.new(SITE_SPEC).test +end + +task :serve do + BuildMaster::Site.new(SITE_SPEC).server +end + +task :setup_site do + BuildMaster::Site.setup(SITE_SPEC) +end + +task :selenium do + server = Selenium::SeleniumServer.new(BuildMaster::Cotta.new, 4444) + server.start +end diff --git a/release.rb b/release.rb index 02af9e4..a5fccd3 100644 --- a/release.rb +++ b/release.rb @@ -1,29 +1,29 @@ -$:.unshift File.dirname(__FILE__) - -require 'buildmaster/cotta' -require 'buildmaster/project' -require 'specs' - -root = BuildMaster::Cotta.file(__FILE__).parent -svn = BuildMaster::SvnDriver.from_path(root) - -release = BuildMaster::Release.new -release.task('version') do - VERSION_NUMBER.increase_build - SPEC.version = VERSION_NUMBER.version_number -end -release.task("rake") {load('rake')} -release.task('commit') {svn.commit('committing before release')} -release.task('tagging') do - tag = "selenium-#{SPEC.version}" - puts "tagging with #{tag}" - svn.tag(tag) -end - -release.task("upload") do - gem = "#{SPEC.name}-#{SPEC.version}" - target_path = "/var/www/gforge-projects/selenium/builds/#{gem}.gem" - BuildMaster::PscpDriver.new("#{svn.user}@selenium.rubyforge.org").copy(root.file("#{gem}.gem").to_s, target_path) -end - +$:.unshift File.dirname(__FILE__) + +require 'buildmaster/cotta' +require 'buildmaster/project' +require 'specs' + +root = BuildMaster::Cotta.file(__FILE__).parent +svn = BuildMaster::SvnDriver.from_path(root) + +release = BuildMaster::Release.new +release.task('version') do + VERSION_NUMBER.increase_build + SPEC.version = VERSION_NUMBER.version_number +end +release.task("rake") {load('rake')} +release.task('commit') {svn.commit('committing before release')} +release.task('tagging') do + tag = "selenium-#{SPEC.version}" + puts "tagging with #{tag}" + svn.tag(tag) +end + +release.task("upload") do + gem = "#{SPEC.name}-#{SPEC.version}" + target_path = "/var/www/gforge-projects/selenium/builds/#{gem}.gem" + BuildMaster::PscpDriver.new("#{svn.user}@selenium.rubyforge.org").copy(root.file("#{gem}.gem").to_s, target_path) +end + release.command(ARGV) \ No newline at end of file diff --git a/site/contribute.txt b/site/contribute.txt index 7b80d53..cc80b97 100644 --- a/site/contribute.txt +++ b/site/contribute.txt @@ -1,20 +1,20 @@ ---- -Contribute ---- -This project is created so that we can share our experiences using ruby and Selenium to test our web applications. -You can start by joining the "selenium-ruby":http://groups.google.com/group/selenium-ruby google group. This project -will be constantly updated on the following area: - -h1. Testing API - -* Creating more wrapper classes that presents HTML elements with behaviors. -* Re-design the API to leverage Ruby language and remove duplication - -h1. Testing Patterns - -* Share your experience of using Selenium with Ruby. What is good, what is bad. -* Share the patterns that you have built in your porject to make test easy and fun. - -h1. Write about it - +--- +Contribute +--- +This project is created so that we can share our experiences using ruby and Selenium to test our web applications. +You can start by joining the "selenium-ruby":http://groups.google.com/group/selenium-ruby google group. This project +will be constantly updated on the following area: + +h1. Testing API + +* Creating more wrapper classes that presents HTML elements with behaviors. +* Re-design the API to leverage Ruby language and remove duplication + +h1. Testing Patterns + +* Share your experience of using Selenium with Ruby. What is good, what is bad. +* Share the patterns that you have built in your porject to make test easy and fun. + +h1. Write about it + * Love it, hate it? Write about it \ No newline at end of file diff --git a/site/cotta.css b/site/cotta.css index 2c458c4..404d575 100644 --- a/site/cotta.css +++ b/site/cotta.css @@ -1,367 +1,367 @@ -body { - padding: 0px; - margin: 0px; - border: 0px; - font-family: helvetica, arial, sans-serif; - background-color: white; - color: black; -} - -h1, h2, h3, h4, h5, h6 { - margin: 0px; - border: 0px; - padding: 0px; - font-weight: normal; -} - -a:link { color: #00a; } -a:active { color: red; } -a:hover { color: darkred; } -a:visited { color: black; } - -#logo { - padding: 10px; -} - -img { - border: 0px; - padding: 0px; - margin: 0px; -} - -p { - border: 0px; - padding: 0px; - margin: 0px; - margin-bottom: 10px; -} - -blockquote { - margin-bottom: 10px; -} - -td { - padding: 2px; -} - -th { - font-weight: normal; - white-space: nowrap; - padding: 2px; - color: white; -} - -th.Row { - text-align: left; - vertical-align: top; -} - -ul, ol { - border: 0px; - padding: 0px; - margin-top: 0px; - margin-bottom: 12px; - margin-left: 20px; -} - -div.header { - top: 0px; - left: 0px; - right: 0px; - width: 100%; - height: 70px; - margin: 0px; - border: 0px; - background-color: #CC9999; - border-bottom: 1px solid #825C47; - padding-left: 0px; - padding-right: 0px; - padding-top: 0px; - padding-bottom: 4px; -} - -h1.header { - padding:0; - margin:0; -} - -a.header { border: 0px; text-decoration: none;} -a.header:visited { color: #00a; } -a.header:hover { color: red; } -a.header:active { color: red; } - -div.left { - float:left; - width:180px; - background-color: white; - padding: 8px; - font-size: small; - font-style: normal; - margin-top: 16px; -} - -div.left h1{ - margin: 0px; - border: 0px; - padding: 4px; - color: #663333; - font-size: small; - font-weight: bold; -} - -div.MenuGroup a { text-decoration: none; } -div.MenuGroup a:link { color: #894926; } -div.MenuGroup a:visited { color: #894926; } -div.MenuGroup a:active { color: red; } -div.MenuGroup a:hover { color: white; background-color:#894926;width:160px;} - -/*--------------------------------------------------------------------------- - * Menus - */ -.MenuGroup { - border-left: 1px solid #825C47; - border-top: 1px solid #825C47; - border-bottom: 1px solid white; /* IE work-around */ - - margin-bottom: 8px; - background-color: white; - color: #894926; -} - -.MenuGroup ul { - margin: 0px; - padding-left: 4px; - list-style-type: none; -} - -.MenuGroup li { - padding: 2px; -} - -.More { - width: 100%; - text-align: right; -} -/*------------------------------------------------------------------------------*/ - -/*------------------------------------------------- - * Right Panel - */ -div.right { - float:right; - width:184px; - margin:0; - background-color: white; - padding: 8px; - font-size: small; - font-style: normal; - margin-top: 16px; -} - -div.right h1{ - margin: 0px; - border: 0px; - padding: 4px; - color: #663333; - font-size: small; - font-weight: bold; -} - -div.right a { text-decoration: none; } -div.right a:link { color: #894926; } -div.right a:visited { color: #894926; } -div.right a:active { color: red; } -div.right a:hover { color: red; } - - -/*--------------------------------------------------------------------------- - * News panel - */ -.NewsGroup { - border-left: 1px solid #825C47; - border-top: 1px solid #825C47; - border-bottom: 1px solid white; /* IE workaround */ - margin-bottom: 8px; - - color: #663333; -} -.NewsItem { - margin: 4px; -} -.NewsTitle { - font-weight: bold; - margin: 0px; - padding: 0px; -} -.NewsDate { - margin: 0px; - padding: 0px; - font-size: smaller; -} -.NewsText { - padding: 0px; - margin: 0px; - margin-bottom: 8px; -} -.NewsText a { text-decoration: underline; } -.NewsText a:link { color: #894926; } -.NewsText a:visited { color: #894926; } -.NewsText a:active { color: red; } -.NewsText a:hover { color: red; } -.NewsMore { - font-size: small; - margin: 4px; - margin-top: 12px; - text-align: left; -} -.NewsGroup td { - font-size: 12px; -} - -/*-------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- - * Document meta-information - */ - -.Meta { - margin-top: 64px; - font-size: smaller; - color: #C0C0C0; - text-align: right; -} - -.Meta a { text-decoration: underline; } -.Meta a:link { color: #C0C0C0; } -.Meta a:visited { color: #C0C0C0; } -.Meta a:active { color: red; } -.Meta a:hover { color: red; } -/*--------------------------------------------------------------------------*/ - -div.Content3Column { - margin-left:200px; - margin-right:216px; -} - -div.Content2Column { - margin-left:200px; - margin-right:16px; -} - -div.content h1 { - width: 100%; - font-size: Larger; - background-color: #663333; - color: white; - padding: 2px; - padding-left: 6px; - margin-top: 24px; - margin-bottom: 12px; -} - -div.content a { text-decoration: underline; } -div.content a:link { color: #894926; } -div.content a:visited { color: #894926; } -div.content a:active { color: green; } -div.content a:hover { color: red; } -div.content h2 { - margin-top: 24px; - margin-bottom: 16px; - font-weight: bold; - font-size: Larger; -} - -div.content li { - margin-bottom: 6px; -} -div.content th { - background-color: #825C47; - color: white; -} -div.content td { - background-color: #D7B19C; -} - -div.Shaded pre { - padding: 4px; - font-family: courier new, monospace; - font-size: smaller; - border: 1px solid #008; - background-color: #CCCC99; - color: black; -} - -div.Shaded:before { - margin: 0px; - padding: 0px; - border: 0px; - font-size: inherit; - /*line-spacing: 100%;*/ -} - -pre.code { - padding: 4px; - font-family: courier new, monospace; - font-size: smaller; - border: 1px solid #008; - background-color: #CCCC99; - color: black; -} - -div.Code { - white-space: pre; - padding: 4px; - font-family: courier new, monospace; - font-size: smaller; - border: 1px solid #008; - background-color: #CCCC99; - color: black; -} - -div.Code:before { - margin: 0px; - padding: 0px; - border: 0px; - font-size: inherit; -} - -div.footer { - color: #894926; - padding:0.5em; - clear:both; - text-align:center; - font-size:75%; -} - -div.footer a { - color:#894926; - font-size:inherit; -} - -div.bottomshadow { - width:100%; - height: 12px; - background-image: url("/border_bottom.gif"); - background-repeat: repeat-x; - padding: 12px; -} - -div#content .Float { - float: right; - margin-left: 8px; - margin-right: 0px; - margin-top: 8px; - margin-bottom: 8px; -} - -div#content .Diagram { - display: block; - margin-left: auto; - margin-right: auto; - margin-top: 8px; - margin-bottom: 8px; -} - -div#content .Inline { - display: inline; -} +body { + padding: 0px; + margin: 0px; + border: 0px; + font-family: helvetica, arial, sans-serif; + background-color: white; + color: black; +} + +h1, h2, h3, h4, h5, h6 { + margin: 0px; + border: 0px; + padding: 0px; + font-weight: normal; +} + +a:link { color: #00a; } +a:active { color: red; } +a:hover { color: darkred; } +a:visited { color: black; } + +#logo { + padding: 10px; +} + +img { + border: 0px; + padding: 0px; + margin: 0px; +} + +p { + border: 0px; + padding: 0px; + margin: 0px; + margin-bottom: 10px; +} + +blockquote { + margin-bottom: 10px; +} + +td { + padding: 2px; +} + +th { + font-weight: normal; + white-space: nowrap; + padding: 2px; + color: white; +} + +th.Row { + text-align: left; + vertical-align: top; +} + +ul, ol { + border: 0px; + padding: 0px; + margin-top: 0px; + margin-bottom: 12px; + margin-left: 20px; +} + +div.header { + top: 0px; + left: 0px; + right: 0px; + width: 100%; + height: 70px; + margin: 0px; + border: 0px; + background-color: #CC9999; + border-bottom: 1px solid #825C47; + padding-left: 0px; + padding-right: 0px; + padding-top: 0px; + padding-bottom: 4px; +} + +h1.header { + padding:0; + margin:0; +} + +a.header { border: 0px; text-decoration: none;} +a.header:visited { color: #00a; } +a.header:hover { color: red; } +a.header:active { color: red; } + +div.left { + float:left; + width:180px; + background-color: white; + padding: 8px; + font-size: small; + font-style: normal; + margin-top: 16px; +} + +div.left h1{ + margin: 0px; + border: 0px; + padding: 4px; + color: #663333; + font-size: small; + font-weight: bold; +} + +div.MenuGroup a { text-decoration: none; } +div.MenuGroup a:link { color: #894926; } +div.MenuGroup a:visited { color: #894926; } +div.MenuGroup a:active { color: red; } +div.MenuGroup a:hover { color: white; background-color:#894926;width:160px;} + +/*--------------------------------------------------------------------------- + * Menus + */ +.MenuGroup { + border-left: 1px solid #825C47; + border-top: 1px solid #825C47; + border-bottom: 1px solid white; /* IE work-around */ + + margin-bottom: 8px; + background-color: white; + color: #894926; +} + +.MenuGroup ul { + margin: 0px; + padding-left: 4px; + list-style-type: none; +} + +.MenuGroup li { + padding: 2px; +} + +.More { + width: 100%; + text-align: right; +} +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------- + * Right Panel + */ +div.right { + float:right; + width:184px; + margin:0; + background-color: white; + padding: 8px; + font-size: small; + font-style: normal; + margin-top: 16px; +} + +div.right h1{ + margin: 0px; + border: 0px; + padding: 4px; + color: #663333; + font-size: small; + font-weight: bold; +} + +div.right a { text-decoration: none; } +div.right a:link { color: #894926; } +div.right a:visited { color: #894926; } +div.right a:active { color: red; } +div.right a:hover { color: red; } + + +/*--------------------------------------------------------------------------- + * News panel + */ +.NewsGroup { + border-left: 1px solid #825C47; + border-top: 1px solid #825C47; + border-bottom: 1px solid white; /* IE workaround */ + margin-bottom: 8px; + + color: #663333; +} +.NewsItem { + margin: 4px; +} +.NewsTitle { + font-weight: bold; + margin: 0px; + padding: 0px; +} +.NewsDate { + margin: 0px; + padding: 0px; + font-size: smaller; +} +.NewsText { + padding: 0px; + margin: 0px; + margin-bottom: 8px; +} +.NewsText a { text-decoration: underline; } +.NewsText a:link { color: #894926; } +.NewsText a:visited { color: #894926; } +.NewsText a:active { color: red; } +.NewsText a:hover { color: red; } +.NewsMore { + font-size: small; + margin: 4px; + margin-top: 12px; + text-align: left; +} +.NewsGroup td { + font-size: 12px; +} + +/*-------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + * Document meta-information + */ + +.Meta { + margin-top: 64px; + font-size: smaller; + color: #C0C0C0; + text-align: right; +} + +.Meta a { text-decoration: underline; } +.Meta a:link { color: #C0C0C0; } +.Meta a:visited { color: #C0C0C0; } +.Meta a:active { color: red; } +.Meta a:hover { color: red; } +/*--------------------------------------------------------------------------*/ + +div.Content3Column { + margin-left:200px; + margin-right:216px; +} + +div.Content2Column { + margin-left:200px; + margin-right:16px; +} + +div.content h1 { + width: 100%; + font-size: Larger; + background-color: #663333; + color: white; + padding: 2px; + padding-left: 6px; + margin-top: 24px; + margin-bottom: 12px; +} + +div.content a { text-decoration: underline; } +div.content a:link { color: #894926; } +div.content a:visited { color: #894926; } +div.content a:active { color: green; } +div.content a:hover { color: red; } +div.content h2 { + margin-top: 24px; + margin-bottom: 16px; + font-weight: bold; + font-size: Larger; +} + +div.content li { + margin-bottom: 6px; +} +div.content th { + background-color: #825C47; + color: white; +} +div.content td { + background-color: #D7B19C; +} + +div.Shaded pre { + padding: 4px; + font-family: courier new, monospace; + font-size: smaller; + border: 1px solid #008; + background-color: #CCCC99; + color: black; +} + +div.Shaded:before { + margin: 0px; + padding: 0px; + border: 0px; + font-size: inherit; + /*line-spacing: 100%;*/ +} + +pre.code { + padding: 4px; + font-family: courier new, monospace; + font-size: smaller; + border: 1px solid #008; + background-color: #CCCC99; + color: black; +} + +div.Code { + white-space: pre; + padding: 4px; + font-family: courier new, monospace; + font-size: smaller; + border: 1px solid #008; + background-color: #CCCC99; + color: black; +} + +div.Code:before { + margin: 0px; + padding: 0px; + border: 0px; + font-size: inherit; +} + +div.footer { + color: #894926; + padding:0.5em; + clear:both; + text-align:center; + font-size:75%; +} + +div.footer a { + color:#894926; + font-size:inherit; +} + +div.bottomshadow { + width:100%; + height: 12px; + background-image: url("/border_bottom.gif"); + background-repeat: repeat-x; + padding: 12px; +} + +div#content .Float { + float: right; + margin-left: 8px; + margin-right: 0px; + margin-top: 8px; + margin-bottom: 8px; +} + +div#content .Diagram { + display: block; + margin-left: auto; + margin-right: auto; + margin-top: 8px; + margin-bottom: 8px; +} + +div#content .Inline { + display: inline; +} diff --git a/site/doc/domain-based-web-testing.txt b/site/doc/domain-based-web-testing.txt index 622798e..6531e70 100644 --- a/site/doc/domain-based-web-testing.txt +++ b/site/doc/domain-based-web-testing.txt @@ -1,60 +1,60 @@ ---- -Domain Based Web Testing ---- -Domain based web testing is a style of writing and organizing testing scripts so that they can: - -* Express the intent of the test. -* Avoid duplication in the test. - -This is crucial especially for a large scale web application. - -h1. Example - -Domain based web testing focusing on the intent of the test rather than the action of the test. - -h2. Watir Style - -The simplest domain based web testing wraps the browser object (the one that provides the API to drive the browser) into a page object that provides API that returns the HTML element object based on what you can do at the current page. This is the style that "watir":http://wtr.rubyforge.org provides. These HTML element object classes are simply wrappers that wraps the action command and delegate to the browser driver class as action based command. - - - -h2. Page Object with Behaviors - -When the user comes to a page, they normally wants to do a certain task that involves a group of actions. The page objects should provide those APIs so that the test is clear on what the test is doing rather than how it is doing it. - - - -h1. Benefit on Testing Quality - -Domain based web testing requires extra work to design and implement the page and HTML element objects. However, experiences have shown that they pay off quickly. - -With the shared code, each tests only need to write the code that is special about the test. This makes it easy to understand the tests and maintain them. For example, with each page provide the way to locate the HTML elements on the page, it is easy to find the code and change it when the element id or name changes. - -The following are the patterns that have been proved to be useful. Try them out and see if they are useful to your project as well. - -h2. Shared Steps - -You can wrap common steps into the behavior of the component (page or HTML element). - -For example, you can create the @login@ method on the login page. This method will enter the user name and password, click on the submit button and make sure that the login was successful. You can even create different user on the fly and login as the user so that different tests will work on different sets of data and won't affect each other. - -h2. Widgets - -Some HTML element does form submission upon change automatically and some doesn't. You can design your HTML element object so that it knows when the value changes, it needs to wait for the page load. - -Some HTML element has Javascript associated with it so that some other part of the page will change, even when there is no page load. You can also design the element to wait for the condition. For example, for a check box that shows and hides a comment filed, it can be designed as following: - - - -In this way, the test code will remain the same and all the work that making sure the test dose what it intends to do is encapsulated into the place where it should be. - -h2. Speed Up Data Setup - -It is always best to exercise the web application during the tests. However, for a large application with lots of tests, it might not be feasible to run everything through browser. You would still want each page to be fully tested but for some of the tests, it is a good idea to create the test data directly into the database. This will speed up your tests and give you better test coverage. - -With the domain based web testing, your tests only concentrate on what kind of data to generate and delegate the generation detail to the page objects. When performance becomes a concern for your tests, you can add additional behavior on those page objects so that for most of the test it delegates the data creation to a back-end API that inserts the data directly into the database. - -h1. Benefit on Communication - -With your domain based testing code expressing the intent of the test, you have created a "domain specific language" for testing of your web application. It would not be hard to go from here and match that language to your domain language. For detail on domain driven design, see "Domain Driven Design":http://domaindrivendesign.org/index.htm - +--- +Domain Based Web Testing +--- +Domain based web testing is a style of writing and organizing testing scripts so that they can: + +* Express the intent of the test. +* Avoid duplication in the test. + +This is crucial especially for a large scale web application. + +h1. Example + +Domain based web testing focusing on the intent of the test rather than the action of the test. + +h2. Watir Style + +The simplest domain based web testing wraps the browser object (the one that provides the API to drive the browser) into a page object that provides API that returns the HTML element object based on what you can do at the current page. This is the style that "watir":http://wtr.rubyforge.org provides. These HTML element object classes are simply wrappers that wraps the action command and delegate to the browser driver class as action based command. + + + +h2. Page Object with Behaviors + +When the user comes to a page, they normally wants to do a certain task that involves a group of actions. The page objects should provide those APIs so that the test is clear on what the test is doing rather than how it is doing it. + + + +h1. Benefit on Testing Quality + +Domain based web testing requires extra work to design and implement the page and HTML element objects. However, experiences have shown that they pay off quickly. + +With the shared code, each tests only need to write the code that is special about the test. This makes it easy to understand the tests and maintain them. For example, with each page provide the way to locate the HTML elements on the page, it is easy to find the code and change it when the element id or name changes. + +The following are the patterns that have been proved to be useful. Try them out and see if they are useful to your project as well. + +h2. Shared Steps + +You can wrap common steps into the behavior of the component (page or HTML element). + +For example, you can create the @login@ method on the login page. This method will enter the user name and password, click on the submit button and make sure that the login was successful. You can even create different user on the fly and login as the user so that different tests will work on different sets of data and won't affect each other. + +h2. Widgets + +Some HTML element does form submission upon change automatically and some doesn't. You can design your HTML element object so that it knows when the value changes, it needs to wait for the page load. + +Some HTML element has Javascript associated with it so that some other part of the page will change, even when there is no page load. You can also design the element to wait for the condition. For example, for a check box that shows and hides a comment filed, it can be designed as following: + + + +In this way, the test code will remain the same and all the work that making sure the test dose what it intends to do is encapsulated into the place where it should be. + +h2. Speed Up Data Setup + +It is always best to exercise the web application during the tests. However, for a large application with lots of tests, it might not be feasible to run everything through browser. You would still want each page to be fully tested but for some of the tests, it is a good idea to create the test data directly into the database. This will speed up your tests and give you better test coverage. + +With the domain based web testing, your tests only concentrate on what kind of data to generate and delegate the generation detail to the page objects. When performance becomes a concern for your tests, you can add additional behavior on those page objects so that for most of the test it delegates the data creation to a back-end API that inserts the data directly into the database. + +h1. Benefit on Communication + +With your domain based testing code expressing the intent of the test, you have created a "domain specific language" for testing of your web application. It would not be hard to go from here and match that language to your domain language. For detail on domain driven design, see "Domain Driven Design":http://domaindrivendesign.org/index.htm + diff --git a/site/doc/example.rb b/site/doc/example.rb index fbd2963..6a8d9ea 100644 --- a/site/doc/example.rb +++ b/site/doc/example.rb @@ -1,51 +1,51 @@ -require 'spec' - -context 'domain based web testing example' do - specify 'basic' do - # START basic - login_page = LoginPage.new(@browser) - login_page.username_field.enter('user') - login_page.password_field.enter('password') - login_page.login_button.click - # END basic - end - - specify 'login' do - # START login - login_page = LoginPage.new(@browser) - login_page.login('user', 'wrongpassword') - work_items_page = WorkItemsPage.new(@browser) - work_item_page.fill_in(data_fixture.create_full_work_item_data) - work_item_page.due_date_field.enter_yesterday - work_item_page.submit_buttoc.click - work_item_page.should be_present - work_item_page.error.should be_visible - work_item_page.error.text.should == 'Due date should be after today' - # END login - end -end - -# START check -class CommentCheckBox - attr_reader :browser, :locator - - def initialize(browser, locator, comment_span) - @browser = browser - @locator = locator - @comment_span = comment_span - end - - def selected - browser.get_value(locator) == 'on' - end - - def click - old_value = selected -<<<<<<< HEAD:site/doc/example.rb - browser.wait_for_condition(@comment_span.script_check_visible((not old_value)), 5000) -======= - browser.wait_for_condition(@comment_span.script_check_visible(not old_value), 5000) ->>>>>>> a3598e23fd3d746137b3a82b575d68ed060b1d4b:site/doc/example.rb - end -end -# END check +require 'spec' + +context 'domain based web testing example' do + specify 'basic' do + # START basic + login_page = LoginPage.new(@browser) + login_page.username_field.enter('user') + login_page.password_field.enter('password') + login_page.login_button.click + # END basic + end + + specify 'login' do + # START login + login_page = LoginPage.new(@browser) + login_page.login('user', 'wrongpassword') + work_items_page = WorkItemsPage.new(@browser) + work_item_page.fill_in(data_fixture.create_full_work_item_data) + work_item_page.due_date_field.enter_yesterday + work_item_page.submit_buttoc.click + work_item_page.should be_present + work_item_page.error.should be_visible + work_item_page.error.text.should == 'Due date should be after today' + # END login + end +end + +# START check +class CommentCheckBox + attr_reader :browser, :locator + + def initialize(browser, locator, comment_span) + @browser = browser + @locator = locator + @comment_span = comment_span + end + + def selected + browser.get_value(locator) == 'on' + end + + def click + old_value = selected +<<<<<<< HEAD:site/doc/example.rb + browser.wait_for_condition(@comment_span.script_check_visible((not old_value)), 5000) +======= + browser.wait_for_condition(@comment_span.script_check_visible(not old_value), 5000) +>>>>>>> a3598e23fd3d746137b3a82b575d68ed060b1d4b:site/doc/example.rb + end +end +# END check diff --git a/site/document.txt b/site/document.txt index 089afc4..dd914cf 100644 --- a/site/document.txt +++ b/site/document.txt @@ -1,24 +1,24 @@ ---- -Document ---- -Please don't forget to check out the "getting started":getting-started.html page - -h1. Selenium Server - -Besides giving you the ability to launch Selenium server with "selenium" command, Selenium Ruby also provides a driver -class, "SeleniumDriver":rdoc/classes/Selenium/SeleniumServer.html, that allows you to start server, check if server is running, -and stop server through ruby program. - - - -h1. Testing with Selenium - -h2. Action Based Testing - -This is provided by "Selenium":http://www.openqa.org/selenium-rc/ project itself. The "SeleniumDriver":rdoc/classes/Selenium/SeleniumDriver.html is bundled -with Selenium ruby gem. There is a more Ruby friendly class "WebPage":rdoc/classes/Selenium/WebPage.html that you can check out as well. - -h2. Object Based Testing - -Selenium Ruby provides a set of commonly used classes like "Link":rdoc/classes/Selenium/Link.html, "Button":rdoc/classes/Selenium/Button.html and +--- +Document +--- +Please don't forget to check out the "getting started":getting-started.html page + +h1. Selenium Server + +Besides giving you the ability to launch Selenium server with "selenium" command, Selenium Ruby also provides a driver +class, "SeleniumDriver":rdoc/classes/Selenium/SeleniumServer.html, that allows you to start server, check if server is running, +and stop server through ruby program. + + + +h1. Testing with Selenium + +h2. Action Based Testing + +This is provided by "Selenium":http://www.openqa.org/selenium-rc/ project itself. The "SeleniumDriver":rdoc/classes/Selenium/SeleniumDriver.html is bundled +with Selenium ruby gem. There is a more Ruby friendly class "WebPage":rdoc/classes/Selenium/WebPage.html that you can check out as well. + +h2. Object Based Testing + +Selenium Ruby provides a set of commonly used classes like "Link":rdoc/classes/Selenium/Link.html, "Button":rdoc/classes/Selenium/Button.html and "TextField":rdoc/classes/Selenium/TextField.html that can help you build an object model that present your web application. \ No newline at end of file diff --git a/site/download.txt b/site/download.txt index 3912ef1..c878cd3 100644 --- a/site/download.txt +++ b/site/download.txt @@ -1,21 +1,21 @@ ---- -Download ---- -h2. RubyGem - -The easiest way to install the published builds is using the following command through "RubyGem":http://rubygems.org/: - -
gem install selenium
- -h2. RubyForge - -You can also download the files from "Rubyforge":http://rubyforge.org/frs/?group_id=2789 - -h2. Snapshot - -You can take the latest snapshot from the "build page":builds/ - -h1. Textmate Bundle - -You can download textmate bundle for Selenium driver from "Project Files":http://rubyforge.org/frs/?group_id=2789&release_id=9004 - +--- +Download +--- +h2. RubyGem + +The easiest way to install the published builds is using the following command through "RubyGem":http://rubygems.org/: + +
gem install selenium
+ +h2. RubyForge + +You can also download the files from "Rubyforge":http://rubyforge.org/frs/?group_id=2789 + +h2. Snapshot + +You can take the latest snapshot from the "build page":builds/ + +h1. Textmate Bundle + +You can download textmate bundle for Selenium driver from "Project Files":http://rubyforge.org/frs/?group_id=2789&release_id=9004 + diff --git a/site/getting-started.txt b/site/getting-started.txt index b20b0e6..3a9b5dc 100644 --- a/site/getting-started.txt +++ b/site/getting-started.txt @@ -1,29 +1,29 @@ -------- -Getting Started -------- -Selenium-Ruby bundles the selenium server and Ruby classes in the gem so that you can use them right away. - -h1. Selenium Server - -Selenium-ruby installs the executable at the ruby/bin directory so you can launch the server through command: - -
-
selenium
-
- -h1. Selenium RC - -You can use Selenium RC that is installed as a gem, so that your existing action based web testing still works. The following -example is using "RSpec":http://rspec.rubyforge.org: - - - -h1. Selenium Ruby - -You can use classes that come with Selenium ruby to write object based web testing. - - - -The class that described Google home page is defined as following - - +------- +Getting Started +------- +Selenium-Ruby bundles the selenium server and Ruby classes in the gem so that you can use them right away. + +h1. Selenium Server + +Selenium-ruby installs the executable at the ruby/bin directory so you can launch the server through command: + +
+
selenium
+
+ +h1. Selenium RC + +You can use Selenium RC that is installed as a gem, so that your existing action based web testing still works. The following +example is using "RSpec":http://rspec.rubyforge.org: + + + +h1. Selenium Ruby + +You can use classes that come with Selenium ruby to write object based web testing. + + + +The class that described Google home page is defined as following + + diff --git a/site/index.txt b/site/index.txt index a4c3b85..24b0547 100644 --- a/site/index.txt +++ b/site/index.txt @@ -1,13 +1,13 @@ -------------------------------- -Home -------------------------------- -Selenium Ruby is a ruby project that aim to make the popular "Selemium RC":http://www.openqa.org/selenium-rc/ available on rubyforge. - -With Selenium Ruby: -* You can install selenium gem available on rubyforge, which includes the selenium server and SeleniumDriver from Selenium RC project. -* Selenium's action based API is wrapped into a object based API. ("Object based web testing":doc/domain-based-web-testing.html) - -h1. Getting Started - -* "Download it":download.html +------------------------------- +Home +------------------------------- +Selenium Ruby is a ruby project that aim to make the popular "Selemium RC":http://www.openqa.org/selenium-rc/ available on rubyforge. + +With Selenium Ruby: +* You can install selenium gem available on rubyforge, which includes the selenium server and SeleniumDriver from Selenium RC project. +* Selenium's action based API is wrapped into a object based API. ("Object based web testing":doc/domain-based-web-testing.html) + +h1. Getting Started + +* "Download it":download.html * "Use it":getting-started.html \ No newline at end of file diff --git a/site/license.txt b/site/license.txt index 8c13e55..7184680 100644 --- a/site/license.txt +++ b/site/license.txt @@ -1,19 +1,19 @@ ----------------------------------- -License ----------------------------------- -
-
Copyright Selenium-Ruby project
-
-Licensed under the Apache License, Version 2.0 (the "License"); 
-you may not use this file except in compliance with the License. 
-You may obtain a copy of the License at 
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software 
-distributed under the License is distributed on an "AS IS" BASIS, 
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-See the License for the specific language governing permissions and 
-limitations under the License.
-
+---------------------------------- +License +---------------------------------- +
+
Copyright Selenium-Ruby project
+
+Licensed under the Apache License, Version 2.0 (the "License"); 
+you may not use this file except in compliance with the License. 
+You may obtain a copy of the License at 
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software 
+distributed under the License is distributed on an "AS IS" BASIS, 
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+See the License for the specific language governing permissions and 
+limitations under the License.
+
\ No newline at end of file diff --git a/site/print.css b/site/print.css index 55bfee9..73c3846 100644 --- a/site/print.css +++ b/site/print.css @@ -1,65 +1,65 @@ -body { - font-family: Times, serif; - font-size: 12pt; - float: none !important; -} - -div.header { - display: none; -} - -div.left { - display:none; -} - -div.bottomshadow { - display:none; -} - -div.poweredby { - display: none; -} - -div.source { - display: none; -} - -div.right { - display:none; -} - -div.content { - font-family: Times, serif; - font-size: 12pt; - width: 100%; -} - -div.Content3Column { - width: 100%; - font-family: Times, serif; - font-size: 12pt; - margin-left: 0px; - margin-right: 0px; -} - -div.Content2Column { - width: 100%; - font-family: Times, serif; - font-size: 12pt; - margin-left: 0px; - margin-right: 0px; -} - -a:link, a:visited { - color: #520; - background: transparent; - font-weight: bold; - text-decoration: underline; - font-size: 12pt; - font-family: Times, serif; -} - -#content a:link:after, #content a:visited:after { - content: " (" attr(href) ") "; - font-size: 90%; +body { + font-family: Times, serif; + font-size: 12pt; + float: none !important; +} + +div.header { + display: none; +} + +div.left { + display:none; +} + +div.bottomshadow { + display:none; +} + +div.poweredby { + display: none; +} + +div.source { + display: none; +} + +div.right { + display:none; +} + +div.content { + font-family: Times, serif; + font-size: 12pt; + width: 100%; +} + +div.Content3Column { + width: 100%; + font-family: Times, serif; + font-size: 12pt; + margin-left: 0px; + margin-right: 0px; +} + +div.Content2Column { + width: 100%; + font-family: Times, serif; + font-size: 12pt; + margin-left: 0px; + margin-right: 0px; +} + +a:link, a:visited { + color: #520; + background: transparent; + font-weight: bold; + text-decoration: underline; + font-size: 12pt; + font-family: Times, serif; +} + +#content a:link:after, #content a:visited:after { + content: " (" attr(href) ") "; + font-size: 90%; } \ No newline at end of file diff --git a/site/rakefile.rb b/site/rakefile.rb index 9826d62..a5ae719 100644 --- a/site/rakefile.rb +++ b/site/rakefile.rb @@ -1,36 +1,36 @@ -$:.unshift File.join(File.dirname(__FILE__), '..') - -# Example usage of server manager and selenium server -# Thanks to http://svn.caldersphere.net/svn/main/rspec_selenium_rc/trunk/Rakefile -# - -# START RAKE -require 'lib/selenium' -require 'rake' -require 'spec/rake/spectask' - -manager = Selenium::ServerManager.new(Selenium::SeleniumServer.new) - -task :default => [:acceptance_cycle] - -task :start_server do - manager.start -end - -task :stop_server do - manager.stop -end - -Spec::Rake::SpecTask.new('example') do |t| - t.spec_files = FileList['selenium*example.rb'] -end - -task :acceptance_cycle do - begin - Rake::Task['start_server'].invoke - Rake::Task['example'].invoke - ensure - Rake::Task['stop_server'].invoke - end -end -# END RAKE +$:.unshift File.join(File.dirname(__FILE__), '..') + +# Example usage of server manager and selenium server +# Thanks to http://svn.caldersphere.net/svn/main/rspec_selenium_rc/trunk/Rakefile +# + +# START RAKE +require 'lib/selenium' +require 'rake' +require 'spec/rake/spectask' + +manager = Selenium::ServerManager.new(Selenium::SeleniumServer.new) + +task :default => [:acceptance_cycle] + +task :start_server do + manager.start +end + +task :stop_server do + manager.stop +end + +Spec::Rake::SpecTask.new('example') do |t| + t.spec_files = FileList['selenium*example.rb'] +end + +task :acceptance_cycle do + begin + Rake::Task['start_server'].invoke + Rake::Task['example'].invoke + ensure + Rake::Task['stop_server'].invoke + end +end +# END RAKE diff --git a/site/references.txt b/site/references.txt index eccdca9..1af0d3e 100644 --- a/site/references.txt +++ b/site/references.txt @@ -1,5 +1,5 @@ ---- -References ---- -This page contains the useful references for anyone who wants to use Selenium with Ruby. You can help making it better by +--- +References +--- +This page contains the useful references for anyone who wants to use Selenium with Ruby. You can help making it better by "contributing to it":contribute.html. \ No newline at end of file diff --git a/site/ruby.css b/site/ruby.css index ec6fdfb..2591b4a 100644 --- a/site/ruby.css +++ b/site/ruby.css @@ -1,14 +1,14 @@ -pre.code span { - font-family: courier new, monospace; -} - -span.keyword, .namespace, .tag { font-weight: bold; font-family: monospace; color: #8B0000;} -.constant, .attribute, .global, .class, .module { font-family: monospace; color: black;} -.string { font-family: monospace; color: #00008B; } -.ident, .method { font-family: monospace; } -.number, .char { font-family: monospace; color: #888800; } -.comment { font-family: monospace; color: #006400; } -.symbol { font-family: monospace; color: #884400; } -.regex { font-family: monospace; color: #808080; } -.punct { font-family: monospace; color: black; } +pre.code span { + font-family: courier new, monospace; +} + +span.keyword, .namespace, .tag { font-weight: bold; font-family: monospace; color: #8B0000;} +.constant, .attribute, .global, .class, .module { font-family: monospace; color: black;} +.string { font-family: monospace; color: #00008B; } +.ident, .method { font-family: monospace; } +.number, .char { font-family: monospace; color: #888800; } +.comment { font-family: monospace; color: #006400; } +.symbol { font-family: monospace; color: #884400; } +.regex { font-family: monospace; color: #808080; } +.punct { font-family: monospace; color: black; } .escape, .interp, .expr { font-family: monospace; color: purple; } \ No newline at end of file diff --git a/site/team.txt b/site/team.txt index eb296ae..ba3a03b 100644 --- a/site/team.txt +++ b/site/team.txt @@ -1,12 +1,12 @@ ---- -Team ---- -|_.ID|_.Name|_.Information| -|wolfdance|Shane Duan|"Home Page":http://www.shaneduan.com| - -h1. Contributors - -First of all, many thanks to the ThoughtWorks and its friends for creating such a wonderful project, "Selenium":http://www.openqa.com/selenium. - -|_.Name|_.Information|_.Contribution| -|Brian Yamabe|n/a|"Selenium Textmate bundle":http://rubyforge.org/frs/?group_id=2789&release_id=9004| +--- +Team +--- +|_.ID|_.Name|_.Information| +|wolfdance|Shane Duan|"Home Page":http://www.shaneduan.com| + +h1. Contributors + +First of all, many thanks to the ThoughtWorks and its friends for creating such a wonderful project, "Selenium":http://www.openqa.com/selenium. + +|_.Name|_.Information|_.Contribution| +|Brian Yamabe|n/a|"Selenium Textmate bundle":http://rubyforge.org/frs/?group_id=2789&release_id=9004| diff --git a/site/test/index.html b/site/test/index.html index 385b9dd..04a861d 100644 --- a/site/test/index.html +++ b/site/test/index.html @@ -1,21 +1,21 @@ - - Test Main Page - -

Testing

-

This is the main test page for selenium-ruby testing

-

Action Tests

-This section test all the action methods. -
-

Double Click

- -

Events

- -
- -License - - + + Test Main Page + +

Testing

+

This is the main test page for selenium-ruby testing

+

Action Tests

+This section test all the action methods. +
+

Double Click

+ +

Events

+ +
+ +License + + diff --git a/site_template.html b/site_template.html index dc701a8..e259d35 100644 --- a/site_template.html +++ b/site_template.html @@ -1,109 +1,109 @@ - - - Selenium Ruby - <template:include elements="/html/head/title/text()"/> - - - - - - -
- -
- - - - - - - - -
- - -
-
-

Latest Versions

- - - - - - - - - - - - - -
Stable:
Prerelease:
Snapshot:
-

About gem version numbers...

-
-
-

Recent News

- -
-

-

-

-
-
- -

News feed (RSS 2.0)

-
-
-
- -
- -
-

- -
-
- -