From 6b1f42ff5ab582e530c9d8a13894d9645b7ecf7a Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Mon, 13 Dec 2021 20:51:36 +0200 Subject: [PATCH 01/23] Add VCR cassette wrapper --- lib/cypress_on_rails/middleware.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/cypress_on_rails/middleware.rb b/lib/cypress_on_rails/middleware.rb index f5ed274..0505feb 100644 --- a/lib/cypress_on_rails/middleware.rb +++ b/lib/cypress_on_rails/middleware.rb @@ -22,7 +22,13 @@ def call(env) warn "/__cypress__/command is deprecated. Please use the install generator to use /__e2e__/command instead." configuration.tagged_logged { handle_command(request) } else - @app.call(env) + if defined?(VCR) + VCR.use_cassette('foobar', { :record => :new_episodes }) do + @app.call(env) + end + else + @app.call(env) + end end end From c260413323409493de6994ac1d346505915ba792 Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Tue, 14 Dec 2021 21:40:02 +0200 Subject: [PATCH 02/23] Add VCR wrapper --- lib/cypress_on_rails/configuration.rb | 4 +++ lib/cypress_on_rails/middleware.rb | 8 +---- lib/cypress_on_rails/vcr_wrapper.rb | 42 +++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 lib/cypress_on_rails/vcr_wrapper.rb diff --git a/lib/cypress_on_rails/configuration.rb b/lib/cypress_on_rails/configuration.rb index b7d32e1..a9c7940 100644 --- a/lib/cypress_on_rails/configuration.rb +++ b/lib/cypress_on_rails/configuration.rb @@ -8,6 +8,8 @@ class Configuration attr_accessor :use_vcr_middleware attr_accessor :before_request attr_accessor :logger + attr_accessor :use_vcr + attr_accessor :vcr_record_mode # Attributes for backwards compatibility def cypress_folder @@ -33,6 +35,8 @@ def reset self.use_vcr_middleware = false self.before_request = -> (request) {} self.logger = Logger.new(STDOUT) + self.use_vcr = false + self.vcr_record_mode = :new_episodes end def tagged_logged diff --git a/lib/cypress_on_rails/middleware.rb b/lib/cypress_on_rails/middleware.rb index 0505feb..be0f3f2 100644 --- a/lib/cypress_on_rails/middleware.rb +++ b/lib/cypress_on_rails/middleware.rb @@ -22,13 +22,7 @@ def call(env) warn "/__cypress__/command is deprecated. Please use the install generator to use /__e2e__/command instead." configuration.tagged_logged { handle_command(request) } else - if defined?(VCR) - VCR.use_cassette('foobar', { :record => :new_episodes }) do - @app.call(env) - end - else - @app.call(env) - end + VCRWrapper.new(app: @app, env: @env).run_with_cassette end end diff --git a/lib/cypress_on_rails/vcr_wrapper.rb b/lib/cypress_on_rails/vcr_wrapper.rb new file mode 100644 index 0000000..154f2b3 --- /dev/null +++ b/lib/cypress_on_rails/vcr_wrapper.rb @@ -0,0 +1,42 @@ +require 'rack' +require 'cypress_on_rails/configuration' + +module CypressOnRails + class VCRWrapper + + def initialize(app:, env:) + @app = app + @env = env + @request = Rack::Request.new(env) + end + + def run_with_cassette + if defined?(VCR) && configuration.use_vcr + VCR.use_cassette(cassette_name, { :record => configuration.vcr_record_mode }) do + logger.info "Handle request with cassette name: #{cassette_name}" + @app.call(env) + end + else + @app.call(env) + end + end + + private + + def configuration + CypressOnRails.configuration + end + + def logger + configuration.logger + end + + def cassette_name + if request.path.start_with?('/graphql') && request.params.key?(:operation) + "#{request.path}/#{request.params[:operation]}" + else + request.path + end + end + end +end From 569b884c6018b3da5b5ff259da357d8453d26e8b Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Wed, 15 Dec 2021 18:32:33 +0200 Subject: [PATCH 03/23] Update VCR wrapper --- lib/cypress_on_rails/middleware.rb | 4 +++- lib/cypress_on_rails/vcr_wrapper.rb | 16 +++++--------- .../spec/cypress/support/commands.js | 22 +++++++++++++++++++ .../spec/cypress/support/on-rails.js | 1 + 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/lib/cypress_on_rails/middleware.rb b/lib/cypress_on_rails/middleware.rb index be0f3f2..fce5ba4 100644 --- a/lib/cypress_on_rails/middleware.rb +++ b/lib/cypress_on_rails/middleware.rb @@ -21,8 +21,10 @@ def call(env) elsif request.path.start_with?("#{configuration.api_prefix}/__cypress__/command") warn "/__cypress__/command is deprecated. Please use the install generator to use /__e2e__/command instead." configuration.tagged_logged { handle_command(request) } + elsif defined?(VCR) && configuration.use_vcr + VCRWrapper.new(app: @app, env: env).run_with_cassette else - VCRWrapper.new(app: @app, env: @env).run_with_cassette + @app.call(env) end end diff --git a/lib/cypress_on_rails/vcr_wrapper.rb b/lib/cypress_on_rails/vcr_wrapper.rb index 154f2b3..6449d16 100644 --- a/lib/cypress_on_rails/vcr_wrapper.rb +++ b/lib/cypress_on_rails/vcr_wrapper.rb @@ -11,13 +11,9 @@ def initialize(app:, env:) end def run_with_cassette - if defined?(VCR) && configuration.use_vcr - VCR.use_cassette(cassette_name, { :record => configuration.vcr_record_mode }) do - logger.info "Handle request with cassette name: #{cassette_name}" - @app.call(env) - end - else - @app.call(env) + VCR.use_cassette(cassette_name, { :record => configuration.vcr_record_mode }) do + logger.info "Handle request with cassette name: #{cassette_name}" + @app.call(@env) end end @@ -32,10 +28,10 @@ def logger end def cassette_name - if request.path.start_with?('/graphql') && request.params.key?(:operation) - "#{request.path}/#{request.params[:operation]}" + if @request.path.start_with?('/graphql') && @request.params.key?('operation') + "#{@request.path}/#{@request.params['operation']}" else - request.path + @request.path end end end diff --git a/lib/generators/cypress_on_rails/templates/spec/cypress/support/commands.js b/lib/generators/cypress_on_rails/templates/spec/cypress/support/commands.js index c1f5a77..40caa52 100644 --- a/lib/generators/cypress_on_rails/templates/spec/cypress/support/commands.js +++ b/lib/generators/cypress_on_rails/templates/spec/cypress/support/commands.js @@ -23,3 +23,25 @@ // // -- This is will overwrite an existing command -- // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) +// +// +// -- This is for Graphql usage. Add proxy-like mock to add operation name into query string -- +// Cypress.Commands.add('mockGraphQL', () => { +// cy.on('window:before:load', (win) => { +// const originalFetch = win.fetch; +// const fetch = (path, options, ...rest) => { +// if (options && options.body) { +// try { +// const body = JSON.parse(options.body); +// if (body.operationName) { +// return originalFetch(`${path}?operation=${body.operationName}`, options, ...rest); +// } +// } catch (e) { +// return originalFetch(path, options, ...rest); +// } +// } +// return originalFetch(path, options, ...rest); +// }; +// cy.stub(win, 'fetch', fetch); +// }); +// }); diff --git a/lib/generators/cypress_on_rails/templates/spec/cypress/support/on-rails.js b/lib/generators/cypress_on_rails/templates/spec/cypress/support/on-rails.js index 79e8eca..947531d 100644 --- a/lib/generators/cypress_on_rails/templates/spec/cypress/support/on-rails.js +++ b/lib/generators/cypress_on_rails/templates/spec/cypress/support/on-rails.js @@ -47,6 +47,7 @@ Cypress.Commands.add('appFixtures', function (options) { // The next is optional // beforeEach(() => { // cy.app('clean') // have a look at cypress/app_commands/clean.rb +// cy.mockGraphQL(); // for GraphQL usage, see cypress/support/commands.rb // }); // comment this out if you do not want to attempt to log additional info on test fail From 109ab4cfdecca3c6640c92d190b51d04d3841fe1 Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Wed, 15 Dec 2021 18:40:12 +0200 Subject: [PATCH 04/23] Add VCR wrapper require call --- lib/cypress_on_rails/middleware.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/cypress_on_rails/middleware.rb b/lib/cypress_on_rails/middleware.rb index fce5ba4..45d3d46 100644 --- a/lib/cypress_on_rails/middleware.rb +++ b/lib/cypress_on_rails/middleware.rb @@ -2,6 +2,7 @@ require 'rack' require 'cypress_on_rails/middleware_config' require 'cypress_on_rails/command_executor' +require 'cypress_on_rails/vcr_wrapper' module CypressOnRails # Middleware to handle testing framework commands and eval From 06b5c8b6225111db90c52b6b997f0c8fc420df47 Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Wed, 19 Apr 2023 18:18:41 +0200 Subject: [PATCH 05/23] Remove old exists? --- specs_e2e/rails_3_2/config/boot.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs_e2e/rails_3_2/config/boot.rb b/specs_e2e/rails_3_2/config/boot.rb index 4489e58..f2830ae 100644 --- a/specs_e2e/rails_3_2/config/boot.rb +++ b/specs_e2e/rails_3_2/config/boot.rb @@ -3,4 +3,4 @@ # Set up gems listed in the Gemfile. ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) -require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) +require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) From a5bcdddd8c2ac9d2c0132c63f4e63c6a4a425be3 Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Sun, 7 Jul 2024 19:32:59 +0200 Subject: [PATCH 06/23] Refactor use_cassette middleware --- lib/cypress_on_rails/configuration.rb | 9 +- lib/cypress_on_rails/middleware.rb | 3 - lib/cypress_on_rails/railtie.rb | 8 +- lib/cypress_on_rails/vcr/base_middleware.rb | 39 ++++++ .../vcr/insert_eject_middleware.rb | 71 ++++++++++ .../vcr/use_cassette_middleware.rb | 41 ++++++ lib/cypress_on_rails/vcr_middleware.rb | 73 ----------- lib/cypress_on_rails/vcr_wrapper.rb | 38 ------ .../initializers/cypress_on_rails.rb.erb | 3 + .../vcr/insert_eject_middleware_spec.rb | 121 ++++++++++++++++++ .../vcr/use_cassette_middleware_spec.rb | 44 +++++++ spec/cypress_on_rails/vcr_middleware_spec.rb | 119 ----------------- 12 files changed, 330 insertions(+), 239 deletions(-) create mode 100644 lib/cypress_on_rails/vcr/base_middleware.rb create mode 100644 lib/cypress_on_rails/vcr/insert_eject_middleware.rb create mode 100644 lib/cypress_on_rails/vcr/use_cassette_middleware.rb delete mode 100644 lib/cypress_on_rails/vcr_middleware.rb delete mode 100644 lib/cypress_on_rails/vcr_wrapper.rb create mode 100644 spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb create mode 100644 spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb delete mode 100644 spec/cypress_on_rails/vcr_middleware_spec.rb diff --git a/lib/cypress_on_rails/configuration.rb b/lib/cypress_on_rails/configuration.rb index a9c7940..8d10510 100644 --- a/lib/cypress_on_rails/configuration.rb +++ b/lib/cypress_on_rails/configuration.rb @@ -6,10 +6,10 @@ class Configuration attr_accessor :install_folder attr_accessor :use_middleware attr_accessor :use_vcr_middleware + attr_accessor :use_vcr_use_cassette_middleware attr_accessor :before_request attr_accessor :logger - attr_accessor :use_vcr - attr_accessor :vcr_record_mode + attr_accessor :vcr_use_cassette_mode # Attributes for backwards compatibility def cypress_folder @@ -27,16 +27,17 @@ def initialize alias :use_middleware? :use_middleware alias :use_vcr_middleware? :use_vcr_middleware + alias :use_vcr_use_cassette_middleware? :use_vcr_use_cassette_middleware def reset self.api_prefix = '' self.install_folder = 'spec/e2e' self.use_middleware = true self.use_vcr_middleware = false + self.use_vcr_use_cassette_middleware = false self.before_request = -> (request) {} self.logger = Logger.new(STDOUT) - self.use_vcr = false - self.vcr_record_mode = :new_episodes + self.vcr_use_cassette_mode = :new_episodes end def tagged_logged diff --git a/lib/cypress_on_rails/middleware.rb b/lib/cypress_on_rails/middleware.rb index 45d3d46..f5ed274 100644 --- a/lib/cypress_on_rails/middleware.rb +++ b/lib/cypress_on_rails/middleware.rb @@ -2,7 +2,6 @@ require 'rack' require 'cypress_on_rails/middleware_config' require 'cypress_on_rails/command_executor' -require 'cypress_on_rails/vcr_wrapper' module CypressOnRails # Middleware to handle testing framework commands and eval @@ -22,8 +21,6 @@ def call(env) elsif request.path.start_with?("#{configuration.api_prefix}/__cypress__/command") warn "/__cypress__/command is deprecated. Please use the install generator to use /__e2e__/command instead." configuration.tagged_logged { handle_command(request) } - elsif defined?(VCR) && configuration.use_vcr - VCRWrapper.new(app: @app, env: env).run_with_cassette else @app.call(env) end diff --git a/lib/cypress_on_rails/railtie.rb b/lib/cypress_on_rails/railtie.rb index de6a582..8ff287b 100644 --- a/lib/cypress_on_rails/railtie.rb +++ b/lib/cypress_on_rails/railtie.rb @@ -9,8 +9,12 @@ class Railtie < Rails::Railtie app.middleware.use Middleware end if CypressOnRails.configuration.use_vcr_middleware? - require 'cypress_on_rails/vcr_middleware' - app.middleware.use VCRMiddleware + require 'cypress_on_rails/vcr/insert_inject_middleware' + app.middleware.use Vcr::InsertEjectMiddleware + end + if CypressOnRails.configuration.use_vcr_use_cassette_middleware? + require 'cypress_on_rails/vcr/use_cassette_middleware' + app.middleware.use Vcr::UseCassetteMiddleware end end end diff --git a/lib/cypress_on_rails/vcr/base_middleware.rb b/lib/cypress_on_rails/vcr/base_middleware.rb new file mode 100644 index 0000000..edfab04 --- /dev/null +++ b/lib/cypress_on_rails/vcr/base_middleware.rb @@ -0,0 +1,39 @@ +require 'json' +require 'rack' +require 'cypress_on_rails/middleware_config' + +module CypressOnRails + module Vcr + # Base abstract Middleware + class BaseMiddleware + include MiddlewareConfig + + def initialize(_app, _vcr = nil) + raise_not_implemented + end + + def call(_env) + raise_not_implemented + end + + def vcr + @vcr ||= configure_vcr + end + + private + + def configure_vcr + require 'vcr' + VCR.configure do |config| + config.cassette_library_dir = "#{configuration.install_folder}/fixtures/vcr_cassettes" + end + VCR + end + + def raise_not_implemented + raise NotImplementedError, + 'BaseMiddleware can not be initialized directly, use InsertEjectMiddleware or UseCassetteMiddleware' + end + end + end +end diff --git a/lib/cypress_on_rails/vcr/insert_eject_middleware.rb b/lib/cypress_on_rails/vcr/insert_eject_middleware.rb new file mode 100644 index 0000000..3a9952e --- /dev/null +++ b/lib/cypress_on_rails/vcr/insert_eject_middleware.rb @@ -0,0 +1,71 @@ +require_relative 'base_middleware' + +module CypressOnRails + module Vcr + # Middleware to handle vcr with insert/eject endpoints + class InsertEjectMiddleware < BaseMiddleware + def initialize(app, vcr = nil) + @app = app + @vcr = vcr + @first_call = false + end + + def call(env) + request = Rack::Request.new(env) + if request.path.start_with?('/__e2e__/vcr/insert') + configuration.tagged_logged { handle_insert(request) } + elsif request.path.start_with?('/__e2e__/vcr/eject') + configuration.tagged_logged { handle_eject } + else + do_first_call unless @first_call + @app.call(env) + end + end + + private + + def handle_insert(req) + WebMock.enable! if defined?(WebMock) + vcr.turn_on! + logger.info "vcr insert cassette: #{body}" + body = parse_request_body(req) + cassette_name, options = extract_cassette_info(body) + vcr.insert_cassette(cassette_name, options) + [201, { 'Content-Type' => 'application/json' }, [{ 'message': 'OK' }.to_json]] + rescue LoadError, ArgumentError => e + [501, { 'Content-Type' => 'application/json' }, [{ 'message': e.message }.to_json]] + end + + def parse_request_body(req) + JSON.parse(req.body.read) + end + + def extract_cassette_info(body) + cassette_name = body[0] + options = (body[1] || {}).symbolize_keys + options[:record] = options[:record].to_sym if options[:record] + options[:match_requests_on] = options[:match_requests_on].map(&:to_sym) if options[:match_requests_on] + options[:serialize_with] = options[:serialize_with].to_sym if options[:serialize_with] + options[:persist_with] = options[:persist_with].to_sym if options[:persist_with] + [cassette_name, options] + end + + def handle_eject + logger.info 'vcr eject cassette' + vcr.eject_cassette + do_first_call + [201, { 'Content-Type' => 'application/json' }, [{ 'message': 'OK' }.to_json]] + rescue LoadError, ArgumentError => e + [501, { 'Content-Type' => 'application/json' }, [{ 'message': e.message }.to_json]] + end + + def do_first_call + @first_call = true + vcr.turn_off! + WebMock.disable! if defined?(WebMock) + rescue LoadError + # nop + end + end + end +end diff --git a/lib/cypress_on_rails/vcr/use_cassette_middleware.rb b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb new file mode 100644 index 0000000..2e6d6bb --- /dev/null +++ b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb @@ -0,0 +1,41 @@ +require 'cypress_on_rails/configuration' +require_relative 'base_middleware' + +module CypressOnRails + module Vcr + # Middleware to handle vcr with use_cassette + class UseCassetteMiddleware < BaseMiddleware + def initialize(app, vcr = nil) + @app = app + @vcr = vcr + end + + def call(env) + request = Rack::Request.new(env) + cassette_name = fetch_request_cassette(request) + vcr.use_cassette(cassette_name, { record: configuration.vcr_use_cassette_mode }) do + logger.info "Handle request with cassette name: #{cassette_name}" + @app.call(env) + end + end + + private + + def configuration + CypressOnRails.configuration + end + + def logger + configuration.logger + end + + def fetch_request_cassette(request) + if request.path.start_with?('/graphql') && request.params.key?('operation') + "#{request.path}/#{request.params['operation']}" + else + request.path + end + end + end + end +end diff --git a/lib/cypress_on_rails/vcr_middleware.rb b/lib/cypress_on_rails/vcr_middleware.rb deleted file mode 100644 index e675dbc..0000000 --- a/lib/cypress_on_rails/vcr_middleware.rb +++ /dev/null @@ -1,73 +0,0 @@ -require 'json' -require 'rack' -require 'cypress_on_rails/middleware_config' - -module CypressOnRails - # Middleware to handle vcr - class VCRMiddleware - include MiddlewareConfig - - def initialize(app, vcr = nil) - @app = app - @vcr = vcr - @first_call = false - end - - def call(env) - request = Rack::Request.new(env) - if request.path.start_with?('/__e2e__/vcr/insert') - configuration.tagged_logged { handle_insert(request) } - elsif request.path.start_with?('/__e2e__/vcr/eject') - configuration.tagged_logged { handle_eject } - else - do_first_call unless @first_call - @app.call(env) - end - end - - private - - def handle_insert(req) - WebMock.enable! if defined?(WebMock) - vcr.turn_on! - body = JSON.parse(req.body.read) - logger.info "vcr insert cassette: #{body}" - cassette_name = body[0] - options = (body[1] || {}).symbolize_keys - options[:record] = options[:record].to_sym if options[:record] - options[:match_requests_on] = options[:match_requests_on].map(&:to_sym) if options[:match_requests_on] - options[:serialize_with] = options[:serialize_with].to_sym if options[:serialize_with] - options[:persist_with] = options[:persist_with].to_sym if options[:persist_with] - vcr.insert_cassette(cassette_name, options) - [201, {'Content-Type' => 'application/json'}, [{'message': 'OK'}.to_json]] - rescue LoadError, ArgumentError => e - [501, {'Content-Type' => 'application/json'}, [{'message': e.message}.to_json]] - end - - def handle_eject - logger.info "vcr eject cassette" - vcr.eject_cassette - do_first_call - [201, {'Content-Type' => 'application/json'}, [{'message': 'OK'}.to_json]] - rescue LoadError, ArgumentError => e - [501, {'Content-Type' => 'application/json'}, [{'message': e.message}.to_json]] - end - - def vcr - return @vcr if @vcr - require 'vcr' - VCR.configure do |config| - config.cassette_library_dir = "#{configuration.install_folder}/fixtures/vcr_cassettes" - end - @vcr = VCR - end - - def do_first_call - @first_call = true - vcr.turn_off! - WebMock.disable! if defined?(WebMock) - rescue LoadError - # nop - end - end -end diff --git a/lib/cypress_on_rails/vcr_wrapper.rb b/lib/cypress_on_rails/vcr_wrapper.rb deleted file mode 100644 index 6449d16..0000000 --- a/lib/cypress_on_rails/vcr_wrapper.rb +++ /dev/null @@ -1,38 +0,0 @@ -require 'rack' -require 'cypress_on_rails/configuration' - -module CypressOnRails - class VCRWrapper - - def initialize(app:, env:) - @app = app - @env = env - @request = Rack::Request.new(env) - end - - def run_with_cassette - VCR.use_cassette(cassette_name, { :record => configuration.vcr_record_mode }) do - logger.info "Handle request with cassette name: #{cassette_name}" - @app.call(@env) - end - end - - private - - def configuration - CypressOnRails.configuration - end - - def logger - configuration.logger - end - - def cassette_name - if @request.path.start_with?('/graphql') && @request.params.key?('operation') - "#{@request.path}/#{@request.params['operation']}" - else - @request.path - end - end - end -end diff --git a/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb b/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb index 77bd389..da6fd4f 100644 --- a/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb +++ b/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb @@ -6,6 +6,9 @@ if defined?(CypressOnRails) # please use with extra caution if enabling on hosted servers or starting your local server on 0.0.0.0 c.use_middleware = !Rails.env.production? <% unless options.experimental %># <% end %> c.use_vcr_middleware = !Rails.env.production? + # Use this if you want to use use_cassette wrapper instead of manual insert/eject + # c.use_vcr_use_cassette_middleware = !Rails.env.production? + # c.vcr_use_cassette_mode = :once # Use to choose VCR record mode (:new_episodes by default) c.logger = Rails.logger # If you want to enable a before_request logic, such as authentication, logging, sending metrics, etc. diff --git a/spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb b/spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb new file mode 100644 index 0000000..ba3f762 --- /dev/null +++ b/spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb @@ -0,0 +1,121 @@ +require 'cypress_on_rails/vcr/insert_eject_middleware' +require 'vcr' +require 'active_support/core_ext/hash' unless {}.respond_to?(:symbolize_keys) + +module CypressOnRails + module Vcr + RSpec.describe InsertEjectMiddleware do + let(:app) { ->(env) { [200, {}, ["app did #{env['PATH_INFO']}"]] } } + let(:vcr) { class_double(VCR, turn_on!: true, turn_off!: true, insert_cassette: true, eject_cassette: true) } + subject { described_class.new(app, vcr) } + + let(:env) { {} } + + let(:response) { subject.call(env) } + + def rack_input(json_value) + StringIO.new(JSON.generate(json_value)) + end + + describe '/__e2e__/vcr/insert' do + before do + env['PATH_INFO'] = '/__e2e__/vcr/insert' + end + + it do + env['rack.input'] = rack_input(['cas1']) + + aggregate_failures do + expect(response).to eq([201, + { 'Content-Type' => 'application/json' }, + ['{"message":"OK"}']]) + expect(vcr).to have_received(:turn_on!) + expect(vcr).to have_received(:insert_cassette).with('cas1', {}) + end + end + + it 'works with record' do + env['rack.input'] = rack_input(['cas1', { 'record' => 'new_episodes' }]) + + aggregate_failures do + expect(response).to eq([201, + { 'Content-Type' => 'application/json' }, + ['{"message":"OK"}']]) + expect(vcr).to have_received(:insert_cassette).with('cas1', record: :new_episodes) + end + end + + it 'works with match_requests_on' do + env['rack.input'] = rack_input(['cas1', { 'match_requests_on' => %w[method uri] }]) + + aggregate_failures do + expect(response).to eq([201, + { 'Content-Type' => 'application/json' }, + ['{"message":"OK"}']]) + expect(vcr).to have_received(:insert_cassette).with('cas1', match_requests_on: %i[method uri]) + end + end + + it 'works with serialize_with' do + env['rack.input'] = rack_input(['cas1', { 'serialize_with' => 'yaml' }]) + + aggregate_failures do + expect(response).to eq([201, + { 'Content-Type' => 'application/json' }, + ['{"message":"OK"}']]) + expect(vcr).to have_received(:insert_cassette).with('cas1', serialize_with: :yaml) + end + end + + it 'works with persist_with' do + env['rack.input'] = rack_input(['cas1', { 'persist_with' => 'file_system' }]) + + aggregate_failures do + expect(response).to eq([201, + { 'Content-Type' => 'application/json' }, + ['{"message":"OK"}']]) + expect(vcr).to have_received(:insert_cassette).with('cas1', persist_with: :file_system) + end + end + end + + describe '/__e2e__/vcr/eject' do + before do + env['PATH_INFO'] = '/__e2e__/vcr/eject' + end + + it do + aggregate_failures do + expect(response).to eq([201, + { 'Content-Type' => 'application/json' }, + ['{"message":"OK"}']]) + expect(vcr).to have_received(:turn_off!) + expect(vcr).to have_received(:eject_cassette) + end + end + end + + describe '"Other paths"' do + it 'calls vcr turn off the first time' do + env['PATH_INFO'] = '/test' + + expect(response).to eq([200, {}, ['app did /test']]) + expect(vcr).to have_received(:turn_off!) + end + + it 'runs app' do + aggregate_failures do + %w[/ /__e2e__/login command /e2e_command /].each do |path| + env['PATH_INFO'] = path + + response = subject.call(env) + + expect(response).to eq([200, {}, ["app did #{path}"]]) + expect(vcr).to have_received(:turn_off!) + end + end + end + end + end + end +end diff --git a/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb b/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb new file mode 100644 index 0000000..2b48686 --- /dev/null +++ b/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb @@ -0,0 +1,44 @@ +require 'cypress_on_rails/vcr/use_cassette_middleware' +require 'vcr' +require 'active_support/core_ext/hash' unless {}.respond_to?(:symbolize_keys) + +module CypressOnRails + module Vcr + RSpec.describe UseCassetteMiddleware do + let(:app) { ->(env) { [200, {}, ["app did #{env['PATH_INFO']}"]] } } + let(:vcr) { VCR } + subject { described_class.new(app, vcr) } + + let(:env) { { 'rack.input' => rack_input([]) } } + + let(:response) { subject.call(env) } + + def rack_input(json_value) + StringIO.new(JSON.generate(json_value)) + end + + before do + allow(vcr).to receive(:use_cassette).and_yield + end + + it 'returns the application response using correct graphql cassette' do + env['PATH_INFO'] = '/graphql' + env['QUERY_STRING'] = 'operation=test' + + expect(response).to eq([200, {}, ['app did /graphql']]) + expect(vcr).to have_received(:use_cassette) + .with('/graphql/test', hash_including(record: :new_episodes)) + end + + it 'returns the application response using default request path cassette' do + allow(CypressOnRails).to receive(:configuration).and_return(double(vcr_use_cassette_mode: :once, + logger: Logger.new(nil))) + env['PATH_INFO'] = '/test/path' + + expect(response).to eq([200, {}, ['app did /test/path']]) + expect(vcr).to have_received(:use_cassette) + .with('/test/path', hash_including(record: :once)) + end + end + end +end diff --git a/spec/cypress_on_rails/vcr_middleware_spec.rb b/spec/cypress_on_rails/vcr_middleware_spec.rb deleted file mode 100644 index fe13616..0000000 --- a/spec/cypress_on_rails/vcr_middleware_spec.rb +++ /dev/null @@ -1,119 +0,0 @@ -require 'cypress_on_rails/vcr_middleware' -require 'vcr' -require 'active_support/core_ext/hash' unless Hash.new.respond_to?(:symbolize_keys) - -module CypressOnRails - RSpec.describe VCRMiddleware do - let(:app) { ->(env) { [200, {}, ["app did #{env['PATH_INFO']}"]] } } - let(:vcr) { class_double(VCR, turn_on!: true, turn_off!: true, insert_cassette: true, eject_cassette: true) } - subject { described_class.new(app, vcr) } - - let(:env) { {} } - - let(:response) { subject.call(env) } - - def rack_input(json_value) - StringIO.new(JSON.generate(json_value)) - end - - describe '/__e2e__/vcr/insert' do - before do - env['PATH_INFO'] = '/__e2e__/vcr/insert' - end - - it do - env['rack.input'] = rack_input(['cas1']) - - aggregate_failures do - expect(response).to eq([201, - {"Content-Type"=>"application/json"}, - ["{\"message\":\"OK\"}"]]) - expect(vcr).to have_received(:turn_on!) - expect(vcr).to have_received(:insert_cassette).with('cas1', {}) - end - end - - it 'works with record' do - env['rack.input'] = rack_input(['cas1', { "record" => "new_episodes" }]) - - aggregate_failures do - expect(response).to eq([201, - {"Content-Type"=>"application/json"}, - ["{\"message\":\"OK\"}"]]) - expect(vcr).to have_received(:insert_cassette).with('cas1', record: :new_episodes) - end - end - - it 'works with match_requests_on' do - env['rack.input'] = rack_input(['cas1', { "match_requests_on" => ["method", "uri"] }]) - - aggregate_failures do - expect(response).to eq([201, - {"Content-Type"=>"application/json"}, - ["{\"message\":\"OK\"}"]]) - expect(vcr).to have_received(:insert_cassette).with('cas1', match_requests_on: [:method, :uri]) - end - end - - it 'works with serialize_with' do - env['rack.input'] = rack_input(['cas1', { "serialize_with" => "yaml" }]) - - aggregate_failures do - expect(response).to eq([201, - {"Content-Type"=>"application/json"}, - ["{\"message\":\"OK\"}"]]) - expect(vcr).to have_received(:insert_cassette).with('cas1', serialize_with: :yaml) - end - end - - it 'works with persist_with' do - env['rack.input'] = rack_input(['cas1', { "persist_with" => "file_system" }]) - - aggregate_failures do - expect(response).to eq([201, - {"Content-Type"=>"application/json"}, - ["{\"message\":\"OK\"}"]]) - expect(vcr).to have_received(:insert_cassette).with('cas1', persist_with: :file_system) - end - end - end - - describe '/__e2e__/vcr/eject' do - before do - env['PATH_INFO'] = '/__e2e__/vcr/eject' - end - - it do - aggregate_failures do - expect(response).to eq([201, - {"Content-Type"=>"application/json"}, - ["{\"message\":\"OK\"}"]]) - expect(vcr).to have_received(:turn_off!) - expect(vcr).to have_received(:eject_cassette) - end - end - end - - describe '"Other paths"' do - it 'calls vcr turn off the first time' do - env['PATH_INFO'] = '/test' - - expect(response).to eq([200, {}, ["app did /test"]]) - expect(vcr).to have_received(:turn_off!) - end - - it 'runs app' do - aggregate_failures do - %w(/ /__e2e__/login command /e2e_command /).each do |path| - env['PATH_INFO'] = path - - response = subject.call(env) - - expect(response).to eq([200, {}, ["app did #{path}"]]) - expect(vcr).to have_received(:turn_off!) - end - end - end - end - end -end From 2b85c20358d1df7be19a828e0ec663266cf45ed8 Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Sun, 7 Jul 2024 20:04:57 +0200 Subject: [PATCH 07/23] Move logger --- lib/cypress_on_rails/vcr/insert_eject_middleware.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cypress_on_rails/vcr/insert_eject_middleware.rb b/lib/cypress_on_rails/vcr/insert_eject_middleware.rb index 3a9952e..33d20e2 100644 --- a/lib/cypress_on_rails/vcr/insert_eject_middleware.rb +++ b/lib/cypress_on_rails/vcr/insert_eject_middleware.rb @@ -27,8 +27,8 @@ def call(env) def handle_insert(req) WebMock.enable! if defined?(WebMock) vcr.turn_on! - logger.info "vcr insert cassette: #{body}" body = parse_request_body(req) + logger.info "vcr insert cassette: #{body}" cassette_name, options = extract_cassette_info(body) vcr.insert_cassette(cassette_name, options) [201, { 'Content-Type' => 'application/json' }, [{ 'message': 'OK' }.to_json]] From 5fda9abd4e5ee65343c667c5fac1a6118998672e Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Sun, 7 Jul 2024 20:53:35 +0200 Subject: [PATCH 08/23] Fix CI issue --- specs_e2e/rails_4_2/Gemfile | 1 + 1 file changed, 1 insertion(+) diff --git a/specs_e2e/rails_4_2/Gemfile b/specs_e2e/rails_4_2/Gemfile index 835f8b5..fe50f9e 100644 --- a/specs_e2e/rails_4_2/Gemfile +++ b/specs_e2e/rails_4_2/Gemfile @@ -3,6 +3,7 @@ source 'https://rubygems.org' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '~> 4.2.10' gem 'sprockets', '~> 3.7.2' +gem 'bigdecimal', '1.3.5' group :development, :test do gem 'vcr' From c58a280f24e10ef91afbff4c71e65476268f5d46 Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Sat, 13 Jul 2024 20:35:11 +0200 Subject: [PATCH 09/23] Typo in path --- lib/cypress_on_rails/railtie.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cypress_on_rails/railtie.rb b/lib/cypress_on_rails/railtie.rb index 8ff287b..924a81d 100644 --- a/lib/cypress_on_rails/railtie.rb +++ b/lib/cypress_on_rails/railtie.rb @@ -9,7 +9,7 @@ class Railtie < Rails::Railtie app.middleware.use Middleware end if CypressOnRails.configuration.use_vcr_middleware? - require 'cypress_on_rails/vcr/insert_inject_middleware' + require 'cypress_on_rails/vcr/insert_eject_middleware' app.middleware.use Vcr::InsertEjectMiddleware end if CypressOnRails.configuration.use_vcr_use_cassette_middleware? From 3cee5e55321676dca09d87deea271cf165002c17 Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Sat, 10 Aug 2024 15:40:25 +0200 Subject: [PATCH 10/23] Remove unused methods --- lib/cypress_on_rails/vcr/base_middleware.rb | 2 +- lib/cypress_on_rails/vcr/use_cassette_middleware.rb | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/cypress_on_rails/vcr/base_middleware.rb b/lib/cypress_on_rails/vcr/base_middleware.rb index edfab04..92b82e2 100644 --- a/lib/cypress_on_rails/vcr/base_middleware.rb +++ b/lib/cypress_on_rails/vcr/base_middleware.rb @@ -8,7 +8,7 @@ module Vcr class BaseMiddleware include MiddlewareConfig - def initialize(_app, _vcr = nil) + def initialize(**_args) raise_not_implemented end diff --git a/lib/cypress_on_rails/vcr/use_cassette_middleware.rb b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb index 2e6d6bb..ccc9fb3 100644 --- a/lib/cypress_on_rails/vcr/use_cassette_middleware.rb +++ b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb @@ -11,6 +11,8 @@ def initialize(app, vcr = nil) end def call(env) + WebMock.enable! if defined?(WebMock) + vcr.turn_on! request = Rack::Request.new(env) cassette_name = fetch_request_cassette(request) vcr.use_cassette(cassette_name, { record: configuration.vcr_use_cassette_mode }) do @@ -21,14 +23,6 @@ def call(env) private - def configuration - CypressOnRails.configuration - end - - def logger - configuration.logger - end - def fetch_request_cassette(request) if request.path.start_with?('/graphql') && request.params.key?('operation') "#{request.path}/#{request.params['operation']}" From f3bcd06a8a377370214974e93689a9a590330a70 Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Sat, 10 Aug 2024 16:35:48 +0200 Subject: [PATCH 11/23] Cleanup comments --- .../cypress_on_rails/templates/spec/cypress/support/on-rails.js | 2 +- specs_e2e/rails_4_2/Gemfile | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/generators/cypress_on_rails/templates/spec/cypress/support/on-rails.js b/lib/generators/cypress_on_rails/templates/spec/cypress/support/on-rails.js index 947531d..adfb3b4 100644 --- a/lib/generators/cypress_on_rails/templates/spec/cypress/support/on-rails.js +++ b/lib/generators/cypress_on_rails/templates/spec/cypress/support/on-rails.js @@ -47,7 +47,7 @@ Cypress.Commands.add('appFixtures', function (options) { // The next is optional // beforeEach(() => { // cy.app('clean') // have a look at cypress/app_commands/clean.rb -// cy.mockGraphQL(); // for GraphQL usage, see cypress/support/commands.rb +// cy.mockGraphQL() // for GraphQL usage, see cypress/support/commands.rb // }); // comment this out if you do not want to attempt to log additional info on test fail diff --git a/specs_e2e/rails_4_2/Gemfile b/specs_e2e/rails_4_2/Gemfile index fe50f9e..3ca9472 100644 --- a/specs_e2e/rails_4_2/Gemfile +++ b/specs_e2e/rails_4_2/Gemfile @@ -3,6 +3,8 @@ source 'https://rubygems.org' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '~> 4.2.10' gem 'sprockets', '~> 3.7.2' +# Solution for issue: NoMethodError: undefined method `new' for BigDecimal:Class +# https://github.com/ruby/bigdecimal?tab=readme-ov-file#which-version-should-you-select gem 'bigdecimal', '1.3.5' group :development, :test do From 6b7f06d761e1f5171c47c650894779e70784872e Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Sun, 18 Aug 2024 16:56:43 +0200 Subject: [PATCH 12/23] Update VCR logic --- lib/cypress_on_rails/vcr/base_middleware.rb | 6 +++- .../vcr/use_cassette_middleware.rb | 10 ++++++- .../vcr/use_cassette_middleware_spec.rb | 28 +++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/lib/cypress_on_rails/vcr/base_middleware.rb b/lib/cypress_on_rails/vcr/base_middleware.rb index 92b82e2..5d2d082 100644 --- a/lib/cypress_on_rails/vcr/base_middleware.rb +++ b/lib/cypress_on_rails/vcr/base_middleware.rb @@ -25,11 +25,15 @@ def vcr def configure_vcr require 'vcr' VCR.configure do |config| - config.cassette_library_dir = "#{configuration.install_folder}/fixtures/vcr_cassettes" + config.cassette_library_dir = cassette_library_dir end VCR end + def cassette_library_dir + "#{configuration.install_folder}/fixtures/vcr_cassettes" + end + def raise_not_implemented raise NotImplementedError, 'BaseMiddleware can not be initialized directly, use InsertEjectMiddleware or UseCassetteMiddleware' diff --git a/lib/cypress_on_rails/vcr/use_cassette_middleware.rb b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb index ccc9fb3..dca75b0 100644 --- a/lib/cypress_on_rails/vcr/use_cassette_middleware.rb +++ b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb @@ -1,4 +1,3 @@ -require 'cypress_on_rails/configuration' require_relative 'base_middleware' module CypressOnRails @@ -11,6 +10,11 @@ def initialize(app, vcr = nil) end def call(env) + vcr_initialized = vcr_defined? && + VCR.configuration.cassette_library_dir.present? && + VCR.configuration.cassette_library_dir != cassette_library_dir + return @app.call(env) if vcr_initialized + WebMock.enable! if defined?(WebMock) vcr.turn_on! request = Rack::Request.new(env) @@ -23,6 +27,10 @@ def call(env) private + def vcr_defined? + defined?(VCR) != nil + end + def fetch_request_cassette(request) if request.path.start_with?('/graphql') && request.params.key?('operation') "#{request.path}/#{request.params['operation']}" diff --git a/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb b/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb index 2b48686..8688333 100644 --- a/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb +++ b/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb @@ -39,6 +39,34 @@ def rack_input(json_value) expect(vcr).to have_received(:use_cassette) .with('/test/path', hash_including(record: :once)) end + + context 'when VCR cassette library directory does not match' do + before do + allow(VCR.configuration).to receive(:cassette_library_dir).and_return('/different/path') + end + + it 'returns the application response without using VCR' do + env['PATH_INFO'] = '/test/path' + + expect(response).to eq([200, {}, ['app did /test/path']]) + expect(vcr).not_to have_received(:use_cassette) + end + end + + context 'when VCR is not defined' do + before do + allow(subject).to receive(:vcr_defined?).and_return(false) + end + + it 'returns the application response without error' do + env['PATH_INFO'] = '/graphql' + env['QUERY_STRING'] = 'operation=test' + + expect(response).to eq([200, {}, ['app did /graphql']]) + expect(vcr).to have_received(:use_cassette) + .with('/graphql/test', hash_including(record: :new_episodes)) + end + end end end end From 47af81d2c17045714102e2aec2e6eadcbcfa7ad8 Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Sun, 8 Sep 2024 10:46:48 +0200 Subject: [PATCH 13/23] Changes cleanup --- lib/cypress_on_rails/configuration.rb | 4 +-- .../vcr/use_cassette_middleware.rb | 33 ++++++++++++------- .../initializers/cypress_on_rails.rb.erb | 2 +- .../spec/cypress/support/on-rails.js | 2 +- .../vcr/use_cassette_middleware_spec.rb | 2 +- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/lib/cypress_on_rails/configuration.rb b/lib/cypress_on_rails/configuration.rb index 8d10510..c7f42b4 100644 --- a/lib/cypress_on_rails/configuration.rb +++ b/lib/cypress_on_rails/configuration.rb @@ -9,7 +9,7 @@ class Configuration attr_accessor :use_vcr_use_cassette_middleware attr_accessor :before_request attr_accessor :logger - attr_accessor :vcr_use_cassette_mode + attr_accessor :vcr_record_mode # Attributes for backwards compatibility def cypress_folder @@ -37,7 +37,7 @@ def reset self.use_vcr_use_cassette_middleware = false self.before_request = -> (request) {} self.logger = Logger.new(STDOUT) - self.vcr_use_cassette_mode = :new_episodes + self.vcr_record_mode = :new_episodes end def tagged_logged diff --git a/lib/cypress_on_rails/vcr/use_cassette_middleware.rb b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb index dca75b0..79d0f48 100644 --- a/lib/cypress_on_rails/vcr/use_cassette_middleware.rb +++ b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb @@ -10,27 +10,38 @@ def initialize(app, vcr = nil) end def call(env) - vcr_initialized = vcr_defined? && - VCR.configuration.cassette_library_dir.present? && - VCR.configuration.cassette_library_dir != cassette_library_dir - return @app.call(env) if vcr_initialized + return @app.call(env) if should_not_use_vcr? + initialize_vcr + handle_request_with_vcr(env) + end + + private + + def vcr_defined? + defined?(VCR) != nil + end + + def should_not_use_vcr? + vcr_defined? && + VCR.configuration.cassette_library_dir.present? && + VCR.configuration.cassette_library_dir != cassette_library_dir + end + + def initialize_vcr WebMock.enable! if defined?(WebMock) vcr.turn_on! + end + + def handle_request_with_vcr(env) request = Rack::Request.new(env) cassette_name = fetch_request_cassette(request) - vcr.use_cassette(cassette_name, { record: configuration.vcr_use_cassette_mode }) do + vcr.use_cassette(cassette_name, { record: configuration.vcr_record_mode }) do logger.info "Handle request with cassette name: #{cassette_name}" @app.call(env) end end - private - - def vcr_defined? - defined?(VCR) != nil - end - def fetch_request_cassette(request) if request.path.start_with?('/graphql') && request.params.key?('operation') "#{request.path}/#{request.params['operation']}" diff --git a/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb b/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb index da6fd4f..2ec6534 100644 --- a/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb +++ b/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb @@ -8,7 +8,7 @@ if defined?(CypressOnRails) <% unless options.experimental %># <% end %> c.use_vcr_middleware = !Rails.env.production? # Use this if you want to use use_cassette wrapper instead of manual insert/eject # c.use_vcr_use_cassette_middleware = !Rails.env.production? - # c.vcr_use_cassette_mode = :once # Use to choose VCR record mode (:new_episodes by default) + # c.vcr_record_mode = :once # Use to choose VCR record mode c.logger = Rails.logger # If you want to enable a before_request logic, such as authentication, logging, sending metrics, etc. diff --git a/lib/generators/cypress_on_rails/templates/spec/cypress/support/on-rails.js b/lib/generators/cypress_on_rails/templates/spec/cypress/support/on-rails.js index adfb3b4..a3bbaef 100644 --- a/lib/generators/cypress_on_rails/templates/spec/cypress/support/on-rails.js +++ b/lib/generators/cypress_on_rails/templates/spec/cypress/support/on-rails.js @@ -47,7 +47,7 @@ Cypress.Commands.add('appFixtures', function (options) { // The next is optional // beforeEach(() => { // cy.app('clean') // have a look at cypress/app_commands/clean.rb -// cy.mockGraphQL() // for GraphQL usage, see cypress/support/commands.rb +// cy.mockGraphQL() // for GraphQL usage with use_cassette, see cypress/support/commands.rb // }); // comment this out if you do not want to attempt to log additional info on test fail diff --git a/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb b/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb index 8688333..e18c8f9 100644 --- a/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb +++ b/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb @@ -31,7 +31,7 @@ def rack_input(json_value) end it 'returns the application response using default request path cassette' do - allow(CypressOnRails).to receive(:configuration).and_return(double(vcr_use_cassette_mode: :once, + allow(CypressOnRails).to receive(:configuration).and_return(double(vcr_record_mode: :once, logger: Logger.new(nil))) env['PATH_INFO'] = '/test/path' From a71b949f3f5c40a014adedbc375426622d56a7d4 Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Sun, 8 Sep 2024 10:46:58 +0200 Subject: [PATCH 14/23] Update readme --- README.md | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9803f04..2dbf1c7 100644 --- a/README.md +++ b/README.md @@ -382,8 +382,11 @@ yarn add cypress-on-rails --dev ### for VCR This only works when you start the Rails server with a single worker and single thread +It can be used in two modes: +- with separate insert/eject calls (more general, recommended way) +- with use_cassette wrapper (supports only GraphQL integration) -#### setup +#### basic setup Add your VCR configuration to your `cypress_helper.rb` @@ -408,13 +411,16 @@ VCR.turn_off! WebMock.disable! if defined?(WebMock) ``` +#### insert/eject setup + Add to your `config/cypress_on_rails.rb`: ```ruby c.use_vcr_middleware = !Rails.env.production? && ENV['CYPRESS'].present? + # c.use_vcr_use_cassette_middleware = !Rails.env.production? && ENV['CYPRESS'].present? ``` -#### usage +#### insert/eject usage You have `vcr_insert_cassette` and `vcr_eject_cassette` available. https://www.rubydoc.info/github/vcr/vcr/VCR:insert_cassette @@ -441,6 +447,60 @@ describe('My First Test', () => { }) ``` +#### use_cassette setup + +Add to your `config/cypress_on_rails.rb`: + +```ruby + # c.use_vcr_middleware = !Rails.env.production? && ENV['CYPRESS'].present? + c.use_vcr_use_cassette_middleware = !Rails.env.production? && ENV['CYPRESS'].present? +``` + +Adjust record mode in `config/cypress_on_rails.rb` if needed: + +```ruby + c.vcr_record_mode = :once # Use to choose VCR record mode +``` + +Add to your `cypress/support/command.js`: + +```js + // Add proxy-like mock to add operation name into query string + Cypress.Commands.add('mockGraphQL', () => { + cy.on('window:before:load', (win) => { + const originalFetch = win.fetch; + const fetch = (path, options, ...rest) => { + if (options && options.body) { + try { + const body = JSON.parse(options.body); + if (body.operationName) { + return originalFetch(`${path}?operation=${body.operationName}`, options, ...rest); + } + } catch (e) { + return originalFetch(path, options, ...rest); + } + } + return originalFetch(path, options, ...rest); + }; + cy.stub(win, 'fetch', fetch); + }); + }); +``` + +Add to your `cypress/support/on-rails.js`, to `beforeEach`: + +```js + cy.mockGraphQL() // for GraphQL usage with use_cassette, see cypress/support/commands.rb +``` + +#### use_cassette usage + +There's nothing special to be called during Cypress scenario. Each request will be wrapped with `VCR.use_cassette`. +Consider VCR configuration in `cypress_helper.rb` to ignore hosts. + +All cassettes will be recorded and saved automatically, using the pattern `/graphql/` + + ## `before_request` configuration You may perform any custom action before running a CypressOnRails command, such as authentication, or sending metrics. Please set `before_request` as part of the CypressOnRails configuration. From eb9277f310872a64fe62816789b308bb8f9cc40a Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Sun, 8 Sep 2024 10:59:43 +0200 Subject: [PATCH 15/23] Update usage readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2dbf1c7..17e2f95 100644 --- a/README.md +++ b/README.md @@ -495,7 +495,7 @@ Add to your `cypress/support/on-rails.js`, to `beforeEach`: #### use_cassette usage -There's nothing special to be called during Cypress scenario. Each request will be wrapped with `VCR.use_cassette`. +There is nothing special to be called during the Cypress scenario. Each request is wrapped with `VCR.use_cassette`. Consider VCR configuration in `cypress_helper.rb` to ignore hosts. All cassettes will be recorded and saved automatically, using the pattern `/graphql/` From b04f479a147cc488d05467e04108fef5cddc4089 Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Fri, 27 Sep 2024 18:02:07 +0200 Subject: [PATCH 16/23] Update middlewares --- .../vcr/insert_eject_middleware.rb | 9 +++--- ...se_middleware.rb => middleware_helpers.rb} | 28 ++++++------------- .../vcr/use_cassette_middleware.rb | 9 ++---- 3 files changed, 17 insertions(+), 29 deletions(-) rename lib/cypress_on_rails/vcr/{base_middleware.rb => middleware_helpers.rb} (55%) diff --git a/lib/cypress_on_rails/vcr/insert_eject_middleware.rb b/lib/cypress_on_rails/vcr/insert_eject_middleware.rb index 33d20e2..9d16c74 100644 --- a/lib/cypress_on_rails/vcr/insert_eject_middleware.rb +++ b/lib/cypress_on_rails/vcr/insert_eject_middleware.rb @@ -1,12 +1,13 @@ -require_relative 'base_middleware' +require_relative 'middleware_helpers' module CypressOnRails module Vcr # Middleware to handle vcr with insert/eject endpoints - class InsertEjectMiddleware < BaseMiddleware + class InsertEjectMiddleware + include MiddlewareHelpers + def initialize(app, vcr = nil) - @app = app - @vcr = vcr + super(app, vcr) @first_call = false end diff --git a/lib/cypress_on_rails/vcr/base_middleware.rb b/lib/cypress_on_rails/vcr/middleware_helpers.rb similarity index 55% rename from lib/cypress_on_rails/vcr/base_middleware.rb rename to lib/cypress_on_rails/vcr/middleware_helpers.rb index 5d2d082..817f930 100644 --- a/lib/cypress_on_rails/vcr/base_middleware.rb +++ b/lib/cypress_on_rails/vcr/middleware_helpers.rb @@ -1,25 +1,24 @@ -require 'json' -require 'rack' require 'cypress_on_rails/middleware_config' module CypressOnRails module Vcr - # Base abstract Middleware - class BaseMiddleware + # Provides helper methods for VCR middlewares + module MiddlewareHelpers include MiddlewareConfig - def initialize(**_args) - raise_not_implemented - end - - def call(_env) - raise_not_implemented + def initialize(app, vcr = nil) + @app = app + @vcr = vcr end def vcr @vcr ||= configure_vcr end + def cassette_library_dir + "#{configuration.install_folder}/fixtures/vcr_cassettes" + end + private def configure_vcr @@ -29,15 +28,6 @@ def configure_vcr end VCR end - - def cassette_library_dir - "#{configuration.install_folder}/fixtures/vcr_cassettes" - end - - def raise_not_implemented - raise NotImplementedError, - 'BaseMiddleware can not be initialized directly, use InsertEjectMiddleware or UseCassetteMiddleware' - end end end end diff --git a/lib/cypress_on_rails/vcr/use_cassette_middleware.rb b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb index 79d0f48..6fda66b 100644 --- a/lib/cypress_on_rails/vcr/use_cassette_middleware.rb +++ b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb @@ -1,13 +1,10 @@ -require_relative 'base_middleware' +require_relative 'middleware_helpers' module CypressOnRails module Vcr # Middleware to handle vcr with use_cassette - class UseCassetteMiddleware < BaseMiddleware - def initialize(app, vcr = nil) - @app = app - @vcr = vcr - end + class UseCassetteMiddleware + include MiddlewareHelpers def call(env) return @app.call(env) if should_not_use_vcr? From 7e132e686a523942122d3c7726c2772814cacecd Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Fri, 18 Oct 2024 19:02:11 +0200 Subject: [PATCH 17/23] Update rescue logic --- .../vcr/insert_eject_middleware.rb | 4 +- .../vcr/insert_eject_middleware_spec.rb | 46 +++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/lib/cypress_on_rails/vcr/insert_eject_middleware.rb b/lib/cypress_on_rails/vcr/insert_eject_middleware.rb index 9d16c74..0c405bb 100644 --- a/lib/cypress_on_rails/vcr/insert_eject_middleware.rb +++ b/lib/cypress_on_rails/vcr/insert_eject_middleware.rb @@ -34,7 +34,7 @@ def handle_insert(req) vcr.insert_cassette(cassette_name, options) [201, { 'Content-Type' => 'application/json' }, [{ 'message': 'OK' }.to_json]] rescue LoadError, ArgumentError => e - [501, { 'Content-Type' => 'application/json' }, [{ 'message': e.message }.to_json]] + [500, { 'Content-Type' => 'application/json' }, [{ 'message': e.message }.to_json]] end def parse_request_body(req) @@ -57,7 +57,7 @@ def handle_eject do_first_call [201, { 'Content-Type' => 'application/json' }, [{ 'message': 'OK' }.to_json]] rescue LoadError, ArgumentError => e - [501, { 'Content-Type' => 'application/json' }, [{ 'message': e.message }.to_json]] + [500, { 'Content-Type' => 'application/json' }, [{ 'message': e.message }.to_json]] end def do_first_call diff --git a/spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb b/spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb index ba3f762..284e34e 100644 --- a/spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb +++ b/spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb @@ -77,6 +77,30 @@ def rack_input(json_value) expect(vcr).to have_received(:insert_cassette).with('cas1', persist_with: :file_system) end end + + context 'when an error occurs' do + it 'returns a 500 error with the error message' do + env['rack.input'] = rack_input(['cas1']) + allow(vcr).to receive(:insert_cassette).and_raise(ArgumentError.new('Invalid cassette name')) + + expect(response).to eq([ + 500, + { 'Content-Type' => 'application/json' }, + ['{"message":"Invalid cassette name"}'] + ]) + end + + it 'returns a 500 error when LoadError occurs' do + env['rack.input'] = rack_input(['cas1']) + allow(vcr).to receive(:insert_cassette).and_raise(LoadError.new('Cannot load VCR')) + + expect(response).to eq([ + 500, + { 'Content-Type' => 'application/json' }, + ['{"message":"Cannot load VCR"}'] + ]) + end + end end describe '/__e2e__/vcr/eject' do @@ -93,6 +117,28 @@ def rack_input(json_value) expect(vcr).to have_received(:eject_cassette) end end + + context 'when an error occurs' do + it 'returns a 500 error with the error message' do + allow(vcr).to receive(:eject_cassette).and_raise(ArgumentError.new('No cassette to eject')) + + expect(response).to eq([ + 500, + { 'Content-Type' => 'application/json' }, + ['{"message":"No cassette to eject"}'] + ]) + end + + it 'returns a 500 error when LoadError occurs' do + allow(vcr).to receive(:eject_cassette).and_raise(LoadError.new('Cannot load VCR')) + + expect(response).to eq([ + 500, + { 'Content-Type' => 'application/json' }, + ['{"message":"Cannot load VCR"}'] + ]) + end + end end describe '"Other paths"' do From 023244baadf42161eb875538af5969c93b509bb2 Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Fri, 18 Oct 2024 19:17:47 +0200 Subject: [PATCH 18/23] Update init method --- lib/cypress_on_rails/vcr/insert_eject_middleware.rb | 5 ++++- lib/cypress_on_rails/vcr/middleware_helpers.rb | 5 ----- lib/cypress_on_rails/vcr/use_cassette_middleware.rb | 5 +++++ .../vcr/insert_eject_middleware_spec.rb | 10 ++++++++++ 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/lib/cypress_on_rails/vcr/insert_eject_middleware.rb b/lib/cypress_on_rails/vcr/insert_eject_middleware.rb index 0c405bb..c67520b 100644 --- a/lib/cypress_on_rails/vcr/insert_eject_middleware.rb +++ b/lib/cypress_on_rails/vcr/insert_eject_middleware.rb @@ -7,7 +7,8 @@ class InsertEjectMiddleware include MiddlewareHelpers def initialize(app, vcr = nil) - super(app, vcr) + @app = app + @vcr = vcr @first_call = false end @@ -33,6 +34,8 @@ def handle_insert(req) cassette_name, options = extract_cassette_info(body) vcr.insert_cassette(cassette_name, options) [201, { 'Content-Type' => 'application/json' }, [{ 'message': 'OK' }.to_json]] + rescue JSON::ParserError => e + [400, { 'Content-Type' => 'application/json' }, [{ 'message': e.message }.to_json]] rescue LoadError, ArgumentError => e [500, { 'Content-Type' => 'application/json' }, [{ 'message': e.message }.to_json]] end diff --git a/lib/cypress_on_rails/vcr/middleware_helpers.rb b/lib/cypress_on_rails/vcr/middleware_helpers.rb index 817f930..2887c31 100644 --- a/lib/cypress_on_rails/vcr/middleware_helpers.rb +++ b/lib/cypress_on_rails/vcr/middleware_helpers.rb @@ -6,11 +6,6 @@ module Vcr module MiddlewareHelpers include MiddlewareConfig - def initialize(app, vcr = nil) - @app = app - @vcr = vcr - end - def vcr @vcr ||= configure_vcr end diff --git a/lib/cypress_on_rails/vcr/use_cassette_middleware.rb b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb index 6fda66b..e90313a 100644 --- a/lib/cypress_on_rails/vcr/use_cassette_middleware.rb +++ b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb @@ -6,6 +6,11 @@ module Vcr class UseCassetteMiddleware include MiddlewareHelpers + def initialize(app, vcr = nil) + @app = app + @vcr = vcr + end + def call(env) return @app.call(env) if should_not_use_vcr? diff --git a/spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb b/spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb index 284e34e..748f306 100644 --- a/spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb +++ b/spec/cypress_on_rails/vcr/insert_eject_middleware_spec.rb @@ -101,6 +101,16 @@ def rack_input(json_value) ]) end end + + it 'returns a 400 error when JSON parsing fails' do + env['rack.input'] = StringIO.new('invalid json') + + expect(response).to eq([ + 400, + { 'Content-Type' => 'application/json' }, + ['{"message":"unexpected token at \'invalid json\'"}'] + ]) + end end describe '/__e2e__/vcr/eject' do From b617bfb1c91a335d8c30c39c7e78d1a2df733393 Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Sun, 27 Oct 2024 16:42:15 +0100 Subject: [PATCH 19/23] remove init --- lib/cypress_on_rails/vcr/use_cassette_middleware.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cypress_on_rails/vcr/use_cassette_middleware.rb b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb index e90313a..0ec4e18 100644 --- a/lib/cypress_on_rails/vcr/use_cassette_middleware.rb +++ b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb @@ -14,7 +14,7 @@ def initialize(app, vcr = nil) def call(env) return @app.call(env) if should_not_use_vcr? - initialize_vcr + # initialize_vcr handle_request_with_vcr(env) end From 99b53a3618d6f70fbbea788c7b166c72c9c7a6ca Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Sat, 14 Dec 2024 15:39:45 +0100 Subject: [PATCH 20/23] Add vcr options support --- README.md | 15 +++++++------ lib/cypress_on_rails/configuration.rb | 4 ++-- .../vcr/middleware_helpers.rb | 21 +++++++++++++++++++ .../vcr/use_cassette_middleware.rb | 2 +- .../initializers/cypress_on_rails.rb.erb | 6 +++++- spec/cypress_on_rails/configuration_spec.rb | 5 ++++- .../vcr/use_cassette_middleware_spec.rb | 12 ++++------- 7 files changed, 46 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 17e2f95..e7edd5b 100644 --- a/README.md +++ b/README.md @@ -388,13 +388,13 @@ It can be used in two modes: #### basic setup -Add your VCR configuration to your `cypress_helper.rb` +Add your VCR configuration to your `config/cypress_on_rails.rb` ```ruby -require 'vcr' -VCR.configure do |config| - config.hook_into :webmock -end +c.vcr_options = { + hook_into: :webmock, + default_cassette_options: { record: :once }, +} ``` Add to your `cypress/support/index.js`: @@ -459,7 +459,10 @@ Add to your `config/cypress_on_rails.rb`: Adjust record mode in `config/cypress_on_rails.rb` if needed: ```ruby - c.vcr_record_mode = :once # Use to choose VCR record mode +c.vcr_options = { + hook_into: :webmock, + default_cassette_options: { record: :once }, +} ``` Add to your `cypress/support/command.js`: diff --git a/lib/cypress_on_rails/configuration.rb b/lib/cypress_on_rails/configuration.rb index c7f42b4..9ff0eda 100644 --- a/lib/cypress_on_rails/configuration.rb +++ b/lib/cypress_on_rails/configuration.rb @@ -9,7 +9,7 @@ class Configuration attr_accessor :use_vcr_use_cassette_middleware attr_accessor :before_request attr_accessor :logger - attr_accessor :vcr_record_mode + attr_accessor :vcr_options # Attributes for backwards compatibility def cypress_folder @@ -37,7 +37,7 @@ def reset self.use_vcr_use_cassette_middleware = false self.before_request = -> (request) {} self.logger = Logger.new(STDOUT) - self.vcr_record_mode = :new_episodes + self.vcr_options = {} end def tagged_logged diff --git a/lib/cypress_on_rails/vcr/middleware_helpers.rb b/lib/cypress_on_rails/vcr/middleware_helpers.rb index 2887c31..df89e7f 100644 --- a/lib/cypress_on_rails/vcr/middleware_helpers.rb +++ b/lib/cypress_on_rails/vcr/middleware_helpers.rb @@ -20,9 +20,30 @@ def configure_vcr require 'vcr' VCR.configure do |config| config.cassette_library_dir = cassette_library_dir + apply_vcr_options(config) if configuration.vcr_options.present? end VCR end + + def apply_vcr_options(config) + configuration.vcr_options.each do |option, value| + next if option.to_sym == :cassette_library_dir + + apply_vcr_option(config, option, value) + end + end + + def apply_vcr_option(config, option, value) + return unless config.respond_to?(option) || config.respond_to?("#{option}=") + + if config.respond_to?("#{option}=") + config.send("#{option}=", value) + elsif value.is_a?(Array) + config.send(option, *value) + else + config.send(option, value) + end + end end end end diff --git a/lib/cypress_on_rails/vcr/use_cassette_middleware.rb b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb index 0ec4e18..e56e0dd 100644 --- a/lib/cypress_on_rails/vcr/use_cassette_middleware.rb +++ b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb @@ -38,7 +38,7 @@ def initialize_vcr def handle_request_with_vcr(env) request = Rack::Request.new(env) cassette_name = fetch_request_cassette(request) - vcr.use_cassette(cassette_name, { record: configuration.vcr_record_mode }) do + vcr.use_cassette(cassette_name) do logger.info "Handle request with cassette name: #{cassette_name}" @app.call(env) end diff --git a/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb b/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb index 2ec6534..c8c26a1 100644 --- a/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb +++ b/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb @@ -8,7 +8,11 @@ if defined?(CypressOnRails) <% unless options.experimental %># <% end %> c.use_vcr_middleware = !Rails.env.production? # Use this if you want to use use_cassette wrapper instead of manual insert/eject # c.use_vcr_use_cassette_middleware = !Rails.env.production? - # c.vcr_record_mode = :once # Use to choose VCR record mode + # Pass custom VCR options + # c.vcr_options = { + # hook_into: :webmock, + # default_cassette_options: { record: :once }, + # } c.logger = Rails.logger # If you want to enable a before_request logic, such as authentication, logging, sending metrics, etc. diff --git a/spec/cypress_on_rails/configuration_spec.rb b/spec/cypress_on_rails/configuration_spec.rb index 26678d0..f790abf 100644 --- a/spec/cypress_on_rails/configuration_spec.rb +++ b/spec/cypress_on_rails/configuration_spec.rb @@ -9,22 +9,25 @@ expect(CypressOnRails.configuration.use_middleware?).to eq(true) expect(CypressOnRails.configuration.logger).to_not be_nil expect(CypressOnRails.configuration.before_request).to_not be_nil + expect(CypressOnRails.configuration.vcr_options).to eq({}) end it 'can be configured' do my_logger = Logger.new(STDOUT) - before_request_lambda = -> (_) { return [200, {}, ['hello world']] } + before_request_lambda = ->(_) { return [200, {}, ['hello world']] } CypressOnRails.configure do |config| config.api_prefix = '/api' config.install_folder = 'my/path' config.use_middleware = false config.logger = my_logger config.before_request = before_request_lambda + config.vcr_options = { hook_into: :webmock } end expect(CypressOnRails.configuration.api_prefix).to eq('/api') expect(CypressOnRails.configuration.install_folder).to eq('my/path') expect(CypressOnRails.configuration.use_middleware?).to eq(false) expect(CypressOnRails.configuration.logger).to eq(my_logger) expect(CypressOnRails.configuration.before_request).to eq(before_request_lambda) + expect(CypressOnRails.configuration.vcr_options).to eq(hook_into: :webmock) end end diff --git a/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb b/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb index e18c8f9..f41ff93 100644 --- a/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb +++ b/spec/cypress_on_rails/vcr/use_cassette_middleware_spec.rb @@ -26,18 +26,15 @@ def rack_input(json_value) env['QUERY_STRING'] = 'operation=test' expect(response).to eq([200, {}, ['app did /graphql']]) - expect(vcr).to have_received(:use_cassette) - .with('/graphql/test', hash_including(record: :new_episodes)) + expect(vcr).to have_received(:use_cassette).with('/graphql/test') end it 'returns the application response using default request path cassette' do - allow(CypressOnRails).to receive(:configuration).and_return(double(vcr_record_mode: :once, - logger: Logger.new(nil))) + allow(CypressOnRails).to receive(:configuration).and_return(double(logger: Logger.new(nil))) env['PATH_INFO'] = '/test/path' expect(response).to eq([200, {}, ['app did /test/path']]) - expect(vcr).to have_received(:use_cassette) - .with('/test/path', hash_including(record: :once)) + expect(vcr).to have_received(:use_cassette).with('/test/path') end context 'when VCR cassette library directory does not match' do @@ -63,8 +60,7 @@ def rack_input(json_value) env['QUERY_STRING'] = 'operation=test' expect(response).to eq([200, {}, ['app did /graphql']]) - expect(vcr).to have_received(:use_cassette) - .with('/graphql/test', hash_including(record: :new_episodes)) + expect(vcr).to have_received(:use_cassette).with('/graphql/test') end end end From 4be8aa951f9ed8556a4c9ab2b05a8123c41ab08f Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Sat, 14 Dec 2024 16:07:59 +0100 Subject: [PATCH 21/23] Update rails 5.2 setup --- .github/workflows/ruby.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index bf58efa..0cfcb29 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -50,11 +50,17 @@ jobs: steps: - uses: actions/checkout@v2 + - name: Install sqlite3 + run: sudo apt-get update && sudo apt-get install -y libsqlite3-dev - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 bundler-cache: true + - name: Update RubyGems + run: | + gem update --system 3.2.3 + gem install bundler - name: Run tests run: bundle exec rake - name: Run interaction tests From 5afef6afa8a6885d81701fcdc3dcd1334796cc81 Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Sun, 15 Dec 2024 19:07:02 +0100 Subject: [PATCH 22/23] Revert vcr init before run --- lib/cypress_on_rails/vcr/use_cassette_middleware.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cypress_on_rails/vcr/use_cassette_middleware.rb b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb index e56e0dd..4f492f2 100644 --- a/lib/cypress_on_rails/vcr/use_cassette_middleware.rb +++ b/lib/cypress_on_rails/vcr/use_cassette_middleware.rb @@ -14,7 +14,7 @@ def initialize(app, vcr = nil) def call(env) return @app.call(env) if should_not_use_vcr? - # initialize_vcr + initialize_vcr handle_request_with_vcr(env) end From 9213daf16b9ca6224b2008af44d784fb9e641c3e Mon Sep 17 00:00:00 2001 From: MUTOgen Date: Sun, 29 Dec 2024 17:37:50 +0100 Subject: [PATCH 23/23] Add configurable cassette_library_dir --- README.md | 2 ++ lib/cypress_on_rails/vcr/middleware_helpers.rb | 4 +++- .../templates/config/initializers/cypress_on_rails.rb.erb | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e7edd5b..a358e96 100644 --- a/README.md +++ b/README.md @@ -394,6 +394,8 @@ Add your VCR configuration to your `config/cypress_on_rails.rb` c.vcr_options = { hook_into: :webmock, default_cassette_options: { record: :once }, + # It's possible to override cassette_library_dir using install_folder + cassette_library_dir: File.expand_path("#{__dir__}/../../spec/cypress/fixtures/vcr_cassettes") } ``` diff --git a/lib/cypress_on_rails/vcr/middleware_helpers.rb b/lib/cypress_on_rails/vcr/middleware_helpers.rb index df89e7f..e20d396 100644 --- a/lib/cypress_on_rails/vcr/middleware_helpers.rb +++ b/lib/cypress_on_rails/vcr/middleware_helpers.rb @@ -11,7 +11,9 @@ def vcr end def cassette_library_dir - "#{configuration.install_folder}/fixtures/vcr_cassettes" + configuration.vcr_options&.fetch(:cassette_library_dir) do + "#{configuration.install_folder}/fixtures/vcr_cassettes" + end end private diff --git a/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb b/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb index c8c26a1..4e4212b 100644 --- a/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb +++ b/lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb @@ -12,6 +12,7 @@ if defined?(CypressOnRails) # c.vcr_options = { # hook_into: :webmock, # default_cassette_options: { record: :once }, + # cassette_library_dir: File.expand_path("#{__dir__}/../../<%= options.install_folder %>/<%= options.framework %>/fixtures/vcr_cassettes") # } c.logger = Rails.logger