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.
- checksums.yaml +4 -4
- data/.github/workflows/claude-code-review.yml +57 -0
- data/.github/workflows/claude.yml +50 -0
- data/.github/workflows/ruby.yml +14 -14
- data/CHANGELOG.md +319 -98
- data/README.md +271 -23
- data/RELEASING.md +200 -0
- data/Rakefile +1 -4
- data/cypress-on-rails.gemspec +1 -0
- data/docs/BEST_PRACTICES.md +678 -0
- data/docs/DX_IMPROVEMENTS.md +163 -0
- data/docs/PLAYWRIGHT_GUIDE.md +554 -0
- data/docs/RELEASE.md +124 -0
- data/docs/TROUBLESHOOTING.md +351 -0
- data/docs/VCR_GUIDE.md +499 -0
- data/docs/authentication.md +30 -0
- data/docs/factory_bot_associations.md +14 -0
- data/lib/cypress_on_rails/configuration.rb +29 -0
- data/lib/cypress_on_rails/railtie.rb +17 -2
- data/lib/cypress_on_rails/server.rb +197 -0
- data/lib/cypress_on_rails/state_reset_middleware.rb +58 -0
- data/lib/cypress_on_rails/vcr/insert_eject_middleware.rb +75 -0
- data/lib/cypress_on_rails/vcr/middleware_helpers.rb +51 -0
- data/lib/cypress_on_rails/vcr/use_cassette_middleware.rb +56 -0
- data/lib/cypress_on_rails/version.rb +1 -1
- data/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb +20 -0
- data/lib/generators/cypress_on_rails/templates/spec/cypress/e2e/rails_examples/using_factory_bot.cy.js +2 -2
- data/lib/generators/cypress_on_rails/templates/spec/cypress/e2e/rails_examples/using_scenarios.cy.js +1 -1
- data/lib/generators/cypress_on_rails/templates/spec/cypress/support/commands.js +22 -0
- data/lib/generators/cypress_on_rails/templates/spec/cypress/support/on-rails.js +2 -1
- data/lib/generators/cypress_on_rails/templates/spec/e2e/e2e_helper.rb.erb +0 -5
- data/lib/tasks/cypress.rake +33 -0
- data/rakelib/release.rake +80 -0
- data/rakelib/task_helpers.rb +23 -0
- data/rakelib/update_changelog.rake +63 -0
- data/spec/cypress_on_rails/configuration_spec.rb +4 -1
- data/spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb +177 -0
- data/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb +68 -0
- data/specs_e2e/rails_6_1/.gitattributes +10 -0
- data/specs_e2e/rails_6_1/Gemfile +20 -0
- data/specs_e2e/{rails_5_2 → rails_6_1}/Rakefile +1 -1
- data/specs_e2e/rails_6_1/app/assets/stylesheets/application.css +15 -0
- data/specs_e2e/rails_6_1/app/jobs/application_job.rb +7 -0
- data/specs_e2e/{rails_5_2 → rails_6_1}/app/views/layouts/application.html.erb +1 -1
- data/specs_e2e/rails_6_1/bin/bundle +114 -0
- data/specs_e2e/rails_6_1/bin/rails +5 -0
- data/specs_e2e/rails_6_1/bin/rake +5 -0
- data/specs_e2e/{rails_5_2 → rails_6_1}/bin/setup +15 -4
- data/specs_e2e/rails_6_1/bin/spring +14 -0
- data/specs_e2e/rails_6_1/bin/yarn +17 -0
- data/specs_e2e/rails_6_1/config/application.rb +34 -0
- data/specs_e2e/rails_6_1/config/boot.rb +4 -0
- data/specs_e2e/rails_6_1/config/cable.yml +10 -0
- data/specs_e2e/rails_6_1/config/credentials.yml.enc +1 -0
- data/specs_e2e/{rails_5_2 → rails_6_1}/config/database.yml +7 -0
- data/specs_e2e/{rails_5_2 → rails_6_1}/config/environment.rb +1 -1
- data/specs_e2e/{rails_5_2 → rails_6_1}/config/environments/development.rb +22 -5
- data/specs_e2e/rails_6_1/config/environments/production.rb +120 -0
- data/specs_e2e/{rails_5_2 → rails_6_1}/config/environments/test.rb +24 -7
- data/specs_e2e/rails_6_1/config/initializers/backtrace_silencers.rb +8 -0
- data/specs_e2e/{rails_5_2 → rails_6_1}/config/initializers/content_security_policy.rb +5 -0
- data/specs_e2e/{rails_4_2 → rails_6_1}/config/initializers/filter_parameter_logging.rb +3 -1
- data/specs_e2e/rails_6_1/config/initializers/permissions_policy.rb +11 -0
- data/specs_e2e/{rails_3_2 → rails_6_1}/config/initializers/wrap_parameters.rb +5 -1
- data/specs_e2e/{rails_5_2 → rails_6_1}/config/locales/en.yml +1 -1
- data/specs_e2e/rails_6_1/config/master.key +1 -0
- data/specs_e2e/rails_6_1/config/puma.rb +43 -0
- data/specs_e2e/rails_6_1/config/storage.yml +34 -0
- data/specs_e2e/{rails_5_2 → rails_6_1}/config.ru +2 -1
- data/specs_e2e/{rails_5_2 → rails_6_1}/db/migrate/20180621085832_create_posts.rb +1 -1
- data/specs_e2e/rails_6_1/package.json +8 -0
- data/specs_e2e/rails_6_1/playwright-report/index.html +71 -0
- data/specs_e2e/rails_6_1/public/robots.txt +1 -0
- data/specs_e2e/rails_6_1/test-results/.last-run.json +4 -0
- data/specs_e2e/{rails_4_2 → rails_6_1}/test.sh +22 -15
- data/specs_e2e/rails_7_2/.gitattributes +9 -0
- data/specs_e2e/rails_7_2/.gitignore +16 -0
- data/specs_e2e/rails_7_2/.rubocop.yml +8 -0
- data/specs_e2e/rails_7_2/Gemfile +11 -0
- data/specs_e2e/{rails_4_2 → rails_7_2}/Rakefile +1 -1
- data/specs_e2e/rails_7_2/app/assets/stylesheets/application.css +15 -0
- data/specs_e2e/rails_7_2/app/controllers/application_controller.rb +4 -0
- data/specs_e2e/rails_7_2/app/controllers/posts_controller.rb +58 -0
- data/specs_e2e/rails_7_2/app/helpers/posts_helper.rb +2 -0
- data/specs_e2e/rails_7_2/app/jobs/application_job.rb +7 -0
- data/specs_e2e/rails_7_2/app/models/application_record.rb +3 -0
- data/specs_e2e/rails_7_2/app/models/post.rb +2 -0
- data/specs_e2e/rails_7_2/app/views/layouts/application.html.erb +22 -0
- data/specs_e2e/rails_7_2/app/views/posts/_form.html.erb +32 -0
- data/specs_e2e/rails_7_2/app/views/posts/edit.html.erb +6 -0
- data/specs_e2e/rails_7_2/app/views/posts/index.html.erb +31 -0
- data/specs_e2e/rails_7_2/app/views/posts/new.html.erb +5 -0
- data/specs_e2e/rails_7_2/app/views/posts/show.html.erb +19 -0
- data/specs_e2e/rails_7_2/bin/brakeman +7 -0
- data/specs_e2e/rails_7_2/bin/bundle +109 -0
- data/specs_e2e/rails_7_2/bin/importmap +4 -0
- data/specs_e2e/rails_7_2/bin/rails +4 -0
- data/specs_e2e/rails_7_2/bin/rake +4 -0
- data/specs_e2e/rails_7_2/bin/setup +37 -0
- data/specs_e2e/rails_7_2/config/application.rb +37 -0
- data/specs_e2e/rails_7_2/config/boot.rb +4 -0
- data/specs_e2e/rails_7_2/config/cable.yml +10 -0
- data/specs_e2e/rails_7_2/config/credentials.yml.enc +1 -0
- data/specs_e2e/rails_7_2/config/database.yml +32 -0
- data/specs_e2e/{rails_4_2 → rails_7_2}/config/environment.rb +1 -1
- data/specs_e2e/rails_7_2/config/environments/development.rb +54 -0
- data/specs_e2e/rails_7_2/config/environments/production.rb +105 -0
- data/specs_e2e/rails_7_2/config/environments/test.rb +45 -0
- data/specs_e2e/rails_7_2/config/importmap.rb +7 -0
- data/specs_e2e/rails_7_2/config/initializers/content_security_policy.rb +25 -0
- data/specs_e2e/rails_7_2/config/initializers/filter_parameter_logging.rb +8 -0
- data/specs_e2e/{rails_5_2 → rails_7_2}/config/initializers/inflections.rb +4 -4
- data/specs_e2e/rails_7_2/config/initializers/permissions_policy.rb +13 -0
- data/specs_e2e/rails_7_2/config/locales/en.yml +31 -0
- data/specs_e2e/rails_7_2/config/master.key +1 -0
- data/specs_e2e/rails_7_2/config/puma.rb +34 -0
- data/specs_e2e/rails_7_2/config/routes.rb +5 -0
- data/specs_e2e/rails_7_2/config/storage.yml +34 -0
- data/specs_e2e/{rails_4_2 → rails_7_2}/config.ru +3 -1
- data/specs_e2e/rails_7_2/db/migrate/20180621085832_create_posts.rb +11 -0
- data/specs_e2e/rails_7_2/db/seeds.rb +9 -0
- data/specs_e2e/rails_7_2/db/test.sqlite3-shm +0 -0
- data/specs_e2e/rails_7_2/db/test.sqlite3-wal +0 -0
- data/specs_e2e/rails_7_2/package.json +8 -0
- data/specs_e2e/rails_7_2/playwright-report/index.html +71 -0
- data/specs_e2e/{rails_4_2 → rails_7_2}/public/404.html +6 -6
- data/specs_e2e/rails_7_2/public/406-unsupported-browser.html +66 -0
- data/specs_e2e/{rails_4_2 → rails_7_2}/public/422.html +6 -6
- data/specs_e2e/{rails_4_2 → rails_7_2}/public/500.html +6 -6
- data/specs_e2e/rails_7_2/public/icon.png +0 -0
- data/specs_e2e/rails_7_2/public/icon.svg +3 -0
- data/specs_e2e/rails_7_2/public/robots.txt +1 -0
- data/specs_e2e/rails_7_2/storage/test.sqlite3 +0 -0
- data/specs_e2e/rails_7_2/test/controllers/posts_controller_test.rb +48 -0
- data/specs_e2e/rails_7_2/test/cypress_fixtures/posts.yml +11 -0
- data/specs_e2e/rails_7_2/test/fixtures/posts.yml +11 -0
- data/specs_e2e/rails_7_2/test/models/post_test.rb +7 -0
- data/specs_e2e/rails_7_2/test-results/.last-run.json +4 -0
- data/specs_e2e/rails_7_2/test.sh +57 -0
- data/specs_e2e/rails_8/.gitattributes +9 -0
- data/specs_e2e/rails_8/.gitignore +16 -0
- data/specs_e2e/rails_8/.rubocop.yml +8 -0
- data/specs_e2e/rails_8/Gemfile +20 -0
- data/specs_e2e/{rails_3_2 → rails_8}/Rakefile +2 -3
- data/specs_e2e/rails_8/app/assets/stylesheets/application.css +10 -0
- data/specs_e2e/rails_8/app/controllers/application_controller.rb +4 -0
- data/specs_e2e/rails_8/app/controllers/posts_controller.rb +58 -0
- data/specs_e2e/rails_8/app/helpers/posts_helper.rb +2 -0
- data/specs_e2e/rails_8/app/jobs/application_job.rb +7 -0
- data/specs_e2e/rails_8/app/models/application_record.rb +3 -0
- data/specs_e2e/rails_8/app/models/post.rb +2 -0
- data/specs_e2e/rails_8/app/views/layouts/application.html.erb +27 -0
- data/specs_e2e/rails_8/app/views/posts/_form.html.erb +32 -0
- data/specs_e2e/rails_8/app/views/posts/edit.html.erb +6 -0
- data/specs_e2e/rails_8/app/views/posts/index.html.erb +31 -0
- data/specs_e2e/rails_8/app/views/posts/new.html.erb +5 -0
- data/specs_e2e/rails_8/app/views/posts/show.html.erb +19 -0
- data/specs_e2e/rails_8/bin/brakeman +7 -0
- data/specs_e2e/rails_8/bin/bundle +109 -0
- data/specs_e2e/rails_8/bin/dev +2 -0
- data/specs_e2e/rails_8/bin/importmap +4 -0
- data/specs_e2e/rails_8/bin/rails +4 -0
- data/specs_e2e/rails_8/bin/rake +4 -0
- data/specs_e2e/rails_8/bin/setup +34 -0
- data/specs_e2e/rails_8/bin/thrust +5 -0
- data/specs_e2e/rails_8/config/application.rb +27 -0
- data/specs_e2e/rails_8/config/boot.rb +4 -0
- data/specs_e2e/rails_8/config/cable.yml +17 -0
- data/specs_e2e/rails_8/config/cache.yml +16 -0
- data/specs_e2e/rails_8/config/credentials.yml.enc +1 -0
- data/specs_e2e/rails_8/config/database.yml +41 -0
- data/specs_e2e/rails_8/config/deploy.yml +116 -0
- data/specs_e2e/rails_8/config/environment.rb +5 -0
- data/specs_e2e/rails_8/config/environments/development.rb +57 -0
- data/specs_e2e/rails_8/config/environments/production.rb +90 -0
- data/specs_e2e/rails_8/config/environments/test.rb +45 -0
- data/specs_e2e/rails_8/config/importmap.rb +7 -0
- data/specs_e2e/rails_8/config/initializers/content_security_policy.rb +25 -0
- data/specs_e2e/rails_8/config/initializers/filter_parameter_logging.rb +8 -0
- data/specs_e2e/rails_8/config/initializers/inflections.rb +16 -0
- data/specs_e2e/rails_8/config/locales/en.yml +31 -0
- data/specs_e2e/rails_8/config/master.key +1 -0
- data/specs_e2e/rails_8/config/puma.rb +41 -0
- data/specs_e2e/rails_8/config/queue.yml +18 -0
- data/specs_e2e/rails_8/config/recurring.yml +10 -0
- data/specs_e2e/rails_8/config/routes.rb +5 -0
- data/specs_e2e/rails_8/config/storage.yml +34 -0
- data/specs_e2e/rails_8/config.ru +6 -0
- data/specs_e2e/rails_8/db/cable_schema.rb +11 -0
- data/specs_e2e/rails_8/db/cache_schema.rb +14 -0
- data/specs_e2e/rails_8/db/migrate/20180621085832_create_posts.rb +11 -0
- data/specs_e2e/rails_8/db/queue_schema.rb +129 -0
- data/specs_e2e/rails_8/db/seeds.rb +9 -0
- data/specs_e2e/rails_8/package.json +8 -0
- data/specs_e2e/rails_8/playwright-report/index.html +71 -0
- data/specs_e2e/rails_8/public/400.html +114 -0
- data/specs_e2e/rails_8/public/404.html +114 -0
- data/specs_e2e/rails_8/public/406-unsupported-browser.html +114 -0
- data/specs_e2e/rails_8/public/422.html +114 -0
- data/specs_e2e/rails_8/public/500.html +114 -0
- data/specs_e2e/rails_8/public/icon.png +0 -0
- data/specs_e2e/rails_8/public/icon.svg +3 -0
- data/specs_e2e/rails_8/public/robots.txt +1 -0
- data/specs_e2e/rails_8/storage/test.sqlite3 +0 -0
- data/specs_e2e/rails_8/storage/test.sqlite3-shm +0 -0
- data/specs_e2e/rails_8/storage/test.sqlite3-wal +0 -0
- data/specs_e2e/rails_8/test/application_system_test_case.rb +5 -0
- data/specs_e2e/rails_8/test/controllers/posts_controller_test.rb +48 -0
- data/specs_e2e/rails_8/test/cypress_fixtures/posts.yml +11 -0
- data/specs_e2e/rails_8/test/fixtures/posts.yml +11 -0
- data/specs_e2e/rails_8/test/models/post_test.rb +7 -0
- data/specs_e2e/rails_8/test/test_helper.rb +15 -0
- data/specs_e2e/rails_8/test-results/.last-run.json +4 -0
- data/specs_e2e/{rails_5_2 → rails_8}/test.sh +1 -1
- metadata +246 -150
- data/lib/cypress_on_rails/vcr_middleware.rb +0 -73
- data/spec/cypress_on_rails/vcr_middleware_spec.rb +0 -119
- data/specs_e2e/rails_3_2/.gitignore +0 -9
- data/specs_e2e/rails_3_2/.ruby_version +0 -1
- data/specs_e2e/rails_3_2/Gemfile +0 -7
- data/specs_e2e/rails_3_2/README.rdoc +0 -261
- data/specs_e2e/rails_3_2/app/assets/stylesheets/application.css +0 -13
- data/specs_e2e/rails_3_2/app/controllers/application_controller.rb +0 -3
- data/specs_e2e/rails_3_2/app/controllers/welcome_controller.rb +0 -4
- data/specs_e2e/rails_3_2/app/helpers/application_helper.rb +0 -2
- data/specs_e2e/rails_3_2/app/models/post.rb +0 -21
- data/specs_e2e/rails_3_2/app/views/layouts/application.html.erb +0 -13
- data/specs_e2e/rails_3_2/app/views/welcome/index.html.erb +0 -24
- data/specs_e2e/rails_3_2/bin/rails +0 -6
- data/specs_e2e/rails_3_2/config/application.rb +0 -68
- data/specs_e2e/rails_3_2/config/boot.rb +0 -6
- data/specs_e2e/rails_3_2/config/environment.rb +0 -5
- data/specs_e2e/rails_3_2/config/environments/development.rb +0 -31
- data/specs_e2e/rails_3_2/config/environments/production.rb +0 -64
- data/specs_e2e/rails_3_2/config/environments/test.rb +0 -35
- data/specs_e2e/rails_3_2/config/initializers/backtrace_silencers.rb +0 -7
- data/specs_e2e/rails_3_2/config/initializers/inflections.rb +0 -15
- data/specs_e2e/rails_3_2/config/initializers/mime_types.rb +0 -5
- data/specs_e2e/rails_3_2/config/initializers/secret_token.rb +0 -7
- data/specs_e2e/rails_3_2/config/initializers/session_store.rb +0 -8
- data/specs_e2e/rails_3_2/config/locales/en.yml +0 -5
- data/specs_e2e/rails_3_2/config/routes.rb +0 -60
- data/specs_e2e/rails_3_2/config.ru +0 -4
- data/specs_e2e/rails_3_2/public/404.html +0 -26
- data/specs_e2e/rails_3_2/public/422.html +0 -26
- data/specs_e2e/rails_3_2/public/500.html +0 -25
- data/specs_e2e/rails_3_2/public/robots.txt +0 -5
- data/specs_e2e/rails_3_2/test.sh +0 -50
- data/specs_e2e/rails_4_2/.gitignore +0 -12
- data/specs_e2e/rails_4_2/Gemfile +0 -11
- data/specs_e2e/rails_4_2/README.rdoc +0 -28
- data/specs_e2e/rails_4_2/app/assets/javascripts/using_vcr.js +0 -2
- data/specs_e2e/rails_4_2/app/assets/stylesheets/using_vcr.css +0 -4
- data/specs_e2e/rails_4_2/app/controllers/application_controller.rb +0 -5
- data/specs_e2e/rails_4_2/app/controllers/using_vcr_controller.rb +0 -10
- data/specs_e2e/rails_4_2/app/controllers/welcome_controller.rb +0 -4
- data/specs_e2e/rails_4_2/app/models/post.rb +0 -23
- data/specs_e2e/rails_4_2/app/views/layouts/application.html.erb +0 -12
- data/specs_e2e/rails_4_2/app/views/using_vcr/index.html.erb +0 -6
- data/specs_e2e/rails_4_2/app/views/using_vcr/record_cats.html.erb +0 -7
- data/specs_e2e/rails_4_2/app/views/welcome/index.html.erb +0 -24
- data/specs_e2e/rails_4_2/bin/bundle +0 -3
- data/specs_e2e/rails_4_2/bin/rails +0 -4
- data/specs_e2e/rails_4_2/bin/rake +0 -4
- data/specs_e2e/rails_4_2/bin/setup +0 -29
- data/specs_e2e/rails_4_2/config/application.rb +0 -32
- data/specs_e2e/rails_4_2/config/boot.rb +0 -3
- data/specs_e2e/rails_4_2/config/environments/development.rb +0 -25
- data/specs_e2e/rails_4_2/config/environments/production.rb +0 -64
- data/specs_e2e/rails_4_2/config/environments/test.rb +0 -42
- data/specs_e2e/rails_4_2/config/initializers/backtrace_silencers.rb +0 -7
- data/specs_e2e/rails_4_2/config/initializers/cookies_serializer.rb +0 -3
- data/specs_e2e/rails_4_2/config/initializers/session_store.rb +0 -3
- data/specs_e2e/rails_4_2/config/initializers/to_time_preserves_timezone.rb +0 -10
- data/specs_e2e/rails_4_2/config/initializers/wrap_parameters.rb +0 -9
- data/specs_e2e/rails_4_2/config/locales/en.yml +0 -23
- data/specs_e2e/rails_4_2/config/routes.rb +0 -61
- data/specs_e2e/rails_4_2/config/secrets.yml +0 -22
- data/specs_e2e/rails_4_2/package.json +0 -12
- data/specs_e2e/rails_4_2/playwright-report/index.html +0 -62
- data/specs_e2e/rails_4_2/public/favicon.ico +0 -0
- data/specs_e2e/rails_4_2/public/robots.txt +0 -5
- data/specs_e2e/rails_4_2/spec/fixtures/vcr_cassettes/cats.yml +0 -63
- data/specs_e2e/rails_5_2/Gemfile +0 -15
- data/specs_e2e/rails_5_2/app/assets/javascripts/posts.js +0 -2
- data/specs_e2e/rails_5_2/app/assets/stylesheets/posts.css +0 -4
- data/specs_e2e/rails_5_2/app/assets/stylesheets/scaffold.css +0 -80
- data/specs_e2e/rails_5_2/app/jobs/application_job.rb +0 -2
- data/specs_e2e/rails_5_2/app/views/welcome/index.html.erb +0 -5
- data/specs_e2e/rails_5_2/bin/bundle +0 -3
- data/specs_e2e/rails_5_2/bin/rails +0 -4
- data/specs_e2e/rails_5_2/bin/rake +0 -4
- data/specs_e2e/rails_5_2/bin/update +0 -25
- data/specs_e2e/rails_5_2/config/application.rb +0 -33
- data/specs_e2e/rails_5_2/config/boot.rb +0 -4
- data/specs_e2e/rails_5_2/config/credentials.yml.enc +0 -1
- data/specs_e2e/rails_5_2/config/environments/production.rb +0 -68
- data/specs_e2e/rails_5_2/config/initializers/backtrace_silencers.rb +0 -7
- data/specs_e2e/rails_5_2/config/initializers/filter_parameter_logging.rb +0 -4
- data/specs_e2e/rails_5_2/config/initializers/mime_types.rb +0 -4
- data/specs_e2e/rails_5_2/config/initializers/wrap_parameters.rb +0 -9
- data/specs_e2e/rails_5_2/config/master.key +0 -1
- data/specs_e2e/rails_5_2/public/favicon.ico +0 -0
- data/specs_e2e/rails_5_2/public/robots.txt +0 -1
- /data/specs_e2e/{rails_5_2 → rails_6_1}/.gitignore +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/app/controllers/application_controller.rb +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/app/controllers/posts_controller.rb +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/app/helpers/posts_helper.rb +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/app/models/application_record.rb +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/app/models/post.rb +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/app/views/posts/_form.html.erb +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/app/views/posts/edit.html.erb +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/app/views/posts/index.html.erb +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/app/views/posts/new.html.erb +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/app/views/posts/show.html.erb +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/config/initializers/application_controller_renderer.rb +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/config/initializers/cookies_serializer.rb +0 -0
- /data/specs_e2e/{rails_4_2 → rails_6_1}/config/initializers/inflections.rb +0 -0
- /data/specs_e2e/{rails_4_2 → rails_6_1}/config/initializers/mime_types.rb +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/config/routes.rb +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/public/404.html +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/public/422.html +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/public/500.html +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/public/apple-touch-icon-precomposed.png +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/public/apple-touch-icon.png +0 -0
- /data/specs_e2e/{rails_3_2 → rails_6_1}/public/favicon.ico +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/test/controllers/posts_controller_test.rb +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/test/cypress_fixtures/posts.yml +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/test/fixtures/posts.yml +0 -0
- /data/specs_e2e/{rails_5_2 → rails_6_1}/test/models/post_test.rb +0 -0
- /data/specs_e2e/{rails_3_2/log → rails_6_1/vendor}/.keep +0 -0
- /data/specs_e2e/{rails_3_2/tmp → rails_7_2/vendor}/.keep +0 -0
- /data/specs_e2e/{rails_4_2/spec → rails_7_2/vendor/javascript}/.keep +0 -0
- /data/specs_e2e/{rails_5_2 → rails_8}/README.md +0 -0
- /data/specs_e2e/{rails_4_2/vendor → rails_8/storage}/.keep +0 -0
- /data/specs_e2e/{rails_5_2 → rails_8}/vendor/.keep +0 -0
- /data/specs_e2e/{rails_3_2/vendor/.gitkeep → rails_8/vendor/javascript/.keep} +0 -0
@@ -0,0 +1,678 @@
|
|
1
|
+
# Best Practices Guide
|
2
|
+
|
3
|
+
This guide provides recommended patterns and practices for using cypress-playwright-on-rails effectively.
|
4
|
+
|
5
|
+
## Table of Contents
|
6
|
+
- [Project Structure](#project-structure)
|
7
|
+
- [Test Organization](#test-organization)
|
8
|
+
- [Data Management](#data-management)
|
9
|
+
- [Performance Optimization](#performance-optimization)
|
10
|
+
- [CI/CD Integration](#cicd-integration)
|
11
|
+
- [Security Considerations](#security-considerations)
|
12
|
+
- [Debugging Strategies](#debugging-strategies)
|
13
|
+
- [Common Patterns](#common-patterns)
|
14
|
+
|
15
|
+
## Project Structure
|
16
|
+
|
17
|
+
### Recommended Directory Layout
|
18
|
+
```
|
19
|
+
├── e2e/ # All E2E test related files
|
20
|
+
│ ├── cypress/ # Cypress tests
|
21
|
+
│ │ ├── e2e/ # Test specs
|
22
|
+
│ │ │ ├── auth/ # Grouped by feature
|
23
|
+
│ │ │ ├── users/
|
24
|
+
│ │ │ └── products/
|
25
|
+
│ │ ├── fixtures/ # Test data
|
26
|
+
│ │ ├── support/ # Helpers and commands
|
27
|
+
│ │ └── downloads/ # Downloaded files during tests
|
28
|
+
│ ├── playwright/ # Playwright tests
|
29
|
+
│ │ ├── e2e/ # Test specs
|
30
|
+
│ │ └── support/ # Helpers
|
31
|
+
│ ├── app_commands/ # Shared Ruby commands
|
32
|
+
│ │ ├── scenarios/ # Complex test setups
|
33
|
+
│ │ └── helpers/ # Ruby helper modules
|
34
|
+
│ └── shared/ # Shared utilities
|
35
|
+
└── config/
|
36
|
+
└── initializers/
|
37
|
+
└── cypress_on_rails.rb # Configuration
|
38
|
+
```
|
39
|
+
|
40
|
+
### Separating Concerns
|
41
|
+
```ruby
|
42
|
+
# e2e/app_commands/helpers/test_data.rb
|
43
|
+
module TestData
|
44
|
+
def self.standard_user
|
45
|
+
{
|
46
|
+
name: 'John Doe',
|
47
|
+
email: 'john@example.com',
|
48
|
+
role: 'user'
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.admin_user
|
53
|
+
{
|
54
|
+
name: 'Admin User',
|
55
|
+
email: 'admin@example.com',
|
56
|
+
role: 'admin'
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# e2e/app_commands/scenarios/standard_setup.rb
|
62
|
+
require_relative '../helpers/test_data'
|
63
|
+
|
64
|
+
User.create!(TestData.standard_user)
|
65
|
+
User.create!(TestData.admin_user)
|
66
|
+
```
|
67
|
+
|
68
|
+
## Test Organization
|
69
|
+
|
70
|
+
### Group Related Tests
|
71
|
+
```js
|
72
|
+
// e2e/cypress/e2e/users/registration.cy.js
|
73
|
+
describe('User Registration', () => {
|
74
|
+
context('Valid Input', () => {
|
75
|
+
it('registers with email', () => {
|
76
|
+
// Test implementation
|
77
|
+
});
|
78
|
+
|
79
|
+
it('registers with social login', () => {
|
80
|
+
// Test implementation
|
81
|
+
});
|
82
|
+
});
|
83
|
+
|
84
|
+
context('Invalid Input', () => {
|
85
|
+
it('shows error for duplicate email', () => {
|
86
|
+
// Test implementation
|
87
|
+
});
|
88
|
+
});
|
89
|
+
});
|
90
|
+
```
|
91
|
+
|
92
|
+
### Use Page Objects
|
93
|
+
```js
|
94
|
+
// e2e/cypress/support/pages/LoginPage.js
|
95
|
+
class LoginPage {
|
96
|
+
visit() {
|
97
|
+
cy.visit('/login');
|
98
|
+
}
|
99
|
+
|
100
|
+
fillEmail(email) {
|
101
|
+
cy.get('[data-cy=email]').type(email);
|
102
|
+
}
|
103
|
+
|
104
|
+
fillPassword(password) {
|
105
|
+
cy.get('[data-cy=password]').type(password);
|
106
|
+
}
|
107
|
+
|
108
|
+
submit() {
|
109
|
+
cy.get('[data-cy=submit]').click();
|
110
|
+
}
|
111
|
+
|
112
|
+
login(email, password) {
|
113
|
+
this.visit();
|
114
|
+
this.fillEmail(email);
|
115
|
+
this.fillPassword(password);
|
116
|
+
this.submit();
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
export default new LoginPage();
|
121
|
+
|
122
|
+
// Usage in test
|
123
|
+
import LoginPage from '../../support/pages/LoginPage';
|
124
|
+
|
125
|
+
it('user can login', () => {
|
126
|
+
LoginPage.login('user@example.com', 'password');
|
127
|
+
cy.url().should('include', '/dashboard');
|
128
|
+
});
|
129
|
+
```
|
130
|
+
|
131
|
+
### Data-Test Attributes
|
132
|
+
```erb
|
133
|
+
<!-- app/views/users/new.html.erb -->
|
134
|
+
<form data-cy="registration-form">
|
135
|
+
<input
|
136
|
+
type="email"
|
137
|
+
name="user[email]"
|
138
|
+
data-cy="email-input"
|
139
|
+
data-test-id="user-email"
|
140
|
+
/>
|
141
|
+
<button
|
142
|
+
type="submit"
|
143
|
+
data-cy="submit-button"
|
144
|
+
data-test-id="register-submit"
|
145
|
+
>
|
146
|
+
Register
|
147
|
+
</button>
|
148
|
+
</form>
|
149
|
+
```
|
150
|
+
|
151
|
+
```js
|
152
|
+
// Prefer data-cy or data-test-id over classes/IDs
|
153
|
+
cy.get('[data-cy=email-input]').type('test@example.com');
|
154
|
+
// NOT: cy.get('#email').type('test@example.com');
|
155
|
+
```
|
156
|
+
|
157
|
+
## Data Management
|
158
|
+
|
159
|
+
### Factory Bot Best Practices
|
160
|
+
```ruby
|
161
|
+
# spec/factories/users.rb
|
162
|
+
FactoryBot.define do
|
163
|
+
factory :user do
|
164
|
+
sequence(:email) { |n| "user#{n}@example.com" }
|
165
|
+
name { Faker::Name.name }
|
166
|
+
confirmed_at { Time.current }
|
167
|
+
|
168
|
+
trait :admin do
|
169
|
+
role { 'admin' }
|
170
|
+
end
|
171
|
+
|
172
|
+
trait :with_posts do
|
173
|
+
transient do
|
174
|
+
posts_count { 3 }
|
175
|
+
end
|
176
|
+
|
177
|
+
after(:create) do |user, evaluator|
|
178
|
+
create_list(:post, evaluator.posts_count, user: user)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
```
|
184
|
+
|
185
|
+
### Scenario Patterns
|
186
|
+
```ruby
|
187
|
+
# e2e/app_commands/scenarios/e_commerce_setup.rb
|
188
|
+
class ECommerceSetup
|
189
|
+
def self.run(options = {})
|
190
|
+
ActiveRecord::Base.transaction do
|
191
|
+
# Create categories
|
192
|
+
categories = create_categories
|
193
|
+
|
194
|
+
# Create products
|
195
|
+
products = create_products(categories)
|
196
|
+
|
197
|
+
# Create users
|
198
|
+
users = create_users
|
199
|
+
|
200
|
+
# Create orders
|
201
|
+
create_orders(users, products) if options[:with_orders]
|
202
|
+
|
203
|
+
{ categories: categories, products: products, users: users }
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
private
|
208
|
+
|
209
|
+
def self.create_categories
|
210
|
+
['Electronics', 'Clothing', 'Books'].map do |name|
|
211
|
+
Category.create!(name: name)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def self.create_products(categories)
|
216
|
+
# Implementation
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# Usage in test
|
221
|
+
ECommerceSetup.run(with_orders: true)
|
222
|
+
```
|
223
|
+
|
224
|
+
### Database Cleaning Strategies
|
225
|
+
```ruby
|
226
|
+
# e2e/app_commands/clean.rb
|
227
|
+
class SmartCleaner
|
228
|
+
PRESERVE_TABLES = %w[
|
229
|
+
schema_migrations
|
230
|
+
ar_internal_metadata
|
231
|
+
spatial_ref_sys # PostGIS
|
232
|
+
].freeze
|
233
|
+
|
234
|
+
def self.clean(strategy: :transaction)
|
235
|
+
case strategy
|
236
|
+
when :transaction
|
237
|
+
DatabaseCleaner.strategy = :transaction
|
238
|
+
when :truncation
|
239
|
+
DatabaseCleaner.strategy = :truncation, {
|
240
|
+
except: PRESERVE_TABLES
|
241
|
+
}
|
242
|
+
when :deletion
|
243
|
+
DatabaseCleaner.strategy = :deletion, {
|
244
|
+
except: PRESERVE_TABLES
|
245
|
+
}
|
246
|
+
end
|
247
|
+
|
248
|
+
DatabaseCleaner.clean
|
249
|
+
|
250
|
+
# Reset sequences
|
251
|
+
reset_sequences if postgresql?
|
252
|
+
|
253
|
+
# Clear caches
|
254
|
+
clear_caches
|
255
|
+
end
|
256
|
+
|
257
|
+
private
|
258
|
+
|
259
|
+
def self.postgresql?
|
260
|
+
ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
|
261
|
+
end
|
262
|
+
|
263
|
+
def self.reset_sequences
|
264
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
265
|
+
ActiveRecord::Base.connection.reset_pk_sequence!(table)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def self.clear_caches
|
270
|
+
Rails.cache.clear
|
271
|
+
I18n.reload! if defined?(I18n)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
```
|
275
|
+
|
276
|
+
## Performance Optimization
|
277
|
+
|
278
|
+
### Minimize Database Operations
|
279
|
+
```js
|
280
|
+
// Bad: Multiple database operations
|
281
|
+
it('creates multiple users', () => {
|
282
|
+
cy.appFactories([['create', 'user', { name: 'User 1' }]]);
|
283
|
+
cy.appFactories([['create', 'user', { name: 'User 2' }]]);
|
284
|
+
cy.appFactories([['create', 'user', { name: 'User 3' }]]);
|
285
|
+
});
|
286
|
+
|
287
|
+
// Good: Batch operations
|
288
|
+
it('creates multiple users', () => {
|
289
|
+
cy.appFactories([
|
290
|
+
['create', 'user', { name: 'User 1' }],
|
291
|
+
['create', 'user', { name: 'User 2' }],
|
292
|
+
['create', 'user', { name: 'User 3' }]
|
293
|
+
]);
|
294
|
+
});
|
295
|
+
|
296
|
+
// Better: Use create_list
|
297
|
+
it('creates multiple users', () => {
|
298
|
+
cy.appFactories([
|
299
|
+
['create_list', 'user', 3]
|
300
|
+
]);
|
301
|
+
});
|
302
|
+
```
|
303
|
+
|
304
|
+
### Smart Waiting Strategies
|
305
|
+
```js
|
306
|
+
// Bad: Fixed waits
|
307
|
+
cy.wait(5000);
|
308
|
+
|
309
|
+
// Good: Wait for specific conditions
|
310
|
+
cy.get('[data-cy=loading]').should('not.exist');
|
311
|
+
cy.get('[data-cy=user-list]').should('be.visible');
|
312
|
+
|
313
|
+
// Better: Wait for API calls
|
314
|
+
cy.intercept('GET', '/api/users').as('getUsers');
|
315
|
+
cy.visit('/users');
|
316
|
+
cy.wait('@getUsers');
|
317
|
+
```
|
318
|
+
|
319
|
+
### Parallel Testing Configuration
|
320
|
+
```ruby
|
321
|
+
# config/database.yml
|
322
|
+
test:
|
323
|
+
<<: *default
|
324
|
+
database: myapp_test<%= ENV['TEST_ENV_NUMBER'] %>
|
325
|
+
|
326
|
+
# config/initializers/cypress_on_rails.rb
|
327
|
+
if ENV['PARALLEL_WORKERS'].present?
|
328
|
+
CypressOnRails.configure do |c|
|
329
|
+
worker_id = ENV['TEST_ENV_NUMBER'] || '1'
|
330
|
+
c.server_port = 5000 + worker_id.to_i
|
331
|
+
end
|
332
|
+
end
|
333
|
+
```
|
334
|
+
|
335
|
+
## CI/CD Integration
|
336
|
+
|
337
|
+
### GitHub Actions Example
|
338
|
+
```yaml
|
339
|
+
# .github/workflows/e2e.yml
|
340
|
+
name: E2E Tests
|
341
|
+
on: [push, pull_request]
|
342
|
+
|
343
|
+
jobs:
|
344
|
+
cypress:
|
345
|
+
runs-on: ubuntu-latest
|
346
|
+
strategy:
|
347
|
+
matrix:
|
348
|
+
browser: [chrome, firefox, edge]
|
349
|
+
|
350
|
+
services:
|
351
|
+
postgres:
|
352
|
+
image: postgres:14
|
353
|
+
env:
|
354
|
+
POSTGRES_PASSWORD: password
|
355
|
+
options: >-
|
356
|
+
--health-cmd pg_isready
|
357
|
+
--health-interval 10s
|
358
|
+
--health-timeout 5s
|
359
|
+
--health-retries 5
|
360
|
+
ports:
|
361
|
+
- 5432:5432
|
362
|
+
|
363
|
+
steps:
|
364
|
+
- uses: actions/checkout@v3
|
365
|
+
|
366
|
+
- name: Setup Ruby
|
367
|
+
uses: ruby/setup-ruby@v1
|
368
|
+
with:
|
369
|
+
bundler-cache: true
|
370
|
+
|
371
|
+
- name: Setup Node
|
372
|
+
uses: actions/setup-node@v3
|
373
|
+
with:
|
374
|
+
node-version: '18'
|
375
|
+
cache: 'yarn'
|
376
|
+
|
377
|
+
- name: Install dependencies
|
378
|
+
run: |
|
379
|
+
yarn install --frozen-lockfile
|
380
|
+
bundle install
|
381
|
+
|
382
|
+
- name: Setup database
|
383
|
+
env:
|
384
|
+
RAILS_ENV: test
|
385
|
+
DATABASE_URL: postgresql://postgres:password@localhost:5432/test
|
386
|
+
run: |
|
387
|
+
bundle exec rails db:create
|
388
|
+
bundle exec rails db:schema:load
|
389
|
+
|
390
|
+
- name: Run E2E tests
|
391
|
+
env:
|
392
|
+
RAILS_ENV: test
|
393
|
+
DATABASE_URL: postgresql://postgres:password@localhost:5432/test
|
394
|
+
run: |
|
395
|
+
bundle exec rails cypress:run
|
396
|
+
|
397
|
+
- name: Upload artifacts
|
398
|
+
uses: actions/upload-artifact@v3
|
399
|
+
if: failure()
|
400
|
+
with:
|
401
|
+
name: cypress-artifacts-${{ matrix.browser }}
|
402
|
+
path: |
|
403
|
+
e2e/cypress/screenshots
|
404
|
+
e2e/cypress/videos
|
405
|
+
```
|
406
|
+
|
407
|
+
### CircleCI Configuration
|
408
|
+
```yaml
|
409
|
+
# .circleci/config.yml
|
410
|
+
version: 2.1
|
411
|
+
|
412
|
+
orbs:
|
413
|
+
cypress: cypress-io/cypress@2
|
414
|
+
|
415
|
+
jobs:
|
416
|
+
e2e-tests:
|
417
|
+
docker:
|
418
|
+
- image: cimg/ruby:3.2-browsers
|
419
|
+
- image: cimg/postgres:14.0
|
420
|
+
environment:
|
421
|
+
POSTGRES_PASSWORD: password
|
422
|
+
|
423
|
+
parallelism: 4
|
424
|
+
|
425
|
+
steps:
|
426
|
+
- checkout
|
427
|
+
|
428
|
+
- restore_cache:
|
429
|
+
keys:
|
430
|
+
- gem-cache-{{ checksum "Gemfile.lock" }}
|
431
|
+
- yarn-cache-{{ checksum "yarn.lock" }}
|
432
|
+
|
433
|
+
- run:
|
434
|
+
name: Install dependencies
|
435
|
+
command: |
|
436
|
+
bundle install --path vendor/bundle
|
437
|
+
yarn install --frozen-lockfile
|
438
|
+
|
439
|
+
- save_cache:
|
440
|
+
key: gem-cache-{{ checksum "Gemfile.lock" }}
|
441
|
+
paths:
|
442
|
+
- vendor/bundle
|
443
|
+
|
444
|
+
- save_cache:
|
445
|
+
key: yarn-cache-{{ checksum "yarn.lock" }}
|
446
|
+
paths:
|
447
|
+
- node_modules
|
448
|
+
|
449
|
+
- run:
|
450
|
+
name: Setup database
|
451
|
+
command: |
|
452
|
+
bundle exec rails db:create db:schema:load
|
453
|
+
environment:
|
454
|
+
RAILS_ENV: test
|
455
|
+
|
456
|
+
- run:
|
457
|
+
name: Run E2E tests
|
458
|
+
command: |
|
459
|
+
TESTFILES=$(circleci tests glob "e2e/cypress/e2e/**/*.cy.js" | circleci tests split)
|
460
|
+
bundle exec rails cypress:run -- --spec $TESTFILES
|
461
|
+
|
462
|
+
- store_test_results:
|
463
|
+
path: test-results
|
464
|
+
|
465
|
+
- store_artifacts:
|
466
|
+
path: e2e/cypress/screenshots
|
467
|
+
|
468
|
+
- store_artifacts:
|
469
|
+
path: e2e/cypress/videos
|
470
|
+
|
471
|
+
workflows:
|
472
|
+
test:
|
473
|
+
jobs:
|
474
|
+
- e2e-tests
|
475
|
+
```
|
476
|
+
|
477
|
+
## Security Considerations
|
478
|
+
|
479
|
+
### Protecting Test Endpoints
|
480
|
+
```ruby
|
481
|
+
# config/initializers/cypress_on_rails.rb
|
482
|
+
CypressOnRails.configure do |c|
|
483
|
+
# Only enable in test/development
|
484
|
+
c.use_middleware = !Rails.env.production?
|
485
|
+
|
486
|
+
# Add authentication
|
487
|
+
c.before_request = lambda { |request|
|
488
|
+
# IP whitelist for CI
|
489
|
+
allowed_ips = ['127.0.0.1', '::1']
|
490
|
+
allowed_ips += ENV['ALLOWED_CI_IPS'].split(',') if ENV['ALLOWED_CI_IPS']
|
491
|
+
|
492
|
+
unless allowed_ips.include?(request.ip)
|
493
|
+
return [403, {}, ['Forbidden']]
|
494
|
+
end
|
495
|
+
|
496
|
+
# Token authentication
|
497
|
+
body = JSON.parse(request.body.string)
|
498
|
+
expected_token = ENV.fetch('CYPRESS_SECRET_TOKEN', 'development-token')
|
499
|
+
|
500
|
+
if body['auth_token'] != expected_token
|
501
|
+
return [401, {}, ['Unauthorized']]
|
502
|
+
end
|
503
|
+
|
504
|
+
nil
|
505
|
+
}
|
506
|
+
end
|
507
|
+
```
|
508
|
+
|
509
|
+
### Environment Variables
|
510
|
+
```bash
|
511
|
+
# .env.test
|
512
|
+
CYPRESS_SECRET_TOKEN=secure-random-token-here
|
513
|
+
CYPRESS_BASE_URL=http://localhost:5017
|
514
|
+
CYPRESS_RAILS_HOST=localhost
|
515
|
+
CYPRESS_RAILS_PORT=5017
|
516
|
+
|
517
|
+
# Never commit real credentials
|
518
|
+
DATABASE_URL=postgresql://localhost/myapp_test
|
519
|
+
REDIS_URL=redis://localhost:6379/1
|
520
|
+
```
|
521
|
+
|
522
|
+
### Sanitizing Test Data
|
523
|
+
```ruby
|
524
|
+
# e2e/app_commands/factory_bot.rb
|
525
|
+
class SafeFactoryBot
|
526
|
+
BLOCKED_FACTORIES = %w[admin super_admin payment_method].freeze
|
527
|
+
|
528
|
+
def self.create(factory_name, *args)
|
529
|
+
raise "Factory '#{factory_name}' is blocked in tests" if BLOCKED_FACTORIES.include?(factory_name.to_s)
|
530
|
+
|
531
|
+
FactoryBot.create(factory_name, *args)
|
532
|
+
end
|
533
|
+
end
|
534
|
+
```
|
535
|
+
|
536
|
+
## Debugging Strategies
|
537
|
+
|
538
|
+
### Verbose Logging
|
539
|
+
```ruby
|
540
|
+
# config/initializers/cypress_on_rails.rb
|
541
|
+
CypressOnRails.configure do |c|
|
542
|
+
c.logger = Logger.new(STDOUT)
|
543
|
+
c.logger.level = ENV['DEBUG'] ? Logger::DEBUG : Logger::INFO
|
544
|
+
end
|
545
|
+
|
546
|
+
# e2e/app_commands/debug.rb
|
547
|
+
def perform
|
548
|
+
logger.debug "Current user count: #{User.count}"
|
549
|
+
logger.debug "Environment: #{Rails.env}"
|
550
|
+
logger.debug "Database: #{ActiveRecord::Base.connection.current_database}"
|
551
|
+
|
552
|
+
result = yield if block_given?
|
553
|
+
|
554
|
+
logger.debug "Result: #{result.inspect}"
|
555
|
+
result
|
556
|
+
end
|
557
|
+
```
|
558
|
+
|
559
|
+
### Screenshot on Failure
|
560
|
+
```js
|
561
|
+
// cypress/support/index.js
|
562
|
+
Cypress.on('fail', (error, runnable) => {
|
563
|
+
// Take screenshot before failing
|
564
|
+
cy.screenshot(`failed-${runnable.title}`, { capture: 'fullPage' });
|
565
|
+
|
566
|
+
// Log additional debugging info
|
567
|
+
cy.task('log', {
|
568
|
+
test: runnable.title,
|
569
|
+
error: error.message,
|
570
|
+
url: cy.url(),
|
571
|
+
timestamp: new Date().toISOString()
|
572
|
+
});
|
573
|
+
|
574
|
+
throw error;
|
575
|
+
});
|
576
|
+
```
|
577
|
+
|
578
|
+
### Interactive Debugging
|
579
|
+
```js
|
580
|
+
// Add debugger statements
|
581
|
+
it('debug this test', () => {
|
582
|
+
cy.appFactories([['create', 'user']]);
|
583
|
+
|
584
|
+
cy.visit('/users');
|
585
|
+
debugger; // Cypress will pause here in open mode
|
586
|
+
|
587
|
+
cy.get('[data-cy=user-list]').should('exist');
|
588
|
+
});
|
589
|
+
|
590
|
+
// Or use cy.pause()
|
591
|
+
it('pause execution', () => {
|
592
|
+
cy.visit('/users');
|
593
|
+
cy.pause(); // Manually resume in Cypress UI
|
594
|
+
cy.get('[data-cy=user-list]').should('exist');
|
595
|
+
});
|
596
|
+
```
|
597
|
+
|
598
|
+
## Common Patterns
|
599
|
+
|
600
|
+
### Authentication Flow
|
601
|
+
```js
|
602
|
+
// cypress/support/commands.js
|
603
|
+
Cypress.Commands.add('login', (email, password) => {
|
604
|
+
cy.session([email, password], () => {
|
605
|
+
cy.visit('/login');
|
606
|
+
cy.get('[data-cy=email]').type(email);
|
607
|
+
cy.get('[data-cy=password]').type(password);
|
608
|
+
cy.get('[data-cy=submit]').click();
|
609
|
+
cy.url().should('include', '/dashboard');
|
610
|
+
});
|
611
|
+
});
|
612
|
+
|
613
|
+
// Usage
|
614
|
+
beforeEach(() => {
|
615
|
+
cy.login('user@example.com', 'password');
|
616
|
+
});
|
617
|
+
```
|
618
|
+
|
619
|
+
### File Upload Testing
|
620
|
+
```js
|
621
|
+
it('uploads a file', () => {
|
622
|
+
cy.fixture('document.pdf', 'base64').then(fileContent => {
|
623
|
+
cy.get('[data-cy=file-input]').attachFile({
|
624
|
+
fileContent,
|
625
|
+
fileName: 'document.pdf',
|
626
|
+
mimeType: 'application/pdf',
|
627
|
+
encoding: 'base64'
|
628
|
+
});
|
629
|
+
});
|
630
|
+
|
631
|
+
cy.get('[data-cy=upload-button]').click();
|
632
|
+
cy.contains('File uploaded successfully');
|
633
|
+
});
|
634
|
+
```
|
635
|
+
|
636
|
+
### API Mocking
|
637
|
+
```js
|
638
|
+
it('handles API errors gracefully', () => {
|
639
|
+
// Mock failed API response
|
640
|
+
cy.intercept('POST', '/api/users', {
|
641
|
+
statusCode: 500,
|
642
|
+
body: { error: 'Internal Server Error' }
|
643
|
+
}).as('createUser');
|
644
|
+
|
645
|
+
cy.visit('/users/new');
|
646
|
+
cy.get('[data-cy=submit]').click();
|
647
|
+
|
648
|
+
cy.wait('@createUser');
|
649
|
+
cy.contains('Something went wrong');
|
650
|
+
});
|
651
|
+
```
|
652
|
+
|
653
|
+
### Testing Async Operations
|
654
|
+
```js
|
655
|
+
it('waits for async operations', () => {
|
656
|
+
// Start a background job
|
657
|
+
cy.appEval(`
|
658
|
+
ImportJob.perform_later('large_dataset.csv')
|
659
|
+
`);
|
660
|
+
|
661
|
+
cy.visit('/imports');
|
662
|
+
|
663
|
+
// Poll for completion
|
664
|
+
cy.get('[data-cy=import-status]', { timeout: 30000 })
|
665
|
+
.should('contain', 'Completed');
|
666
|
+
});
|
667
|
+
```
|
668
|
+
|
669
|
+
## Summary
|
670
|
+
|
671
|
+
Following these best practices will help you:
|
672
|
+
- Write more maintainable and reliable tests
|
673
|
+
- Improve test performance and reduce flakiness
|
674
|
+
- Better organize your test code
|
675
|
+
- Secure your test infrastructure
|
676
|
+
- Debug issues more effectively
|
677
|
+
|
678
|
+
Remember: E2E tests should focus on critical user journeys. Use unit and integration tests for comprehensive coverage of edge cases.
|