rwebspec-webdriver 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,87 @@
1
+ module RWebSpec
2
+
3
+ module ElementLocator
4
+
5
+ BUTTON_VALID_TYPES = %w[button reset submit image]
6
+ def button_elements
7
+ find_elements(:xpath, ".//button | .//input[#{attribute_expression :type => BUTTON_VALID_TYPES}]")
8
+ end
9
+
10
+ CHECK_BOX_TYPES = %w(checkbox)
11
+ def check_box_elements(how, what, opts = [])
12
+ find_elements(:xpath, ".//input[#{attribute_expression :type => CHECK_BOX_TYPES}]")
13
+ end
14
+
15
+ RADIO_TYPES = %w(radio)
16
+ def radio_elements(how, what, opts = [])
17
+ find_elements(:xpath, ".//input[#{attribute_expression :type => RADIO_TYPES}]")
18
+ end
19
+
20
+ def select_elements(how, what, opts = [])
21
+ find_elements(:xpath, ".//input[#{attribute_expression :type => RADIO_TYPES}]")
22
+ end
23
+
24
+ # TextField, TextArea
25
+ TEXT_FILED_TYPES = %w(text)
26
+ def text_field_elements
27
+ find_elements(:xpath, ".//input[#{attribute_expression :type => TEXT_FILED_TYPES}]")
28
+ end
29
+
30
+ def text_area_elements
31
+ find_elements(:xpath, ".//textarea")
32
+ end
33
+
34
+ FILE_FIELD_TYPES = %w(file)
35
+ def file_field_elements
36
+ find_elements(:xpath, ".//input[#{attribute_expression :type => FILE_FIELD_TYPES}]")
37
+ end
38
+
39
+ HIDDEN_TYPES = %w(hidden)
40
+ def hidden_elements
41
+ find_elements(:xpath, ".//input[#{attribute_expression :type => HIDDEN_TYPES}]")
42
+ end
43
+
44
+ #---
45
+ def find_by_tag(tag)
46
+ find_elements(:tag_name, tag)
47
+ end
48
+
49
+ def should_use_label_element?
50
+ @selector[:tag_name] != "option" rescue false
51
+ end
52
+
53
+ def equal_pair(key, value)
54
+ # we assume :label means a corresponding label element, not the attribute
55
+ if key == :label && should_use_label_element?
56
+ "@id=//label[normalize-space()='#{value}']/@for"
57
+ else
58
+ "#{lhs_for(key)}='#{value}'"
59
+ end
60
+ end
61
+
62
+ def lhs_for(key)
63
+ case key
64
+ when :text, 'text'
65
+ 'normalize-space()'
66
+ when :href
67
+ # TODO: change this behaviour?
68
+ 'normalize-space(@href)'
69
+ else
70
+ "@#{key.to_s.gsub("_", "-")}"
71
+ end
72
+ end
73
+
74
+
75
+ def attribute_expression(selectors)
76
+ selectors.map do |key, val|
77
+ if val.kind_of?(Array)
78
+ "(" + val.map { |v| equal_pair(key, v) }.join(" or ") + ")"
79
+ else
80
+ equal_pair(key, val)
81
+ end
82
+ end.join(" and ")
83
+ end
84
+
85
+ end
86
+
87
+ end
@@ -0,0 +1,172 @@
1
+
2
+ module RWebSpec
3
+ module LoadTestHelper
4
+
5
+ include RWebSpec::Utils
6
+ include RWebSpec::Assert
7
+
8
+ MAX_VU = 1000
9
+
10
+ # only support firefox or Celerity
11
+ def open_browser(base_url, options = {})
12
+ default_options = {:resynchronize => false, :firefox => false }
13
+ options = default_options.merge(options)
14
+ options[:firefox] ||= (ENV['LOADWISE_PREVIEW'] || $LOADWISE_PREVIEW)
15
+ RWebSpec::WebBrowser.new(base_url, nil, options)
16
+ end
17
+
18
+ # maybe attach_browser
19
+
20
+ # Does not provide real function, other than make enhancing test syntax
21
+ #
22
+ # Example:
23
+ # allow { click_button('Register') }
24
+ def allow(&block)
25
+ yield
26
+ end
27
+ alias shall_allow allow
28
+ alias allowing allow
29
+
30
+ # try operation, ignore if errors occur
31
+ #
32
+ # Example:
33
+ # failsafe { click_link("Logout") } # try logout, but it still OK if not being able to (already logout))
34
+ def failsafe(&block)
35
+ begin
36
+ yield
37
+ rescue =>e
38
+ end
39
+ end
40
+ alias fail_safe failsafe
41
+
42
+ # Try the operation up to specified timeout (in seconds), and sleep given interval (in seconds).
43
+ # Error will be ignored until timeout
44
+ # Example
45
+ # try { click_link('waiting')}
46
+ # try(10, 2) { click_button('Search' } # try to click the 'Search' button upto 10 seconds, try every 2 seconds
47
+ # try { click_button('Search' }
48
+ def try(timeout = @@default_timeout, polling_interval = @@default_polling_interval || 1, &block)
49
+ start_time = Time.now
50
+
51
+ last_error = nil
52
+ until (duration = Time.now - start_time) > timeout
53
+ begin
54
+ return if yield
55
+ last_error = nil
56
+ rescue => e
57
+ last_error = e
58
+ end
59
+ sleep polling_interval
60
+ end
61
+
62
+ raise "Timeout after #{duration.to_i} seconds with error: #{last_error}." if last_error
63
+ raise "Timeout after #{duration.to_i} seconds."
64
+ end
65
+ alias try_upto try
66
+
67
+ ##
68
+ # Convert :first to 1, :second to 2, and so on...
69
+ def symbol_to_sequence(symb)
70
+ value = { :zero => 0,
71
+ :first => 1,
72
+ :second => 2,
73
+ :third => 3,
74
+ :fourth => 4,
75
+ :fifth => 5,
76
+ :sixth => 6,
77
+ :seventh => 7,
78
+ :eighth => 8,
79
+ :ninth => 9,
80
+ :tenth => 10 }[symb]
81
+ return value || symb.to_i
82
+ end
83
+
84
+ # monitor current execution using
85
+ #
86
+ # Usage
87
+ # log_time { browser.click_button('Confirm') }
88
+ def log_time(msg, &block)
89
+ start_time = Time.now
90
+ yield
91
+ end_time = Time.now
92
+
93
+ Thread.current[:log] ||= []
94
+ Thread.current[:log] << {:file => File.basename(__FILE__),
95
+ :message => msg,
96
+ :start_time => Time.now,
97
+ :duration => Time.now - start_time}
98
+
99
+ if $LOADWISE_MONITOR
100
+ begin
101
+ require 'java'
102
+ puts "Calling Java 1"
103
+ java_import com.loadwise.db.MemoryDatabase
104
+ #puts "Calling Java 2: #{MemoryDatabase.count}"
105
+ MemoryDatabase.addEntry(1, "zdfa01", "a_spec.rb", msg, start_time, end_time);
106
+ puts "Calling Java Ok: #{MemoryDatabase.count}"
107
+ rescue NameError => ne
108
+ puts "Name Error: #{ne}"
109
+ # failed to load Java class
110
+ rescue => e
111
+ puts "Failed to calling Java: #{e.class.name}"
112
+ end
113
+ end
114
+ # How to notify LoadWise at real time
115
+ # LoadWise to collect CPU
116
+ end
117
+
118
+ def run_with_virtual_users(virtual_user_count = 2, preview = false, &block)
119
+ raise "too many virtual users" if virtual_user_count > MAX_VU
120
+
121
+ begin
122
+ if defined?(LOADWISE_PREVIEW)
123
+ preview = LOADWISE_PREVIEW
124
+ end
125
+ rescue => e1
126
+ end
127
+
128
+ if preview
129
+ virtual_user_count = 1
130
+ $LOADWISE_PREVIEW = true
131
+ end
132
+
133
+ if (virtual_user_count <= 1)
134
+ yield
135
+ else
136
+ threads = []
137
+ vu_reports = {}
138
+ virtual_user_count.times do |idx|
139
+ threads[idx] = Thread.new do
140
+ start_time = Time.now
141
+ vu_reports[idx] ||= []
142
+ begin
143
+ yield
144
+ vu_reports[idx] = Thread.current[:log]
145
+ rescue => e
146
+ vu_reports[idx] = Thread.current[:log]
147
+ vu_reports[idx] ||= []
148
+ vu_reports[idx] << { :error => e }
149
+ end
150
+ vu_reports[idx] ||= []
151
+ vu_reports[idx] << { :message => "Total Duration", :duration => Time.now - start_time }
152
+ puts "VU[#{idx+1}] #{Time.now - start_time}s"
153
+ end
154
+ end
155
+
156
+ threads.each {|t| t.join; }
157
+ vu_reports.each do |key, value|
158
+ value.each do |entry|
159
+ if entry[:error] then
160
+ puts "Error: #{entry[:error]}"
161
+ else
162
+ puts "[#{key}] #{entry[:message]}, #{entry[:duration]}"
163
+ end
164
+ end
165
+ end
166
+
167
+ return vu_reports
168
+ end
169
+ end
170
+
171
+ end
172
+ end
@@ -0,0 +1,37 @@
1
+ class ContainsText
2
+
3
+ # this is what the matcher is called on.
4
+ # In this case:
5
+ # foo.should contains(:bars)
6
+ # foo would be passed to the +initialize+
7
+ def initialize(expected)
8
+ @expected = expected
9
+ end
10
+
11
+ def matches?(actual)
12
+ @actual = actual
13
+ return actual && actual.include?(@expected)
14
+ end
15
+
16
+ def actual_text
17
+ @actual.to_s.length > 256 ? @actual[0, 255] : @actual
18
+ end
19
+
20
+ # error message for should
21
+ def failure_message
22
+ "expected '#{actual_text}' to contain '#{@expected}', but it didn't"
23
+ end
24
+
25
+ # error message for should_not
26
+ def negative_failure_message
27
+ "expected '#{actual_text}' not to contain '#{@expected}', but it did"
28
+ end
29
+
30
+ end
31
+
32
+
33
+ # This method is the one you use with should/should_not
34
+ def contains_text?(expected)
35
+ ContainsText.new(expected)
36
+ end
37
+ alias contains? contains_text?
@@ -0,0 +1,147 @@
1
+ module RWebSpec
2
+ module Popup
3
+
4
+ #= Popup
5
+ #
6
+
7
+ # Start background thread to click popup windows
8
+ # Warning:
9
+ # Make browser window active
10
+ # Don't mouse your mouse to focus other window during test execution
11
+ def check_for_popups
12
+ autoit = WIN32OLE.new('AutoItX3.Control')
13
+ #
14
+ # Do forever - assumes popups could occur anywhere/anytime in your
15
+ # application.
16
+ loop do
17
+ # Look for window with given title. Give up after 1 second.
18
+ ret = autoit.WinWait('Windows Internet Explorer', '', 1)
19
+ #
20
+ # If window found, send appropriate keystroke (e.g. {enter}, {Y}, {N}).
21
+ if (ret==1) then
22
+ autoit.Send('{enter}')
23
+ end
24
+ #
25
+ # Take a rest to avoid chewing up cycles and give another thread a go.
26
+ # Then resume the loop.
27
+ sleep(3)
28
+ end
29
+ end
30
+
31
+ ##
32
+ # Check for "Security Information" and "Security Alert" alert popup, click 'Yes'
33
+ #
34
+ # Usage: For individual test suite
35
+ #
36
+ # before(:all) do
37
+ # $popup = Thread.new { check_for_alerts }
38
+ # open_in_browser
39
+ # ...
40
+ # end
41
+ #
42
+ # after(:all) do
43
+ # close_browser
44
+ # Thread.kill($popup)
45
+ # end
46
+ #
47
+ # or for all tests,
48
+ # $popup = Thread.new { check_for_alerts }
49
+ # at_exit{ Thread.kill($popup) }
50
+ def check_for_security_alerts
51
+ autoit = WIN32OLE.new('AutoItX3.Control')
52
+ loop do
53
+ ["Security Alert", "Security Information"].each do |win_title|
54
+ ret = autoit.WinWait(win_title, '', 1)
55
+ if (ret==1) then
56
+ autoit.Send('{Y}')
57
+ end
58
+ end
59
+ sleep(3)
60
+ end
61
+ end
62
+
63
+ def verify_alert(title = "Microsoft Internet Explorer", button = "OK")
64
+ if is_windows? && !is_firefox?
65
+ WIN32OLE.new('AutoItX3.Control').ControlClick(title, '', button)
66
+ else
67
+ raise "This function only supports IE"
68
+ end
69
+ end
70
+
71
+ def click_button_in_security_information_popup(button = "&Yes")
72
+ verify_alert("Security Information", "", button)
73
+ end
74
+ alias click_security_information_popup click_button_in_security_information_popup
75
+
76
+ def click_button_in_security_alert_popup(button = "&Yes")
77
+ verify_alert("Security Alert", "", button)
78
+ end
79
+ alias click_security_alert_popup click_button_in_security_alert_popup
80
+
81
+ def click_button_in_javascript_popup(button = "OK")
82
+ verify_alert()
83
+ end
84
+ alias click_javascript_popup click_button_in_javascript_popup
85
+
86
+ ##
87
+ # This only works for IEs
88
+ # Cons:
89
+ # - Slow
90
+ # - only works in IE
91
+ # - does not work for security alert ?
92
+ def ie_popup_clicker(button_name = "OK", max_wait = 15)
93
+ require 'watir/contrib/enabled_popup'
94
+ require 'win32ole'
95
+ hwnd = ie.enabled_popup(15)
96
+ if (hwnd) #yeah! a popup
97
+ popup = WinClicker.new
98
+ popup.makeWindowActive(hwnd) #Activate the window.
99
+ popup.clickWindowsButton_hwnd(hwnd, button_name) #Click the button
100
+ #popup.clickWindowsButton(/Internet/,button_name,30)
101
+ popup = nil
102
+ end
103
+ end
104
+
105
+ def click_popup_window(button, wait_time= 9, user_input=nil )
106
+ @web_browser.start_clicker(button, wait_time, user_input)
107
+ sleep 0.5
108
+ end
109
+ # run a separate process waiting for the popup window to click
110
+ #
111
+ #
112
+ def prepare_to_click_button_in_popup(button = "OK", wait_time = 3)
113
+ # !@web_browser.is_firefox?
114
+ # TODO: firefox is OK
115
+ if RUBY_PLATFORM =~ /mswin/ || RUBY_PLATFORM =~ /mingw/ then
116
+ start_checking_js_dialog(button, wait_time)
117
+ else
118
+ raise "this only support on Windows and on IE"
119
+ end
120
+ end
121
+
122
+ # Start a background process to click the button on a javascript popup window
123
+ def start_checking_js_dialog(button = "OK", wait_time = 3)
124
+ w = WinClicker.new
125
+ longName = File.expand_path(File.dirname(__FILE__)).gsub("/", "\\" )
126
+ shortName = w.getShortFileName(longName)
127
+ c = "start ruby #{shortName}\\clickJSDialog.rb #{button} #{wait_time} "
128
+ w.winsystem(c)
129
+ w = nil
130
+ end
131
+
132
+ # Click the button in javascript popup dialog
133
+ # Usage:
134
+ # click_button_in_popup_after { click_link('Cancel')}
135
+ # click_button_in_popup_after("OK") { click_link('Cancel')}
136
+ #
137
+ def click_button_in_popup_after(options = {:button => "OK", :wait_time => 3}, &block)
138
+ if is_windows? then
139
+ start_checking_js_dialog(options[:button], options[:wait_time])
140
+ yield
141
+ else
142
+ raise "this only support on Windows and on IE"
143
+ end
144
+ end
145
+
146
+ end
147
+ end
@@ -0,0 +1,99 @@
1
+ require 'uri'
2
+ require File.dirname(__FILE__) + "/driver"
3
+ require File.dirname(__FILE__) + "/web_page"
4
+ require File.dirname(__FILE__) + "/assert"
5
+
6
+ # ZZ patches to RSpec 1.1.2 - 1.1.4
7
+ # - add to_s method to example_group
8
+ module Spec
9
+ module Example
10
+ class ExampleGroup
11
+ def to_s
12
+ @_defined_description
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ # example
19
+ # should link_by_text(text, options).size > 0
20
+
21
+ module RWebSpec
22
+ module RSpecHelper
23
+ include RWebSpec::Driver
24
+ include RWebSpec::Assert
25
+ include RWebSpec::Utils
26
+
27
+ # --
28
+ # Content
29
+ # --
30
+
31
+ def table_source(table_id)
32
+ table(:id, table_id).innerHTML
33
+ # elem = @web_browser.document.getElementById(table_id)
34
+ # raise "The element '#{table_id}' is not a table or there are multple elements with same id" unless elem.name.uppercase == "TABLE"
35
+ # elem.innerHTML
36
+ end
37
+ alias table_source_by_id table_source
38
+
39
+ def element_text(elem_id)
40
+ @web_browser.element_value(elem_id)
41
+ end
42
+ alias element_text_by_id element_text
43
+
44
+ #TODO: is it working?
45
+ def element_source(elem_id)
46
+ @web_browser.get_html_in_element(elem_id)
47
+ end
48
+
49
+
50
+ def button_by_id(button_id)
51
+ button(:id, button_id)
52
+ end
53
+
54
+ def buttons_by_caption(text)
55
+ button(:text, text)
56
+ end
57
+ alias buttons_by_text buttons_by_caption
58
+
59
+ def link_by_id(link_id)
60
+ link(:id, link_id)
61
+ end
62
+
63
+ # default options: exact => true
64
+ def links_by_text(link_text, options = {})
65
+ options.merge!({:exact=> true})
66
+ matching_links = []
67
+ links.each { |link|
68
+ matching_links << link if (options[:exact] ? link.text == link_text : link.text.include?(link_text))
69
+ }
70
+ return matching_links
71
+ end
72
+ alias links_with_text links_by_text
73
+
74
+ def save_page(file_name = nil)
75
+ @web_browser.save_page(file_name)
76
+ end
77
+
78
+ def save_content_to_file(content, file_name = nil)
79
+ file_name ||= Time.now.strftime("%Y%m%d%H%M%S") + ".html"
80
+ puts "about to save page: #{File.expand_path(file_name)}"
81
+ File.open(file_name, "w").puts content
82
+ end
83
+
84
+ # When running
85
+ def debugging?
86
+ $ITEST2_DEBUGGING && $ITEST2_RUNNING_AS == "test_case"
87
+ end
88
+
89
+ # RSpec Matchers
90
+ #
91
+ # Example,
92
+ # a_number.should be_odd_number
93
+ def be_odd_number
94
+ simple_matcher("must be odd number") { |actual| actual && actual.to_id % 2 == 1}
95
+ end
96
+
97
+ end
98
+
99
+ end