ruby_raider 1.1.4 → 3.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 (278) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/e2e_tests.yml +58 -0
  3. data/.github/workflows/integration.yml +4 -6
  4. data/.github/workflows/reek.yml +6 -5
  5. data/.github/workflows/release.yml +175 -0
  6. data/.github/workflows/rubocop.yml +7 -6
  7. data/.github/workflows/steep.yml +21 -0
  8. data/.github/workflows/system_tests.yml +83 -0
  9. data/.gitignore +1 -1
  10. data/.reek.yml +46 -4
  11. data/.rubocop.yml +24 -0
  12. data/.ruby-version +1 -1
  13. data/README.md +140 -77
  14. data/RELEASE.md +412 -0
  15. data/RELEASE_QUICK_GUIDE.md +77 -0
  16. data/Steepfile +22 -0
  17. data/assets/ruby_raider_logo.svg +51 -0
  18. data/bin/release +186 -0
  19. data/lib/adopter/adopt_menu.rb +146 -0
  20. data/lib/adopter/converters/base_converter.rb +84 -0
  21. data/lib/adopter/converters/identity_converter.rb +53 -0
  22. data/lib/adopter/migration_plan.rb +74 -0
  23. data/lib/adopter/migrator.rb +96 -0
  24. data/lib/adopter/plan_builder.rb +275 -0
  25. data/lib/adopter/project_analyzer.rb +252 -0
  26. data/lib/adopter/project_detector.rb +157 -0
  27. data/lib/commands/adopt_commands.rb +42 -0
  28. data/lib/commands/plugin_commands.rb +0 -2
  29. data/lib/commands/scaffolding_commands.rb +220 -37
  30. data/lib/commands/utility_commands.rb +82 -2
  31. data/lib/generators/automation/automation_generator.rb +0 -7
  32. data/lib/generators/automation/templates/account.tt +9 -5
  33. data/lib/generators/automation/templates/appium_caps.tt +60 -6
  34. data/lib/generators/automation/templates/home.tt +4 -4
  35. data/lib/generators/automation/templates/login.tt +61 -4
  36. data/lib/generators/automation/templates/page.tt +13 -7
  37. data/lib/generators/automation/templates/partials/element.tt +1 -1
  38. data/lib/generators/automation/templates/partials/home_page_selector.tt +4 -4
  39. data/lib/generators/automation/templates/partials/initialize_selector.tt +3 -8
  40. data/lib/generators/automation/templates/partials/pdp_page_selector.tt +4 -4
  41. data/lib/generators/automation/templates/partials/url_methods.tt +0 -1
  42. data/lib/generators/automation/templates/partials/visit_method.tt +11 -1
  43. data/lib/generators/automation/templates/pdp.tt +1 -1
  44. data/lib/generators/common_generator.rb +12 -0
  45. data/lib/generators/cucumber/cucumber_generator.rb +36 -0
  46. data/lib/generators/cucumber/templates/accessibility_feature.tt +5 -0
  47. data/lib/generators/cucumber/templates/accessibility_steps.tt +21 -0
  48. data/lib/generators/cucumber/templates/cucumber.tt +8 -1
  49. data/lib/generators/cucumber/templates/env.tt +6 -4
  50. data/lib/generators/cucumber/templates/feature.tt +0 -4
  51. data/lib/generators/cucumber/templates/partials/appium_env.tt +5 -0
  52. data/lib/generators/cucumber/templates/partials/capybara_env.tt +38 -0
  53. data/lib/generators/cucumber/templates/partials/capybara_world.tt +6 -0
  54. data/lib/generators/cucumber/templates/partials/driver_world.tt +1 -4
  55. data/lib/generators/cucumber/templates/partials/mobile_steps.tt +2 -2
  56. data/lib/generators/cucumber/templates/partials/selenium_env.tt +22 -35
  57. data/lib/generators/cucumber/templates/partials/watir_env.tt +20 -1
  58. data/lib/generators/cucumber/templates/partials/web_steps.tt +10 -15
  59. data/lib/generators/cucumber/templates/performance_feature.tt +5 -0
  60. data/lib/generators/cucumber/templates/performance_steps.tt +17 -0
  61. data/lib/generators/cucumber/templates/steps.tt +2 -2
  62. data/lib/generators/cucumber/templates/visual_feature.tt +5 -0
  63. data/lib/generators/cucumber/templates/visual_steps.tt +19 -0
  64. data/lib/generators/cucumber/templates/world.tt +5 -3
  65. data/lib/generators/generator.rb +50 -7
  66. data/lib/generators/helper_generator.rb +39 -9
  67. data/lib/generators/infrastructure/github_generator.rb +6 -0
  68. data/lib/generators/infrastructure/templates/github.tt +12 -8
  69. data/lib/generators/infrastructure/templates/github_appium.tt +108 -0
  70. data/lib/generators/infrastructure/templates/gitlab.tt +6 -3
  71. data/lib/generators/invoke_generators.rb +43 -9
  72. data/lib/generators/menu_generator.rb +122 -11
  73. data/lib/generators/minitest/minitest_generator.rb +35 -0
  74. data/lib/generators/minitest/templates/accessibility_test.tt +26 -0
  75. data/lib/generators/minitest/templates/performance_test.tt +18 -0
  76. data/lib/generators/minitest/templates/test.tt +64 -0
  77. data/lib/generators/minitest/templates/visual_test.tt +23 -0
  78. data/lib/generators/rspec/rspec_generator.rb +16 -4
  79. data/lib/generators/rspec/templates/accessibility_spec.tt +25 -0
  80. data/lib/generators/rspec/templates/performance_spec.tt +18 -0
  81. data/lib/generators/rspec/templates/spec.tt +13 -41
  82. data/lib/generators/rspec/templates/visual_spec.tt +20 -0
  83. data/lib/generators/template_renderer/partial_cache.rb +126 -0
  84. data/lib/generators/template_renderer/partial_resolver.rb +110 -0
  85. data/lib/generators/template_renderer/template_error.rb +50 -0
  86. data/lib/generators/template_renderer.rb +106 -0
  87. data/lib/generators/templates/common/config.tt +2 -2
  88. data/lib/generators/templates/common/gemfile.tt +36 -9
  89. data/lib/generators/templates/common/git_ignore.tt +6 -1
  90. data/lib/generators/templates/common/partials/mobile_config.tt +5 -1
  91. data/lib/generators/templates/common/partials/web_config.tt +17 -8
  92. data/lib/generators/templates/common/rakefile.tt +36 -0
  93. data/lib/generators/templates/common/read_me.tt +43 -91
  94. data/lib/generators/templates/common/rspec.tt +3 -0
  95. data/lib/generators/templates/common/ruby_version.tt +1 -0
  96. data/lib/generators/templates/helpers/allure_helper.tt +13 -2
  97. data/lib/generators/templates/helpers/browser_helper.tt +13 -2
  98. data/lib/generators/templates/helpers/capybara_helper.tt +32 -0
  99. data/lib/generators/templates/helpers/debug_helper.tt +190 -0
  100. data/lib/generators/templates/helpers/driver_helper.tt +3 -11
  101. data/lib/generators/templates/helpers/partials/allure_imports.tt +3 -1
  102. data/lib/generators/templates/helpers/partials/allure_requirements.tt +3 -1
  103. data/lib/generators/templates/helpers/partials/appium_driver.tt +44 -0
  104. data/lib/generators/templates/helpers/partials/browserstack_config.tt +13 -0
  105. data/lib/generators/templates/helpers/partials/debug_diagnostics.tt +7 -0
  106. data/lib/generators/templates/helpers/partials/debug_start.tt +7 -0
  107. data/lib/generators/templates/helpers/partials/driver_and_options.tt +5 -115
  108. data/lib/generators/templates/helpers/partials/quit_driver.tt +3 -1
  109. data/lib/generators/templates/helpers/partials/screenshot.tt +3 -1
  110. data/lib/generators/templates/helpers/partials/selenium_driver.tt +26 -0
  111. data/lib/generators/templates/helpers/partials/video_start.tt +9 -0
  112. data/lib/generators/templates/helpers/partials/video_stop.tt +4 -0
  113. data/lib/generators/templates/helpers/performance_helper.tt +57 -0
  114. data/lib/generators/templates/helpers/spec_helper.tt +72 -10
  115. data/lib/generators/templates/helpers/test_helper.tt +94 -0
  116. data/lib/generators/templates/helpers/video_helper.tt +270 -0
  117. data/lib/generators/templates/helpers/visual_helper.tt +39 -46
  118. data/lib/llm/client.rb +79 -0
  119. data/lib/llm/config.rb +57 -0
  120. data/lib/llm/prompts.rb +84 -0
  121. data/lib/llm/provider.rb +27 -0
  122. data/lib/llm/providers/anthropic_provider.rb +43 -0
  123. data/lib/llm/providers/ollama_provider.rb +56 -0
  124. data/lib/llm/providers/openai_provider.rb +42 -0
  125. data/lib/llm/response_parser.rb +67 -0
  126. data/lib/plugin/plugin.rb +22 -20
  127. data/lib/plugin/plugin_exposer.rb +16 -38
  128. data/lib/ruby_raider.rb +51 -11
  129. data/lib/scaffolding/crud_generator.rb +94 -0
  130. data/lib/scaffolding/dry_run_presenter.rb +16 -0
  131. data/lib/scaffolding/name_normalizer.rb +63 -0
  132. data/lib/scaffolding/page_introspector.rb +45 -0
  133. data/lib/scaffolding/project_detector.rb +72 -0
  134. data/lib/scaffolding/scaffold_menu.rb +103 -0
  135. data/lib/scaffolding/scaffolding.rb +158 -11
  136. data/lib/scaffolding/templates/component.tt +30 -0
  137. data/lib/scaffolding/templates/feature.tt +4 -4
  138. data/lib/scaffolding/templates/helper.tt +15 -1
  139. data/lib/scaffolding/templates/page_from_url.tt +75 -0
  140. data/lib/scaffolding/templates/page_object.tt +50 -1
  141. data/lib/scaffolding/templates/spec.tt +33 -2
  142. data/lib/scaffolding/templates/spec_from_page.tt +31 -0
  143. data/lib/scaffolding/templates/spec_from_url.tt +46 -0
  144. data/lib/scaffolding/templates/steps.tt +17 -5
  145. data/lib/scaffolding/url_analyzer.rb +179 -0
  146. data/lib/utilities/desktop_downloader.rb +177 -0
  147. data/lib/utilities/logo.rb +83 -0
  148. data/lib/utilities/utilities.rb +53 -20
  149. data/lib/version +1 -1
  150. data/ruby_raider.gemspec +1 -0
  151. data/sig/adopter/adopt_menu.rbs +25 -0
  152. data/sig/adopter/converters/base_converter.rbs +23 -0
  153. data/sig/adopter/converters/identity_converter.rbs +16 -0
  154. data/sig/adopter/migration_plan.rbs +34 -0
  155. data/sig/adopter/migrator.rbs +21 -0
  156. data/sig/adopter/plan_builder.rbs +38 -0
  157. data/sig/adopter/project_analyzer.rbs +39 -0
  158. data/sig/adopter/project_detector.rbs +26 -0
  159. data/sig/commands/adopt_commands.rbs +8 -0
  160. data/sig/commands/loaded_commands.rbs +5 -0
  161. data/sig/commands/plugin_commands.rbs +9 -0
  162. data/sig/commands/scaffolding_commands.rbs +28 -0
  163. data/sig/commands/utility_commands.rbs +21 -0
  164. data/sig/generators/automation/automation_generator.rbs +20 -0
  165. data/sig/generators/common_generator.rbs +12 -0
  166. data/sig/generators/cucumber/cucumber_generator.rbs +16 -0
  167. data/sig/generators/generator.rbs +40 -0
  168. data/sig/generators/helper_generator.rbs +18 -0
  169. data/sig/generators/infrastructure/github_generator.rbs +5 -0
  170. data/sig/generators/infrastructure/gitlab_generator.rbs +4 -0
  171. data/sig/generators/invoke_generators.rbs +10 -0
  172. data/sig/generators/menu_generator.rbs +29 -0
  173. data/sig/generators/minitest/minitest_generator.rbs +8 -0
  174. data/sig/generators/rspec/rspec_generator.rbs +8 -0
  175. data/sig/generators/template_renderer/partial_cache.rbs +20 -0
  176. data/sig/generators/template_renderer/partial_resolver.rbs +20 -0
  177. data/sig/generators/template_renderer/template_error.rbs +19 -0
  178. data/sig/generators/template_renderer.rbs +10 -0
  179. data/sig/llm/client.rbs +15 -0
  180. data/sig/llm/config.rbs +20 -0
  181. data/sig/llm/prompts.rbs +8 -0
  182. data/sig/llm/provider.rbs +12 -0
  183. data/sig/llm/providers/anthropic_provider.rbs +16 -0
  184. data/sig/llm/providers/ollama_provider.rbs +18 -0
  185. data/sig/llm/providers/openai_provider.rbs +16 -0
  186. data/sig/llm/response_parser.rbs +13 -0
  187. data/sig/plugin/plugin.rbs +24 -0
  188. data/sig/plugin/plugin_exposer.rbs +20 -0
  189. data/sig/ruby_raider.rbs +15 -0
  190. data/sig/scaffolding/crud_generator.rbs +16 -0
  191. data/sig/scaffolding/dry_run_presenter.rbs +4 -0
  192. data/sig/scaffolding/name_normalizer.rbs +17 -0
  193. data/sig/scaffolding/page_introspector.rbs +14 -0
  194. data/sig/scaffolding/project_detector.rbs +14 -0
  195. data/sig/scaffolding/scaffold_menu.rbs +18 -0
  196. data/sig/scaffolding/scaffolding.rbs +55 -0
  197. data/sig/scaffolding/url_analyzer.rbs +28 -0
  198. data/sig/utilities/desktop_downloader.rbs +23 -0
  199. data/sig/utilities/logger.rbs +13 -0
  200. data/sig/utilities/logo.rbs +16 -0
  201. data/sig/utilities/utilities.rbs +30 -0
  202. data/sig/vendor/thor.rbs +34 -0
  203. data/sig/vendor/tty_prompt.rbs +15 -0
  204. data/spec/adopter/adopt_menu_spec.rb +176 -0
  205. data/spec/adopter/converters/identity_converter_spec.rb +145 -0
  206. data/spec/adopter/migration_plan_spec.rb +113 -0
  207. data/spec/adopter/migrator_spec.rb +277 -0
  208. data/spec/adopter/plan_builder_spec.rb +298 -0
  209. data/spec/adopter/project_analyzer_spec.rb +337 -0
  210. data/spec/adopter/project_detector_spec.rb +295 -0
  211. data/spec/commands/raider_commands_spec.rb +129 -0
  212. data/spec/generators/fixtures/templates/test.tt +1 -0
  213. data/spec/generators/fixtures/templates/test_partial.tt +1 -0
  214. data/spec/generators/generator_spec.rb +23 -0
  215. data/spec/generators/template_renderer_spec.rb +298 -0
  216. data/spec/integration/commands/scaffolding_commands_spec.rb +2 -2
  217. data/spec/integration/commands/utility_commands_spec.rb +24 -4
  218. data/spec/integration/content/ci_content_spec.rb +119 -0
  219. data/spec/integration/content/common_content_spec.rb +288 -0
  220. data/spec/integration/content/config_content_spec.rb +175 -0
  221. data/spec/integration/content/content_helper.rb +32 -0
  222. data/spec/integration/content/gemfile_content_spec.rb +209 -0
  223. data/spec/integration/content/helper_content_spec.rb +485 -0
  224. data/spec/integration/content/page_content_spec.rb +259 -0
  225. data/spec/integration/content/reporter_content_spec.rb +236 -0
  226. data/spec/integration/content/skip_flags_content_spec.rb +206 -0
  227. data/spec/integration/content/syntax_validation_spec.rb +30 -0
  228. data/spec/integration/content/test_content_spec.rb +266 -0
  229. data/spec/integration/end_to_end_features_spec.rb +690 -0
  230. data/spec/integration/end_to_end_spec.rb +361 -0
  231. data/spec/integration/generators/automation_generator_spec.rb +9 -21
  232. data/spec/integration/generators/axe_addon_spec.rb +150 -0
  233. data/spec/integration/generators/common_generator_spec.rb +48 -49
  234. data/spec/integration/generators/config_features_spec.rb +155 -0
  235. data/spec/integration/generators/cucumber_generator_spec.rb +7 -7
  236. data/spec/integration/generators/debug_helper_spec.rb +68 -0
  237. data/spec/integration/generators/github_generator_spec.rb +8 -8
  238. data/spec/integration/generators/gitlab_generator_spec.rb +8 -8
  239. data/spec/integration/generators/helpers_generator_spec.rb +70 -44
  240. data/spec/integration/generators/lighthouse_addon_spec.rb +132 -0
  241. data/spec/integration/generators/minitest_generator_spec.rb +64 -0
  242. data/spec/integration/generators/reporter_spec.rb +159 -0
  243. data/spec/integration/generators/rspec_generator_spec.rb +7 -7
  244. data/spec/integration/generators/skip_flags_spec.rb +134 -0
  245. data/spec/integration/generators/visual_addon_spec.rb +148 -0
  246. data/spec/integration/settings_helper.rb +1 -4
  247. data/spec/integration/spec_helper.rb +46 -11
  248. data/spec/llm/client_spec.rb +79 -0
  249. data/spec/llm/config_spec.rb +92 -0
  250. data/spec/llm/prompts_spec.rb +49 -0
  251. data/spec/llm/response_parser_spec.rb +92 -0
  252. data/spec/menus/adopter_adopt_menu_spec.rb +97 -0
  253. data/spec/menus/menu_generator_spec.rb +263 -0
  254. data/spec/scaffolding/name_normalizer_spec.rb +113 -0
  255. data/spec/scaffolding/page_introspector_spec.rb +82 -0
  256. data/spec/scaffolding/scaffold_project_detector_spec.rb +104 -0
  257. data/spec/scaffolding/scaffolding_features_spec.rb +311 -0
  258. data/spec/scaffolding/url_analyzer_spec.rb +110 -0
  259. data/spec/system/adopt_matrix_spec.rb +537 -0
  260. data/spec/system/adopt_spec.rb +225 -0
  261. data/spec/system/capybara_spec.rb +42 -0
  262. data/spec/system/selenium_spec.rb +19 -17
  263. data/spec/system/support/system_test_helper.rb +33 -0
  264. data/spec/system/watir_spec.rb +19 -17
  265. data/spec/utilities/desktop_downloader_spec.rb +92 -0
  266. metadata +193 -18
  267. data/.github/workflows/push_gem.yml +0 -37
  268. data/.github/workflows/selenium.yml +0 -22
  269. data/.github/workflows/watir.yml +0 -22
  270. data/lib/generators/automation/templates/partials/android_caps.tt +0 -17
  271. data/lib/generators/automation/templates/partials/cross_platform_caps.tt +0 -25
  272. data/lib/generators/automation/templates/partials/ios_caps.tt +0 -18
  273. data/lib/generators/automation/templates/partials/selenium_account.tt +0 -9
  274. data/lib/generators/automation/templates/partials/selenium_login.tt +0 -34
  275. data/lib/generators/automation/templates/partials/watir_account.tt +0 -7
  276. data/lib/generators/automation/templates/partials/watir_login.tt +0 -32
  277. data/lib/generators/automation/templates/visual_options.tt +0 -16
  278. data/lib/generators/templates/helpers/visual_spec_helper.tt +0 -35
