terminus_spec 0.5.0

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.
Files changed (64) hide show
  1. data/.gitignore +26 -0
  2. data/.rspec +1 -0
  3. data/.rvmrc +2 -0
  4. data/.travis.yml +6 -0
  5. data/Gemfile +7 -0
  6. data/HISTORY.md +54 -0
  7. data/LICENSE +20 -0
  8. data/README.md +13 -0
  9. data/Rakefile +43 -0
  10. data/cucumber.yml +6 -0
  11. data/lib/terminus_spec.rb +200 -0
  12. data/lib/terminus_spec/factory.rb +27 -0
  13. data/lib/terminus_spec/generators.rb +80 -0
  14. data/lib/terminus_spec/locators.rb +23 -0
  15. data/lib/terminus_spec/logger.rb +7 -0
  16. data/lib/terminus_spec/matchers.rb +41 -0
  17. data/lib/terminus_spec/platform_selenium.rb +18 -0
  18. data/lib/terminus_spec/platform_selenium/platform_object.rb +214 -0
  19. data/lib/terminus_spec/platform_selenium/web_objects/all.rb +98 -0
  20. data/lib/terminus_spec/platform_selenium/web_objects/button.rb +13 -0
  21. data/lib/terminus_spec/platform_selenium/web_objects/link.rb +13 -0
  22. data/lib/terminus_spec/platform_selenium/web_objects/text_field.rb +14 -0
  23. data/lib/terminus_spec/platform_watir.rb +18 -0
  24. data/lib/terminus_spec/platform_watir/platform_object.rb +190 -0
  25. data/lib/terminus_spec/platform_watir/web_objects/all.rb +88 -0
  26. data/lib/terminus_spec/platform_watir/web_objects/text_field.rb +13 -0
  27. data/lib/terminus_spec/platforms.rb +25 -0
  28. data/lib/terminus_spec/version.rb +3 -0
  29. data/lib/terminus_spec/web_objects/all.rb +172 -0
  30. data/lib/terminus_spec/web_objects/button.rb +32 -0
  31. data/lib/terminus_spec/web_objects/link.rb +40 -0
  32. data/lib/terminus_spec/web_objects/text_field.rb +45 -0
  33. data/spec/spec_helper.rb +37 -0
  34. data/spec/terminus_spec/factory_spec.rb +40 -0
  35. data/spec/terminus_spec/generators_spec.rb +179 -0
  36. data/spec/terminus_spec/locators_spec.rb +30 -0
  37. data/spec/terminus_spec/platform_selenium_spec.rb +28 -0
  38. data/spec/terminus_spec/platform_watir_spec.rb +32 -0
  39. data/spec/terminus_spec/platforms_spec.rb +43 -0
  40. data/spec/terminus_spec/terminus_spec.rb +271 -0
  41. data/spec/terminus_spec/web_objects/all_spec.rb +87 -0
  42. data/spec/terminus_spec/web_objects/button_spec.rb +35 -0
  43. data/spec/terminus_spec/web_objects/link_spec.rb +46 -0
  44. data/spec/terminus_spec/web_objects/text_field_spec.rb +48 -0
  45. data/spec/terminus_spec/webobject_selenium_spec.rb +154 -0
  46. data/spec/terminus_spec/webobject_watir_spec.rb +120 -0
  47. data/specs/app/favicon.ico +0 -0
  48. data/specs/app/images/mass_extinction.jpg +0 -0
  49. data/specs/app/index.html +20 -0
  50. data/specs/app/modal_1.html +41 -0
  51. data/specs/app/modal_2.html +29 -0
  52. data/specs/app/server.rb +25 -0
  53. data/specs/app/style.css +18 -0
  54. data/specs/app/success_1.html +12 -0
  55. data/specs/app/success_2.html +12 -0
  56. data/specs/app/test_event.html +39 -0
  57. data/specs/app/test_form.html +114 -0
  58. data/specs/app/test_frame.html +15 -0
  59. data/specs/app/test_iframe.html +15 -0
  60. data/specs/app/test_static.html +92 -0
  61. data/specs/engine/borg.rb +27 -0
  62. data/specs/engine/hooks.rb +23 -0
  63. data/terminus_spec.gemspec +31 -0
  64. metadata +198 -0
