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
data/docs/VCR_GUIDE.md
ADDED
@@ -0,0 +1,499 @@
|
|
1
|
+
# VCR Integration Guide
|
2
|
+
|
3
|
+
Complete guide for recording and replaying HTTP interactions in your tests using VCR with cypress-playwright-on-rails.
|
4
|
+
|
5
|
+
## Table of Contents
|
6
|
+
- [Overview](#overview)
|
7
|
+
- [Installation](#installation)
|
8
|
+
- [Configuration](#configuration)
|
9
|
+
- [Insert/Eject Mode](#inserteject-mode)
|
10
|
+
- [Use Cassette Mode](#use-cassette-mode)
|
11
|
+
- [GraphQL Integration](#graphql-integration)
|
12
|
+
- [Advanced Usage](#advanced-usage)
|
13
|
+
- [Troubleshooting](#troubleshooting)
|
14
|
+
|
15
|
+
## Overview
|
16
|
+
|
17
|
+
VCR (Video Cassette Recorder) records your test suite's HTTP interactions and replays them during future test runs for fast, deterministic tests. This is particularly useful for:
|
18
|
+
- Testing against third-party APIs
|
19
|
+
- Avoiding rate limits
|
20
|
+
- Testing without internet connection
|
21
|
+
- Ensuring consistent test data
|
22
|
+
- Speeding up test execution
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
### 1. Add required gems
|
27
|
+
```ruby
|
28
|
+
# Gemfile
|
29
|
+
group :test, :development do
|
30
|
+
gem 'vcr'
|
31
|
+
gem 'webmock'
|
32
|
+
gem 'cypress-on-rails', '~> 1.0'
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
### 2. Install npm package (optional, for enhanced features)
|
37
|
+
```bash
|
38
|
+
yarn add -D cypress-on-rails
|
39
|
+
# or
|
40
|
+
npm install --save-dev cypress-on-rails
|
41
|
+
```
|
42
|
+
|
43
|
+
## Configuration
|
44
|
+
|
45
|
+
### Basic VCR Setup
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
# config/initializers/cypress_on_rails.rb
|
49
|
+
CypressOnRails.configure do |c|
|
50
|
+
# Enable VCR middleware
|
51
|
+
c.use_vcr_middleware = !Rails.env.production? && ENV['CYPRESS'].present?
|
52
|
+
|
53
|
+
# VCR configuration options
|
54
|
+
c.vcr_options = {
|
55
|
+
# HTTP library to hook into
|
56
|
+
hook_into: :webmock,
|
57
|
+
|
58
|
+
# Default recording mode
|
59
|
+
default_cassette_options: {
|
60
|
+
record: :once, # :once, :new_episodes, :none, :all
|
61
|
+
match_requests_on: [:method, :uri, :body],
|
62
|
+
allow_unused_http_interactions: false
|
63
|
+
},
|
64
|
+
|
65
|
+
# Where to save cassettes
|
66
|
+
cassette_library_dir: Rails.root.join('spec/fixtures/vcr_cassettes'),
|
67
|
+
|
68
|
+
# Configure which hosts to ignore
|
69
|
+
ignore_hosts: ['localhost', '127.0.0.1', '0.0.0.0'],
|
70
|
+
|
71
|
+
# Filter sensitive data
|
72
|
+
filter_sensitive_data: {
|
73
|
+
'<API_KEY>' => ENV['EXTERNAL_API_KEY'],
|
74
|
+
'<AUTH_TOKEN>' => ENV['AUTH_TOKEN']
|
75
|
+
},
|
76
|
+
|
77
|
+
# Preserve exact body bytes for binary data
|
78
|
+
preserve_exact_body_bytes: true,
|
79
|
+
|
80
|
+
# Allow HTTP connections when no cassette
|
81
|
+
allow_http_connections_when_no_cassette: false
|
82
|
+
}
|
83
|
+
end
|
84
|
+
```
|
85
|
+
|
86
|
+
### Cypress Setup
|
87
|
+
|
88
|
+
```js
|
89
|
+
// cypress/support/index.js
|
90
|
+
import 'cypress-on-rails/support/index'
|
91
|
+
|
92
|
+
// Optional: Configure VCR commands
|
93
|
+
Cypress.Commands.add('vcrInsert', (name, options = {}) => {
|
94
|
+
cy.app('vcr_insert_cassette', { name, ...options });
|
95
|
+
});
|
96
|
+
|
97
|
+
Cypress.Commands.add('vcrEject', () => {
|
98
|
+
cy.app('vcr_eject_cassette');
|
99
|
+
});
|
100
|
+
```
|
101
|
+
|
102
|
+
### Clean Command Setup
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
# e2e/app_commands/clean.rb
|
106
|
+
# Ensure cassettes are ejected between tests
|
107
|
+
VCR.eject_cassette if VCR.current_cassette
|
108
|
+
VCR.turn_off!
|
109
|
+
WebMock.disable! if defined?(WebMock)
|
110
|
+
|
111
|
+
# Your existing clean logic...
|
112
|
+
DatabaseCleaner.clean
|
113
|
+
```
|
114
|
+
|
115
|
+
## Insert/Eject Mode
|
116
|
+
|
117
|
+
Insert/eject mode gives you explicit control over when to start and stop recording.
|
118
|
+
|
119
|
+
### Configuration
|
120
|
+
```ruby
|
121
|
+
CypressOnRails.configure do |c|
|
122
|
+
c.use_vcr_middleware = !Rails.env.production? && ENV['CYPRESS'].present?
|
123
|
+
# Don't enable use_cassette mode
|
124
|
+
end
|
125
|
+
```
|
126
|
+
|
127
|
+
### Basic Usage
|
128
|
+
```js
|
129
|
+
describe('External API Tests', () => {
|
130
|
+
afterEach(() => {
|
131
|
+
cy.vcr_eject_cassette();
|
132
|
+
});
|
133
|
+
|
134
|
+
it('fetches weather data', () => {
|
135
|
+
// Start recording
|
136
|
+
cy.vcr_insert_cassette('weather_api', {
|
137
|
+
record: 'new_episodes'
|
138
|
+
});
|
139
|
+
|
140
|
+
cy.visit('/weather');
|
141
|
+
cy.contains('Current Temperature');
|
142
|
+
|
143
|
+
// Recording continues until ejected
|
144
|
+
});
|
145
|
+
|
146
|
+
it('handles API errors', () => {
|
147
|
+
// Use pre-recorded cassette
|
148
|
+
cy.vcr_insert_cassette('weather_api_error', {
|
149
|
+
record: 'none' // Only replay, don't record
|
150
|
+
});
|
151
|
+
|
152
|
+
cy.visit('/weather?city=invalid');
|
153
|
+
cy.contains('City not found');
|
154
|
+
});
|
155
|
+
});
|
156
|
+
```
|
157
|
+
|
158
|
+
### Advanced Options
|
159
|
+
```js
|
160
|
+
cy.vcr_insert_cassette('api_calls', {
|
161
|
+
record: 'new_episodes', // Recording mode
|
162
|
+
match_requests_on: ['method', 'uri', 'body'], // Request matching
|
163
|
+
erb: true, // Enable ERB in cassettes
|
164
|
+
allow_playback_repeats: true, // Allow multiple replays
|
165
|
+
exclusive: true, // Disallow other cassettes
|
166
|
+
serialize_with: 'json', // Use JSON format
|
167
|
+
preserve_exact_body_bytes: true, // For binary data
|
168
|
+
decode_compressed_response: true // Handle gzipped responses
|
169
|
+
});
|
170
|
+
```
|
171
|
+
|
172
|
+
## Use Cassette Mode
|
173
|
+
|
174
|
+
Use cassette mode automatically wraps each request with VCR.use_cassette.
|
175
|
+
|
176
|
+
### Configuration
|
177
|
+
```ruby
|
178
|
+
CypressOnRails.configure do |c|
|
179
|
+
# Use this instead of use_vcr_middleware
|
180
|
+
c.use_vcr_use_cassette_middleware = !Rails.env.production? && ENV['CYPRESS'].present?
|
181
|
+
|
182
|
+
c.vcr_options = {
|
183
|
+
hook_into: :webmock,
|
184
|
+
default_cassette_options: {
|
185
|
+
record: :once,
|
186
|
+
match_requests_on: [:method, :uri]
|
187
|
+
},
|
188
|
+
cassette_library_dir: Rails.root.join('spec/fixtures/vcr_cassettes')
|
189
|
+
}
|
190
|
+
end
|
191
|
+
```
|
192
|
+
|
193
|
+
### How It Works
|
194
|
+
Each request is automatically wrapped with `VCR.use_cassette`. The cassette name is derived from the request URL or operation name.
|
195
|
+
|
196
|
+
### Directory Structure
|
197
|
+
```
|
198
|
+
spec/fixtures/vcr_cassettes/
|
199
|
+
├── api/
|
200
|
+
│ ├── users/
|
201
|
+
│ │ └── index.yml
|
202
|
+
│ └── products/
|
203
|
+
│ ├── index.yml
|
204
|
+
│ └── show.yml
|
205
|
+
└── graphql/
|
206
|
+
├── GetUser.yml
|
207
|
+
└── CreatePost.yml
|
208
|
+
```
|
209
|
+
|
210
|
+
## GraphQL Integration
|
211
|
+
|
212
|
+
GraphQL requires special handling due to all requests going to the same endpoint.
|
213
|
+
|
214
|
+
### Setup for GraphQL
|
215
|
+
|
216
|
+
```js
|
217
|
+
// cypress/support/commands.js
|
218
|
+
Cypress.Commands.add('mockGraphQL', () => {
|
219
|
+
cy.on('window:before:load', (win) => {
|
220
|
+
const originalFetch = win.fetch;
|
221
|
+
const fetch = (path, options, ...rest) => {
|
222
|
+
if (options && options.body) {
|
223
|
+
try {
|
224
|
+
const body = JSON.parse(options.body);
|
225
|
+
// Add operation name to URL for VCR matching
|
226
|
+
if (body.operationName) {
|
227
|
+
return originalFetch(
|
228
|
+
`${path}?operation=${body.operationName}`,
|
229
|
+
options,
|
230
|
+
...rest
|
231
|
+
);
|
232
|
+
}
|
233
|
+
} catch (e) {
|
234
|
+
return originalFetch(path, options, ...rest);
|
235
|
+
}
|
236
|
+
}
|
237
|
+
return originalFetch(path, options, ...rest);
|
238
|
+
};
|
239
|
+
cy.stub(win, 'fetch', fetch);
|
240
|
+
});
|
241
|
+
});
|
242
|
+
|
243
|
+
// cypress/support/index.js
|
244
|
+
beforeEach(() => {
|
245
|
+
cy.mockGraphQL(); // Enable GraphQL operation tracking
|
246
|
+
});
|
247
|
+
```
|
248
|
+
|
249
|
+
### GraphQL Test Example
|
250
|
+
```js
|
251
|
+
it('queries user data', () => {
|
252
|
+
// Cassette will be saved as vcr_cassettes/graphql/GetUser.yml
|
253
|
+
cy.visit('/profile');
|
254
|
+
|
255
|
+
// The GraphQL query with operationName: 'GetUser'
|
256
|
+
// will be automatically recorded
|
257
|
+
|
258
|
+
cy.contains('John Doe');
|
259
|
+
});
|
260
|
+
```
|
261
|
+
|
262
|
+
### Custom GraphQL Matching
|
263
|
+
```ruby
|
264
|
+
# config/initializers/cypress_on_rails.rb
|
265
|
+
c.vcr_options = {
|
266
|
+
match_requests_on: [:method, :uri,
|
267
|
+
lambda { |req1, req2|
|
268
|
+
# Custom matching for GraphQL requests
|
269
|
+
if req1.uri.path == '/graphql' && req2.uri.path == '/graphql'
|
270
|
+
body1 = JSON.parse(req1.body)
|
271
|
+
body2 = JSON.parse(req2.body)
|
272
|
+
|
273
|
+
# Match by operation name and variables
|
274
|
+
body1['operationName'] == body2['operationName'] &&
|
275
|
+
body1['variables'] == body2['variables']
|
276
|
+
else
|
277
|
+
true
|
278
|
+
end
|
279
|
+
}
|
280
|
+
]
|
281
|
+
}
|
282
|
+
```
|
283
|
+
|
284
|
+
## Advanced Usage
|
285
|
+
|
286
|
+
### Dynamic Cassette Names
|
287
|
+
```js
|
288
|
+
// Use test context for cassette names
|
289
|
+
it('fetches user data', function() {
|
290
|
+
const cassetteName = `${this.currentTest.parent.title}_${this.currentTest.title}`
|
291
|
+
.replace(/\s+/g, '_')
|
292
|
+
.toLowerCase();
|
293
|
+
|
294
|
+
cy.vcr_insert_cassette(cassetteName, { record: 'once' });
|
295
|
+
|
296
|
+
cy.visit('/users');
|
297
|
+
// Test continues...
|
298
|
+
});
|
299
|
+
```
|
300
|
+
|
301
|
+
### Conditional Recording
|
302
|
+
```js
|
303
|
+
const shouldRecord = Cypress.env('RECORD_VCR') === 'true';
|
304
|
+
|
305
|
+
cy.vcr_insert_cassette('api_calls', {
|
306
|
+
record: shouldRecord ? 'new_episodes' : 'none'
|
307
|
+
});
|
308
|
+
```
|
309
|
+
|
310
|
+
### Multiple Cassettes
|
311
|
+
```js
|
312
|
+
it('combines multiple API sources', () => {
|
313
|
+
// Stack multiple cassettes
|
314
|
+
cy.vcr_insert_cassette('weather_api');
|
315
|
+
cy.vcr_insert_cassette('news_api');
|
316
|
+
|
317
|
+
cy.visit('/dashboard');
|
318
|
+
|
319
|
+
// Both APIs will be recorded
|
320
|
+
|
321
|
+
// Eject in reverse order
|
322
|
+
cy.vcr_eject_cassette(); // Ejects news_api
|
323
|
+
cy.vcr_eject_cassette(); // Ejects weather_api
|
324
|
+
});
|
325
|
+
```
|
326
|
+
|
327
|
+
### Custom Matchers
|
328
|
+
```ruby
|
329
|
+
# e2e/app_commands/vcr_custom.rb
|
330
|
+
VCR.configure do |c|
|
331
|
+
# Custom request matcher
|
332
|
+
c.register_request_matcher :uri_ignoring_params do |req1, req2|
|
333
|
+
URI(req1.uri).host == URI(req2.uri).host &&
|
334
|
+
URI(req1.uri).path == URI(req2.uri).path
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
# Use in test
|
339
|
+
VCR.use_cassette('api_call',
|
340
|
+
match_requests_on: [:method, :uri_ignoring_params]
|
341
|
+
)
|
342
|
+
```
|
343
|
+
|
344
|
+
### Filtering Sensitive Data
|
345
|
+
```ruby
|
346
|
+
VCR.configure do |c|
|
347
|
+
# Filter authorization headers
|
348
|
+
c.filter_sensitive_data('<AUTHORIZATION>') do |interaction|
|
349
|
+
interaction.request.headers['Authorization']&.first
|
350
|
+
end
|
351
|
+
|
352
|
+
# Filter API keys from URLs
|
353
|
+
c.filter_sensitive_data('<API_KEY>') do |interaction|
|
354
|
+
URI(interaction.request.uri).query
|
355
|
+
&.match(/api_key=([^&]+)/)
|
356
|
+
&.captures
|
357
|
+
&.first
|
358
|
+
end
|
359
|
+
|
360
|
+
# Filter response tokens
|
361
|
+
c.filter_sensitive_data('<TOKEN>') do |interaction|
|
362
|
+
JSON.parse(interaction.response.body)['token'] rescue nil
|
363
|
+
end
|
364
|
+
end
|
365
|
+
```
|
366
|
+
|
367
|
+
## Troubleshooting
|
368
|
+
|
369
|
+
### Issue: "No route matches [POST] '/api/__e2e__/vcr/insert'"
|
370
|
+
|
371
|
+
**Solution:** Ensure VCR middleware is enabled:
|
372
|
+
```ruby
|
373
|
+
# config/initializers/cypress_on_rails.rb
|
374
|
+
c.use_vcr_middleware = !Rails.env.production? && ENV['CYPRESS'].present?
|
375
|
+
```
|
376
|
+
|
377
|
+
And that the API prefix matches:
|
378
|
+
```ruby
|
379
|
+
c.api_prefix = '/api' # If your app uses /api prefix
|
380
|
+
```
|
381
|
+
|
382
|
+
### Issue: "VCR::Errors::UnhandledHTTPRequestError"
|
383
|
+
|
384
|
+
**Cause:** Request not matching any cassette.
|
385
|
+
|
386
|
+
**Solutions:**
|
387
|
+
1. Re-record the cassette:
|
388
|
+
```js
|
389
|
+
cy.vcr_insert_cassette('my_cassette', { record: 'new_episodes' });
|
390
|
+
```
|
391
|
+
|
392
|
+
2. Adjust matching criteria:
|
393
|
+
```ruby
|
394
|
+
c.vcr_options = {
|
395
|
+
default_cassette_options: {
|
396
|
+
match_requests_on: [:method, :host, :path] # Ignore query params
|
397
|
+
}
|
398
|
+
}
|
399
|
+
```
|
400
|
+
|
401
|
+
3. Allow new requests:
|
402
|
+
```ruby
|
403
|
+
c.vcr_options = {
|
404
|
+
default_cassette_options: {
|
405
|
+
record: 'new_episodes', # Record new requests
|
406
|
+
allow_unused_http_interactions: true
|
407
|
+
}
|
408
|
+
}
|
409
|
+
```
|
410
|
+
|
411
|
+
### Issue: "Cassette not found"
|
412
|
+
|
413
|
+
**Solution:** Check the cassette path:
|
414
|
+
```ruby
|
415
|
+
# Verify the directory exists
|
416
|
+
c.vcr_options = {
|
417
|
+
cassette_library_dir: Rails.root.join('spec/fixtures/vcr_cassettes')
|
418
|
+
}
|
419
|
+
```
|
420
|
+
|
421
|
+
Create the directory if needed:
|
422
|
+
```bash
|
423
|
+
mkdir -p spec/fixtures/vcr_cassettes
|
424
|
+
```
|
425
|
+
|
426
|
+
### Issue: "WebMock::NetConnectNotAllowedError"
|
427
|
+
|
428
|
+
**Cause:** HTTP connection attempted without cassette.
|
429
|
+
|
430
|
+
**Solutions:**
|
431
|
+
1. Insert a cassette before the request:
|
432
|
+
```js
|
433
|
+
cy.vcr_insert_cassette('api_calls');
|
434
|
+
```
|
435
|
+
|
436
|
+
2. Allow connections to specific hosts:
|
437
|
+
```ruby
|
438
|
+
WebMock.disable_net_connect!(
|
439
|
+
allow_localhost: true,
|
440
|
+
allow: ['chromedriver.storage.googleapis.com']
|
441
|
+
)
|
442
|
+
```
|
443
|
+
|
444
|
+
3. Disable WebMock for specific tests:
|
445
|
+
```js
|
446
|
+
cy.app('eval', { code: 'WebMock.disable!' });
|
447
|
+
// Run test
|
448
|
+
cy.app('eval', { code: 'WebMock.enable!' });
|
449
|
+
```
|
450
|
+
|
451
|
+
### Issue: Binary/Encoded Response Issues
|
452
|
+
|
453
|
+
**Solution:** Configure VCR to handle binary data:
|
454
|
+
```ruby
|
455
|
+
c.vcr_options = {
|
456
|
+
preserve_exact_body_bytes: true,
|
457
|
+
decode_compressed_response: true
|
458
|
+
}
|
459
|
+
```
|
460
|
+
|
461
|
+
### Issue: Timestamps in Recordings
|
462
|
+
|
463
|
+
**Solution:** Filter dynamic timestamps:
|
464
|
+
```ruby
|
465
|
+
VCR.configure do |c|
|
466
|
+
c.before_record do |interaction|
|
467
|
+
# Normalize timestamps in responses
|
468
|
+
if interaction.response.headers['date']
|
469
|
+
interaction.response.headers['date'] = ['2024-01-01 00:00:00']
|
470
|
+
end
|
471
|
+
end
|
472
|
+
end
|
473
|
+
```
|
474
|
+
|
475
|
+
## Best Practices
|
476
|
+
|
477
|
+
1. **Organize cassettes by feature**: Use subdirectories for different features
|
478
|
+
2. **Use descriptive names**: Make cassette names self-documenting
|
479
|
+
3. **Commit cassettes to version control**: Share recordings with team
|
480
|
+
4. **Periodically refresh cassettes**: Re-record to catch API changes
|
481
|
+
5. **Filter sensitive data**: Never commit real API keys or tokens
|
482
|
+
6. **Use appropriate record modes**:
|
483
|
+
- `:once` for stable APIs
|
484
|
+
- `:new_episodes` during development
|
485
|
+
- `:none` for CI/production
|
486
|
+
7. **Document external dependencies**: List which APIs are being mocked
|
487
|
+
8. **Handle errors gracefully**: Record both success and error responses
|
488
|
+
|
489
|
+
## Summary
|
490
|
+
|
491
|
+
VCR integration with cypress-playwright-on-rails provides powerful HTTP mocking capabilities. Choose between:
|
492
|
+
- **Insert/Eject mode**: For explicit control over recording
|
493
|
+
- **Use Cassette mode**: For automatic recording, especially with GraphQL
|
494
|
+
|
495
|
+
Remember to:
|
496
|
+
- Configure VCR appropriately for your needs
|
497
|
+
- Filter sensitive data
|
498
|
+
- Organize cassettes logically
|
499
|
+
- Keep cassettes up to date
|
data/docs/authentication.md
CHANGED
@@ -51,3 +51,33 @@ cy.forceLogin()
|
|
51
51
|
cy.forceLogin({redirect_to: '/profile'})
|
52
52
|
cy.forceLogin({email: 'someuser@mail.com'})
|
53
53
|
```
|
54
|
+
|
55
|
+
In `playwright/support/on-rails.js`:
|
56
|
+
|
57
|
+
```js
|
58
|
+
async function forceLogin(page, { email, redirect_to = '/' }) {
|
59
|
+
// Validate inputs
|
60
|
+
if (typeof email !== 'string' || typeof redirect_to !== 'string') {
|
61
|
+
throw new Error('Invalid input: email and redirect_to must be non-empty strings');
|
62
|
+
}
|
63
|
+
|
64
|
+
const response = await page.request.post('/__e2e__/force_login', {
|
65
|
+
data: { email: email, redirect_to: redirect_to },
|
66
|
+
headers: { 'Content-Type': 'application/json' }
|
67
|
+
});
|
68
|
+
|
69
|
+
// Handle response based on status code
|
70
|
+
if (response.ok()) {
|
71
|
+
await page.goto(redirect_to);
|
72
|
+
} else {
|
73
|
+
// Throw an exception for specific error statuses
|
74
|
+
throw new Error(`Login failed with status: ${response.status()}`);
|
75
|
+
}
|
76
|
+
}
|
77
|
+
```
|
78
|
+
|
79
|
+
Examples of usage in Playwright specs:
|
80
|
+
```js
|
81
|
+
await forceLogin(page, { email: 'someuser@mail.com', redirect_to: '/profile' });
|
82
|
+
|
83
|
+
```
|
@@ -54,6 +54,15 @@ cy.appFactories([['create', 'author']]).then((records) => {
|
|
54
54
|
})
|
55
55
|
```
|
56
56
|
|
57
|
+
then in Playwright
|
58
|
+
There are a few ways you can set up associations with the correct data using Playwright and FactoryBot.
|
59
|
+
```js
|
60
|
+
const records = await appFactories([['create', 'author', { name: 'James' }]], context);
|
61
|
+
await appFactories([['create', 'post', { title: 'Playwright is cool', author_id: records[0].id }]], context);
|
62
|
+
// Note: These Playwright examples demonstrate asynchronous interactions with the server for setting up data associations. Ensure that your environment is configured to handle these async operations.
|
63
|
+
```
|
64
|
+
|
65
|
+
|
57
66
|
## 2. Using transient attributes
|
58
67
|
|
59
68
|
```rb
|
@@ -81,6 +90,11 @@ cy.appFactories([['create', 'post', { title: 'Cypress is cool', author_name: 'Ja
|
|
81
90
|
cy.appFactories([['create', 'post']])
|
82
91
|
```
|
83
92
|
|
93
|
+
then in Playwright
|
94
|
+
```js
|
95
|
+
const records = await appFactories([['create', 'post', { title: 'Playwright is cool', author_name: 'James' }]]);
|
96
|
+
```
|
97
|
+
|
84
98
|
## 3. Using Nested Attributes
|
85
99
|
|
86
100
|
```rb
|
@@ -6,8 +6,22 @@ module CypressOnRails
|
|
6
6
|
attr_accessor :install_folder
|
7
7
|
attr_accessor :use_middleware
|
8
8
|
attr_accessor :use_vcr_middleware
|
9
|
+
attr_accessor :use_vcr_use_cassette_middleware
|
9
10
|
attr_accessor :before_request
|
10
11
|
attr_accessor :logger
|
12
|
+
attr_accessor :vcr_options
|
13
|
+
|
14
|
+
# Server hooks for managing test lifecycle
|
15
|
+
attr_accessor :before_server_start
|
16
|
+
attr_accessor :after_server_start
|
17
|
+
attr_accessor :after_transaction_start
|
18
|
+
attr_accessor :after_state_reset
|
19
|
+
attr_accessor :before_server_stop
|
20
|
+
|
21
|
+
# Server configuration
|
22
|
+
attr_accessor :server_host
|
23
|
+
attr_accessor :server_port
|
24
|
+
attr_accessor :transactional_server
|
11
25
|
|
12
26
|
# Attributes for backwards compatibility
|
13
27
|
def cypress_folder
|
@@ -25,14 +39,29 @@ module CypressOnRails
|
|
25
39
|
|
26
40
|
alias :use_middleware? :use_middleware
|
27
41
|
alias :use_vcr_middleware? :use_vcr_middleware
|
42
|
+
alias :use_vcr_use_cassette_middleware? :use_vcr_use_cassette_middleware
|
28
43
|
|
29
44
|
def reset
|
30
45
|
self.api_prefix = ''
|
31
46
|
self.install_folder = 'spec/e2e'
|
32
47
|
self.use_middleware = true
|
33
48
|
self.use_vcr_middleware = false
|
49
|
+
self.use_vcr_use_cassette_middleware = false
|
34
50
|
self.before_request = -> (request) {}
|
35
51
|
self.logger = Logger.new(STDOUT)
|
52
|
+
self.vcr_options = {}
|
53
|
+
|
54
|
+
# Server hooks
|
55
|
+
self.before_server_start = nil
|
56
|
+
self.after_server_start = nil
|
57
|
+
self.after_transaction_start = nil
|
58
|
+
self.after_state_reset = nil
|
59
|
+
self.before_server_stop = nil
|
60
|
+
|
61
|
+
# Server configuration
|
62
|
+
self.server_host = ENV.fetch('CYPRESS_RAILS_HOST', 'localhost')
|
63
|
+
self.server_port = ENV.fetch('CYPRESS_RAILS_PORT', nil)
|
64
|
+
self.transactional_server = true
|
36
65
|
end
|
37
66
|
|
38
67
|
def tagged_logged
|
@@ -3,14 +3,29 @@ require 'cypress_on_rails/configuration'
|
|
3
3
|
|
4
4
|
module CypressOnRails
|
5
5
|
class Railtie < Rails::Railtie
|
6
|
+
rake_tasks do
|
7
|
+
load 'tasks/cypress.rake'
|
8
|
+
end
|
6
9
|
initializer :setup_cypress_middleware, after: :load_config_initializers do |app|
|
7
10
|
if CypressOnRails.configuration.use_middleware?
|
8
11
|
require 'cypress_on_rails/middleware'
|
9
12
|
app.middleware.use Middleware
|
13
|
+
|
14
|
+
# Add state reset middleware for compatibility with cypress-rails
|
15
|
+
require 'cypress_on_rails/state_reset_middleware'
|
16
|
+
app.middleware.use StateResetMiddleware
|
10
17
|
end
|
11
18
|
if CypressOnRails.configuration.use_vcr_middleware?
|
12
|
-
require 'cypress_on_rails/
|
13
|
-
app.middleware.use
|
19
|
+
require 'cypress_on_rails/vcr/insert_eject_middleware'
|
20
|
+
app.middleware.use Vcr::InsertEjectMiddleware
|
21
|
+
end
|
22
|
+
if CypressOnRails.configuration.use_vcr_use_cassette_middleware?
|
23
|
+
if CypressOnRails.configuration.use_vcr_middleware?
|
24
|
+
raise 'Configure only one VCR middleware at a time: use_vcr_middleware OR use_vcr_use_cassette_middleware'
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'cypress_on_rails/vcr/use_cassette_middleware'
|
28
|
+
app.middleware.use Vcr::UseCassetteMiddleware
|
14
29
|
end
|
15
30
|
end
|
16
31
|
end
|