@@ -1,7 +1,61 @@
1
- <% if ios? %>
2
- <%= ERB.new(File.read(File.expand_path('./partials/ios_caps.tt', __dir__))).result(binding) -%>
3
- <% elsif android? %>
4
- <%= ERB.new(File.read(File.expand_path('./partials/android_caps.tt', __dir__))).result(binding) -%>
5
- <% else %>
6
- <%= ERB.new(File.read(File.expand_path('./partials/cross_platform_caps.tt', __dir__))).result(binding) -%>
1
+ <% if cross_platform? %>android:
2
+ platformName: Android
3
+ appium:options:
4
+ platformVersion: '14'
5
+ automationName: UiAutomator2
6
+ deviceName: Pixel 8 API 34
7
+ app: app-release.apk
8
+ ios:
9
+ platformName: iOS
10
+ appium:options:
11
+ platformVersion: '17.0'
12
+ deviceName: iPhone 15
13
+ automationName: XCUITest
14
+ app: RaiderTestApp.app
15
+ autoDismissAlerts: true
16
+
17
+ browserstack:
18
+ platformName: Android
19
+ os_version: '9.0'
20
+ deviceName: Google Pixel 3
21
+ app: app: <%= ENV['APP_URL'] %>
22
+ browserstack.user: <%= ENV['BROWSERSTACK_USER'] %>
23
+ browserstack.key: <%= ENV['BROWSERSTACK_KEY'] %>
24
+ project: 'RaiderTestApp'
25
+ name: 'RaiderTestApp-Android'
26
+ <% elsif ios? %>platformName: iOS
27
+ appium:options:
28
+ url: http://localhost:4723/wd/hub
29
+ platformVersion: '17.0'
30
+ deviceName: iPhone 15
31
+ automationName: XCUITest
32
+ app: RaiderTestApp.app
33
+ autoDismissAlerts: true
34
+
35
+ browserstack:
36
+ platformName: iOS
37
+ os_version: '17.5.1'
38
+ deviceName: iPhone 15
39
+ app: <%= ENV['APP_URL'] %>
40
+ browserstack.user: <%= ENV['BROWSERSTACK_USER'] %>
41
+ browserstack.key: <%= ENV['BROWSERSTACK_KEY'] %>
42
+ project: 'RaiderTestApp'
43
+ name: 'RaiderTestApp-IOS'
44
+ <% elsif android? %>platformName: Android
45
+ appium:options:
46
+ url: http://localhost:4723/wd/hub
47
+ platformVersion: '14'
48
+ automationName: UiAutomator2
49
+ deviceName: Pixel 8 API 34
50
+ app: app-release.apk
51
+
52
+ browserstack:
53
+ platformName: Android
54
+ os_version: '9.0'
55
+ deviceName: Google Pixel 3
56
+ app: app: <%= ENV['APP_URL'] %>
57
+ browserstack.user: <%= ENV['BROWSERSTACK_USER'] %>
58
+ browserstack.key: <%= ENV['BROWSERSTACK_KEY'] %>
59
+ project: 'RaiderTestApp'
60
+ name: 'RaiderTestApp-Android'
7
61
  <% end %>