@@ -0,0 +1,18 @@
1
+ module TerminusSpec
2
+ module Platforms
3
+ module WatirWebDriver
4
+
5
+ def self.create_platform_object_for(browser)
6
+ require 'terminus_spec/platform_watir/platform_object'
7
+ return WatirWebDriver::PlatformObject.new(browser)
8
+ end
9
+
10
+ def self.works_for?(browser)
11
+ browser.is_a?(Watir::Browser)
12
+ end
13
+
14
+ end # module WatirWebDriver
15
+ end # module Platforms
16
+ end # module TerminusSpec
17
+
18
+ TerminusSpec::Platforms.associate(:watir_webdriver, TerminusSpec::Platforms::WatirWebDriver)
@@ -0,0 +1,190 @@
1
+ module TerminusSpec
2
+ module Platforms
3
+ module WatirWebDriver
4
+
5
+ class PlatformObject
6
+
7
+ attr_reader :browser
8
+
9
+ def initialize(browser)
10
+ @browser = browser
11
+ end
12
+
13
+ # Platform method to navigate to a specified URL.
14
+ # See TerminusSpec#navigate_to
15
+ def navigate_to(url)
16
+ @browser.goto url
17
+ end
18
+
19
+ # Platform method to retrieve the title for the current page.
20
+ # See TerminusSpec#title
21
+ def title
22
+ @browser.title
23
+ end
24
+
25
+ # Platform method to retrieve text from the current page.
26
+ # See TerminusSpec#text
27
+ def text
28
+ @browser.text
29
+ end
30
+
31
+ # Platform method to retrieve the HTML markup for the current page.
32
+ # See TerminusSpec#html
33
+ def html
34
+ @browser.html
35
+ end
36
+
37
+ # Platform method to get the current URL.
38
+ # See TerminusSpec#current_url
39
+ def current_url
40
+ @browser.url
41
+ end
42
+
43
+ # Platform method to refresh the page.
44
+ # See TerminusSpec#refresh
45
+ def refresh
46
+ @browser.refresh
47
+ end
48
+
49
+ # Platform method to go to the preceding page in history.
50
+ # See TerminusSpec#back
51
+ def back
52
+ @browser.back
53
+ end
54
+
55
+ # Platform method to go to the succeeding page in history.
56
+ # See TerminusSpec#forward
57
+ def forward
58
+ @browser.forward
59
+ end
60
+
61
+ # Platform method to clear the cookies from the browser.
62
+ # See TerminusSpec#clear_cookies
63
+ def clear_cookies
64
+ @browser.clear_cookies
65
+ end
66
+
67
+ # Platform method to save the current screenshot to a file.
68
+ # See TerminusSpec#save_screenshot
69
+ def save_screenshot(file_name)
70
+ @browser.wd.save_screenshot(file_name)
71
+ end
72
+
73
+ # Platform method to wait for a condition on a page to be true.
74
+ # See TerminusSpec#wait_until
75
+ def wait_until(timeout, message, &block)
76
+ @browser.wait_until(timeout, message, &block)
77
+ end
78
+
79
+ # Platform method to handle an alert popup message box.
80
+ # See TerminusSpec#will_alert
81
+ def will_alert(&block)
82
+ @browser.wd.execute_script "window.alert = function(msg) { window.__lastWatirAlert=msg; }"
83
+ yield
84
+ value = @browser.wd.execute_script "return window.__lastWatirAlert"
85
+ value
86
+ end
87
+
88
+ # Platform method to handle a confirmation popup message box.
89
+ # See TerminusSpec#will_confirm
90
+ def will_confirm(response, &block)
91
+ @browser.wd.execute_script "window.confirm = function(msg) { window.__lastWatirConfirm=msg; return #{!!response} }"
92
+ yield
93
+ value = @browser.wd.execute_script "return window.__lastWatirConfirm"
94
+ value
95
+ end
96
+
97
+ # Platform method to handle a prompt popup message box.
98
+ # See TerminusSpec#will_prompt
99
+ def will_prompt(response, &block)
100
+ @browser.wd.execute_script "window.prompt = function(text, value) { window.__lastWatirPrompt = { message: text, default_value: value }; return #{response.to_json}; }"
101
+ yield
102
+ result = @browser.wd.execute_script "return window.__lastWatirPrompt"
103
+ result && result.dup.each_key { |k| result[k.to_sym] = result.delete(k) }
104
+ result
105
+ end
106
+
107
+ # Platform method to attach to a displayed window.
108
+ # See TerminusSpec#attach_to_window
109
+ def attach_to_window(identifier, &block)
110
+ win_id = {identifier.keys.first => /#{Regexp.escape(identifier.values.first)}/}
111
+ @browser.window(win_id).use(&block)
112
+ end
113
+
114
+ # Platform method to return a link object.
115
+ # Link objects are of type: TerminusSpec::WebObjects::Link
116
+ # See TerminusSpec::Generators#link
117
+ def get_link_for(locator)
118
+ locator = get_platform_locator_for(locator, WebObjects::Link)
119
+ web_object = @browser.instance_eval "link(locator)"
120
+ WebObjects::Link.new(web_object, :platform => :watir_webdriver)
121
+ end
122
+
123
+ # Platform method to click a link object.
124
+ # See TerminusSpec::Generators#link
125
+ def click_link_for(locator)
126
+ locator = get_platform_locator_for(locator, WebObjects::Link)
127
+ @browser.instance_eval "link(locator).click if locator"
128
+ end
129
+
130
+ # Platform method to return a text field object.
131
+ # Text field objects are of type: TerminusSpec::WebObjects::TextField
132
+ # See TerminusSpec::Generators#text_field
133
+ def get_text_field_for(locator)
134
+ identifier = get_platform_locator_for(locator, WebObjects::TextField)
135
+ web_object = @browser.instance_eval "text_field(locator)"
136
+ WebObjects::TextField.new(web_object, :platform => :watir_webdriver)
137
+ end
138
+
139
+ # Platform method to get the value in a text field object.
140
+ # See TerminusSpec::Generators#text_field
141
+ def get_text_field_value_for(locator)
142
+ identifier = get_platform_locator_for(locator, WebObjects::TextField)
143
+ value = @browser.instance_eval "text_field(locator).value"
144
+ value
145
+ end
146
+
147
+ # Platform method to set a value in a text field object.
148
+ # See TerminusSpec::Generators#text_field
149
+ def set_text_field_value_for(locator, text)
150
+ identifier = get_platform_locator_for(locator, WebObjects::TextField)
151
+ @browser.instance_eval "text_field(locator).set(text)"
152
+ end
153
+
154
+ # Platform method to return a button object.
155
+ # Button objects are of type: TerminusSpec::WebObjects::Button
156
+ # See TerminusSpec::Generators#button
157
+ def get_button_for(locator)
158
+ identifier = get_platform_locator_for(locator, WebObjects::Button)
159
+ web_object = @browser.instance_eval "button(locator)"
160
+ WebObjects::Button.new(web_object, :platform => :watir_webdriver)
161
+ end
162
+
163
+ # Platform method to click a button object.
164
+ # See TerminusSpec::Generators#button
165
+ def click_button_for(locator)
166
+ identifier = get_platform_locator_for(locator, WebObjects::Button)
167
+ @browser.instance_eval "button(locator).click"
168
+ end
169
+
170
+ protected
171
+
172
+ def get_platform_locator_for(locator, web_object, tag=nil)
173
+ locator = qualify_with_tagname_for locator, tag if tag
174
+ locator = web_object.have_watir_find_object_with locator
175
+ return locator
176
+ end
177
+
178
+ def qualify_with_tagname_for(locator, tag)
179
+ return locator if locator.length < 2 and not locator[:name]
180
+ locator[:tag_name] = tag if locator[:name]
181
+ locator
182
+ end
183
+
184
+ end # class PlatformObject
185
+
186
+ end # module WatirWebDriver
187
+ end # module Platforms
188
+ end # module TerminusSpec
189
+
190
+ Dir["#{File.dirname(__FILE__)}/../web_objects/**/*.rb"].each { |file| require file }
@@ -0,0 +1,88 @@
1
+ module TerminusSpec
2
+ module Platforms
3
+ module WatirWebDriver
4
+ module WebObject
5
+
6
+ def ==(other)
7
+ @web_object == other # other.element??
8
+ end
9
+
10
+ def visible?
11
+ @web_object.present?
12
+ end
13
+
14
+ def exists?
15
+ @web_object.exists?
16
+ end
17
+
18
+ def text
19
+ @web_object.text
20
+ end
21
+
22
+ def value
23
+ @web_object.value
24
+ end
25
+
26
+ def tag_name
27
+ @web_object.tag_name
28
+ end
29
+
30
+ def clear
31
+ @web_object.clear
32
+ end
33
+
34
+ # Send keystrokes to the object.
35
+ # @param [String, Symbol, Array]
36
+ # @examples
37
+ # web_object.send_keys "test" #=> value: 'foo'
38
+ # web_object.send_keys "tet", :arrow_left, "s" #=> value: 'test'
39
+ # web_object.send_keys [:control, 'a'], :space #=> value: ' '
40
+ # @see Selenium::WebDriver::Keys::KEYS
41
+ def send_keys(*args)
42
+ @web_object.send_keys(*args)
43
+ end
44
+
45
+ # Waits until an object is present on the screen.
46
+ # @param [Integer] (defaults to: 5) seconds to wait before timing out
47
+ def when_present(timeout=5)
48
+ @web_object.wait_until_present(timeout)
49
+ self
50
+ end
51
+
52
+ # Waits until an object is visible on the screen.
53
+ # @param [Integer] (defaults to: 5) seconds to wait before timing out
54
+ def when_visible(timeout=5)
55
+ Object::Watir::Wait.until(timeout, "Object was not visible in #{timeout} seconds") do
56
+ visible?
57
+ end
58
+ self
59
+ end
60
+
61
+ # Waits until an object is not visible on the screen.
62
+ # @param [Integer] (defaults to: 5) seconds to wait before timing out
63
+ def when_not_visible(timeout=5)
64
+ Object::Watir::Wait.while(timeout, "Object still visible after #{timeout} seconds") do
65
+ visible?
66
+ end
67
+ self
68
+ end
69
+
70
+ # Waits until a given returns true (and thus was executed).
71
+ # @param [Integer] (defaults to: 5) seconds to wait before timing out
72
+ # @param [String] the message to display if the event times out
73
+ # @param the block to execute when the event occurs
74
+ def wait_until(timeout=5, message=nil, &block)
75
+ Object::Watir::Wait.until(timeout, message, &block)
76
+ end
77
+
78
+ # Get the value of a the given attribute of the object.
79
+ # @param [String] attribute name
80
+ # @return [String,nil] attribute value
81
+ def attribute(attribute_name)
82
+ @web_object.attribute_value attribute_name
83
+ end
84
+
85
+ end # module WebObject
86
+ end # module WatirWebDriver
87
+ end # module Platforms
88
+ end # module TerminusSpec
@@ -0,0 +1,13 @@
1
+ module TerminusSpec
2
+ module Platforms
3
+ module WatirWebDriver
4
+ module TextField
5
+
6
+ def value=(this)
7
+ @web_object.set(this)
8
+ end
9
+
10
+ end # module TextField
11
+ end # module WatirWebDriver
12
+ end # module Platforms
13
+ end # module TerminusSpec
@@ -0,0 +1,25 @@
1
+ module TerminusSpec
2
+ module Platforms
3
+
4
+ @@drivers = {}
5
+
6
+ def self.list
7
+ @@drivers
8
+ end
9
+
10
+ def self.associate(key, driver)
11
+ @@drivers[key] = driver
12
+ end
13
+
14
+ def platform_for(browser, drivers)
15
+ drivers.each_value { |driver|
16
+ return driver.create_platform_object_for browser if driver.works_for? browser
17
+ }
18
+ raise "Unable to associate a platform using the provided browser."
19
+ end
20
+
21
+ end # module Platforms
22
+ end # module TerminusSpec
23
+
24
+ require 'terminus_spec/platform_watir'
25
+ require 'terminus_spec/platform_selenium'
@@ -0,0 +1,3 @@
1
+ module TerminusSpec
2
+ VERSION = "0.5.0"
3
+ end
@@ -0,0 +1,172 @@
1
+ module TerminusSpec
2
+ module WebObjects
3
+
4
+ class WebObject
5
+
6
+ def initialize(web_object, platform)
7
+ @web_object = web_object
8
+ mixin_web_objects_for platform
9
+ end
10
+
11
+ def self.have_watir_find_object_with(locator)
12
+ if need_to_construct_watir_xpath(locator)
13
+ key_path = :xpath
14
+ value_path = construct_xpath_for(locator)
15
+ return key_path => value_path
16
+ end
17
+
18
+ locator_list = {}
19
+
20
+ locator.each do |key, value|
21
+ current = {key => value}
22
+ #puts "****** What I got: #{current}"
23
+ object_locator = locator_for(current, locators_for_watir, mappings_for_watir)
24
+ #puts "****** What I gave: #{object_locator}"
25
+ locator_list[object_locator.keys.first] = object_locator.values.first
26
+ end
27
+
28
+ locator_list
29
+ end
30
+
31
+ def self.have_selenium_find_object_with(locator)
32
+ if locator.length == 1
33
+ #puts "****** What I got: #{locator}"
34
+ object_locator = locator_for(locator, locators_for_selenium, mappings_for_selenium)
35
+ #puts "****** What I gave: #{object_locator}"
36
+ return object_locator.keys.first, object_locator.values.first
37
+ elsif locator.length > 1
38
+ key = :xpath
39
+ value = construct_xpath_for locator
40
+ return key, value
41
+ end
42
+ end
43
+
44
+ # Used to delegate calls to the driver object.
45
+ def method_missing(*args, &block)
46
+ m = args.shift
47
+ begin
48
+ @web_object.send m, *args, &block
49
+ rescue Exception => e
50
+ raise
51
+ end
52
+ end
53
+
54
+ protected
55
+
56
+ def self.locator_for(locator, direct_find, mapping_find)
57
+ key, value = locator.keys.first, locator.values.first
58
+ return key => value if direct_find.include? key
59
+ return mapping_find[key] => value if mapping_find[key]
60
+ return nil => value
61
+ end
62
+
63
+ def self.locators_for_watir
64
+ [:class, :id, :index, :name, :xpath]
65
+ end
66
+
67
+ def self.mappings_for_watir
68
+ {}
69
+ end
70
+
71
+ def self.locators_for_selenium
72
+ [:class, :id, :index, :name, :xpath]
73
+ end
74
+
75
+ def self.mappings_for_selenium
76
+ {}
77
+ end
78
+
79
+ # This method will only return true if a tag name matches one in the list
80
+ # AND an attribute of :name is used. That's a potentially specialized
81
+ # condition. Selenium requires xpath quite a bit more than Watir.
82
+ def self.need_to_construct_watir_xpath(locator)
83
+ ['table', 'span', 'div', 'td', 'li', 'ul', 'ol', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p'].include? locator[:tag_name] and locator[:name]
84
+ end
85
+
86
+ def self.construct_xpath_for(locator)
87
+ tag_locator = locator.delete(:tag_name)
88
+ index_locator = locator.delete(:index)
89
+ if tag_locator == 'input' and locator[:type] == 'submit'
90
+ locator.delete(:type)
91
+ button_locator = locator.clone
92
+ if button_locator[:value]
93
+ button_locator[:text] = button_locator[:value]
94
+ button_locator.delete(:value)
95
+ end
96
+ xpath = ".//button"
97
+ xpath << "[#{express_attributes_for(button_locator)}]" unless button_locator.empty?
98
+ xpath << "[#{index_locator+1}]" if index_locator
99
+ locator[:type] = %w[button reset submit image]
100
+ xpath << " | .//input"
101
+ else
102
+ xpath = ".//#{tag_locator}"
103
+ end
104
+ xpath << "[#{express_attributes_for(locator)}]" unless locator.empty?
105
+ xpath << "[#{index_locator+1}]" if index_locator
106
+ xpath
107
+ end
108
+
109
+ def self.express_attributes_for(locator)
110
+ locator.map do |key, value|
111
+ if value.kind_of?(Array)
112
+ "(" + value.map { |v| equal_pair(key, v) }.join(" or ") + ")"
113
+ else
114
+ get_valid_xpath_pair_for(key, value)
115
+ end
116
+ end.join(" and ")
117
+ end
118
+
119
+ # The inclusion of normalize-space means that leading and trailing spaces
120
+ # will be removed before comparison. This will also make sure that any
121
+ # internal sequences of white space will be replaced with just one
122
+ # space. The @for will be used to grab the for attribute for a label
123
+ # if it exists.
124
+ def self.get_valid_xpath_pair_for(key, value)
125
+ if key == :label
126
+ "@id=//label[normalize-space()=#{finalize_xpath_string(value)}]/@for"
127
+ else
128
+ "#{qualify_lhs_for(key)}=#{finalize_xpath_string(value)}"
129
+ end
130
+ end
131
+
132
+ def self.qualify_lhs_for(key)
133
+ case key
134
+ when :text, 'text'
135
+ 'normalize-space()'
136
+ when :href
137
+ 'normalize-space(@href)'
138
+ else
139
+ "@#{key.to_s.gsub("_", "-")}"
140
+ end
141
+ end
142
+
143
+ def self.finalize_xpath_string(value)
144
+ if value.include? "'"
145
+ parts = value.split("'", -1).map { |part| "'#{part}'" }
146
+ string = parts.join(%{,"'",})
147
+ "concat(#{string})"
148
+ else
149
+ "'#{value}'"
150
+ end
151
+ end
152
+
153
+ def mixin_web_objects_for(platform)
154
+ if platform[:platform] == :watir_webdriver
155
+ require "terminus_spec/platform_watir/web_objects/all"
156
+ require "terminus_spec/platform_watir/platform_object"
157
+ self.class.send :include, TerminusSpec::Platforms::WatirWebDriver::WebObject
158
+ @platform = TerminusSpec::Platforms::WatirWebDriver::PlatformObject.new(@web_object)
159
+ elsif platform[:platform] == :selenium_webdriver
160
+ require "terminus_spec/platform_selenium/web_objects/all"
161
+ require "terminus_spec/platform_selenium/platform_object"
162
+ self.class.send :include, TerminusSpec::Platforms::SeleniumWebDriver::WebObject
163
+ @platform = TerminusSpec::Platforms::SeleniumWebDriver::PlatformObject.new(@web_object)
164
+ else
165
+ raise ArgumentError, "Unable to mixin web objects for the specified platform."
166
+ end
167
+ end
168
+
169
+ end # class WebObject
170
+
171
+ end # module WebObjects
172
+ end # module TerminusSpec