ruby_raider 3.13.0 → 4.0.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 (225) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/runtime.yml +38 -0
  3. data/.github/workflows/system_tests.yml +1 -23
  4. data/.reek.yml +1 -0
  5. data/.rspec +1 -0
  6. data/Gemfile +2 -0
  7. data/README.md +16 -49
  8. data/RELEASE.md +22 -0
  9. data/bin/raider +5 -0
  10. data/lib/commands/scaffolding_commands.rb +2 -25
  11. data/lib/commands/utility_commands.rb +23 -3
  12. data/lib/generators/automation/automation_generator.rb +0 -5
  13. data/lib/generators/automation/templates/component.tt +1 -0
  14. data/lib/generators/automation/templates/home.tt +2 -2
  15. data/lib/generators/automation/templates/login.tt +6 -26
  16. data/lib/generators/automation/templates/page.tt +23 -18
  17. data/lib/generators/automation/templates/partials/home_page_selector.tt +1 -2
  18. data/lib/generators/automation/templates/partials/initialize_selector.tt +0 -8
  19. data/lib/generators/automation/templates/partials/pdp_page_selector.tt +1 -2
  20. data/lib/generators/automation/templates/partials/url_methods.tt +8 -2
  21. data/lib/generators/automation/templates/partials/visit_method.tt +0 -5
  22. data/lib/generators/automation/templates/pdp.tt +1 -9
  23. data/lib/generators/common_generator.rb +0 -2
  24. data/lib/generators/generator.rb +12 -19
  25. data/lib/generators/helper_generator.rb +21 -19
  26. data/lib/generators/infrastructure/templates/azure_pipelines.tt +1 -1
  27. data/lib/generators/infrastructure/templates/github.tt +2 -3
  28. data/lib/generators/infrastructure/templates/github_appium.tt +0 -8
  29. data/lib/generators/invoke_generators.rb +4 -23
  30. data/lib/generators/menu_generator.rb +1 -9
  31. data/lib/generators/rspec/templates/accessibility_spec.tt +1 -9
  32. data/lib/generators/rspec/templates/spec.tt +8 -24
  33. data/lib/generators/template_renderer/partial_cache.rb +3 -1
  34. data/lib/generators/template_renderer.rb +1 -1
  35. data/lib/generators/templates/common/gemfile.tt +3 -10
  36. data/lib/generators/templates/common/git_ignore.tt +0 -5
  37. data/lib/generators/templates/common/partials/mobile_config.tt +3 -1
  38. data/lib/generators/templates/common/partials/web_config.tt +10 -1
  39. data/lib/generators/templates/common/rakefile.tt +0 -15
  40. data/lib/generators/templates/common/read_me.tt +357 -250
  41. data/lib/generators/templates/common/rubocop.tt +0 -2
  42. data/lib/generators/templates/helpers/driver_helper.tt +8 -0
  43. data/lib/generators/templates/helpers/gesture_helper.tt +78 -0
  44. data/lib/generators/templates/helpers/network_helper.tt +521 -0
  45. data/lib/generators/templates/helpers/partials/quit_driver.tt +0 -2
  46. data/lib/generators/templates/helpers/partials/screenshot.tt +0 -2
  47. data/lib/generators/templates/helpers/partials/selenium_driver.tt +5 -2
  48. data/lib/generators/templates/helpers/screenshot_helper.tt +490 -0
  49. data/lib/generators/templates/helpers/spec_helper.tt +39 -29
  50. data/lib/generators/templates/helpers/trace_helper.tt +240 -95
  51. data/lib/generators/templates/helpers/video_helper.tt +3 -8
  52. data/lib/ruby_raider/runtime/actionability.rb +129 -0
  53. data/lib/ruby_raider/runtime/actionable.rb +49 -0
  54. data/lib/ruby_raider/runtime/by_role.rb +55 -0
  55. data/lib/ruby_raider/runtime/config.rb +79 -0
  56. data/lib/ruby_raider/runtime/context.rb +38 -0
  57. data/lib/ruby_raider/runtime/errors.rb +69 -0
  58. data/lib/ruby_raider/runtime/finders.rb +73 -0
  59. data/lib/ruby_raider/runtime/js/actionability.js +134 -0
  60. data/lib/ruby_raider/runtime/js/role_engine.js +315 -0
  61. data/lib/ruby_raider/runtime/locator_converter.rb +72 -0
  62. data/lib/ruby_raider/runtime/matchers/base.rb +222 -0
  63. data/lib/ruby_raider/runtime/matchers/element.rb +183 -0
  64. data/lib/ruby_raider/runtime/matchers/page.rb +71 -0
  65. data/lib/ruby_raider/runtime/matchers/presence.rb +41 -0
  66. data/lib/ruby_raider/runtime/matchers/retrying_block.rb +104 -0
  67. data/lib/ruby_raider/runtime/observer.rb +170 -0
  68. data/lib/ruby_raider/runtime/role_finder.rb +83 -0
  69. data/lib/ruby_raider/runtime/rspec.rb +78 -0
  70. data/lib/ruby_raider/runtime/selectors.rb +60 -0
  71. data/lib/ruby_raider/runtime/strict.rb +142 -0
  72. data/lib/ruby_raider/runtime/wait.rb +84 -0
  73. data/lib/ruby_raider/runtime.rb +20 -0
  74. data/lib/scaffolding/name_normalizer.rb +1 -1
  75. data/lib/scaffolding/project_detector.rb +2 -28
  76. data/lib/scaffolding/scaffolding.rb +0 -20
  77. data/lib/scaffolding/templates/component.tt +0 -14
  78. data/lib/scaffolding/templates/page_object.tt +2 -14
  79. data/lib/scaffolding/templates/spec.tt +1 -9
  80. data/lib/utilities/utilities.rb +10 -8
  81. data/lib/version +1 -1
  82. data/ruby_raider.gemspec +2 -1
  83. data/sig/commands/scaffolding_commands.rbs +0 -2
  84. data/sig/commands/utility_commands.rbs +6 -0
  85. data/sig/generators/generator.rbs +0 -4
  86. data/sig/generators/helper_generator.rbs +0 -1
  87. data/sig/generators/menu_generator.rbs +0 -1
  88. data/sig/ruby_raider/runtime/actionability.rbs +25 -0
  89. data/sig/ruby_raider/runtime/actionable.rbs +13 -0
  90. data/sig/ruby_raider/runtime/by_role.rbs +15 -0
  91. data/sig/ruby_raider/runtime/config.rbs +26 -0
  92. data/sig/ruby_raider/runtime/context.rbs +12 -0
  93. data/sig/ruby_raider/runtime/errors.rbs +36 -0
  94. data/sig/ruby_raider/runtime/finders.rbs +26 -0
  95. data/sig/ruby_raider/runtime/locator_converter.rbs +21 -0
  96. data/sig/ruby_raider/runtime/matchers/base.rbs +64 -0
  97. data/sig/ruby_raider/runtime/matchers/element.rbs +78 -0
  98. data/sig/ruby_raider/runtime/matchers/page.rbs +38 -0
  99. data/sig/ruby_raider/runtime/matchers/presence.rbs +21 -0
  100. data/sig/ruby_raider/runtime/matchers/retrying_block.rbs +27 -0
  101. data/sig/ruby_raider/runtime/observer.rbs +46 -0
  102. data/sig/ruby_raider/runtime/role_finder.rbs +18 -0
  103. data/sig/ruby_raider/runtime/selectors.rbs +21 -0
  104. data/sig/ruby_raider/runtime/strict.rbs +35 -0
  105. data/sig/ruby_raider/runtime/wait.rbs +17 -0
  106. data/sig/ruby_raider/runtime.rbs +2 -0
  107. data/sig/scaffolding/project_detector.rbs +0 -4
  108. data/sig/scaffolding/scaffolding.rbs +0 -5
  109. data/sig/utilities/utilities.rbs +2 -1
  110. data/sig/vendor/selenium_webdriver.rbs +71 -0
  111. data/spec/commands/raider_commands_spec.rb +38 -3
  112. data/spec/commands/scaffolding_commands_spec.rb +27 -0
  113. data/spec/commands/utility_commands_spec.rb +53 -0
  114. data/spec/generators/gesture_helper_spec.rb +123 -0
  115. data/spec/generators/network_helper_spec.rb +634 -0
  116. data/spec/generators/screenshot_helper_spec.rb +776 -0
  117. data/spec/generators/template_renderer_spec.rb +0 -4
  118. data/spec/generators/trace_helper_spec.rb +489 -97
  119. data/spec/generators/video_helper_spec.rb +0 -9
  120. data/spec/integration/commands/browser_update_after_creation_spec.rb +0 -8
  121. data/spec/integration/commands/scaffolding_commands_spec.rb +12 -70
  122. data/spec/integration/commands/utility_commands_spec.rb +19 -41
  123. data/spec/integration/content/azure_content_spec.rb +2 -6
  124. data/spec/integration/content/ci_content_spec.rb +1 -55
  125. data/spec/integration/content/common_content_spec.rb +1 -118
  126. data/spec/integration/content/config_content_spec.rb +34 -31
  127. data/spec/integration/content/gemfile_content_spec.rb +7 -72
  128. data/spec/integration/content/helper_content_spec.rb +105 -99
  129. data/spec/integration/content/page_content_spec.rb +85 -87
  130. data/spec/integration/content/readme_content_spec.rb +134 -75
  131. data/spec/integration/content/rspec_reporter_content_spec.rb +2 -2
  132. data/spec/integration/content/rubocop_content_spec.rb +1 -1
  133. data/spec/integration/content/syntax_validation_spec.rb +2 -2
  134. data/spec/integration/content/test_content_spec.rb +23 -147
  135. data/spec/integration/end_to_end_features_spec.rb +1 -43
  136. data/spec/integration/end_to_end_spec.rb +319 -326
  137. data/spec/integration/generators/automation_generator_spec.rb +3 -37
  138. data/spec/integration/generators/axe_addon_spec.rb +2 -35
  139. data/spec/integration/generators/azure_generator_spec.rb +1 -1
  140. data/spec/integration/generators/common_generator_spec.rb +1 -40
  141. data/spec/integration/generators/config_features_spec.rb +1 -24
  142. data/spec/integration/generators/github_generator_spec.rb +0 -12
  143. data/spec/integration/generators/helpers_generator_spec.rb +74 -80
  144. data/spec/integration/generators/invoke_generators_spec.rb +54 -45
  145. data/spec/integration/generators/rspec_generator_spec.rb +0 -6
  146. data/spec/integration/scaffolding_e2e_spec.rb +17 -179
  147. data/spec/integration/spec_helper.rb +4 -6
  148. data/spec/integration/trace_format_checker.rb +11 -2
  149. data/spec/integration/trace_page_server.rb +72 -5
  150. data/spec/menus/menu_generator_spec.rb +14 -39
  151. data/spec/runtime/actionability_spec.rb +207 -0
  152. data/spec/runtime/actionable_spec.rb +125 -0
  153. data/spec/runtime/browser/actionability_script_browser_spec.rb +150 -0
  154. data/spec/runtime/browser/actionable_browser_spec.rb +98 -0
  155. data/spec/runtime/browser/finders_browser_spec.rb +148 -0
  156. data/spec/runtime/browser/matchers_browser_spec.rb +67 -0
  157. data/spec/runtime/browser/retrying_block_browser_spec.rb +37 -0
  158. data/spec/runtime/browser/role_engine_browser_spec.rb +184 -0
  159. data/spec/runtime/browser/strict_browser_spec.rb +38 -0
  160. data/spec/runtime/by_role_spec.rb +52 -0
  161. data/spec/runtime/config_spec.rb +79 -0
  162. data/spec/runtime/context_spec.rb +73 -0
  163. data/spec/runtime/errors_spec.rb +89 -0
  164. data/spec/runtime/finders_spec.rb +165 -0
  165. data/spec/runtime/fixtures/actionability.html +70 -0
  166. data/spec/runtime/fixtures/locators.html +46 -0
  167. data/spec/runtime/fixtures/matchers.html +33 -0
  168. data/spec/runtime/fixtures/roles.html +162 -0
  169. data/spec/runtime/matchers/base_spec.rb +165 -0
  170. data/spec/runtime/matchers/element_spec.rb +277 -0
  171. data/spec/runtime/matchers/page_spec.rb +102 -0
  172. data/spec/runtime/matchers/presence_spec.rb +59 -0
  173. data/spec/runtime/matchers/retrying_block_spec.rb +165 -0
  174. data/spec/runtime/observer_spec.rb +341 -0
  175. data/spec/runtime/role_finder_spec.rb +156 -0
  176. data/spec/runtime/role_query_spec.rb +75 -0
  177. data/spec/runtime/selectors_spec.rb +135 -0
  178. data/spec/runtime/strict_spec.rb +257 -0
  179. data/spec/runtime/support/browser.rb +48 -0
  180. data/spec/runtime/support/fake_bridge.rb +117 -0
  181. data/spec/runtime/wait_spec.rb +71 -0
  182. data/spec/scaffolding/name_normalizer_spec.rb +3 -2
  183. data/spec/scaffolding/scaffold_project_detector_spec.rb +4 -43
  184. data/spec/system/selenium_spec.rb +1 -5
  185. data/spec/system/support/system_test_helper.rb +2 -5
  186. data/spec/utilities/headless_config_spec.rb +0 -7
  187. data/spec/utilities/utilities_spec.rb +24 -0
  188. metadata +113 -48
  189. data/lib/generators/automation/templates/header.tt +0 -9
  190. data/lib/generators/cucumber/cucumber_generator.rb +0 -58
  191. data/lib/generators/cucumber/templates/accessibility_feature.tt +0 -5
  192. data/lib/generators/cucumber/templates/accessibility_steps.tt +0 -17
  193. data/lib/generators/cucumber/templates/cucumber.tt +0 -1
  194. data/lib/generators/cucumber/templates/env.tt +0 -7
  195. data/lib/generators/cucumber/templates/feature.tt +0 -21
  196. data/lib/generators/cucumber/templates/partials/appium_env.tt +0 -26
  197. data/lib/generators/cucumber/templates/partials/driver_world.tt +0 -18
  198. data/lib/generators/cucumber/templates/partials/mobile_steps.tt +0 -20
  199. data/lib/generators/cucumber/templates/partials/selenium_env.tt +0 -120
  200. data/lib/generators/cucumber/templates/partials/watir_env.tt +0 -48
  201. data/lib/generators/cucumber/templates/partials/watir_world.tt +0 -4
  202. data/lib/generators/cucumber/templates/partials/web_steps.tt +0 -28
  203. data/lib/generators/cucumber/templates/steps.tt +0 -5
  204. data/lib/generators/cucumber/templates/user_factory.tt +0 -15
  205. data/lib/generators/cucumber/templates/world.tt +0 -7
  206. data/lib/generators/templates/helpers/browser_helper.tt +0 -31
  207. data/lib/generators/templates/helpers/raider_element.tt +0 -159
  208. data/lib/generators/templates/helpers/wait_helper.tt +0 -611
  209. data/lib/scaffolding/templates/feature.tt +0 -6
  210. data/lib/scaffolding/templates/steps.tt +0 -19
  211. data/sig/generators/cucumber/cucumber_generator.rbs +0 -12
  212. data/spec/fixtures/watir_master/cucumber_watir/Readme.md.snapshot +0 -175
  213. data/spec/fixtures/watir_master/cucumber_watir/features/step_definitions/login_steps.rb.snapshot +0 -24
  214. data/spec/fixtures/watir_master/cucumber_watir/page_objects/abstract/page.rb.snapshot +0 -37
  215. data/spec/fixtures/watir_master/cucumber_watir/page_objects/pages/login.rb.snapshot +0 -33
  216. data/spec/fixtures/watir_master/rspec_watir/Readme.md.snapshot +0 -174
  217. data/spec/fixtures/watir_master/rspec_watir/page_objects/abstract/page.rb.snapshot +0 -37
  218. data/spec/fixtures/watir_master/rspec_watir/page_objects/pages/login.rb.snapshot +0 -33
  219. data/spec/fixtures/watir_master/rspec_watir/spec/login_page_spec.rb.snapshot +0 -49
  220. data/spec/integration/content/cucumber_reporter_content_spec.rb +0 -161
  221. data/spec/integration/generators/cucumber_generator_spec.rb +0 -100
  222. data/spec/integration/helpers/wait_helper_mobile_spec.rb +0 -281
  223. data/spec/integration/helpers/wait_helper_spec.rb +0 -679
  224. data/spec/integration/helpers/wait_helper_support.rb +0 -183
  225. data/spec/system/watir_spec.rb +0 -38