@@ -6,15 +6,15 @@ class Home < Page
6
6
 
7
7
  # Actions
8
8
 
9
- def go_to_backpack_pdp
10
- driver.wait { backpack_image }.click
9
+ def go_to_product_detail
10
+ driver.wait { first_product }.click
11
11
  end
12
12
 
13
13
  private
14
14
 
15
15
  # Elements
16
16
 
17
- def backpack_image
18
- <%= ERB.new(File.read(File.expand_path('./partials/home_page_selector.tt', __dir__)), trim_mode: '-').result(binding) -%>
17
+ def first_product
18
+ <%= partial('home_page_selector') -%>
19
19
  end
20
20
  end
@@ -1,5 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../abstract/page'
4
+
5
+ class Login < Page
6
+ def url(_page)
7
+ 'index.php?rt=account/login'
8
+ end
9
+
10
+ # Actions
11
+
12
+ <%- if capybara? -%>
13
+ def login(username, password)
14
+ fill_in 'loginFrm_loginname', with: username
15
+ fill_in 'loginFrm_password', with: password
16
+ click_button 'Login'
17
+ end
18
+ <%- elsif selenium_based? -%>
19
+ def login(username, password)
20
+ username_field.send_keys username
21
+ password_field.send_keys password
22
+ login_button.click
23
+ end
24
+ alias log_as login
25
+ <%- else -%>
26
+ def login(username, password)
27
+ username_field.set username
28
+ password_field.set password
29
+ login_button.click
30
+ end
31
+ <%- end -%>
32
+ <%- unless capybara? -%>
33
+
34
+ private
35
+
36
+ # Elements
37
+
38
+ def username_field
1
39
  <%- if selenium_based? -%>
