Skip to content

Commit 308eddd

Browse files
committed
Refactor use_cassette middleware
1 parent 111630a commit 308eddd

12 files changed

+330
-253
lines changed

lib/cypress_on_rails/configuration.rb

+5-4
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ class Configuration
66
attr_accessor :install_folder
77
attr_accessor :use_middleware
88
attr_accessor :use_vcr_middleware
9+
attr_accessor :use_vcr_use_cassette_middleware
910
attr_accessor :before_request
1011
attr_accessor :logger
11-
attr_accessor :use_vcr
12-
attr_accessor :vcr_record_mode
12+
attr_accessor :vcr_use_cassette_mode
1313

1414
# Attributes for backwards compatibility
1515
def cypress_folder
@@ -27,16 +27,17 @@ def initialize
2727

2828
alias :use_middleware? :use_middleware
2929
alias :use_vcr_middleware? :use_vcr_middleware
30+
alias :use_vcr_use_cassette_middleware? :use_vcr_use_cassette_middleware
3031

3132
def reset
3233
self.api_prefix = ''
3334
self.install_folder = 'spec/e2e'
3435
self.use_middleware = true
3536
self.use_vcr_middleware = false
37+
self.use_vcr_use_cassette_middleware = false
3638
self.before_request = -> (request) {}
3739
self.logger = Logger.new(STDOUT)
38-
self.use_vcr = false
39-
self.vcr_record_mode = :new_episodes
40+
self.vcr_use_cassette_mode = :new_episodes
4041
end
4142

4243
def tagged_logged

lib/cypress_on_rails/middleware.rb

-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
require 'rack'
33
require 'cypress_on_rails/middleware_config'
44
require 'cypress_on_rails/command_executor'
5-
require 'cypress_on_rails/vcr_wrapper'
65

76
module CypressOnRails
87
# Middleware to handle testing framework commands and eval
@@ -22,8 +21,6 @@ def call(env)
2221
elsif request.path.start_with?("#{configuration.api_prefix}/__cypress__/command")
2322
warn "/__cypress__/command is deprecated. Please use the install generator to use /__e2e__/command instead."
2423
configuration.tagged_logged { handle_command(request) }
25-
elsif defined?(VCR) && configuration.use_vcr
26-
VCRWrapper.new(app: @app, env: env).run_with_cassette
2724
else
2825
@app.call(env)
2926
end

lib/cypress_on_rails/railtie.rb

