diff --git a/lib/cypress_on_rails/configuration.rb b/lib/cypress_on_rails/configuration.rb index a08571c..3479d40 100644 --- a/lib/cypress_on_rails/configuration.rb +++ b/lib/cypress_on_rails/configuration.rb @@ -5,6 +5,8 @@ class Configuration attr_accessor :cypress_folder attr_accessor :use_middleware attr_accessor :logger + attr_accessor :use_vcr + attr_accessor :vcr_record_mode def initialize reset @@ -16,6 +18,8 @@ def reset self.cypress_folder = 'spec/cypress' self.use_middleware = true 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 5aad679..dffebfa 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/configuration' require 'cypress_on_rails/command_executor' +require 'cypress_on_rails/vcr_wrapper' module CypressOnRails # Middleware to handle cypress commands and eval @@ -16,6 +17,8 @@ def call(env) request = Rack::Request.new(env) if request.path.start_with?('/__cypress__/command') 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 @@ -53,7 +56,7 @@ def handle_command(req) body = JSON.parse(req.body.read) logger.info "handle_command: #{body}" commands = Command.from_body(body, configuration) - missing_command = commands.find {|command| !@file.exists?(command.file_path) } + missing_command = commands.find {|command| !@file.exist?(command.file_path) } if missing_command.nil? begin diff --git a/lib/cypress_on_rails/vcr_wrapper.rb b/lib/cypress_on_rails/vcr_wrapper.rb new file mode 100644 index 0000000..6449d16 --- /dev/null +++ b/lib/cypress_on_rails/vcr_wrapper.rb @@ -0,0 +1,38 @@ +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/install_generator.rb b/lib/generators/cypress_on_rails/install_generator.rb index f5b6b08..83319e7 100644 --- a/lib/generators/cypress_on_rails/install_generator.rb +++ b/lib/generators/cypress_on_rails/install_generator.rb @@ -7,7 +7,7 @@ class InstallGenerator < Rails::Generators::Base source_root File.expand_path('../templates', __FILE__) def install_cypress - if !Dir.exists?(options.cypress_folder) || Dir["#{options.cypress_folder}/*"].empty? + if !Dir.exist?(options.cypress_folder) || Dir["#{options.cypress_folder}/*"].empty? directories = options.cypress_folder.split('/') directories.pop install_dir = "#{Dir.pwd}/#{directories.join('/')}" 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 be6ad63..3068b95 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 @@ -5,6 +5,20 @@ 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? c.logger = Rails.logger + c.use_vcr = ENV['WITH_VCR'].present? + + # # Setup VCR to mock external HTTP requests + # if ENV['WITH_VCR'].present? + # # c.vcr_record_mode = :once # Use to choose VCR record mode (:new_episodes by default) + # + # require 'vcr' + # VCR.configure do |config| + # config.cassette_library_dir = Rails.root.join('spec', 'cypress', 'fixtures', 'cassettes') # Update cassettes path as nedded + # config.hook_into :webmock + # config.ignore_localhost = true + # config.ignore_hosts('localhost', '127.0.0.1', '0.0.0.0') + # end + # end end # # if you compile your asssets on CI 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 f5b8f42..23723f4 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 @@ -44,6 +44,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 diff --git a/spec/integrations/rails_3_2/config/boot.rb b/spec/integrations/rails_3_2/config/boot.rb index 4489e58..f2830ae 100644 --- a/spec/integrations/rails_3_2/config/boot.rb +++ b/spec/integrations/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'])