2
- <%=- ERB.new(File.read(File.expand_path('./partials/selenium_login.tt', __dir__)), trim_mode: '-').result(binding) -%>
3
- <%- elsif watir? -%>
4
- <%=- ERB.new(File.read(File.expand_path('./partials/watir_login.tt', __dir__)), trim_mode: '-').result(binding) -%>
5
- <%- end -%>
40
+ driver.find_element(id: 'loginFrm_loginname')
41
+ <%- else -%>
42
+ browser.text_field(id: 'loginFrm_loginname')
43
+ <%- end -%>
44
+ end
45
+
46
+ def password_field
47
+ <%- if selenium_based? -%>
48
+ driver.find_element(id: 'loginFrm_password')
49
+ <%- else -%>
50
+ browser.text_field(id: 'loginFrm_password')
51
+ <%- end -%>
52
+ end
53
+
54
+ def login_button
55
+ <%- if selenium_based? -%>
56
+ driver.find_element(xpath: "//button[@title='Login']")
57
+ <%- else -%>
58
+ browser.button(xpath: "//button[@title='Login']")
59
+ <%- end -%>
60
+ end
61
+ <%- end -%>
62
+ end
@@ -6,25 +6,31 @@ class Page
6
6
  <%- if cross_platform? -%>
7
7
  include AppiumHelper
