cypress-on-rails 1.17.0 → 1.19.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 (337) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/claude-code-review.yml +57 -0
  3. data/.github/workflows/claude.yml +50 -0
  4. data/.github/workflows/ruby.yml +14 -14
  5. data/CHANGELOG.md +319 -98
  6. data/README.md +271 -23
  7. data/RELEASING.md +200 -0
  8. data/Rakefile +1 -4
  9. data/cypress-on-rails.gemspec +1 -0
  10. data/docs/BEST_PRACTICES.md +678 -0
  11. data/docs/DX_IMPROVEMENTS.md +163 -0
  12. data/docs/PLAYWRIGHT_GUIDE.md +554 -0
  13. data/docs/RELEASE.md +124 -0
  14. data/docs/TROUBLESHOOTING.md +351 -0
  15. data/docs/VCR_GUIDE.md +499 -0
  16. data/docs/authentication.md +30 -0
  17. data/docs/factory_bot_associations.md +14 -0
  18. data/lib/cypress_on_rails/configuration.rb +29 -0
  19. data/lib/cypress_on_rails/railtie.rb +17 -2
  20. data/lib/cypress_on_rails/server.rb +197 -0
  21. data/lib/cypress_on_rails/state_reset_middleware.rb +58 -0
  22. data/lib/cypress_on_rails/vcr/insert_eject_middleware.rb +75 -0
  23. data/lib/cypress_on_rails/vcr/middleware_helpers.rb +51 -0
  24. data/lib/cypress_on_rails/vcr/use_cassette_middleware.rb +56 -0
  25. data/lib/cypress_on_rails/version.rb +1 -1
  26. data/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb +20 -0
  27. data/lib/generators/cypress_on_rails/templates/spec/cypress/e2e/rails_examples/using_factory_bot.cy.js +2 -2
  28. data/lib/generators/cypress_on_rails/templates/spec/cypress/e2e/rails_examples/using_scenarios.cy.js +1 -1
  29. data/lib/generators/cypress_on_rails/templates/spec/cypress/support/commands.js +22 -0
  30. data/lib/generators/cypress_on_rails/templates/spec/cypress/support/on-rails.js +2 -1
  31. data/lib/generators/cypress_on_rails/templates/spec/e2e/e2e_helper.rb.erb +0 -5
  32. data/lib/tasks/cypress.rake +33 -0
  33. data/rakelib/release.rake +80 -0
  34. data/rakelib/task_helpers.rb +23 -0
  35. data/rakelib/update_changelog.rake +63 -0
  36. data/spec/cypress_on_rails/configuration_spec.rb +4 -1
  37. data/spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb +177 -0
  38. data/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb +68 -0
  39. data/specs_e2e/rails_6_1/.gitattributes +10 -0
  40. data/specs_e2e/rails_6_1/Gemfile +20 -0
  41. data/specs_e2e/{rails_5_2 → rails_6_1}/Rakefile +1 -1
  42. data/specs_e2e/rails_6_1/app/assets/stylesheets/application.css +15 -0
  43. data/specs_e2e/rails_6_1/app/jobs/application_job.rb +7 -0
  44. data/specs_e2e/{rails_5_2 → rails_6_1}/app/views/layouts/application.html.erb +1 -1
  45. data/specs_e2e/rails_6_1/bin/bundle +114 -0
  46. data/specs_e2e/rails_6_1/bin/rails +5 -0
  47. data/specs_e2e/rails_6_1/bin/rake +5 -0
  48. data/specs_e2e/{rails_5_2 → rails_6_1}/bin/setup +15 -4
  49. data/specs_e2e/rails_6_1/bin/spring +14 -0
  50. data/specs_e2e/rails_6_1/bin/yarn +17 -0
  51. data/specs_e2e/rails_6_1/config/application.rb +34 -0
  52. data/specs_e2e/rails_6_1/config/boot.rb +4 -0
  53. data/specs_e2e/rails_6_1/config/cable.yml +10 -0
  54. data/specs_e2e/rails_6_1/config/credentials.yml.enc +1 -0
  55. data/specs_e2e/{rails_5_2 → rails_6_1}/config/database.yml +7 -0
  56. data/specs_e2e/{rails_5_2 → rails_6_1}/config/environment.rb +1 -1
  57. data/specs_e2e/{rails_5_2 → rails_6_1}/config/environments/development.rb +22 -5
  58. data/specs_e2e/rails_6_1/config/environments/production.rb +120 -0
  59. data/specs_e2e/{rails_5_2 → rails_6_1}/config/environments/test.rb +24 -7
  60. data/specs_e2e/rails_6_1/config/initializers/backtrace_silencers.rb +8 -0
  61. data/specs_e2e/{rails_5_2 → rails_6_1}/config/initializers/content_security_policy.rb +5 -0
  62. data/specs_e2e/{rails_4_2 → rails_6_1}/config/initializers/filter_parameter_logging.rb +3 -1
  63. data/specs_e2e/rails_6_1/config/initializers/permissions_policy.rb +11 -0
  64. data/specs_e2e/{rails_3_2 → rails_6_1}/config/initializers/wrap_parameters.rb +5 -1
  65. data/specs_e2e/{rails_5_2 → rails_6_1}/config/locales/en.yml +1 -1
  66. data/specs_e2e/rails_6_1/config/master.key +1 -0
  67. data/specs_e2e/rails_6_1/config/puma.rb +43 -0
  68. data/specs_e2e/rails_6_1/config/storage.yml +34 -0
  69. data/specs_e2e/{rails_5_2 → rails_6_1}/config.ru +2 -1
  70. data/specs_e2e/{rails_5_2 → rails_6_1}/db/migrate/20180621085832_create_posts.rb +1 -1
  71. data/specs_e2e/rails_6_1/package.json +8 -0
  72. data/specs_e2e/rails_6_1/playwright-report/index.html +71 -0
  73. data/specs_e2e/rails_6_1/public/robots.txt +1 -0
  74. data/specs_e2e/rails_6_1/test-results/.last-run.json +4 -0
  75. data/specs_e2e/{rails_4_2 → rails_6_1}/test.sh +22 -15
  76. data/specs_e2e/rails_7_2/.gitattributes +9 -0
  77. data/specs_e2e/rails_7_2/.gitignore +16 -0
  78. data/specs_e2e/rails_7_2/.rubocop.yml +8 -0
  79. data/specs_e2e/rails_7_2/Gemfile +11 -0
  80. data/specs_e2e/{rails_4_2 → rails_7_2}/Rakefile +1 -1
  81. data/specs_e2e/rails_7_2/app/assets/stylesheets/application.css +15 -0
  82. data/specs_e2e/rails_7_2/app/controllers/application_controller.rb +4 -0
  83. data/specs_e2e/rails_7_2/app/controllers/posts_controller.rb +58 -0
  84. data/specs_e2e/rails_7_2/app/helpers/posts_helper.rb +2 -0
  85. data/specs_e2e/rails_7_2/app/jobs/application_job.rb +7 -0
  86. data/specs_e2e/rails_7_2/app/models/application_record.rb +3 -0
  87. data/specs_e2e/rails_7_2/app/models/post.rb +2 -0
  88. data/specs_e2e/rails_7_2/app/views/layouts/application.html.erb +22 -0
  89. data/specs_e2e/rails_7_2/app/views/posts/_form.html.erb +32 -0
  90. data/specs_e2e/rails_7_2/app/views/posts/edit.html.erb +6 -0
  91. data/specs_e2e/rails_7_2/app/views/posts/index.html.erb +31 -0
  92. data/specs_e2e/rails_7_2/app/views/posts/new.html.erb +5 -0
  93. data/specs_e2e/rails_7_2/app/views/posts/show.html.erb +19 -0
  94. data/specs_e2e/rails_7_2/bin/brakeman +7 -0
  95. data/specs_e2e/rails_7_2/bin/bundle +109 -0
  96. data/specs_e2e/rails_7_2/bin/importmap +4 -0
  97. data/specs_e2e/rails_7_2/bin/rails +4 -0
  98. data/specs_e2e/rails_7_2/bin/rake +4 -0
  99. data/specs_e2e/rails_7_2/bin/setup +37 -0
  100. data/specs_e2e/rails_7_2/config/application.rb +37 -0
  101. data/specs_e2e/rails_7_2/config/boot.rb +4 -0
  102. data/specs_e2e/rails_7_2/config/cable.yml +10 -0
  103. data/specs_e2e/rails_7_2/config/credentials.yml.enc +1 -0
  104. data/specs_e2e/rails_7_2/config/database.yml +32 -0
  105. data/specs_e2e/{rails_4_2 → rails_7_2}/config/environment.rb +1 -1
  106. data/specs_e2e/rails_7_2/config/environments/development.rb +54 -0
  107. data/specs_e2e/rails_7_2/config/environments/production.rb +105 -0
  108. data/specs_e2e/rails_7_2/config/environments/test.rb +45 -0
  109. data/specs_e2e/rails_7_2/config/importmap.rb +7 -0
  110. data/specs_e2e/rails_7_2/config/initializers/content_security_policy.rb +25 -0
  111. data/specs_e2e/rails_7_2/config/initializers/filter_parameter_logging.rb +8 -0
  112. data/specs_e2e/{rails_5_2 → rails_7_2}/config/initializers/inflections.rb +4 -4
  113. data/specs_e2e/rails_7_2/config/initializers/permissions_policy.rb +13 -0
  114. data/specs_e2e/rails_7_2/config/locales/en.yml +31 -0
  115. data/specs_e2e/rails_7_2/config/master.key +1 -0
  116. data/specs_e2e/rails_7_2/config/puma.rb +34 -0
  117. data/specs_e2e/rails_7_2/config/routes.rb +5 -0
  118. data/specs_e2e/rails_7_2/config/storage.yml +34 -0
  119. data/specs_e2e/{rails_4_2 → rails_7_2}/config.ru +3 -1
  120. data/specs_e2e/rails_7_2/db/migrate/20180621085832_create_posts.rb +11 -0
  121. data/specs_e2e/rails_7_2/db/seeds.rb +9 -0
  122. data/specs_e2e/rails_7_2/db/test.sqlite3-shm +0 -0
  123. data/specs_e2e/rails_7_2/db/test.sqlite3-wal +0 -0
  124. data/specs_e2e/rails_7_2/package.json +8 -0
  125. data/specs_e2e/rails_7_2/playwright-report/index.html +71 -0
  126. data/specs_e2e/{rails_4_2 → rails_7_2}/public/404.html +6 -6
  127. data/specs_e2e/rails_7_2/public/406-unsupported-browser.html +66 -0
  128. data/specs_e2e/{rails_4_2 → rails_7_2}/public/422.html +6 -6
  129. data/specs_e2e/{rails_4_2 → rails_7_2}/public/500.html +6 -6
  130. data/specs_e2e/rails_7_2/public/icon.png +0 -0
  131. data/specs_e2e/rails_7_2/public/icon.svg +3 -0
  132. data/specs_e2e/rails_7_2/public/robots.txt +1 -0
  133. data/specs_e2e/rails_7_2/storage/test.sqlite3 +0 -0
  134. data/specs_e2e/rails_7_2/test/controllers/posts_controller_test.rb +48 -0
  135. data/specs_e2e/rails_7_2/test/cypress_fixtures/posts.yml +11 -0
  136. data/specs_e2e/rails_7_2/test/fixtures/posts.yml +11 -0
  137. data/specs_e2e/rails_7_2/test/models/post_test.rb +7 -0
  138. data/specs_e2e/rails_7_2/test-results/.last-run.json +4 -0
  139. data/specs_e2e/rails_7_2/test.sh +57 -0
  140. data/specs_e2e/rails_8/.gitattributes +9 -0
  141. data/specs_e2e/rails_8/.gitignore +16 -0
  142. data/specs_e2e/rails_8/.rubocop.yml +8 -0
  143. data/specs_e2e/rails_8/Gemfile +20 -0
  144. data/specs_e2e/{rails_3_2 → rails_8}/Rakefile +2 -3
  145. data/specs_e2e/rails_8/app/assets/stylesheets/application.css +10 -0
  146. data/specs_e2e/rails_8/app/controllers/application_controller.rb +4 -0
  147. data/specs_e2e/rails_8/app/controllers/posts_controller.rb +58 -0
  148. data/specs_e2e/rails_8/app/helpers/posts_helper.rb +2 -0
  149. data/specs_e2e/rails_8/app/jobs/application_job.rb +7 -0
  150. data/specs_e2e/rails_8/app/models/application_record.rb +3 -0
  151. data/specs_e2e/rails_8/app/models/post.rb +2 -0
  152. data/specs_e2e/rails_8/app/views/layouts/application.html.erb +27 -0
  153. data/specs_e2e/rails_8/app/views/posts/_form.html.erb +32 -0
  154. data/specs_e2e/rails_8/app/views/posts/edit.html.erb +6 -0
  155. data/specs_e2e/rails_8/app/views/posts/index.html.erb +31 -0
  156. data/specs_e2e/rails_8/app/views/posts/new.html.erb +5 -0
  157. data/specs_e2e/rails_8/app/views/posts/show.html.erb +19 -0
  158. data/specs_e2e/rails_8/bin/brakeman +7 -0
  159. data/specs_e2e/rails_8/bin/bundle +109 -0
  160. data/specs_e2e/rails_8/bin/dev +2 -0
  161. data/specs_e2e/rails_8/bin/importmap +4 -0
  162. data/specs_e2e/rails_8/bin/rails +4 -0
  163. data/specs_e2e/rails_8/bin/rake +4 -0
  164. data/specs_e2e/rails_8/bin/setup +34 -0
  165. data/specs_e2e/rails_8/bin/thrust +5 -0
  166. data/specs_e2e/rails_8/config/application.rb +27 -0
  167. data/specs_e2e/rails_8/config/boot.rb +4 -0
  168. data/specs_e2e/rails_8/config/cable.yml +17 -0
  169. data/specs_e2e/rails_8/config/cache.yml +16 -0
  170. data/specs_e2e/rails_8/config/credentials.yml.enc +1 -0
  171. data/specs_e2e/rails_8/config/database.yml +41 -0
  172. data/specs_e2e/rails_8/config/deploy.yml +116 -0
  173. data/specs_e2e/rails_8/config/environment.rb +5 -0
  174. data/specs_e2e/rails_8/config/environments/development.rb +57 -0
  175. data/specs_e2e/rails_8/config/environments/production.rb +90 -0
  176. data/specs_e2e/rails_8/config/environments/test.rb +45 -0
  177. data/specs_e2e/rails_8/config/importmap.rb +7 -0
  178. data/specs_e2e/rails_8/config/initializers/content_security_policy.rb +25 -0
  179. data/specs_e2e/rails_8/config/initializers/filter_parameter_logging.rb +8 -0
  180. data/specs_e2e/rails_8/config/initializers/inflections.rb +16 -0
  181. data/specs_e2e/rails_8/config/locales/en.yml +31 -0
  182. data/specs_e2e/rails_8/config/master.key +1 -0
  183. data/specs_e2e/rails_8/config/puma.rb +41 -0
  184. data/specs_e2e/rails_8/config/queue.yml +18 -0
  185. data/specs_e2e/rails_8/config/recurring.yml +10 -0
  186. data/specs_e2e/rails_8/config/routes.rb +5 -0
  187. data/specs_e2e/rails_8/config/storage.yml +34 -0
  188. data/specs_e2e/rails_8/config.ru +6 -0
  189. data/specs_e2e/rails_8/db/cable_schema.rb +11 -0
  190. data/specs_e2e/rails_8/db/cache_schema.rb +14 -0
  191. data/specs_e2e/rails_8/db/migrate/20180621085832_create_posts.rb +11 -0
  192. data/specs_e2e/rails_8/db/queue_schema.rb +129 -0
  193. data/specs_e2e/rails_8/db/seeds.rb +9 -0
  194. data/specs_e2e/rails_8/package.json +8 -0
  195. data/specs_e2e/rails_8/playwright-report/index.html +71 -0
  196. data/specs_e2e/rails_8/public/400.html +114 -0
  197. data/specs_e2e/rails_8/public/404.html +114 -0
  198. data/specs_e2e/rails_8/public/406-unsupported-browser.html +114 -0
  199. data/specs_e2e/rails_8/public/422.html +114 -0
  200. data/specs_e2e/rails_8/public/500.html +114 -0
  201. data/specs_e2e/rails_8/public/icon.png +0 -0
  202. data/specs_e2e/rails_8/public/icon.svg +3 -0
  203. data/specs_e2e/rails_8/public/robots.txt +1 -0
  204. data/specs_e2e/rails_8/storage/test.sqlite3 +0 -0
  205. data/specs_e2e/rails_8/storage/test.sqlite3-shm +0 -0
  206. data/specs_e2e/rails_8/storage/test.sqlite3-wal +0 -0
  207. data/specs_e2e/rails_8/test/application_system_test_case.rb +5 -0
  208. data/specs_e2e/rails_8/test/controllers/posts_controller_test.rb +48 -0
  209. data/specs_e2e/rails_8/test/cypress_fixtures/posts.yml +11 -0
  210. data/specs_e2e/rails_8/test/fixtures/posts.yml +11 -0
  211. data/specs_e2e/rails_8/test/models/post_test.rb +7 -0
  212. data/specs_e2e/rails_8/test/test_helper.rb +15 -0
  213. data/specs_e2e/rails_8/test-results/.last-run.json +4 -0
  214. data/specs_e2e/{rails_5_2 → rails_8}/test.sh +1 -1
  215. metadata +246 -150
  216. data/lib/cypress_on_rails/vcr_middleware.rb +0 -73
  217. data/spec/cypress_on_rails/vcr_middleware_spec.rb +0 -119
  218. data/specs_e2e/rails_3_2/.gitignore +0 -9
  219. data/specs_e2e/rails_3_2/.ruby_version +0 -1
  220. data/specs_e2e/rails_3_2/Gemfile +0 -7
  221. data/specs_e2e/rails_3_2/README.rdoc +0 -261
  222. data/specs_e2e/rails_3_2/app/assets/stylesheets/application.css +0 -13
  223. data/specs_e2e/rails_3_2/app/controllers/application_controller.rb +0 -3
  224. data/specs_e2e/rails_3_2/app/controllers/welcome_controller.rb +0 -4
  225. data/specs_e2e/rails_3_2/app/helpers/application_helper.rb +0 -2
  226. data/specs_e2e/rails_3_2/app/models/post.rb +0 -21
  227. data/specs_e2e/rails_3_2/app/views/layouts/application.html.erb +0 -13
  228. data/specs_e2e/rails_3_2/app/views/welcome/index.html.erb +0 -24
  229. data/specs_e2e/rails_3_2/bin/rails +0 -6
  230. data/specs_e2e/rails_3_2/config/application.rb +0 -68
  231. data/specs_e2e/rails_3_2/config/boot.rb +0 -6
  232. data/specs_e2e/rails_3_2/config/environment.rb +0 -5
  233. data/specs_e2e/rails_3_2/config/environments/development.rb +0 -31
  234. data/specs_e2e/rails_3_2/config/environments/production.rb +0 -64
  235. data/specs_e2e/rails_3_2/config/environments/test.rb +0 -35
  236. data/specs_e2e/rails_3_2/config/initializers/backtrace_silencers.rb +0 -7
  237. data/specs_e2e/rails_3_2/config/initializers/inflections.rb +0 -15
  238. data/specs_e2e/rails_3_2/config/initializers/mime_types.rb +0 -5
  239. data/specs_e2e/rails_3_2/config/initializers/secret_token.rb +0 -7
  240. data/specs_e2e/rails_3_2/config/initializers/session_store.rb +0 -8
  241. data/specs_e2e/rails_3_2/config/locales/en.yml +0 -5
  242. data/specs_e2e/rails_3_2/config/routes.rb +0 -60
  243. data/specs_e2e/rails_3_2/config.ru +0 -4
  244. data/specs_e2e/rails_3_2/public/404.html +0 -26
  245. data/specs_e2e/rails_3_2/public/422.html +0 -26
  246. data/specs_e2e/rails_3_2/public/500.html +0 -25
  247. data/specs_e2e/rails_3_2/public/robots.txt +0 -5
  248. data/specs_e2e/rails_3_2/test.sh +0 -50
  249. data/specs_e2e/rails_4_2/.gitignore +0 -12
  250. data/specs_e2e/rails_4_2/Gemfile +0 -11
  251. data/specs_e2e/rails_4_2/README.rdoc +0 -28
  252. data/specs_e2e/rails_4_2/app/assets/javascripts/using_vcr.js +0 -2
  253. data/specs_e2e/rails_4_2/app/assets/stylesheets/using_vcr.css +0 -4
  254. data/specs_e2e/rails_4_2/app/controllers/application_controller.rb +0 -5
  255. data/specs_e2e/rails_4_2/app/controllers/using_vcr_controller.rb +0 -10
  256. data/specs_e2e/rails_4_2/app/controllers/welcome_controller.rb +0 -4
  257. data/specs_e2e/rails_4_2/app/models/post.rb +0 -23
  258. data/specs_e2e/rails_4_2/app/views/layouts/application.html.erb +0 -12
  259. data/specs_e2e/rails_4_2/app/views/using_vcr/index.html.erb +0 -6
  260. data/specs_e2e/rails_4_2/app/views/using_vcr/record_cats.html.erb +0 -7
  261. data/specs_e2e/rails_4_2/app/views/welcome/index.html.erb +0 -24
  262. data/specs_e2e/rails_4_2/bin/bundle +0 -3
  263. data/specs_e2e/rails_4_2/bin/rails +0 -4
  264. data/specs_e2e/rails_4_2/bin/rake +0 -4
  265. data/specs_e2e/rails_4_2/bin/setup +0 -29
  266. data/specs_e2e/rails_4_2/config/application.rb +0 -32
  267. data/specs_e2e/rails_4_2/config/boot.rb +0 -3
  268. data/specs_e2e/rails_4_2/config/environments/development.rb +0 -25
  269. data/specs_e2e/rails_4_2/config/environments/production.rb +0 -64
  270. data/specs_e2e/rails_4_2/config/environments/test.rb +0 -42
  271. data/specs_e2e/rails_4_2/config/initializers/backtrace_silencers.rb +0 -7
  272. data/specs_e2e/rails_4_2/config/initializers/cookies_serializer.rb +0 -3
  273. data/specs_e2e/rails_4_2/config/initializers/session_store.rb +0 -3
  274. data/specs_e2e/rails_4_2/config/initializers/to_time_preserves_timezone.rb +0 -10
  275. data/specs_e2e/rails_4_2/config/initializers/wrap_parameters.rb +0 -9
  276. data/specs_e2e/rails_4_2/config/locales/en.yml +0 -23
  277. data/specs_e2e/rails_4_2/config/routes.rb +0 -61
  278. data/specs_e2e/rails_4_2/config/secrets.yml +0 -22
  279. data/specs_e2e/rails_4_2/package.json +0 -12
  280. data/specs_e2e/rails_4_2/playwright-report/index.html +0 -62
  281. data/specs_e2e/rails_4_2/public/favicon.ico +0 -0
  282. data/specs_e2e/rails_4_2/public/robots.txt +0 -5
  283. data/specs_e2e/rails_4_2/spec/fixtures/vcr_cassettes/cats.yml +0 -63
  284. data/specs_e2e/rails_5_2/Gemfile +0 -15
  285. data/specs_e2e/rails_5_2/app/assets/javascripts/posts.js +0 -2
  286. data/specs_e2e/rails_5_2/app/assets/stylesheets/posts.css +0 -4
  287. data/specs_e2e/rails_5_2/app/assets/stylesheets/scaffold.css +0 -80
  288. data/specs_e2e/rails_5_2/app/jobs/application_job.rb +0 -2
  289. data/specs_e2e/rails_5_2/app/views/welcome/index.html.erb +0 -5
  290. data/specs_e2e/rails_5_2/bin/bundle +0 -3
  291. data/specs_e2e/rails_5_2/bin/rails +0 -4
  292. data/specs_e2e/rails_5_2/bin/rake +0 -4
  293. data/specs_e2e/rails_5_2/bin/update +0 -25
  294. data/specs_e2e/rails_5_2/config/application.rb +0 -33
  295. data/specs_e2e/rails_5_2/config/boot.rb +0 -4
  296. data/specs_e2e/rails_5_2/config/credentials.yml.enc +0 -1
  297. data/specs_e2e/rails_5_2/config/environments/production.rb +0 -68
  298. data/specs_e2e/rails_5_2/config/initializers/backtrace_silencers.rb +0 -7
  299. data/specs_e2e/rails_5_2/config/initializers/filter_parameter_logging.rb +0 -4
  300. data/specs_e2e/rails_5_2/config/initializers/mime_types.rb +0 -4
  301. data/specs_e2e/rails_5_2/config/initializers/wrap_parameters.rb +0 -9
  302. data/specs_e2e/rails_5_2/config/master.key +0 -1
  303. data/specs_e2e/rails_5_2/public/favicon.ico +0 -0
  304. data/specs_e2e/rails_5_2/public/robots.txt +0 -1
  305. /data/specs_e2e/{rails_5_2 → rails_6_1}/.gitignore +0 -0
  306. /data/specs_e2e/{rails_5_2 → rails_6_1}/app/controllers/application_controller.rb +0 -0
  307. /data/specs_e2e/{rails_5_2 → rails_6_1}/app/controllers/posts_controller.rb +0 -0
  308. /data/specs_e2e/{rails_5_2 → rails_6_1}/app/helpers/posts_helper.rb +0 -0
  309. /data/specs_e2e/{rails_5_2 → rails_6_1}/app/models/application_record.rb +0 -0
  310. /data/specs_e2e/{rails_5_2 → rails_6_1}/app/models/post.rb +0 -0
  311. /data/specs_e2e/{rails_5_2 → rails_6_1}/app/views/posts/_form.html.erb +0 -0
  312. /data/specs_e2e/{rails_5_2 → rails_6_1}/app/views/posts/edit.html.erb +0 -0
  313. /data/specs_e2e/{rails_5_2 → rails_6_1}/app/views/posts/index.html.erb +0 -0
  314. /data/specs_e2e/{rails_5_2 → rails_6_1}/app/views/posts/new.html.erb +0 -0
  315. /data/specs_e2e/{rails_5_2 → rails_6_1}/app/views/posts/show.html.erb +0 -0
  316. /data/specs_e2e/{rails_5_2 → rails_6_1}/config/initializers/application_controller_renderer.rb +0 -0
  317. /data/specs_e2e/{rails_5_2 → rails_6_1}/config/initializers/cookies_serializer.rb +0 -0
  318. /data/specs_e2e/{rails_4_2 → rails_6_1}/config/initializers/inflections.rb +0 -0
  319. /data/specs_e2e/{rails_4_2 → rails_6_1}/config/initializers/mime_types.rb +0 -0
  320. /data/specs_e2e/{rails_5_2 → rails_6_1}/config/routes.rb +0 -0
  321. /data/specs_e2e/{rails_5_2 → rails_6_1}/public/404.html +0 -0
  322. /data/specs_e2e/{rails_5_2 → rails_6_1}/public/422.html +0 -0
  323. /data/specs_e2e/{rails_5_2 → rails_6_1}/public/500.html +0 -0
  324. /data/specs_e2e/{rails_5_2 → rails_6_1}/public/apple-touch-icon-precomposed.png +0 -0
  325. /data/specs_e2e/{rails_5_2 → rails_6_1}/public/apple-touch-icon.png +0 -0
  326. /data/specs_e2e/{rails_3_2 → rails_6_1}/public/favicon.ico +0 -0
  327. /data/specs_e2e/{rails_5_2 → rails_6_1}/test/controllers/posts_controller_test.rb +0 -0
  328. /data/specs_e2e/{rails_5_2 → rails_6_1}/test/cypress_fixtures/posts.yml +0 -0
  329. /data/specs_e2e/{rails_5_2 → rails_6_1}/test/fixtures/posts.yml +0 -0
  330. /data/specs_e2e/{rails_5_2 → rails_6_1}/test/models/post_test.rb +0 -0
  331. /data/specs_e2e/{rails_3_2/log → rails_6_1/vendor}/.keep +0 -0
  332. /data/specs_e2e/{rails_3_2/tmp → rails_7_2/vendor}/.keep +0 -0
  333. /data/specs_e2e/{rails_4_2/spec → rails_7_2/vendor/javascript}/.keep +0 -0
  334. /data/specs_e2e/{rails_5_2 → rails_8}/README.md +0 -0
  335. /data/specs_e2e/{rails_4_2/vendor → rails_8/storage}/.keep +0 -0
  336. /data/specs_e2e/{rails_5_2 → rails_8}/vendor/.keep +0 -0
  337. /data/specs_e2e/{rails_3_2/vendor/.gitkeep → rails_8/vendor/javascript/.keep} +0 -0
