testcentricity 2.4.3 → 3.0.2

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 (126) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +29 -0
  3. data/.rspec +2 -1
  4. data/.rubocop.yml +38 -0
  5. data/.ruby-version +1 -1
  6. data/.simplecov +9 -0
  7. data/.yardopts +3 -0
  8. data/CHANGELOG.md +282 -0
  9. data/CODE_OF_CONDUCT.md +13 -0
  10. data/{LICENSE.txt → LICENSE.md} +3 -4
  11. data/README.md +938 -1384
  12. data/Rakefile +63 -1
  13. data/config/cucumber.yml +145 -0
  14. data/config/locales/en-US.yml +56 -0
  15. data/config/test_data/LOCAL_data.yml +11 -0
  16. data/config/test_data/data.yml +10 -0
  17. data/features/deep_links.feature +26 -0
  18. data/features/login.feature +30 -0
  19. data/features/navigation.feature +31 -0
  20. data/features/step_definitions/generic_steps.rb +72 -0
  21. data/features/support/android/screens/about_screen.rb +11 -0
  22. data/features/support/android/screens/base_app_screen.rb +29 -0
  23. data/features/support/android/screens/checkout_address_screen.rb +17 -0
  24. data/features/support/android/screens/checkout_payment_screen.rb +22 -0
  25. data/features/support/android/screens/login_screen.rb +18 -0
  26. data/features/support/android/screens/products_screen.rb +13 -0
  27. data/features/support/android/screens/saucebot_screen.rb +16 -0
  28. data/features/support/android/screens/webview_screen.rb +13 -0
  29. data/features/support/android/sections/nav_widgets/nav_menu.rb +39 -0
  30. data/features/support/env.rb +61 -0
  31. data/features/support/hooks.rb +135 -0
  32. data/features/support/ios/screens/about_screen.rb +11 -0
  33. data/features/support/ios/screens/base_app_screen.rb +19 -0
  34. data/features/support/ios/screens/checkout_address_screen.rb +17 -0
  35. data/features/support/ios/screens/checkout_payment_screen.rb +22 -0
  36. data/features/support/ios/screens/login_screen.rb +18 -0
  37. data/features/support/ios/screens/products_screen.rb +13 -0
  38. data/features/support/ios/screens/saucebot_screen.rb +16 -0
  39. data/features/support/ios/screens/webview_screen.rb +13 -0
  40. data/features/support/ios/sections/list_items/product_cell_item.rb +13 -0
  41. data/features/support/ios/sections/modals/base_modal.rb +23 -0
  42. data/features/support/ios/sections/modals/logout_modal.rb +6 -0
  43. data/features/support/ios/sections/modals/reset_app_state_modal.rb +6 -0
  44. data/features/support/ios/sections/nav_widgets/nav_bar.rb +31 -0
  45. data/features/support/ios/sections/nav_widgets/nav_menu.rb +41 -0
  46. data/features/support/shared_components/screens/base_app_screen.rb +31 -0
  47. data/features/support/shared_components/screens/checkout_address_screen.rb +17 -0
  48. data/features/support/shared_components/screens/checkout_payment_screen.rb +22 -0
  49. data/features/support/shared_components/screens/login_screen.rb +39 -0
  50. data/features/support/shared_components/screens/saucebot_screen.rb +17 -0
  51. data/features/support/shared_components/screens/webview_screen.rb +12 -0
  52. data/features/support/shared_components/sections/nav_menu.rb +58 -0
  53. data/features/support/world_data.rb +12 -0
  54. data/features/support/world_pages.rb +26 -0
  55. data/lib/testcentricity/app_core/appium_connect_helper.rb +343 -111
  56. data/lib/testcentricity/app_core/screen_object.rb +252 -0
  57. data/lib/testcentricity/app_core/screen_objects_helper.rb +29 -201
  58. data/lib/testcentricity/app_core/{screen_sections_helper.rb → screen_section.rb} +40 -105
  59. data/lib/testcentricity/app_elements/app_element_helper.rb +17 -8
  60. data/lib/testcentricity/app_elements/checkbox.rb +3 -3
  61. data/lib/testcentricity/data_objects/environment.rb +133 -39
  62. data/lib/testcentricity/version.rb +1 -1
  63. data/lib/testcentricity.rb +4 -129
  64. data/reports/.keep +1 -0
  65. data/spec/fixtures/page_object.rb +22 -0
  66. data/spec/fixtures/page_section_object.rb +21 -0
  67. data/spec/fixtures/screen_object.rb +16 -0
  68. data/spec/fixtures/screen_section_object.rb +16 -0
  69. data/spec/spec_helper.rb +28 -9
  70. data/spec/testcentricity/elements/button_spec.rb +18 -0
  71. data/spec/testcentricity/elements/checkbox_spec.rb +28 -0
  72. data/spec/testcentricity/elements/image_spec.rb +13 -0
  73. data/spec/testcentricity/elements/label_spec.rb +18 -0
  74. data/spec/testcentricity/elements/list_spec.rb +13 -0
  75. data/spec/testcentricity/elements/ui_element_spec.rb +72 -0
  76. data/spec/testcentricity/mobile/appium_connect_spec.rb +117 -0
  77. data/spec/testcentricity/mobile/screen_object_spec.rb +63 -0
  78. data/spec/testcentricity/mobile/screen_section_object_spec.rb +56 -0
  79. data/spec/testcentricity/version_spec.rb +7 -0
  80. data/spec/testcentricity/web/browser_spec.rb +41 -0
  81. data/spec/testcentricity/web/local_webdriver_spec.rb +86 -0
  82. data/spec/testcentricity/web/mobile_webdriver_spec.rb +123 -0
  83. data/spec/testcentricity/web/page_object_spec.rb +85 -0
  84. data/spec/testcentricity/web/page_section_object_spec.rb +72 -0
  85. data/testcentricity.gemspec +30 -27
  86. metadata +216 -119
  87. data/.ruby-gemset +0 -1
  88. data/Gemfile.lock +0 -93
  89. data/bin/console +0 -14
  90. data/bin/setup +0 -8
  91. data/lib/devices/devices.yml +0 -352
  92. data/lib/testcentricity/app_core/appium_server.rb +0 -69
  93. data/lib/testcentricity/browser_helper.rb +0 -174
  94. data/lib/testcentricity/data_objects/data_objects_helper.rb +0 -78
  95. data/lib/testcentricity/data_objects/excel_helper.rb +0 -242
  96. data/lib/testcentricity/exception_queue_helper.rb +0 -111
  97. data/lib/testcentricity/utility_helpers.rb +0 -32
  98. data/lib/testcentricity/web_core/drag_drop_helper.rb +0 -15
  99. data/lib/testcentricity/web_core/page_objects_helper.rb +0 -677
  100. data/lib/testcentricity/web_core/page_sections_helper.rb +0 -895
  101. data/lib/testcentricity/web_core/webdriver_helper.rb +0 -588
  102. data/lib/testcentricity/web_elements/button.rb +0 -8
  103. data/lib/testcentricity/web_elements/cell_button.rb +0 -8
  104. data/lib/testcentricity/web_elements/cell_checkbox.rb +0 -38
  105. data/lib/testcentricity/web_elements/cell_element.rb +0 -69
  106. data/lib/testcentricity/web_elements/cell_image.rb +0 -8
  107. data/lib/testcentricity/web_elements/cell_radio.rb +0 -31
  108. data/lib/testcentricity/web_elements/checkbox.rb +0 -100
  109. data/lib/testcentricity/web_elements/file_field.rb +0 -45
  110. data/lib/testcentricity/web_elements/image.rb +0 -34
  111. data/lib/testcentricity/web_elements/label.rb +0 -8
  112. data/lib/testcentricity/web_elements/link.rb +0 -8
  113. data/lib/testcentricity/web_elements/list.rb +0 -100
  114. data/lib/testcentricity/web_elements/list_button.rb +0 -8
  115. data/lib/testcentricity/web_elements/list_checkbox.rb +0 -38
  116. data/lib/testcentricity/web_elements/list_element.rb +0 -61
  117. data/lib/testcentricity/web_elements/list_radio.rb +0 -31
  118. data/lib/testcentricity/web_elements/radio.rb +0 -74
  119. data/lib/testcentricity/web_elements/select_list.rb +0 -208
  120. data/lib/testcentricity/web_elements/siebel_open_ui_helper.rb +0 -15
  121. data/lib/testcentricity/web_elements/table.rb +0 -612
  122. data/lib/testcentricity/web_elements/textfield.rb +0 -114
  123. data/lib/testcentricity/web_elements/ui_elements_helper.rb +0 -532
  124. data/lib/testcentricity/world_extensions.rb +0 -26
  125. data/my_templates/default/method_details/setup.rb +0 -3
  126. data/spec/testcentricity_spec.rb +0 -9