8
8
  <%- end -%>
9
- <%=- ERB.new(File.read(File.expand_path('./partials/initialize_selector.tt', __dir__))).result(binding) -%>
10
- <%=- ERB.new(File.read(File.expand_path('./partials/visit_method.tt', __dir__))).result(binding) -%>
11
- <%=- ERB.new(File.read(File.expand_path('./partials/url_methods.tt', __dir__))).result(binding) -%>
9
+ <%=- partial('initialize_selector', trim: false) -%>
10
+ <%=- partial('visit_method', trim: false) -%>
11
+ <%=- partial('url_methods', trim: false) -%>
12
12
 
13
13
  def to_s
14
14
  self.class.to_s.sub('Page', ' Page')
15
15
  end
16
16
 
17
- <%- if selenium_based? -%>
17
+ <%- if capybara? -%>
18
18
  # Components
19
19
 
20
20
  def header
21
- Header.new(driver.find_element(id: 'customer_menu_top'))
21
+ Header.new(find('.welcome-msg'))
22
22
  end
23
- <%- elsif watir? -%>
23
+ <%- elsif selenium_based? -%>
24
24
  # Components
25
25
 
26
26
  def header
27
- Header.new(browser.element(id: 'customer_menu_top'))
27
+ Header.new(driver.find_element(css: '.welcome-msg'))
28
+ end
29
+ <%- elsif watir? -%>
30
+ # Components
31
+
32
+ def header
33
+ Header.new(browser.element(css: '.welcome-msg'))
28
34
  end
29
35
  <%- end -%>
30
36
  end
@@ -1,4 +1,4 @@
1
- <% if %w[selenium axe applitools appium_ios appium_android].include?(automation) -%>
1
+ <% if %w[selenium appium_ios appium_android].include?(automation) -%>
2
2
  driver.find_element
3
3
  <% else -%>
4
4
  browser.element
@@ -1,8 +1,8 @@
1
1
  <%- if ios? -%>
2
- driver.find_element(predicate: 'label == "Sauce Labs Backpack"')
2
+ driver.find_element(accessibility_id: 'product-item-1')
3
3
  <%- elsif android? -%>
4
- driver.find_element(xpath: '(//android.view.ViewGroup[@content-desc="store item"])[1]/android.view.ViewGroup[1]')
4
+ driver.find_element(accessibility_id: 'product-item-1')
5
5
  <%- else -%>