+6-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,12 @@ class Railtie < Rails::Railtie
99
app.middleware.use Middleware
1010
end
1111
if CypressOnRails.configuration.use_vcr_middleware?
12-
require 'cypress_on_rails/vcr_middleware'
13-
app.middleware.use VCRMiddleware
12+
require 'cypress_on_rails/vcr/insert_inject_middleware'
13+
app.middleware.use Vcr::InsertEjectMiddleware
14+
end
15+
if CypressOnRails.configuration.use_vcr_use_cassette_middleware?
16+
require 'cypress_on_rails/vcr/use_cassette_middleware'
17+
app.middleware.use Vcr::UseCassetteMiddleware
1418
end
1519
end
1620
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
require 'json'
2+
require 'rack'
3+
require 'cypress_on_rails/middleware_config'
4+
5+
module CypressOnRails
6+
module Vcr
7+
# Base abstract Middleware
8+
class BaseMiddleware
9+
include MiddlewareConfig
10+
11+
def initialize(_app, _vcr = nil)
12+
raise_not_implemented
13+
end
14+
15+
def call(_env)
16+
raise_not_implemented
17+
end
18+
19+
def vcr
20+
@vcr ||= configure_vcr
21+
end
22+
23+
private
24+
25+
def configure_vcr
26+
require 'vcr'
27+
VCR.configure do |config|
28+
config.cassette_library_dir = "#{configuration.install_folder}/fixtures/vcr_cassettes"
29+
end
30+
VCR
31+
end
32+
33+
def raise_not_implemented
34+
raise NotImplementedError,
35+
'BaseMiddleware can not be initialized directly, use InsertEjectMiddleware or UseCassetteMiddleware'
36+
end
37+
end
38+
end
39+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
require_relative 'base_middleware'
2+
3+
module CypressOnRails
4+
module Vcr
5+
# Middleware to handle vcr with insert/eject endpoints
6+
class InsertEjectMiddleware < BaseMiddleware
7+
def initialize(app, vcr = nil)
8+
@app = app
9+
@vcr = vcr
10+
@first_call = false
11+
end
12+
13+
def call(env)
14+
request = Rack::Request.new(env)
15+
if request.path.start_with?('/__e2e__/vcr/insert')
16+
configuration.tagged_logged { handle_insert(request) }
17+
elsif request.path.start_with?('/__e2e__/vcr/eject')
18+
configuration.tagged_logged { handle_eject }
19+
else
20+
do_first_call unless @first_call
21+
@app.call(env)
22+
end
23+
end
24+
25+
private
26+
27+
def handle_insert(req)
28+
WebMock.enable! if defined?(WebMock)
29+
vcr.turn_on!
30+
logger.info "vcr insert cassette: #{body}"
31+
body = parse_request_body(req)
32+
cassette_name, options = extract_cassette_info(body)
33+
vcr.insert_cassette(cassette_name, options)
34+
[201, { 'Content-Type' => 'application/json' }, [{ 'message': 'OK' }.to_json]]
35+
rescue LoadError, ArgumentError => e
36+
[501, { 'Content-Type' => 'application/json' }, [{ 'message': e.message }.to_json]]
37+
end
38+
39+
def parse_request_body(req)
40+
JSON.parse(req.body.read)
41+
end
42+
43+
def extract_cassette_info(body)
44+
cassette_name = body[0]
45+
options = (body[1] || {}).symbolize_keys
46+
options[:record] = options[:record].to_sym if options[:record]
47+
options[:match_requests_on] = options[:match_requests_on].map(&:to_sym) if options[:match_requests_on]
48+
options[:serialize_with] = options[:serialize_with].to_sym if options[:serialize_with]
49+
options[:persist_with] = options[:persist_with].to_sym if options[:persist_with]
50+
[cassette_name, options]
51+
end
52+
53+
def handle_eject
54+
logger.info 'vcr eject cassette'
55+
vcr.eject_cassette
56+
do_first_call
57+
[201, { 'Content-Type' => 'application/json' }, [{ 'message': 'OK' }.to_json]]
58+
rescue LoadError, ArgumentError => e
59+
[501, { 'Content-Type' => 'application/json' }, [{ 'message': e.message }.to_json]]
60+
end
61+
62+
def do_first_call
63+
@first_call = true
64+
vcr.turn_off!
65+
WebMock.disable! if defined?(WebMock)
66+
rescue LoadError
67+
# nop
68+
end
69+
end
70+
end
71+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
require 'cypress_on_rails/configuration'
2+
require_relative 'base_middleware'
3+
4+
module CypressOnRails
5+
module Vcr
6+
# Middleware to handle vcr with use_cassette
7+
class UseCassetteMiddleware < BaseMiddleware
8+
def initialize(app, vcr = nil)
9+
@app = app
10+
@vcr = vcr
11+
end
12+
13+
def call(env)
14+
request = Rack::Request.new(env)
15+
cassette_name = fetch_request_cassette(request)
16+
vcr.use_cassette(cassette_name, { record: configuration.vcr_use_cassette_mode }) do
17+
logger.info "Handle request with cassette name: #{cassette_name}"
18+
@app.call(env)
19+
end
20+
end
21+
22+
private
23+
24+
def configuration
25+
CypressOnRails.configuration
26+
end
27+
28+
def logger
29+
configuration.logger
30+
end
31+
32+
def fetch_request_cassette(request)
33+
if request.path.start_with?('/graphql') && request.params.key?('operation')
34+
"#{request.path}/#{request.params['operation']}"
35+
else
36+
request.path
37+
end
38+
end
39+
end
40+
end
41+
end

lib/cypress_on_rails/vcr_middleware.rb

-73
This file was deleted.

lib/cypress_on_rails/vcr_wrapper.rb

-38
This file was deleted.

lib/generators/cypress_on_rails/templates/config/initializers/cypress_on_rails.rb.erb

+3-14
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,10 @@ if defined?(CypressOnRails)
66
# please use with extra caution if enabling on hosted servers or starting your local server on 0.0.0.0
77
c.use_middleware = !Rails.env.production?
88
<% unless options.experimental %># <% end %> c.use_vcr_middleware = !Rails.env.production?
9+
# Use this if you want to use use_cassette wrapper instead of manual insert/eject
10+
# c.use_vcr_use_cassette_middleware = !Rails.env.production?
11+
# c.vcr_use_cassette_mode = :once # Use to choose VCR record mode (:new_episodes by default)
912
c.logger = Rails.logger
10-
c.use_vcr = ENV['WITH_VCR'].present?
11-
12-
# # Setup VCR to mock external HTTP requests
13-
# if ENV['WITH_VCR'].present?
14-
# # c.vcr_record_mode = :once # Use to choose VCR record mode (:new_episodes by default)
15-
#
16-
# require 'vcr'
17-
# VCR.configure do |config|
18-
# config.cassette_library_dir = Rails.root.join('spec', 'cypress', 'fixtures', 'cassettes') # Update cassettes path as nedded
19-
# config.hook_into :webmock
20-
# config.ignore_localhost = true
21-
# config.ignore_hosts('localhost', '127.0.0.1', '0.0.0.0')
22-
# end
23-
# end
2413

2514
# If you want to enable a before_request logic, such as authentication, logging, sending metrics, etc.
2615
# Refer to https://www.rubydoc.info/gems/rack/Rack/Request for the `request` argument.

0 commit comments

Comments
 (0)