watirsplash 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -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