6
- element(ios: { predicate: 'label == "Sauce Labs Backpack"' },
7
- android: { xpath: '(//android.view.ViewGroup[@content-desc="store item"])[1]/android.view.ViewGroup[1]' })
6
+ element(ios: { accessibility_id: 'product-item-1' },
7
+ android: { accessibility_id: 'product-item-1' })
8
8
  <%- end -%>
@@ -1,16 +1,11 @@
1
- <% if watir? %>
1
+ <% if capybara? %>
2
+ include Capybara::DSL
3
+ <% elsif watir? %>
2
4
  attr_reader :browser
3
5
 
4
6
  def initialize(browser)
5
7
  @browser = browser
6
8
  end
7
- <% elsif axe? %>
8
- attr_reader :driver
9
- alias page driver
10
-
11
- def initialize(driver)
12
- @driver = driver
13
- end
14
9
  <% else %>
15
10
  attr_reader :driver
16
11
 
@@ -1,8 +1,8 @@
1
1
  <%- if ios? -%>
2
- driver.find_element(accessibility_id: 'Add To Cart button')
2
+ driver.find_element(accessibility_id: 'add-to-cart-button')
3
3
  <%- elsif android? -%>
4
- driver.find_element(xpath: '//android.view.ViewGroup[@content-desc="Add To Cart button"]/android.widget.TextView')
4
+ driver.find_element(accessibility_id: 'add-to-cart-button')
5
5
  <%- else -%>
6
- element(ios: { accessibility_id: 'Add To Cart button' },
7
- android: { xpath: '//android.view.ViewGroup[@content-desc="Add To Cart button"]/android.widget.TextView' })
6
+ element(ios: { accessibility_id: 'add-to-cart-button' },
7
+ android: { accessibility_id: 'add-to-cart-button' })
8
8
  <%- end -%>
@@ -3,7 +3,6 @@
3
3
  "#{base_url}#{url(*page)}"
4
4
  end
5
5
 
6
- # :reek:UtilityFunction
7
6
  def base_url
8
7
  YAML.load_file('config/config.yml')['url']
9
8
  end
@@ -1,5 +1,15 @@
1
1
  <% if web? %>
2
+ <% if capybara? %>
3
+ def visit_page(*page)
4
+ Capybara.visit full_url(page.first)
5
+ end
6
+ <% elsif selenium_based? %>
7
+ def visit(*page)
8
+ @driver.navigate.to full_url(page.first)
9
+ end
10
+ <% else %>
2
11
  def visit(*page)
3
- <% if selenium_based? %>@driver.navigate.to full_url(page.first) <% else %>@browser.goto full_url(page.first)<% end %>
12
+ @browser.goto full_url(page.first)
4
13
  end
14
+ <% end %>
5
15
  <% end %>
@@ -13,6 +13,6 @@ class Pdp < Page
13
13
  # Elements
14
14
 
15
15
  def add_to_cart_button
16
- <%= ERB.new(File.read(File.expand_path('./partials/pdp_page_selector.tt', __dir__)), trim_mode: '-').result(binding) -%>
16
+ <%= partial('pdp_page_selector') -%>
17
17
  end
18
18
  end
@@ -17,6 +17,10 @@ class CommonGenerator < Generator
17
17
  template('common/rakefile.tt', "#{name}/Rakefile")
18
18
  end
19
19
 
20
+ def generate_ruby_version_file
21
+ template('common/ruby_version.tt', "#{name}/.ruby-version")
22
+ end
23
+
20
24
  def generate_gemfile
21
25
  template('common/gemfile.tt', "#{name}/Gemfile")
22
26
  end
@@ -33,7 +37,15 @@ class CommonGenerator < Generator
33
37
  template('common/git_ignore.tt', "#{name}/.gitignore")
34
38
  end
35
39
 
40
+ def generate_rspec_file
41
+ return unless rspec?
42
+
43
+ template('common/rspec.tt', "#{name}/.rspec")
44
+ end
45
+
36
46
  def create_allure_folder
47
+ return unless allure_reporter?
48
+
37
49
  empty_directory "#{name}/allure-results"
38
50
  end
39
51
  end
@@ -27,6 +27,42 @@ class CucumberGenerator < Generator
27
27
  template('cucumber.tt', "#{name}/cucumber.yml")
28
28
  end
29
29
 
30
+ def generate_visual_feature
31
+ return unless visual_addon? && web?
32
+
33
+ template('visual_feature.tt', "#{name}/features/visual.feature")
34
+ end
35
+
36
+ def generate_visual_steps
37
+ return unless visual_addon? && web?
38
+
39
+ template('visual_steps.tt', "#{name}/features/step_definitions/visual_steps.rb")
40
+ end
41
+
42
+ def generate_accessibility_feature
43
+ return unless axe_addon? && web?
44
+
45
+ template('accessibility_feature.tt', "#{name}/features/accessibility.feature")
46
+ end
47
+
48
+ def generate_accessibility_steps
49
+ return unless axe_addon? && web?
50
+
51
+ template('accessibility_steps.tt', "#{name}/features/step_definitions/accessibility_steps.rb")
52
+ end
53
+
54
+ def generate_performance_feature
55
+ return unless lighthouse_addon? && web?
56
+
57
+ template('performance_feature.tt', "#{name}/features/performance.feature")
58
+ end
59
+
60
+ def generate_performance_steps
61
+ return unless lighthouse_addon? && web?
62
+
63
+ template('performance_steps.tt', "#{name}/features/step_definitions/performance_steps.rb")
64
+ end
65
+
30
66
  def template_name
31
67
  @template_name ||= (@_initializer.first & %w[android ios cross_platform]).empty? ? 'login' : 'home'
32
68
  end