@@ -1,21 +0,0 @@
1
- <%- if web? -%>
2
- Feature: Login Page
3
-
4
- Scenario: A user can login
5
- Given I'm a registered user on the login page
6
- When I login with my credentials
7
- Then I'm logged in
8
-
9
- @logged_in
10
- Scenario: A logged-in user opens the account page
11
- Given I'm a registered user
12
- Then I'm logged in
13
-
14
- <%- else -%>
15
- Feature: Home Page
16
-
17
- Scenario: A user can go to the product details page
18
- Given I'm an anonymous user on the home page
19
- When I select one of the products
20
- Then I'm redirected to the product details page
21
- <%- end %>
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'raider_reporter/cucumber'
4
- require 'tmpdir'
5
- require_relative '../../helpers/video_helper'
6
-
7
- Before do
8
- driver.start_driver
9
- @video_recorder = VideoHelper.recorder_for(driver)
10
- @video_recorder.start
11
- end
12
-
13
- After do |scenario|
14
- video_path = @video_recorder&.stop(keep: scenario.failed?)
15
- RaiderReporter.attach('video', video_path, type: :mp4) if video_path
16
- if scenario.failed?
17
- Dir.mktmpdir do |temp_folder|
18
- screenshot_path = File.join(temp_folder, 'screenshot.png')
19
- driver.screenshot(screenshot_path)
20
- RaiderReporter.attach('screenshot', screenshot_path, type: :png)
21
- end
22
- end
23
- ensure
24
- @video_recorder&.cleanup
25
- driver.quit_driver
26
- end
@@ -1,18 +0,0 @@
1
- require_relative '../../helpers/driver_helper'
2
- <%- if wait_helper? -%>
3
- require_relative '../../helpers/wait_helper'
4
- <%- end -%>
5
- <%- if selenium_based? -%>
6
- <%- if examples? -%>
7
- require_relative '../../models/user_factory'
8
- <%- end -%>
9
-
10
- World(DriverHelper)
11
- World(WaitHelper)
12
- <%- else -%>
13
-
14
- World(DriverHelper)
15
- <%- if wait_helper? -%>
16
- World(WaitHelper)
17
- <%- end -%>
18
- <%- end -%>
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- <%- if cross_platform? -%>
4
- require_relative '../../helpers/appium_helper'
5
- <%- end -%>
6
- require_relative '../../page_objects/pages/home'
7
- require_relative '../../page_objects/pages/pdp'
8
-
9
- Given("I'm an anonymous user on the home page") do
10
- @home_page = Home.new(driver)
11
- end
12
-
13
- When('I select one of the products') do
14
- @home_page.go_to_product_detail
15
- end
16
-
17
- Then("I'm redirected to the product details page") do
18
- pdp_page = Pdp.new(driver)
19
- eventually { expect(pdp_page.add_to_cart_text).to eq 'Add to Cart' }
20
- end
@@ -1,120 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- <%- if axe_addon? && cucumber? -%>
4
- require 'axe-rspec'
5
- <%- end -%>
6
- require 'rspec'
7
- require 'raider_reporter/cucumber'
8
- require 'tmpdir'
9
- require 'yaml'
10
- require_relative '../../helpers/video_helper'
11
- <%- if trace_helper? -%>
12
- require_relative '../../helpers/trace_helper'
13
- <%- end -%>
14
- require_relative '../../helpers/session_state'
15
- <%- if examples? -%>
16
- require_relative '../../models/user_factory'
17
- require_relative '../../page_objects/pages/account'
18
- require_relative '../../page_objects/pages/login'
19
- <%- end -%>
20
-
21
- <%- if trace_helper? -%>
22
- # Attempts per scenario across --retry, keyed on the scenario's location, for the trace of each attempt.
23
- TRACE_ATTEMPTS = Hash.new(0) unless defined?(TRACE_ATTEMPTS)
24
-
25
- # Each Gherkin step becomes a group in the trace, named by its keyword and text; hook steps are not steps.
26
- InstallPlugin do |config, _registry|
27
- if defined?(TraceHelper)
28
- begin
29
- ast_lookup = Cucumber::Formatter::AstLookup.new(config)
30
- groups = {}
31
- config.on_event(:test_step_started) do |event|
32
- next if event.test_step.hook?
33
-
34
- step = event.test_step
35
- keyword = begin
36
- ast_lookup.step_source(step).step.keyword.strip
37
- rescue StandardError
38
- nil
39
- end
40
- location = { file: step.location.file, line: step.location.lines.min }
41
- groups[step.id] = TraceHelper.active_recorder&.step_started(name: [keyword, step.text].compact.join(' '), source: location)
42
- rescue StandardError => e
43
- TraceHelper.disable!("step groups failed: #{e.message}") if defined?(TraceHelper)
44
- end
45
- config.on_event(:test_step_finished) do |event|
46
- next if event.test_step.hook?
47
-
48
- status = %i[passed failed].include?(event.result.to_sym) ? event.result.to_sym : :skipped
49
- error = event.result.failed? ? event.result.exception : nil
50
- TraceHelper.active_recorder&.step_finished(groups.delete(event.test_step.id), status: status, error: error)
51
- rescue StandardError => e
52
- TraceHelper.disable!("step groups failed: #{e.message}") if defined?(TraceHelper)
53
- end
54
- rescue StandardError => e
55
- TraceHelper.warn_once("Gherkin step groups unavailable: #{e.message}")
56
- end
57
- end
58
- end
59
-
60
- <%- end -%>
61
- Before do<%= trace_helper? ? ' |scenario|' : '' %>
62
- viewport = YAML.load_file('config/config.yml')['viewport']
63
- if viewport
64
- driver.manage.window.resize_to(viewport['width'], viewport['height'])
65
- else
66
- driver.manage.window.maximize
67
- end
68
- @video_recorder = VideoHelper.recorder_for(driver)
69
- @video_recorder.start
70
- <%- if trace_helper? -%>
71
- if defined?(TraceHelper)
72
- @trace_attempt = (TRACE_ATTEMPTS[scenario.location.to_s] += 1)
73
- @trace_test = { identifier: scenario.location.to_s, full_name: scenario.name, attempt: @trace_attempt }
74
- @trace_recorder = TraceHelper.recorder_for(driver)
75
- @trace_recorder.start
76
- end
77
- <%- end -%>
78
- end
79
-
80
- <%- if examples? -%>
81
- Before('@logged_in') do
82
- user = UserFactory.for('registered user')
83
- account = Account.new(driver)
84
- SessionState.new(driver).reuse(
85
- valid: -> { account.tap(&:visit).header.customer_name == "Welcome back #{user['name']}" }
86
- ) do
87
- login = Login.new(driver)
88
- login.visit
89
- login.login(user['username'], user['password'])
90
- end
91
- end
92
-
93
- <%- end -%>
94
- After do |scenario|
95
- <%- if trace_helper? -%>
96
- if defined?(TraceHelper)
97
- keep_trace = TraceHelper.keep_all? || scenario.failed?
98
- trace_test = @trace_test&.merge(status: scenario.failed? ? 'failed' : 'passed', error: scenario.exception)
99
- trace_path = @trace_recorder&.stop(keep: keep_trace, test: trace_test)
100
- end
101
- <%- end -%>
102
- video_path = @video_recorder&.stop(keep: scenario.failed?)
103
- RaiderReporter.attach('video', video_path, type: :webm) if video_path
104
- <%- if trace_helper? -%>
105
- RaiderReporter.attach('trace', trace_path, type: :trace, attempt: @trace_attempt) if trace_path
106
- <%- end -%>
107
- if scenario.failed?
108
- Dir.mktmpdir do |temp_folder|
109
- screenshot_path = File.join(temp_folder, 'screenshot.png')
110
- driver.save_screenshot(screenshot_path)
111
- RaiderReporter.attach('screenshot', screenshot_path, type: :png)
112
- end
113
- end
114
- ensure
115
- <%- if trace_helper? -%>
116
- @trace_recorder&.cleanup
117
- <%- end -%>
118
- @video_recorder&.cleanup
119
- driver.quit
120
- end
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'raider_reporter/cucumber'
4
- require 'tmpdir'
5
- require 'yaml'
6
- require_relative '../../helpers/video_helper'
7
- require_relative '../../helpers/session_state'
8
- require_relative '../../models/user_factory'
9
- require_relative '../../page_objects/pages/account'
10
- require_relative '../../page_objects/pages/login'
11
-
12
- Before do
13
- viewport = YAML.load_file('config/config.yml')['viewport']
14
- if viewport
15
- browser.window.resize_to(viewport['width'], viewport['height'])
16
- else
17
- browser.window.maximize
18
- end
19
- @video_recorder = VideoHelper.recorder_for(browser)
20
- @video_recorder.start
21
- end
22
-
23
- Before('@logged_in') do
24
- user = UserFactory.for('registered user')
25
- account = Account.new(browser)
26
- SessionState.new(browser.driver).reuse(
27
- valid: -> { account.tap(&:visit).header.customer_name == "Welcome back #{user['name']}" }
28
- ) do
29
- login = Login.new(browser)
30
- login.visit
31
- login.login(user['username'], user['password'])
32
- end
33
- end
34
-
35
- After do |scenario|
36
- video_path = @video_recorder&.stop(keep: scenario.failed?)
37
- RaiderReporter.attach('video', video_path, type: :webm) if video_path
38
- if scenario.failed?
39
- Dir.mktmpdir do |temp_folder|
40
- screenshot_path = File.join(temp_folder, 'screenshot.png')
41
- browser.screenshot.save(screenshot_path)
42
- RaiderReporter.attach('screenshot', screenshot_path, type: :png)
43
- end
44
- end
45
- ensure
46
- @video_recorder&.cleanup
47
- browser.quit
48
- end
@@ -1,4 +0,0 @@
1
- require_relative '../../helpers/browser_helper'
2
- require_relative '../../models/user_factory'
3
-
4
- World(BrowserHelper)
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../../page_objects/pages/account'
4
- require_relative '../../page_objects/pages/login'
5
-
6
- Given("I'm a {user} on the login page") do |user|
7
- @user = user
8
- @login_page = <% if watir? %>Login.new(browser)<% else %>Login.new(driver)<% end %>
9
- @login_page.visit
10
- end
11
-
12
- Given("I'm a {user}") do |user|
13
- @user = user
14
- end
15
-
16
- When('I login with my credentials') do
17
- @login_page.login(@user['username'], @user['password'])
18
- end
19
-
20
- Then("I'm logged in") do
21
- account_page = <% if watir? %>Account.new(browser)<% else %>Account.new(driver)<% end %>
22
- account_page.visit
23
- <%- if watir? -%>
24
- expect(account_page.header.customer_name).to eq "Welcome back #{@user['name']}"
25
- <%- else -%>
26
- eventually { expect(account_page.header.customer_name).to eq "Welcome back #{@user['name']}" }
27
- <%- end -%>
28
- end
@@ -1,5 +0,0 @@
1
- <%- if web? -%>
2
- <%= partial('web_steps', strip: true) %>
3
- <%- else -%>
4
- <%= partial('mobile_steps', strip: true) %>
5
- <%- end -%>
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'model_factory'
4
-
5
- class UserFactory < ModelFactory
6
- def self.for(user)
7
- super('users')[user]
8
- end
9
- end
10
-
11
- ParameterType(
12
- name: 'user',
13
- regexp: /[A-Za-z0-9]+ user/,
14
- transformer: ->(user) { UserFactory.for(user) }
15
- )
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- <%- if watir? -%>
4
- <%= partial('watir_world', strip: true) %>
5
- <%- else -%>
6
- <%= partial('driver_world', strip: true) %>
7
- <%- end -%>
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/core_ext/string/inflections'
4
- require 'yaml'
5
- require 'watir'
6
- require_relative 'video_helper'
7
-
8
- module BrowserHelper
9
- def browser(*args)
10
- @browser ||= create_browser(*args)
11
- end
12
-
13
- private
14
-
15
- def config
16
- @config ||= YAML.load_file('config/config.yml')
17
- end
18
-
19
- def create_browser(*args)
20
- Watir.default_timeout = config.fetch('timeout', 10)
21
- browser_name = config['browser'].to_s
22
- args = args.empty? ? config['browser_arguments'][browser_name] : args
23
- args += ['--headless'] if (ENV['HEADLESS'] || config['headless']) && !args.include?('--headless')
24
- capitalized = browser_name == 'ie' ? browser_name.upcase : browser_name.capitalize
25
- browser_options = "Selenium::WebDriver::#{capitalized}::Options".constantize.new(args: args)
26
- arguments = { options: browser_options }
27
- listener = VideoHelper.listener
28
- arguments[:listener] = listener if listener
29
- Watir::Browser.new(browser_name.to_sym, **arguments)
30
- end
31
- end
@@ -1,159 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- <%- if mobile? -%>
4
- # An element found through WaitHelper. It has the same waiting methods as the
5
- # mixin, minus the locator, so calls chain:
6
- # find_element(accessibility_id: 'list').find_element(accessibility_id: 'row').tap
7
- # find_element(accessibility_id: 'card').swipe('left')
8
- # Everything else (tag_name, rect, location, ...) goes to the raw Appium
9
- # element without waiting. APIs that type-check their argument
10
- # (driver.action, execute_script) need .native.
11
- <%- else -%>
12
- # An element found through WaitHelper. It has the same waiting methods as the
13
- # mixin, minus the locator, so calls chain:
14
- # find_element(css: '.form').find_element(id: 'email').send_keys('a')
15
- # Everything else (tag_name, rect, property, ...) goes to the raw Selenium
16
- # element without waiting. Selenium APIs that type-check their argument
17
- # (switch_to.frame, Support::Select, driver.action, execute_script) need .native.
18
- <%- end -%>
19
- class RaiderElement
20
- def initialize(driver, lookup)
21
- @driver = driver
22
- @lookup = lookup
23
- end
24
-
25
- def native
26
- @lookup.element
27
- end
28
-
29
- def find_element(locator = nil, visible: true, timeout: nil, **by)
30
- waiter(timeout).find_element(child(locator, by), visible)
31
- end
32
-
33
- def find_elements(locator = nil, timeout: nil, **by)
34
- waiter(timeout).find_elements(child(locator, by))
35
- end
36
-
37
- <%- if mobile? -%>
38
- %i[click clear].each do |action|
39
- define_method(action) do |timeout: nil|
40
- perform(action, timeout) { |element| element.public_send(action) }
41
- self
42
- end
43
- end
44
-
45
- # tap is Appium's word for click. With a block it stays Ruby's Object#tap.
46
- def tap(timeout: nil, &block)
47
- return super(&block) if block
48
-
49
- perform(:tap, timeout, &:click)
50
- self
51
- end
52
- <%- else -%>
53
- %i[click clear submit].each do |action|
54
- define_method(action) do |timeout: nil|
55
- perform(action, timeout) { |element| element.public_send(action) }
56
- self
57
- end
58
- end
59
- <%- end -%>
60
-
61
- %i[text displayed? enabled? selected?].each do |reader|
62
- define_method(reader) do |timeout: nil|
63
- perform(reader, timeout) { |element| element.public_send(reader) }
64
- end
65
- end
66
-
67
- def send_keys(*keys, timeout: nil)
68
- perform(:send_keys, timeout, args: keys) { |element| element.send_keys(*keys) }
69
- self
70
- end
71
-
72
- <%- unless mobile? -%>
73
- def select_by(how, what, timeout: nil)
74
- perform(:select_by, timeout, args: [how, what]) { |element| Selenium::WebDriver::Support::Select.new(element).select_by(how, what) }
75
- self
76
- end
77
-
78
- <%- end -%>
79
- def attribute(name, timeout: nil)
80
- perform(:attribute, timeout) { |element| element.attribute(name) }
81
- end
82
-
83
- <%- if mobile? -%>
84
- # direction: 'up', 'down', 'left' or 'right'.
85
- %i[swipe scroll].each do |kind|
86
- define_method(kind) do |direction, timeout: nil|
87
- gesture = WaitHelper::Gesture.new(@driver, kind, direction)
88
- perform(kind, timeout) { |element| gesture.perform(element) }
89
- self
90
- end
91
- end
92
-
93
- # Scrolls the screen until this element is visible, up to max_scrolls times.
94
- def scroll_to(direction: 'down', max_scrolls: 10, timeout: nil)
95
- scroller = WaitHelper::Scroller.new(WaitHelper::Gesture.new(@driver, :scroll, direction), max_scrolls)
96
- waiter(timeout).perform_action(:scroll_to, @lookup, WaitHelper::Waiter::CHECKS[:scroll_to], between: scroller) { nil }
97
- self
98
- end
99
- <%- else -%>
100
- def hover(timeout: nil)
101
- perform(:hover, timeout) { |element| @driver.action.move_to(element).perform }
102
- self
103
- end
104
-
105
- def scroll_into_view(timeout: nil)
106
- perform(:scroll_into_view, timeout) { |element| @driver.action.scroll_to(element).perform }
107
- self
108
- end
109
-
110
- # target: a RaiderElement, a raw element, or a driver-scoped locator.
111
- def drag_and_drop(target, timeout: nil)
112
- drop = WaitHelper::Lookup.for(@driver, target, {})
113
- waiter(timeout).perform_action(:drag_and_drop, @lookup, WaitHelper::Waiter::CHECKS[:drag_and_drop],
114
- target: drop) do |source, destination|
115
- @driver.action.drag_and_drop(source, destination).perform
116
- end
117
- self
118
- end
119
- <%- end -%>
120
-
121
- def ==(other)
122
- native == (other.is_a?(RaiderElement) ? other.native : other)
123
- end
124
-
125
- def eql?(other)
126
- self == other
127
- end
128
-
129
- def hash
130
- native.hash
131
- end
132
-
133
- private
134
-
135
- # WaitHelper::Lookup.for reads this to reuse how a wrapper was found.
136
- attr_reader :lookup
137
-
138
- def waiter(timeout)
139
- WaitHelper::Waiter.new(@driver, timeout: timeout)
140
- end
141
-
142
- def child(locator, by)
143
- WaitHelper::Lookup.for(@driver, locator, by, scope: @lookup)
144
- end
145
-
146
- def perform(action, timeout, args: nil, &block)
147
- waiter(timeout).perform_action(action, @lookup, WaitHelper::Waiter::CHECKS.fetch(action), args: args, &block)
148
- end
149
-
150
- def method_missing(name, *args, **options, &block)
151
- return super unless native.respond_to?(name)
152
-
153
- native.public_send(name, *args, **options, &block)
154
- end
155
-
156
- def respond_to_missing?(name, include_private = false)
157
- native.respond_to?(name) || super
158
- end
159
- end