@@ -0,0 +1,163 @@
1
+ # Developer Experience Improvements
2
+
3
+ Based on analysis of user issues and feedback, here are the key improvements made to cypress-playwright-on-rails to enhance developer experience.
4
+
5
+ ## 🎯 Issues Addressed
6
+
7
+ ### 1. Manual Server Management (#152, #153)
8
+ **Previous Pain Point:** Users had to manually start Rails server in a separate terminal.
9
+
10
+ **Solution Implemented:**
11
+ - ✅ Added rake tasks: `cypress:open`, `cypress:run`, `playwright:open`, `playwright:run`
12
+ - ✅ Automatic server lifecycle management
13
+ - ✅ Dynamic port selection
14
+ - ✅ Server hooks for customization
15
+
16
+ ### 2. Playwright Feature Parity (#169)
17
+ **Previous Pain Point:** Playwright users lacked documentation and helper functions.
18
+
19
+ **Solution Implemented:**
20
+ - ✅ Comprehensive [Playwright Guide](PLAYWRIGHT_GUIDE.md)
21
+ - ✅ Complete helper functions in examples
22
+ - ✅ Migration guide from Cypress to Playwright
23
+ - ✅ Playwright-specific rake tasks
24
+
25
+ ### 3. VCR Configuration Confusion (#175, #160)
26
+ **Previous Pain Point:** VCR integration was poorly documented and error-prone.
27
+
28
+ **Solution Implemented:**
29
+ - ✅ Detailed [VCR Integration Guide](VCR_GUIDE.md)
30
+ - ✅ Troubleshooting for common VCR errors
31
+ - ✅ GraphQL-specific VCR configuration
32
+ - ✅ Examples for both insert/eject and use_cassette modes
33
+
34
+ ### 4. Test Environment Issues (#157, #118)
35
+ **Previous Pain Point:** Confusion about running in test vs development environment.
36
+
37
+ **Solution Implemented:**
38
+ - ✅ Clear documentation in [Troubleshooting Guide](TROUBLESHOOTING.md)
39
+ - ✅ Environment configuration examples
40
+ - ✅ Support for `CYPRESS_RAILS_HOST` and `CYPRESS_RAILS_PORT`
41
+ - ✅ Guidance on enabling file watching in test environment
42
+
43
+ ### 5. Database Management (#155, #114)
44
+ **Previous Pain Point:** Database cleaning issues and lack of transactional support.
45
+
46
+ **Solution Implemented:**
47
+ - ✅ Transactional test mode with automatic rollback
48
+ - ✅ Smart database cleaning strategies
49
+ - ✅ ApplicationRecord error handling
50
+ - ✅ Rails transactional fixtures support
51
+
52
+ ### 6. Authentication & Security (#137)
53
+ **Previous Pain Point:** No built-in way to secure test endpoints.
54
+
55
+ **Solution Implemented:**
56
+ - ✅ `before_request` hook for authentication
57
+ - ✅ Security best practices documentation
58
+ - ✅ IP whitelisting examples
59
+ - ✅ Token-based authentication examples
60
+
61
+ ## 📊 Impact Summary
62
+
63
+ ### Before These Improvements
64
+ - 😤 Manual server management required
65
+ - 📖 Sparse documentation
66
+ - 🔍 Issues buried in GitHub
67
+ - 🐛 Common errors without solutions
68
+ - 🎭 Playwright as second-class citizen
69
+
70
+ ### After These Improvements
71
+ - 🚀 One-command test execution
72
+ - 📚 Comprehensive documentation
73
+ - 🛠 Solutions for all common issues
74
+ - ✨ Feature parity for Playwright
75
+ - 🔒 Security best practices included
76
+
77
+ ## 🗺 Documentation Structure
78
+
79
+ ```
80
+ docs/
81
+ ├── BEST_PRACTICES.md # Patterns and recommendations
82
+ ├── TROUBLESHOOTING.md # Solutions to common issues
83
+ ├── PLAYWRIGHT_GUIDE.md # Complete Playwright documentation
84
+ ├── VCR_GUIDE.md # VCR integration details
85
+ └── DX_IMPROVEMENTS.md # This file
86
+ ```
87
+
88
+ ## 🚀 Quick Wins for New Users
89
+
90
+ 1. **Start Testing in 30 Seconds**
91
+ ```bash
92
+ gem 'cypress-on-rails'
93
+ bundle install
94
+ rails g cypress_on_rails:install
95
+ rails cypress:open # Done!
96
+ ```
97
+
98
+ 2. **Switch from cypress-rails**
99
+ - Drop-in replacement with same commands
100
+ - Migration guide in CHANGELOG
101
+
102
+ 3. **Debug Failures Easily**
103
+ - Comprehensive troubleshooting guide
104
+ - Common errors with solutions
105
+ - Stack Overflow-style Q&A format
106
+
107
+ ## 🔮 Future Improvements
108
+
109
+ Based on remaining open issues, consider implementing:
110
+
111
+ 1. **Parallel Testing Support (#119)**
112
+ - Native parallel execution
113
+ - Automatic database partitioning
114
+ - CI-specific optimizations
115
+
116
+ 2. **Better Error Messages**
117
+ - Contextual help in error output
118
+ - Links to relevant documentation
119
+ - Suggested fixes
120
+
121
+ 3. **Interactive Setup Wizard**
122
+ - Guided installation process
123
+ - Framework detection
124
+ - Automatic configuration
125
+
126
+ 4. **Performance Monitoring**
127
+ - Test execution metrics
128
+ - Slow test detection
129
+ - Optimization suggestions
130
+
131
+ ## 💡 Developer Experience Principles
132
+
133
+ These improvements follow key DX principles:
134
+
135
+ 1. **Zero to Testing Fast** - Minimize time to first test
136
+ 2. **Pit of Success** - Make the right thing the easy thing
137
+ 3. **Progressive Disclosure** - Simple things simple, complex things possible
138
+ 4. **Excellent Error Messages** - Every error should suggest a solution
139
+ 5. **Documentation as Code** - Keep docs next to implementation
140
+ 6. **Community Driven** - Address real user pain points
141
+
142
+ ## 📈 Metrics of Success
143
+
144
+ Improvements can be measured by:
145
+ - ⬇️ Reduced issue creation for solved problems
146
+ - ⬇️ Decreased time to first successful test
147
+ - ⬆️ Increased adoption rate
148
+ - ⬆️ Higher user satisfaction
149
+ - 🔄 More contributions from community
150
+
151
+ ## 🤝 Contributing
152
+
153
+ To continue improving developer experience:
154
+
155
+ 1. **Report Issues** with detailed reproduction steps
156
+ 2. **Suggest Improvements** via GitHub discussions
157
+ 3. **Share Solutions** that worked for you
158
+ 4. **Contribute Examples** to documentation
159
+ 5. **Help Others** in Slack/forums
160
+
161
+ ## Conclusion
162
+
163
+ These documentation and feature improvements directly address the most common pain points users face. By providing comprehensive guides, troubleshooting resources, and automated solutions, we've significantly improved the developer experience for both new and existing users of cypress-playwright-on-rails.
@@ -0,0 +1,554 @@
1
+ # Complete Playwright Guide
2
+
3
+ This guide provides comprehensive documentation for using Playwright with cypress-playwright-on-rails.
4
+
5
+ ## Table of Contents
6
+ - [Installation](#installation)
7
+ - [Basic Setup](#basic-setup)
8
+ - [Commands and Helpers](#commands-and-helpers)
9
+ - [Factory Bot Integration](#factory-bot-integration)
10
+ - [Fixtures and Scenarios](#fixtures-and-scenarios)
11
+ - [Database Management](#database-management)
12
+ - [Advanced Configuration](#advanced-configuration)
13
+ - [Migration from Cypress](#migration-from-cypress)
14
+
15
+ ## Installation
16
+
17
+ ### 1. Add the gem to your Gemfile
18
+ ```ruby
19
+ group :test, :development do
20
+ gem 'cypress-on-rails', '~> 1.0'
21
+ end
22
+ ```
23
+
24
+ ### 2. Install with Playwright framework
25
+ ```bash
26
+ bundle install
27
+ bin/rails g cypress_on_rails:install --framework playwright
28
+
29
+ # Or with custom folder
30
+ bin/rails g cypress_on_rails:install --framework playwright --install_folder=spec/e2e
31
+ ```
32
+
33
+ ### 3. Install Playwright
34
+ ```bash
35
+ # Using yarn
36
+ yarn add -D @playwright/test
37
+
38
+ # Using npm
39
+ npm install --save-dev @playwright/test
40
+
41
+ # Install browsers
42
+ npx playwright install
43
+ ```
44
+
45
+ ## Basic Setup
46
+
47
+ ### Directory Structure
48
+ ```
49
+ e2e/
50
+ ├── playwright/
51
+ │ ├── e2e/ # Test files
52
+ │ │ └── example.spec.js
53
+ │ ├── support/
54
+ │ │ └── on-rails.js # Helper functions
55
+ │ ├── e2e_helper.rb # Ruby helper
56
+ │ └── app_commands/ # Ruby commands
57
+ │ ├── clean.rb
58
+ │ ├── factory_bot.rb
59
+ │ └── scenarios/
60
+ │ └── basic.rb
61
+ └── playwright.config.js # Playwright configuration
62
+ ```
63
+
64
+ ### Playwright Configuration
65
+ ```js
66
+ // playwright.config.js
67
+ module.exports = {
68
+ testDir: './e2e/playwright/e2e',
69
+ timeout: 30000,
70
+ use: {
71
+ baseURL: process.env.BASE_URL || 'http://localhost:5017',
72
+ trace: 'on-first-retry',
73
+ screenshot: 'only-on-failure',
74
+ video: 'retain-on-failure'
75
+ },
76
+ projects: [
77
+ { name: 'chromium', use: { browserName: 'chromium' } },
78
+ { name: 'firefox', use: { browserName: 'firefox' } },
79
+ { name: 'webkit', use: { browserName: 'webkit' } }
80
+ ]
81
+ };
82
+ ```
83
+
84
+ ## Commands and Helpers
85
+
86
+ ### Complete on-rails.js Helper File
87
+ ```js
88
+ // e2e/playwright/support/on-rails.js
89
+ const { request } = require('@playwright/test');
90
+
91
+ const API_PREFIX = ''; // or '/api' if configured
92
+
93
+ async function appCommands(body) {
94
+ const context = await request.newContext();
95
+ const response = await context.post(`${API_PREFIX}/__e2e__/command`, {
96
+ data: body,
97
+ headers: {
98
+ 'Content-Type': 'application/json'
99
+ }
100
+ });
101
+
102
+ if (!response.ok()) {
103
+ const text = await response.text();
104
+ throw new Error(`Command failed: ${response.status()} - ${text}`);
105
+ }
106
+
107
+ return response.json();
108
+ }
109
+
110
+ async function app(name, commandOptions = {}) {
111
+ const result = await appCommands({
112
+ name,
113
+ options: commandOptions
114
+ });
115
+ return result[0];
116
+ }
117
+
118
+ async function appScenario(name, options = {}) {
119
+ return app(`scenarios/${name}`, options);
120
+ }
121
+
122
+ async function appFactories(factories) {
123
+ return app('factory_bot', factories);
124
+ }
125
+
126
+ async function appFixtures() {
127
+ return app('activerecord_fixtures');
128
+ }
129
+
130
+ async function appClean() {
131
+ return app('clean');
132
+ }
133
+
134
+ async function appEval(code) {
135
+ return app('eval', { code });
136
+ }
137
+
138
+ module.exports = {
139
+ app,
140
+ appCommands,
141
+ appScenario,
142
+ appFactories,
143
+ appFixtures,
144
+ appClean,
145
+ appEval
146
+ };
147
+ ```
148
+
149
+ ### Using Helpers in Tests
150
+ ```js
151
+ // e2e/playwright/e2e/user.spec.js
152
+ const { test, expect } = require('@playwright/test');
153
+ const { app, appFactories, appScenario, appClean } = require('../support/on-rails');
154
+
155
+ test.describe('User Management', () => {
156
+ test.beforeEach(async () => {
157
+ await appClean();
158
+ });
159
+
160
+ test('create and view user', async ({ page }) => {
161
+ // Create user with factory bot
162
+ const users = await appFactories([
163
+ ['create', 'user', { name: 'John Doe', email: 'john@example.com' }]
164
+ ]);
165
+
166
+ await page.goto(`/users/${users[0].id}`);
167
+ await expect(page.locator('h1')).toContainText('John Doe');
168
+ });
169
+
170
+ test('load scenario', async ({ page }) => {
171
+ await appScenario('user_with_posts');
172
+ await page.goto('/users');
173
+ await expect(page.locator('.user-count')).toContainText('5 users');
174
+ });
175
+ });
176
+ ```
177
+
178
+ ## Factory Bot Integration
179
+
180
+ ### Creating Records
181
+ ```js
182
+ test('factory bot examples', async ({ page }) => {
183
+ // Single record
184
+ const user = await appFactories([
185
+ ['create', 'user', { name: 'Alice' }]
186
+ ]);
187
+
188
+ // Multiple records
189
+ const posts = await appFactories([
190
+ ['create_list', 'post', 3, { published: true }]
191
+ ]);
192
+
193
+ // With traits
194
+ const adminUser = await appFactories([
195
+ ['create', 'user', 'admin', { name: 'Admin User' }]
196
+ ]);
197
+
198
+ // With associations
199
+ const postWithComments = await appFactories([
200
+ ['create', 'post', 'with_comments', { comment_count: 5 }]
201
+ ]);
202
+
203
+ // Building without saving
204
+ const userData = await appFactories([
205
+ ['build', 'user', { name: 'Not Saved' }]
206
+ ]);
207
+ });
208
+ ```
209
+
210
+ ### Using Attributes For
211
+ ```js
212
+ test('get factory attributes', async ({ page }) => {
213
+ const attributes = await appFactories([
214
+ ['attributes_for', 'user']
215
+ ]);
216
+
217
+ // Use attributes to fill form
218
+ await page.fill('[name="user[name]"]', attributes[0].name);
219
+ await page.fill('[name="user[email]"]', attributes[0].email);
220
+ });
221
+ ```
222
+
223
+ ## Fixtures and Scenarios
224
+
225
+ ### Loading Rails Fixtures
226
+ ```js
227
+ test('load fixtures', async ({ page }) => {
228
+ await appFixtures();
229
+
230
+ await page.goto('/products');
231
+ // Fixtures are loaded
232
+ });
233
+ ```
234
+
235
+ ### Creating Scenarios
236
+ ```ruby
237
+ # e2e/playwright/app_commands/scenarios/complex_setup.rb
238
+ # Create a complex test scenario
239
+ 5.times do |i|
240
+ user = User.create!(
241
+ name: "User #{i}",
242
+ email: "user#{i}@example.com"
243
+ )
244
+
245
+ 3.times do |j|
246
+ user.posts.create!(
247
+ title: "Post #{j} by User #{i}",
248
+ content: "Content for post #{j}",
249
+ published: j.even?
250
+ )
251
+ end
252
+ end
253
+
254
+ # Add some comments
255
+ Post.published.each do |post|
256
+ 2.times do
257
+ post.comments.create!(
258
+ author: "Commenter",
259
+ content: "Great post!"
260
+ )
261
+ end
262
+ end
263
+ ```
264
+
265
+ Using scenarios in tests:
266
+ ```js
267
+ test('complex scenario', async ({ page }) => {
268
+ await appScenario('complex_setup');
269
+
270
+ await page.goto('/posts');
271
+ await expect(page.locator('.post')).toHaveCount(15);
272
+ await expect(page.locator('.published')).toHaveCount(7);
273
+ });
274
+ ```
275
+
276
+ ## Database Management
277
+
278
+ ### Cleaning Between Tests
279
+ ```js
280
+ // Global setup
281
+ test.beforeEach(async () => {
282
+ await appClean();
283
+ });
284
+
285
+ // Or selectively
286
+ test('with fresh database', async ({ page }) => {
287
+ await appClean();
288
+ await app('load_seed'); // Optionally load seeds
289
+
290
+ // Your test here
291
+ });
292
+ ```
293
+
294
+ ### Custom Clean Commands
295
+ ```ruby
296
+ # e2e/playwright/app_commands/clean.rb
297
+ if defined?(DatabaseCleaner)
298
+ DatabaseCleaner.strategy = :truncation
299
+ DatabaseCleaner.clean
300
+ else
301
+ # Manual cleaning
302
+ tables = ActiveRecord::Base.connection.tables
303
+ tables.delete('schema_migrations')
304
+ tables.delete('ar_internal_metadata')
305
+
306
+ tables.each do |table|
307
+ ActiveRecord::Base.connection.execute("DELETE FROM #{table}")
308
+ end
309
+ end
310
+
311
+ # Reset sequences for PostgreSQL
312
+ if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
313
+ ActiveRecord::Base.connection.tables.each do |table|
314
+ ActiveRecord::Base.connection.reset_pk_sequence!(table)
315
+ end
316
+ end
317
+
318
+ Rails.cache.clear if Rails.cache
319
+ ```
320
+
321
+ ## Advanced Configuration
322
+
323
+ ### Running Custom Ruby Code
324
+ ```js
325
+ test('execute ruby code', async ({ page }) => {
326
+ // Run arbitrary Ruby code
327
+ const result = await appEval(`
328
+ User.count
329
+ `);
330
+ console.log('User count:', result);
331
+
332
+ // More complex evaluation
333
+ const stats = await appEval(`
334
+ {
335
+ users: User.count,
336
+ posts: Post.count,
337
+ latest_user: User.last&.name
338
+ }
339
+ `);
340
+ });
341
+ ```
342
+
343
+ ### Authentication for Commands
344
+ ```js
345
+ // e2e/playwright/support/authenticated-on-rails.js
346
+ const TOKEN = process.env.CYPRESS_SECRET_TOKEN;
347
+
348
+ async function authenticatedCommand(name, options = {}) {
349
+ const context = await request.newContext();
350
+ const response = await context.post('/__e2e__/command', {
351
+ data: {
352
+ name,
353
+ options,
354
+ cypress_token: TOKEN
355
+ },
356
+ headers: {
357
+ 'Content-Type': 'application/json'
358
+ }
359
+ });
360
+
361
+ if (response.status() === 401) {
362
+ throw new Error('Authentication failed');
363
+ }
364
+
365
+ return response.json();
366
+ }
367
+ ```
368
+
369
+ ### Parallel Testing
370
+ ```js
371
+ // playwright.config.js
372
+ module.exports = {
373
+ workers: 4, // Run 4 tests in parallel
374
+ fullyParallel: true,
375
+
376
+ use: {
377
+ // Each worker gets unique database
378
+ baseURL: process.env.BASE_URL || 'http://localhost:5017',
379
+ },
380
+
381
+ globalSetup: './global-setup.js',
382
+ globalTeardown: './global-teardown.js'
383
+ };
384
+
385
+ // global-setup.js
386
+ module.exports = async config => {
387
+ // Setup databases for parallel workers
388
+ for (let i = 0; i < config.workers; i++) {
389
+ process.env[`TEST_ENV_NUMBER_${i}`] = i.toString();
390
+ }
391
+ };
392
+ ```
393
+
394
+ ## Migration from Cypress
395
+
396
+ ### Command Comparison
397
+
398
+ | Cypress | Playwright |
399
+ |---------|------------|
400
+ | `cy.app('clean')` | `await app('clean')` |
401
+ | `cy.appFactories([...])` | `await appFactories([...])` |
402
+ | `cy.appScenario('name')` | `await appScenario('name')` |
403
+ | `cy.visit('/path')` | `await page.goto('/path')` |
404
+ | `cy.contains('text')` | `await expect(page.locator('text')).toBeVisible()` |
405
+ | `cy.get('.class')` | `page.locator('.class')` |
406
+ | `cy.click()` | `await locator.click()` |
407
+
408
+ ### Converting Test Files
409
+ ```js
410
+ // Cypress version
411
+ describe('Test', () => {
412
+ beforeEach(() => {
413
+ cy.app('clean');
414
+ cy.appFactories([
415
+ ['create', 'user', { name: 'Test' }]
416
+ ]);
417
+ });
418
+
419
+ it('works', () => {
420
+ cy.visit('/users');
421
+ cy.contains('Test');
422
+ });
423
+ });
424
+
425
+ // Playwright version
426
+ const { test, expect } = require('@playwright/test');
427
+ const { app, appFactories } = require('../support/on-rails');
428
+
429
+ test.describe('Test', () => {
430
+ test.beforeEach(async () => {
431
+ await app('clean');
432
+ await appFactories([
433
+ ['create', 'user', { name: 'Test' }]
434
+ ]);
435
+ });
436
+
437
+ test('works', async ({ page }) => {
438
+ await page.goto('/users');
439
+ await expect(page.locator('text=Test')).toBeVisible();
440
+ });
441
+ });
442
+ ```
443
+
444
+ ## Running Tests
445
+
446
+ ### Using Rake Tasks
447
+ ```bash
448
+ # Open Playwright UI
449
+ bin/rails playwright:open
450
+
451
+ # Run tests headless
452
+ bin/rails playwright:run
453
+ ```
454
+
455
+ ### Manual Execution
456
+ ```bash
457
+ # Start Rails server
458
+ CYPRESS=1 bin/rails server -p 5017
459
+
460
+ # In another terminal
461
+ npx playwright test
462
+
463
+ # With specific browser
464
+ npx playwright test --project=chromium
465
+
466
+ # With UI mode
467
+ npx playwright test --ui
468
+
469
+ # Debug mode
470
+ npx playwright test --debug
471
+ ```
472
+
473
+ ### CI Configuration
474
+ ```yaml
475
+ # .github/workflows/playwright.yml
476
+ name: Playwright Tests
477
+ on: [push, pull_request]
478
+
479
+ jobs:
480
+ test:
481
+ runs-on: ubuntu-latest
482
+ steps:
483
+ - uses: actions/checkout@v3
484
+ - uses: actions/setup-node@v3
485
+ - uses: ruby/setup-ruby@v1
486
+ with:
487
+ bundler-cache: true
488
+
489
+ - run: yarn install
490
+ - run: npx playwright install --with-deps
491
+
492
+ - run: bundle exec rails db:create db:schema:load
493
+ env:
494
+ RAILS_ENV: test
495
+
496
+ - run: bundle exec rails playwright:run
497
+ env:
498
+ RAILS_ENV: test
499
+
500
+ - uses: actions/upload-artifact@v3
501
+ if: failure()
502
+ with:
503
+ name: playwright-traces
504
+ path: test-results/
505
+ ```
506
+
507
+ ## Best Practices
508
+
509
+ 1. **Always clean between tests** to ensure isolation
510
+ 2. **Use Page Object Model** for complex applications
511
+ 3. **Leverage Playwright's auto-waiting** instead of explicit waits
512
+ 4. **Run tests in parallel** for faster CI
513
+ 5. **Use fixtures for static data**, factories for dynamic data
514
+ 6. **Commit test recordings** for debugging failures
515
+
516
+ ## Debugging
517
+
518
+ ### Enable Debug Mode
519
+ ```bash
520
+ # Run with debug
521
+ PWDEBUG=1 npx playwright test
522
+
523
+ # This will:
524
+ # - Open browser in headed mode
525
+ # - Open Playwright Inspector
526
+ # - Pause at the start of each test
527
+ ```
528
+
529
+ ### Using Traces
530
+ ```js
531
+ // Enable traces for debugging
532
+ const { chromium } = require('playwright');
533
+
534
+ test('debug this', async ({ page }, testInfo) => {
535
+ // Start tracing
536
+ await page.context().tracing.start({
537
+ screenshots: true,
538
+ snapshots: true
539
+ });
540
+
541
+ // Your test
542
+ await page.goto('/');
543
+
544
+ // Save trace
545
+ await page.context().tracing.stop({
546
+ path: `trace-${testInfo.title}.zip`
547
+ });
548
+ });
549
+ ```
550
+
551
+ View traces:
552
+ ```bash
553
+ npx playwright show-trace trace-debug-this.zip
554
+ ```