@@ -0,0 +1,5 @@
1
+ Feature: Accessibility
2
+
3
+ Scenario: Page has no accessibility violations
4
+ Given I am on the home page
5
+ Then the page should be accessible
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ Given('I am on the home page') do
4
+ <% if capybara? -%>
5
+ visit '/'
6
+ <% elsif watir? -%>
7
+ browser.goto 'https://raider-test-site.onrender.com/'
8
+ <% else -%>
9
+ driver.get 'https://raider-test-site.onrender.com/'
10
+ <% end -%>
11
+ end
12
+
13
+ Then('the page should be accessible') do
14
+ <% if capybara? -%>
15
+ expect(page).to be_axe_clean
16
+ <% elsif watir? -%>
17
+ expect(browser.driver).to be_axe_clean
18
+ <% else -%>
19
+ expect(driver).to be_axe_clean
20
+ <% end -%>
21
+ end
@@ -1 +1,8 @@
1
- default: --format AllureCucumber::CucumberFormatter --out allure-results --publish-quiet
1
+ <%- if allure_reporter? -%>
2
+ default: --format AllureCucumber::CucumberFormatter --out allure-results --publish-quiet --retry 0
3
+ <%- else -%>
4
+ default: --publish-quiet --retry 0
5
+ <%- end -%>
6
+ <%- if json_reporter? -%>
7
+ json: --format json --out results/results.json --publish-quiet
8
+ <%- end -%>
@@ -1,7 +1,9 @@
1
- <%- if selenium_based? -%>
2
- <%= ERB.new(File.read(File.expand_path('./partials/selenium_env.tt', __dir__)), trim_mode: '-').result(binding) -%>
1
+ <%- if capybara? -%>
2
+ <%= partial('capybara_env') -%>
3
+ <%- elsif selenium_based? -%>
4
+ <%= partial('selenium_env') -%>
3
5
  <%- elsif mobile? -%>
4
- <%= ERB.new(File.read(File.expand_path('./partials/appium_env.tt', __dir__)), trim_mode: '-').result(binding) -%>
6
+ <%= partial('appium_env') -%>
5
7
  <%- else -%>
6
- <%= ERB.new(File.read(File.expand_path('./partials/watir_env.tt', __dir__)), trim_mode: '-').result(binding) -%>
8
+ <%= partial('watir_env') -%>
7
9
  <%- end -%>
@@ -4,11 +4,7 @@ Feature: Login Page
4
4
  Scenario: A user can login
5
5
  Given I'm a registered user on the login page
6
6
  When I login with my credentials
7
- <%- if axe? -%>
8
- Then the page should be axe clean
9
- <%- else -%>
10
7
  Then I'm logged in
11
- <% end -%>
12
8
 
13
9
  <%- else -%>
14
10
  Feature: Home Page
@@ -1,12 +1,17 @@
1
1
  require 'tmpdir'
2
2
  require_relative '../../helpers/allure_helper'
3
+ require_relative '../../helpers/video_helper'
3
4
 
4
5
  Before do
5
6
  AllureHelper.configure
6
7
  driver.start_driver
8
+ @video_recorder = VideoHelper.recorder_for(driver)
9
+ @video_recorder&.start(self.class.to_s)
7
10
  end
8
11
 
9
12
  After do |scenario|
13
+ video_file = @video_recorder&.stop
14
+ AllureHelper.add_video(scenario.name, video_file)
10
15
  Dir.mktmpdir do |temp_folder|
11
16
  screenshot = driver.screenshot("#{temp_folder}/#{scenario.name}.png")
12
17
  AllureHelper.add_screenshot(scenario.name, screenshot)
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec'
4
+ require 'tmpdir'
5
+ require_relative '../../helpers/allure_helper'
6
+ require_relative '../../helpers/capybara_helper'
7
+ require_relative '../../helpers/video_helper'
8
+ require_relative '../../helpers/debug_helper'
9
+
10
+ CapybaraHelper.configure
11
+
12
+ Before do
13
+ viewport = YAML.load_file('config/config.yml')['viewport']
14
+ if viewport
15
+ Capybara.current_session.driver.browser.manage.window.resize_to(viewport['width'], viewport['height'])
16
+ else
17
+ Capybara.current_session.driver.browser.manage.window.maximize
18
+ end
19
+ @video_recorder = VideoHelper.recorder_for(Capybara.current_session.driver)
20
+ @video_recorder&.start(self.class.to_s)
21
+ DebugHelper.enable_network_logging(Capybara.current_session.driver)
22
+ @debug_action_logger = DebugHelper.action_logger_for(self.class.to_s)
23
+ end
24
+
25
+ After do |scenario|
26
+ if scenario.failed?
27
+ DebugHelper.capture_failure_diagnostics(Capybara.current_session.driver, scenario.name, exception: scenario.exception)
28
+ DebugHelper.capture_network_logs(DebugHelper.resolve_selenium_driver(Capybara.current_session.driver), DebugHelper.sanitize(scenario.name))
29
+ end
30
+ @debug_action_logger&.close
31
+ video_file = @video_recorder&.stop
32
+ AllureHelper.add_video(scenario.name, video_file)
33
+ Dir.mktmpdir do |temp_folder|
34
+ screenshot = Capybara.page.save_screenshot("#{temp_folder}/#{scenario.name}.png")
35
+ AllureHelper.add_screenshot(scenario.name, screenshot)
36
+ end
37
+ Capybara.reset_sessions!
38
+ end
@@ -0,0 +1,6 @@
1
+ require 'capybara/dsl'
2
+ require_relative '../../helpers/capybara_helper'
3
+ require_relative '../../models/user_factory'
4
+
5
+ CapybaraHelper.configure
6
+ World(Capybara::DSL)
@@ -1,11 +1,8 @@
1
1
  require_relative '../../helpers/driver_helper'
