watirsplash 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,35 @@
1
+ module WatirSplash
2
+ # class for common functionality
3
+ class Util
4
+ @@ui_test_common_dir = "ui-test-common"
5
+
6
+ class << self
7
+
8
+ # loads ui-test-common/environment.rb
9
+ #
10
+ # ui-test-common has to be located at some higher level within directory
11
+ # structure compared to project/ui-test directory
12
+ def load_common
13
+ dir = common_dir
14
+ puts "Loading ui-test-common from #{dir}..."
15
+ require File.join(dir, "environment.rb")
16
+ end
17
+
18
+ private
19
+
20
+ def common_dir
21
+ Dir.chdir("..") do
22
+ dirs = Dir.entries(Dir.pwd).find_all {|entry| File.directory?(entry)}
23
+ if dirs.include?(@@ui_test_common_dir) && File.exists?(@@ui_test_common_dir + "/environment.rb")
24
+ File.join(Dir.pwd, @@ui_test_common_dir)
25
+ elsif dirs.include?("..")
26
+ common_dir
27
+ else
28
+ raise "#{@@ui_test_common_dir} directory was not found! It has to exist somewhere higher in directory tree than your project's directory and it has to have environment.rb file in it!"
29
+ end
30
+ end
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,3 @@
1
+ module WatirSplash
2
+ VERSION = "0.1.9"
3
+ end
@@ -0,0 +1,29 @@
1
+ module WatirSplash
2
+ module Waiter
3
+ # waits until some condition is true and
4
+ # throws Watir::Exception::TimeOutException upon timeout
5
+ #
6
+ # examples:
7
+ # wait_until! {text_field(:name => 'x').exists?} # waits until text field exists
8
+ # wait_until!(5) {...} # waits maximum of 5 seconds condition to be true
9
+ def wait_until! *arg
10
+ Watir::Waiter.wait_until(*arg) {yield}
11
+ end
12
+
13
+ # waits until some condition is true and
14
+ # returns false if timeout occurred, true otherwise
15
+ #
16
+ # examples:
17
+ # wait_until {text_field(:name => 'x').exists?} # waits until text field exists
18
+ # wait_until(5) {...} # waits maximum of 5 seconds condition to be true
19
+ def wait_until *arg
20
+ begin
21
+ wait_until!(*arg) {yield}
22
+ rescue Watir::Exception::TimeOutException
23
+ return false
24
+ end
25
+
26
+ return true
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,151 @@
1
+ module Watir
2
+ module PageCheckers
3
+ # raises an error if javascript error was found
4
+ JAVASCRIPT_ERRORS_CHECKER = lambda {|ie| raise "Got JavaScript error!" if ie.status =~ /Error on page/}
5
+ end
6
+ end
7
+
8
+ # patches for Watir
9
+ module Watir
10
+ class IE #:nodoc:all
11
+ # This is Watir's overriden wait method, which is used in many places for deciding
12
+ # if browser is ready or not. We have to patch one line in it to work properly
13
+ # when file save as dialog has been displayed. For some reason READYSTATE (4)
14
+ # property value will be READYSTATE_INTERACTIVE (3) after file has been downloaded
15
+ # and not 4, thus wait will stay blocking.
16
+ # read more about IE READYSTATE property:
17
+ # http://msdn.microsoft.com/en-us/library/aa768362(VS.85).aspx
18
+ def wait(no_sleep=false)
19
+ @xml_parser_doc = nil
20
+ @down_load_time = 0.0
21
+ a_moment = 0.2 # seconds
22
+ start_load_time = Time.now
23
+
24
+ begin
25
+ while @ie.busy # XXX need to add time out
26
+ sleep a_moment
27
+ end
28
+ # this is the line which has been changed to accept also state 3
29
+ until @ie.readyState <= READYSTATE_COMPLETE do
30
+ sleep a_moment
31
+ end
32
+ sleep a_moment
33
+ until @ie.document do
34
+ sleep a_moment
35
+ end
36
+
37
+ documents_to_wait_for = [@ie.document]
38
+
39
+ rescue WIN32OLERuntimeError # IE window must have been closed
40
+ @down_load_time = Time.now - start_load_time
41
+ sleep @pause_after_wait unless no_sleep
42
+ return @down_load_time
43
+ end
44
+
45
+ while doc = documents_to_wait_for.shift
46
+ begin
47
+ until doc.readyState == "complete" do
48
+ sleep a_moment
49
+ end
50
+ @url_list << doc.location.href unless @url_list.include?(doc.location.href)
51
+ doc.frames.length.times do |n|
52
+ begin
53
+ documents_to_wait_for << doc.frames[n.to_s].document
54
+ rescue WIN32OLERuntimeError, NoMethodError
55
+ end
56
+ end
57
+ rescue WIN32OLERuntimeError
58
+ end
59
+ end
60
+
61
+ @down_load_time = Time.now - start_load_time
62
+ run_error_checks
63
+ sleep @pause_after_wait unless no_sleep
64
+ @down_load_time
65
+ end
66
+
67
+ # Closes the browser even if #wait throws an exception.
68
+ # It happens mostly when #run_error_checks throws some exception.
69
+ def close
70
+ return unless exists?
71
+ @closing = true
72
+ @ie.stop
73
+ begin
74
+ wait
75
+ rescue
76
+ end
77
+ chwnd = @ie.hwnd.to_i
78
+ @ie.quit
79
+ while Win32API.new("user32", "IsWindow", 'L', 'L').Call(chwnd) == 1
80
+ sleep 0.3
81
+ end
82
+ end
83
+ end
84
+
85
+ module PageContainer #:nodoc:all
86
+ # patch for .click_no_wait
87
+ def eval_in_spawned_process(command)
88
+ command.strip!
89
+ ruby_code = "require 'rubygems';"
90
+ ruby_code << "require 'watir/ie';"
91
+ ruby_code << "pc = #{attach_command};"
92
+ ruby_code << "pc.instance_eval(#{command.inspect});"
93
+ exec_string = "start rubyw -e #{ruby_code.inspect}".gsub("\\\"", "'")
94
+ system(exec_string)
95
+ end
96
+ end
97
+
98
+ class Table < Element
99
+
100
+ # This method returns multi-dimensional array of the text's in table.
101
+ #
102
+ # It works with tr, th, td elements, colspan, rowspan and nested tables.
103
+ def to_a
104
+ assert_exists
105
+ y = []
106
+ @o.rows.each do |row|
107
+ y << TableRow.new(@container, :ole_object, row).to_a
108
+ end
109
+ y
110
+ end
111
+ end
112
+
113
+ class TableRow < Element
114
+
115
+ # This method returns (multi-dimensional) array of the text's in table's row.
116
+ #
117
+ # It works with th, td elements, colspan, rowspan and nested tables.
118
+ def to_a
119
+ assert_exists
120
+ y = []
121
+ @o.cells.each do |cell|
122
+ inner_tables = cell.getElementsByTagName("TABLE")
123
+ inner_tables.each do |inner_table|
124
+ # make sure that the inner table is directly child for this cell
125
+ if inner_table?(cell, inner_table)
126
+ y << Table.new(@container, :ole_object, inner_table).to_a
127
+ end
128
+ end
129
+
130
+ if inner_tables.length == 0
131
+ y << cell.innerText.strip
132
+ end
133
+ end
134
+ y
135
+ end
136
+
137
+ private
138
+ # returns true if inner_table is direct child
139
+ # table for cell and there's not any table-s in between
140
+ def inner_table?(cell, inner_table)
141
+ parent_element = inner_table.parentElement
142
+ if parent_element.uniqueID == cell.uniqueID
143
+ return true
144
+ elsif parent_element.tagName == "TABLE"
145
+ return false
146
+ else
147
+ return inner_table?(cell, parent_element)
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,11 @@
1
+ require "rubygems"
2
+ require "require_all"
3
+ require "spec"
4
+ require "watir"
5
+ require "watirsplash/util"
6
+ require "watirsplash/waiter"
7
+ require "watirsplash/spec_helper"
8
+ require "watirsplash/spec"
9
+ require "watirsplash/watir"
10
+ require "watirsplash/autoit"
11
+
@@ -0,0 +1,56 @@
1
+ require "watirsplash"
2
+ require "spec/autorun"
3
+
4
+ describe WatirSplash::SpecHelper do
5
+
6
+ it "opens browser automatically" do
7
+ @browser.should exist
8
+ @browser.url.should == "about:blank"
9
+ @browser.title.should == ""
10
+ end
11
+
12
+ it "redirects method calls to Watir::Browser" do
13
+ goto "http://google.com"
14
+ url.should =~ /google/
15
+ title.should =~ /google/i
16
+ text_field = text_field(:name => "q")
17
+ text_field.should exist
18
+ text_field.should be_visible
19
+ end
20
+
21
+ it "has wait_until" do
22
+ result = wait_until {sleep 0.1; true}
23
+ result.should be_true
24
+
25
+ result = wait_until(0.5) {sleep 0.1; false}
26
+ result.should be_false
27
+ end
28
+
29
+ it "has wait_until!" do
30
+ lambda {wait_until!(0.5) {sleep 0.1; true}}.should_not raise_exception
31
+ lambda {wait_until!(0.5) {sleep 0.1; false}}.should raise_exception(Watir::Exception::TimeOutException)
32
+ end
33
+
34
+ it "has file_path methods without using formatter" do
35
+ file_name = "blah.temp"
36
+ ext = File.extname(file_name)
37
+ base = File.basename(file_name, ext)
38
+ expected_path = File.join(Dir.pwd, "#{base}_\\d{6}#{ext}")
39
+
40
+ file_path(file_name).should =~ Regexp.new(expected_path)
41
+ expected_path = expected_path.gsub("/", "\\")
42
+ native_file_path(file_path(file_name)).should =~ Regexp.new(Regexp.escape(expected_path).gsub("\\\\d\\{6\\}", "\\d{6}"))
43
+ end
44
+
45
+ it "has download_file method" do
46
+ begin
47
+ goto "http://dl.dropbox.com/u/2731643/misc/download.html"
48
+ link(:text => "Download").click_no_wait
49
+ file = download_file("download.zip")
50
+ File.read(file).should == "this is a 'zip' file!"
51
+ ensure
52
+ FileUtils.rm file
53
+ end
54
+ end
55
+
56
+ end
@@ -0,0 +1,21 @@
1
+ require "spec/autorun"
2
+ require "watirsplash"
3
+
4
+ describe "Array match_array matcher" do
5
+
6
+ it "matches other arrays with regexps" do
7
+ expected_ary = ["1", "2", "3", /\d/]
8
+ ["1", "2", "3", "5"].should match_array(expected_ary)
9
+
10
+ expected_ary = ["1", ["2", /\d+/], /3/]
11
+ ["1", [], "4"].should_not match_array(expected_ary)
12
+ ["1", ["2", "55"], "3"].should match_array(expected_ary)
13
+ end
14
+
15
+ it "doesn't work with other objects than Array" do
16
+ lambda {"".should match_array("")}.should raise_exception
17
+ lambda {[].should match_array("")}.should raise_exception
18
+ lambda {"".should match_array([])}.should raise_exception
19
+ end
20
+
21
+ end
data/spec/util_spec.rb ADDED
@@ -0,0 +1,38 @@
1
+ require "watirsplash"
2
+ require "spec/autorun"
3
+
4
+ describe WatirSplash::Util do
5
+
6
+ it "loads ui-test-common" do
7
+ class WatirSplash::Util
8
+ @@ui_test_common_dir = "ui-test-common-for-test"
9
+ end
10
+
11
+ begin
12
+ ui_test_common_dir = "../ui-test-common-for-test"
13
+ FileUtils.mkdir(ui_test_common_dir)
14
+ File.open(File.join(ui_test_common_dir, "environment.rb"), "w") do |f|
15
+ f.puts "
16
+ module GlobalApplication
17
+ LOADED = true
18
+ end"
19
+ end
20
+
21
+ lambda {WatirSplash::Util.load_common}.should_not raise_exception
22
+ GlobalApplication::LOADED.should be_true
23
+ ensure
24
+ FileUtils.rm_rf(ui_test_common_dir)
25
+ end
26
+ end
27
+
28
+ it "raises exception if ui-test-common is not found" do
29
+ class WatirSplash::Util
30
+ @@ui_test_common_dir = "nonexisting_ui_test_common_dir"
31
+ end
32
+
33
+ lambda {WatirSplash::Util.load_common}.
34
+ should raise_exception(RuntimeError,
35
+ "nonexisting_ui_test_common_dir directory was not found! It has to exist somewhere higher in directory tree than your project's directory and it has to have environment.rb file in it!")
36
+ end
37
+
38
+ end
@@ -0,0 +1,13 @@
1
+ require "watirsplash"
2
+ require "spec/autorun"
3
+
4
+ describe Watir::IE do
5
+
6
+ it "closes the browser even when Watir::IE#run_error_checks throws an exception" do
7
+ @browser.add_checker lambda {raise "let's fail IE#wait in IE#close"}
8
+ @browser.should exist
9
+ lambda {@browser.close}.should_not raise_exception
10
+ @browser.should_not exist
11
+ end
12
+
13
+ end
@@ -0,0 +1,46 @@
1
+ require "watirsplash"
2
+ require "spec/autorun"
3
+
4
+ describe Watir::TableRow do
5
+ include WatirSplash::SpecHelper
6
+
7
+ before :all do
8
+ goto "http://dl.dropbox.com/u/2731643/misc/tables.html"
9
+ end
10
+
11
+ it "#to_a works with regular row" do
12
+ first_row = table(:id => "normal")[1]
13
+ first_row.to_a.should == ["1", "2", "3"]
14
+ end
15
+
16
+ it "#to_a works with headers in row" do
17
+ first_row = table(:id => "headers")[1]
18
+ first_row.to_a.should == ["1", "2", "3", "4"]
19
+ end
20
+
21
+ it "#to_a works with nested tables" do
22
+ second_row = table(:id => "nested")[2]
23
+ second_row.to_a.should == [[["11", "12"], ["13","14"]], "3"]
24
+ end
25
+
26
+ it "#to_a works with deep-nested tables" do
27
+ second_row = table(:id => "deepnested")[2]
28
+ second_row.to_a.should == [[["11", "12"],
29
+ [[["404", "405"], ["406", "407"]], "14"]], "3"]
30
+ end
31
+
32
+ it "#to_a works with colspan" do
33
+ second_row = table(:id => "colspan")[2]
34
+ second_row.to_a.should == ["3"]
35
+ end
36
+
37
+ it "#to_a works with rowspan" do
38
+ t = table(:id => "rowspan")
39
+ second_row = t[2]
40
+ second_row.to_a.should == ["3", "4"]
41
+
42
+ third_row = t[3]
43
+ third_row.to_a.should == ["5"]
44
+ end
45
+
46
+ end
@@ -0,0 +1,79 @@
1
+ require "watirsplash"
2
+ require "spec/autorun"
3
+
4
+ describe Watir::Table do
5
+ include WatirSplash::SpecHelper
6
+
7
+ before :all do
8
+ goto "http://dl.dropbox.com/u/2731643/misc/tables.html"
9
+ end
10
+
11
+ it "#to_a works with regular table" do
12
+ expected_table = [
13
+ ["1", "2", "3"],
14
+ ["4", "5", "6"],
15
+ ["7", "8", "9"]
16
+ ]
17
+ table(:id => "normal").to_a.should == expected_table
18
+ end
19
+
20
+ it "#to_a works with table with headers" do
21
+ expected_table = [
22
+ ["1", "2", "3", "4"],
23
+ ["5", "6", "7", "8"],
24
+ ["9", "10", "11", "12"]
25
+ ]
26
+ table(:id => "headers").to_a.should == expected_table
27
+ end
28
+
29
+ it "#to_a works with nested tables" do
30
+ expected_table =
31
+ [
32
+ ["1", "2"],
33
+ [[["11", "12"],
34
+ ["13", "14"]], "3"]
35
+ ]
36
+ table(:id => "nested").to_a.should == expected_table
37
+ end
38
+
39
+ it "#to_a works with nested table with non-direct child" do
40
+ expected_table =
41
+ [
42
+ ["1", "2"],
43
+ [[["11", "12"],
44
+ ["13", "14"]], "3"]
45
+ ]
46
+
47
+ table(:id => "nestednondirectchild").to_a.should == expected_table
48
+ end
49
+
50
+ it "#to_a works with deep-nested tables" do
51
+ expected_table =
52
+ [
53
+ ["1", "2"],
54
+ [[["11", "12"],
55
+ [[["404", "405"],
56
+ ["406", "407"]], "14"]], "3"]
57
+ ]
58
+ table(:id => "deepnested").to_a.should == expected_table
59
+ end
60
+
61
+ it "#to_a works with colspan" do
62
+ expected_table =
63
+ [
64
+ ["1", "2"],
65
+ ["3"]
66
+ ]
67
+ table(:id => "colspan").to_a.should == expected_table
68
+ end
69
+
70
+ it "#to_a works with rowspan" do
71
+ expected_table =
72
+ [
73
+ ["1", "2"],
74
+ ["3", "4"],
75
+ ["5"]
76
+ ]
77
+ table(:id => "rowspan").to_a.should match_array(expected_table)
78
+ end
79
+ end
@@ -0,0 +1,28 @@
1
+ =begin
2
+ Global configuration constants
3
+ For example, you can use the URL constant below from your projects like this:
4
+
5
+ In your projects' config.rb:
6
+
7
+ module Config
8
+ module Application
9
+ URL = Config.full_url("my_subpage/index.html") # => equals "http://localhost/my_subpage/index.html
10
+ end
11
+ end
12
+ =end
13
+
14
+ require "uri"
15
+
16
+ module Config
17
+ module GlobalApplication
18
+ URL = "http://localhost"
19
+ end
20
+
21
+ def Config.full_url relative_url
22
+ URI.join(GlobalApplication::URL, relative_url).to_s
23
+ end
24
+ end
25
+
26
+ Spec::Runner.configure do |config|
27
+ config.include(CommonApplicationHelper)
28
+ end
@@ -0,0 +1,17 @@
1
+ =begin
2
+ you have to load this file from your projects' environment.rb, which
3
+ will use common functionality:
4
+ WatirSplash::Util.load_common
5
+
6
+ add all your require statements into this file to avoid unnecessary
7
+ code in your other projects' files
8
+
9
+ by default everything, which is not a spec file, will be loaded
10
+ =end
11
+
12
+ local_dir = File.join(File.dirname(__FILE__), "**/*.rb")
13
+ filtered_ruby_files = Dir.glob(local_dir).delete_if do |file|
14
+ File.directory?(file) || File.basename(file) =~ /(config|_spec)\.rb$/
15
+ end
16
+ require_all filtered_ruby_files
17
+ require_rel "config.rb"
@@ -0,0 +1,14 @@
1
+ # you can create under this directory common libraries/helpers/methods which you could
2
+ # use within your specs in different projects
3
+
4
+ module CommonApplicationHelper
5
+
6
+ # you can use these methods automatically inside of your it-blocks
7
+ # it "does something" do
8
+ # new_global_method.should == "it just works"
9
+ # end
10
+ def new_global_method
11
+ "it just works"
12
+ end
13
+
14
+ end
@@ -0,0 +1,18 @@
1
+ # ApplicationHelper module has helper methods for easy use in specs
2
+ # see usages in spec/dummy_spec.rb
3
+
4
+ module ApplicationHelper
5
+
6
+ def helper_method_one
7
+ "one"
8
+ end
9
+
10
+ def has_second_method?
11
+ true
12
+ end
13
+
14
+ def correct?
15
+ false
16
+ end
17
+
18
+ end
@@ -0,0 +1,20 @@
1
+ # Config for your application
2
+ module Config
3
+ module Application
4
+ # URL, which will be opened by every test
5
+ # replace it with the URL of your application under test
6
+ # or if ui-test-common is used then
7
+ # URL = Config.full_url("/relative/url/index.html")
8
+ URL = "about:blank"
9
+ end
10
+ end
11
+
12
+ # A global configuration for specs in this project, which will include by default
13
+ # a ApplicationHelper module and open Config::Application::URL with
14
+ # the browser.
15
+ # You can read more about RSpec-s before and after syntax from:
16
+ # http://rspec.info/documentation/before_and_after.html
17
+ Spec::Runner.configure do |config|
18
+ config.include(ApplicationHelper)
19
+ config.before(:all) {goto Config::Application::URL}
20
+ end
@@ -0,0 +1,13 @@
1
+ # add all your require statements into this file to avoid unnecessary
2
+ # code in your spec files
3
+
4
+ # uncomment following line to load functionality from ui-test-common
5
+ # WatirSplash::Util.load_common
6
+
7
+ # by default everything, which is not a spec file, will be loaded
8
+ local_dir = File.join(File.dirname(__FILE__), "**/*.rb")
9
+ filtered_ruby_files = Dir.glob(local_dir).delete_if do |file|
10
+ File.directory?(file) || File.basename(file) =~ /(ide_runner|config|_spec)\.rb$/
11
+ end
12
+ require_all filtered_ruby_files
13
+ require_rel "config.rb"
@@ -0,0 +1,3 @@
1
+ # this file is needed for launching specs from IDE
2
+ require "watirsplash/runner"
3
+ exit ::WatirSplash::Runner.run
@@ -0,0 +1,44 @@
1
+ # this is a fully working dummy spec file which you can run to see if
2
+ # your configuration is correct and everything is working as expected
3
+
4
+ describe "WatirSplash" do
5
+
6
+ it "has the browser window opened" do
7
+ url.should == "about:blank"
8
+ end
9
+
10
+ it "has easy access to ApplicationHelper methods" do
11
+ # ApplicationHelper#helper_method_one will be executed
12
+ helper_method_one.should == "one"
13
+ # ApplicationHelper#has_second_method? will be execute
14
+ should have_second_method
15
+ # ApplicationHelper#correct? method will be execute
16
+ should_not be_correct
17
+ end
18
+
19
+ it "fails the example and makes a screenshot of the browser" do
20
+ false.should be_true
21
+ end
22
+
23
+ it "is in pending status" do
24
+ goto "http://google.com"
25
+ title.should == "Google"
26
+ text_field(:name => "q").set "Bing"
27
+ search_button = button(:name => "btnG")
28
+ search_button.should exist
29
+ search_button.should be_visible
30
+ search_button.click
31
+ text.should include("Bing")
32
+ pending "this is a known 'bug'" do
33
+ title.should == "Bing"
34
+ end
35
+ end
36
+
37
+ it "has also access to global methods" do
38
+ pending "it fails as long as there's not executed 'watirsplash generate_common' command
39
+ and ui-test-common is not loaded by this project" do
40
+ new_global_method.should == "it just works"
41
+ end
42
+ end
43
+
44
+ end