@@ -1,242 +0,0 @@
1
- require 'time'
2
- require 'chronic'
3
- require 'faker'
4
- require 'spreadsheet'
5
-
6
-
7
- module TestCentricity
8
- class ExcelData
9
- @mru = {}
10
-
11
- def self.worksheet_exists?(file, sheet)
12
- exists = false
13
- if File.exist?(file)
14
- work_book = Spreadsheet.open file
15
- worksheets = work_book.worksheets
16
- worksheets.each do |worksheet|
17
- if worksheet.name == sheet
18
- exists = true
19
- break
20
- end
21
- end
22
- end
23
- exists
24
- end
25
-
26
- def self.rowspec_exists?(file, sheet, rowspec)
27
- exists = false
28
- if worksheet_exists?(file, sheet)
29
- work_book = Spreadsheet.open file
30
- work_sheet = work_book.worksheet sheet
31
- # get column headings from row 0 of worksheet
32
- headings = work_sheet.row(0)
33
- # if rowspec is a string then we have to find a matching row name
34
- if rowspec.is_a? String
35
- column_number = 0
36
- exists = false
37
- headings.each do |heading|
38
- if heading == 'ROW_NAME'
39
- exists = true
40
- break
41
- end
42
- column_number += 1
43
- end
44
- raise "Could not find a column named ROW_NAME in worksheet #{sheet}" unless exists
45
- # find first cell in ROW_NAME column containing a string that matches the rowspec parameter
46
- exists = false
47
- row_number = 0
48
- work_sheet.each do |row|
49
- if row[column_number] == rowspec
50
- exists = true
51
- break
52
- end
53
- row_number += 1
54
- end
55
- end
56
- end
57
- exists
58
- end
59
-
60
- def self.read_row_from_pool(file, sheet, rowspec, columns = nil)
61
- raise "File #{file} does not exists" unless File.exist?(file)
62
- work_book = Spreadsheet.open file
63
- work_sheet = work_book.worksheet sheet
64
-
65
- pool_spec_key = "#{sheet}:#{rowspec}"
66
- if @mru.key?(pool_spec_key)
67
- pool_spec = @mru[pool_spec_key]
68
- row_start = pool_spec[:start_row]
69
- row_end = pool_spec[:num_rows]
70
- pool_rows = (row_start..row_start + row_end - 1).to_a
71
- mru_rows = pool_spec[:used_rows]
72
- new_row = pool_rows.sample.to_i
73
- if mru_rows.size == pool_spec[:num_rows]
74
- mru_rows = [new_row]
75
- else
76
- while mru_rows.include?(new_row)
77
- new_row = pool_rows.sample.to_i
78
- end
79
- mru_rows.push(new_row)
80
- mru_rows.sort!
81
- end
82
-
83
- pool_spec = {
84
- :start_row => row_start,
85
- :num_rows => row_end,
86
- :used_rows => mru_rows
87
- }
88
- else
89
- # get column headings from row 0 of worksheet
90
- headings = work_sheet.row(0)
91
- column_number = 0
92
- found = false
93
- headings.each do |heading|
94
- if heading == 'ROW_NAME'
95
- found = true
96
- break
97
- end
98
- column_number += 1
99
- end
100
- raise "Could not find a column named ROW_NAME in worksheet #{sheet}" unless found
101
- # find cell(s) in ROW_NAME column containing a string that matches the rowspec parameter
102
- found = []
103
- row_number = 0
104
- work_sheet.each do |row|
105
- if row[column_number] == rowspec
106
- found.push(row_number)
107
- elsif !found.empty?
108
- break
109
- end
110
- row_number += 1
111
- end
112
- raise "Could not find a row named '#{rowspec}' in worksheet #{sheet}" if found.empty?
113
-
114
- new_row = found.sample.to_i
115
- pool_spec = {
116
- :start_row => found[0],
117
- :num_rows => found.size,
118
- :used_rows => [new_row]
119
- }
120
- end
121
- @mru[pool_spec_key] = pool_spec
122
-
123
- read_row_data(file, sheet, new_row, columns)
124
- end
125
-
126
- def self.read_row_data(file, sheet, rowspec, columns = nil)
127
- raise "File #{file} does not exists" unless File.exist?(file)
128
- work_book = Spreadsheet.open file
129
- work_sheet = work_book.worksheet sheet
130
- # get column headings from row 0 of worksheet
131
- headings = work_sheet.row(0)
132
- # if rowspec is a string then we have to find a matching row name
133
- if rowspec.is_a? String
134
- column_number = 0
135
- found = false
136
- headings.each do |heading|
137
- if heading == 'ROW_NAME'
138
- found = true
139
- break
140
- end
141
- column_number += 1
142
- end
143
- raise "Could not find a column named ROW_NAME in worksheet #{sheet}" unless found
144
- # find first cell in ROW_NAME column containing a string that matches the rowspec parameter
145
- found = false
146
- row_number = 0
147
- work_sheet.each do |row|
148
- if row[column_number] == rowspec
149
- found = true
150
- break
151
- end
152
- row_number += 1
153
- end
154
- raise "Could not find a row named '#{rowspec}' in worksheet #{sheet}" unless found
155
- data = work_sheet.row(row_number)
156
- # if rowspec is a number then ensure that it doesn't exceed the number of available rows
157
- elsif rowspec.is_a? Numeric
158
- raise "Row # #{rowspec} is greater than number of rows in worksheet #{sheet}" if rowspec > work_sheet.last_row_index
159
- data = work_sheet.row(rowspec)
160
- end
161
-
162
- # if no columns have been specified, return all columns
163
- columns = headings if columns.nil?
164
- # create results hash table
165
- result = Hash.new
166
- columns.each do |column|
167
- column_number = 0
168
- found = false
169
- headings.each do |heading|
170
- if column == heading
171
- value = data[column_number].to_s
172
- value = calculate_dynamic_value(value) if value.start_with? 'eval!'
173
- result[column] = value
174
- found = true
175
- break
176
- end
177
- column_number += 1
178
- end
179
- raise "Could not find a column named '#{column}' in worksheet #{sheet}" unless found
180
- end
181
- result
182
- end
183
-
184
- def self.read_range_data(file, sheet, rangespec)
185
- raise "File #{file} does not exists" unless File.exist?(file)
186
- work_book = Spreadsheet.open file
187
- work_sheet = work_book.worksheet sheet
188
- # get column headings from row 0 of worksheet
189
- headings = work_sheet.row(0)
190
- column_number = 0
191
- found = false
192
- headings.each do |heading|
193
- if heading == 'ROW_NAME'
194
- found = true
195
- break
196
- end
197
- column_number += 1
198
- end
199
- raise "Could not find a column named ROW_NAME in worksheet #{sheet}" unless found
200
- # find cell(s) in ROW_NAME column containing a string that matches the rangespec parameter
201
- found = []
202
- row_number = 0
203
- work_sheet.each do |row|
204
- if row[column_number] == rangespec
205
- found.push(row_number)
206
- elsif !found.empty?
207
- break
208
- end
209
- row_number += 1
210
- end
211
- raise "Could not find a row named '#{rangespec}' in worksheet #{sheet}" if found.empty?
212
-
213
- result = []
214
- found.each do |row|
215
- result.push(read_row_data(file, sheet, row))
216
- end
217
- result
218
- end
219
-
220
- private
221
-
222
- def self.calculate_dynamic_value(value)
223
- test_value = value.split('!', 2)
224
- parameter = test_value[1].split('.', 2)
225
- case parameter[0]
226
- when 'Date'
227
- result = eval("Chronic.parse('#{parameter[1]}')")
228
- when 'FormattedDate', 'FormatDate'
229
- date_time_params = parameter[1].split(' format! ', 2)
230
- date_time = eval("Chronic.parse('#{date_time_params[0].strip}')")
231
- result = date_time.to_s.format_date_time("#{date_time_params[1].strip}")
232
- else
233
- if Faker.constants.include?(parameter[0].to_sym)
234
- result = eval("Faker::#{parameter[0]}.#{parameter[1]}")
235
- else
236
- result = eval(test_value[1])
237
- end
238
- end
239
- result.to_s
240
- end
241
- end
242
- end
@@ -1,111 +0,0 @@
1
- module TestCentricity
2
- class ExceptionQueue
3
- include Capybara::DSL
4
-
5
- @error_queue
6
-
7
- def self.enqueue_assert_equal(expected, actual, error_message)
8
- unless expected == actual
9
- enqueue("#{error_message} to be\n '#{expected}'\nbut found\n '#{actual}'")
10
- enqueue_screenshot
11
- end
12
- end
13
-
14
- def self.enqueue_assert_not_equal(expected, actual, error_message)
15
- unless expected != actual
16
- enqueue("#{error_message} to not be equal to '#{expected}'")
17
- enqueue_screenshot
18
- end
19
- end
20
-
21
- def self.enqueue_exception(error_message)
22
- enqueue(error_message)
23
- end
24
-
25
- def self.post_exceptions
26
- raise @error_queue unless @error_queue.nil?
27
- ensure
28
- @error_queue = nil
29
- end
30
-
31
- def self.enqueue_comparison(state, actual, error_msg)
32
- if state.is_a?(Hash) && state.length == 1
33
- state.each do |key, value|
34
- case key
35
- when :lt, :less_than
36
- enqueue_exception("#{error_msg} be less than #{value} but found '#{actual}'") unless actual < value
37
- when :lt_eq, :less_than_or_equal
38
- enqueue_exception("#{error_msg} be less than or equal to #{value} but found '#{actual}'") unless actual <= value
39
- when :gt, :greater_than
40
- enqueue_exception("#{error_msg} be greater than #{value} but found '#{actual}'") unless actual > value
41
- when :gt_eq, :greater_than_or_equal
42
- enqueue_exception("#{error_msg} be greater than or equal to #{value} but found '#{actual}'") unless actual >= value
43
- when :starts_with
44
- enqueue_exception("#{error_msg} start with '#{value}' but found '#{actual}'") unless actual.start_with?(value)
45
- when :ends_with
46
- enqueue_exception("#{error_msg} end with '#{value}' but found '#{actual}'") unless actual.end_with?(value)
47
- when :contains
48
- enqueue_exception("#{error_msg} contain '#{value}' but found '#{actual}'") unless actual.include?(value)
49
- when :not_contains, :does_not_contain
50
- enqueue_exception("#{error_msg} not contain '#{value}' but found '#{actual}'") if actual.include?(value)
51
- when :not_equal
52
- enqueue_exception("#{error_msg} not equal '#{value}' but found '#{actual}'") if actual == value
53
- when :like, :is_like
54
- actual_like = actual.delete("\n")
55
- actual_like = actual_like.delete("\r")
56
- actual_like = actual_like.delete("\t")
57
- actual_like = actual_like.delete(' ')
58
- actual_like = actual_like.downcase
59
- expected = value.delete("\n")
60
- expected = expected.delete("\r")
61
- expected = expected.delete("\t")
62
- expected = expected.delete(' ')
63
- expected = expected.downcase
64
- enqueue_exception("#{error_msg} be like '#{value}' but found '#{actual}'") unless actual_like.include?(expected)
65
- when :translate
66
- expected = I18n.t(value)
67
- enqueue_assert_equal(expected, actual, error_msg)
68
- when :translate_upcase
69
- expected = I18n.t(value).upcase
70
- enqueue_assert_equal(expected, actual, error_msg)
71
- when :translate_downcase
72
- expected = I18n.t(value).downcase
73
- enqueue_assert_equal(expected, actual, error_msg)
74
- when :translate_capitalize
75
- expected = I18n.t(value).capitalize
76
- enqueue_assert_equal(expected, actual, error_msg)
77
- end
78
- end
79
- else
80
- enqueue_assert_equal(state, actual, error_msg)
81
- end
82
- end
83
-
84
- private
85
-
86
- def self.enqueue(message)
87
- @error_queue = "#{@error_queue}#{message}\n\n"
88
- end
89
-
90
- def self.enqueue_screenshot
91
- timestamp = Time.now.strftime('%Y%m%d%H%M%S')
92
- filename = "Screenshot-#{timestamp}"
93
- path = File.join Dir.pwd, 'reports/screenshots/', filename
94
- if Environ.driver == :appium
95
- AppiumConnect.take_screenshot("#{path}.png")
96
- else
97
- Capybara.save_screenshot "#{path}.png"
98
- end
99
- puts "Screenshot saved at #{path}.png"
100
- screen_shot = { :path => path, :filename => filename }
101
- Environ.save_screen_shot(screen_shot)
102
- end
103
- end
104
-
105
-
106
- class ObjectNotFoundError < StandardError
107
- def initialize(message)
108
- super(message)
109
- end
110
- end
111
- end
@@ -1,32 +0,0 @@
1
- class Object
2
- def blank?
3
- respond_to?(:empty?) ? empty? : !self
4
- end
5
-
6
- def present?
7
- !blank?
8
- end
9
- end
10
-
11
-
12
- class String
13
- def to_bool
14
- return true if self == true || self =~ (/(true|t|yes|y|x|1)$/i)
15
- return false if self == false || self.blank? || self =~ (/(false|f|no|n|0)$/i)
16
- raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
17
- end
18
-
19
- def string_between(marker1, marker2)
20
- self[/#{Regexp.escape(marker1)}(.*?)#{Regexp.escape(marker2)}/m, 1]
21
- end
22
-
23
- def format_date_time(date_time_format)
24
- return if self.blank?
25
- new_date = DateTime.parse(self)
26
- if ENV['LOCALE'] && date_time_format.is_a?(Symbol)
27
- I18n.l(new_date, format: date_time_format)
28
- else
29
- new_date.strftime(date_time_format)
30
- end
31
- end
32
- end
@@ -1,15 +0,0 @@
1
- module CapybaraExtension
2
- def drag_by(right_by, down_by)
3
- base.drag_by(right_by, down_by)
4
- end
5
- end
6
-
7
-
8
- module CapybaraSeleniumExtension
9
- def drag_by(right_by, down_by)
10
- driver.browser.action.drag_and_drop_by(native, right_by, down_by).perform
11
- end
12
- end
13
-
14
- ::Capybara::Selenium::Node.send :include, CapybaraSeleniumExtension
15
- ::Capybara::Node::Element.send :include, CapybaraExtension