2
- <%- if visual? -%>
3
- require_relative '../../helpers/visual_helper'
4
- <%- end -%>
5
2
  <%- if selenium_based? -%>
6
3
  require_relative '../../models/user_factory'
7
4
 
8
- World(DriverHelper<%- if visual? -%>, VisualHelper<%- end -%>)
5
+ World(DriverHelper)
9
6
  <%- else -%>
10
7
 
11
8
  World(DriverHelper)
@@ -11,10 +11,10 @@ Given("I'm an anonymous user on the home page") do
11
11
  end
12
12
 
13
13
  When('I select one of the products') do
14
- @home_page.go_to_backpack_pdp
14
+ @home_page.go_to_product_detail
15
15
  end
16
16
 
17
17
  Then("I'm redirected to the product details page") do
18
18
  pdp_page = Pdp.new(driver)
19
- expect(pdp_page.add_to_cart_text).to eq 'Add To Cart'
19
+ expect(pdp_page.add_to_cart_text).to eq 'Add to Cart'
20
20
  end
@@ -1,52 +1,39 @@
1
1
  # frozen_string_literal: true
2
- <%- if visual? -%>
3
2
 
4
- require 'tmpdir'
5
- require_relative '../../helpers/allure_helper'
6
- require_relative '../../helpers/driver_helper'
7
- require_relative '../../helpers/visual_helper'
8
-
9
- include DriverHelper
10
- include VisualHelper
11
-
12
- Before do
13
- OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
14
- @grid_runner = VisualHelper.create_grid_runner
15
- @eyes = VisualHelper.create_eyes(@grid_runner)
16
- VisualHelper.configure_eyes @eyes
17
- @driver = @eyes.open(driver: driver)
18
- end
19
-
20
- After do |scenario|
21
- Dir.mktmpdir do |temp_folder|
22
- screenshot = driver.save_screenshot("#{temp_folder}/#{scenario.name}.png")
23
- AllureHelper.add_screenshot(scenario.name, screenshot)
24
- end
25
- @eyes.close
26
- @driver.quit
27
- @eyes.abort_async
28
- results = @grid_runner.get_all_test_results
29
- puts results
30
- end
31
-
32
- <%- else -%>
33
-
34
- <%- if axe? && cucumber? -%>
3
+ <%- if axe_addon? && cucumber? -%>
35
4
  require 'axe-rspec'
36
5
  <%- end -%>
37
6
  require 'rspec'
38
7
  require 'tmpdir'
8
+ require 'yaml'
39
9
  require_relative '../../helpers/allure_helper'
10
+ require_relative '../../helpers/video_helper'
11
+ require_relative '../../helpers/debug_helper'
40
12
 
41
13
  Before do
42
- driver.manage.window.maximize
14
+ viewport = YAML.load_file('config/config.yml')['viewport']
15
+ if viewport
16
+ driver.manage.window.resize_to(viewport['width'], viewport['height'])
17
+ else
18
+ driver.manage.window.maximize
19
+ end
20
+ @video_recorder = VideoHelper.recorder_for(driver)
21
+ @video_recorder&.start(self.class.to_s)
22
+ DebugHelper.enable_network_logging(driver)
23
+ @debug_action_logger = DebugHelper.action_logger_for(self.class.to_s)
43
24
  end
44
25
 
45
26
  After do |scenario|
27
+ if scenario.failed?
28
+ DebugHelper.capture_failure_diagnostics(driver, scenario.name, exception: scenario.exception)
29
+ DebugHelper.capture_network_logs(DebugHelper.resolve_selenium_driver(driver), DebugHelper.sanitize(scenario.name))
30
+ end
31
+ @debug_action_logger&.close
32
+ video_file = @video_recorder&.stop
33
+ AllureHelper.add_video(scenario.name, video_file)
46
34
  Dir.mktmpdir do |temp_folder|
47
35
  screenshot = driver.save_screenshot("#{temp_folder}/#{scenario.name}.png")
48
36
  AllureHelper.add_screenshot(scenario.name, screenshot)
49
37
  end
50
38
  driver.quit
51
- end
52
- <%- end -%>
39
+ end
@@ -1,13 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'tmpdir'
4
+ require 'yaml'
4
5
  require_relative '../../helpers/allure_helper'
6
+ require_relative '../../helpers/video_helper'
7
+ require_relative '../../helpers/debug_helper'
5
8
 
6
9
  Before do
7
- browser.window.maximize
10
+ viewport = YAML.load_file('config/config.yml')['viewport']
11
+ if viewport
12
+ browser.window.resize_to(viewport['width'], viewport['height'])
13
+ else
14
+ browser.window.maximize
15
+ end
16
+ @video_recorder = VideoHelper.recorder_for(browser)
17
+ @video_recorder&.start(self.class.to_s)
18
+ DebugHelper.enable_network_logging(browser)
19
+ @debug_action_logger = DebugHelper.action_logger_for(self.class.to_s)
8
20
  end
9
21
 
10
22
  After do |scenario|
23
+ if scenario.failed?
24
+ DebugHelper.capture_failure_diagnostics(browser, scenario.name, exception: scenario.exception)
25
+ DebugHelper.capture_network_logs(DebugHelper.resolve_selenium_driver(browser), DebugHelper.sanitize(scenario.name))
26
+ end
27
+ @debug_action_logger&.close
28
+ video_file = @video_recorder&.stop
29
+ AllureHelper.add_video(scenario.name, video_file)
11
30
  Dir.mktmpdir do |temp_folder|
12
31
  screenshot = browser.screenshot.save("#{temp_folder}/#{scenario.name}.png")
13
32
  AllureHelper.add_screenshot(scenario.name, screenshot)