vcr.rb 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. VCR_IGNORE_MATCHING_HOSTS = %w[elasticsearch selenium zammad.org zammad.com znuny.com google.com login.microsoftonline.com github.com].freeze
  2. VCR_IGNORE_MATCHING_REGEXPS = [%r{^192\.168\.\d+\.\d+$}].freeze
  3. VCR.configure do |config|
  4. config.cassette_library_dir = 'test/data/vcr_cassettes'
  5. config.hook_into :webmock
  6. config.allow_http_connections_when_no_cassette = false
  7. config.ignore_localhost = true
  8. config.ignore_request do |request|
  9. uri = URI(request.uri)
  10. next true if VCR_IGNORE_MATCHING_HOSTS.any? { |elem| uri.host.include? elem }
  11. next true if VCR_IGNORE_MATCHING_REGEXPS.any? { |elem| uri.host.match? elem }
  12. end
  13. config.register_request_matcher(:oauth_headers) do |r1, r2|
  14. without_onetime_oauth_params = ->(params) { params.gsub(%r{oauth_(nonce|signature|timestamp)="[^"]+", }, '') }
  15. r1.headers.except('Authorization') == r2.headers.except('Authorization') &&
  16. r1.headers['Authorization']&.map(&without_onetime_oauth_params) ==
  17. r2.headers['Authorization']&.map(&without_onetime_oauth_params)
  18. end
  19. end
  20. module RSpec
  21. VCR_ADVISORY = <<~MSG.freeze
  22. If this test is failing unexpectedly, the VCR cassette may be to blame.
  23. This can happen when changing `describe`/`context` labels on some specs;
  24. see commit message 1ebddff95 for details.
  25. Check `git status` to see if a new VCR cassette has been generated.
  26. If so, rename the old cassette to replace the new one and try again.
  27. MSG
  28. module Support
  29. module VCRHelper
  30. def self.inject_advisory(example)
  31. # block argument is an #<RSpec::Expectations::ExpectationNotMetError>
  32. define_method(:notify_failure) do |e, options = {}|
  33. super(e.exception(VCR_ADVISORY + e.message), options)
  34. end
  35. example.run
  36. ensure
  37. remove_method(:notify_failure)
  38. end
  39. end
  40. singleton_class.send(:prepend, VCRHelper)
  41. end
  42. module Expectations
  43. module VCRHelper
  44. def self.inject_advisory(example)
  45. define_method(:handle_matcher) do |*args|
  46. super(*args)
  47. rescue => e
  48. raise e.exception(VCR_ADVISORY + e.message)
  49. end
  50. example.run
  51. ensure
  52. remove_method(:handle_matcher)
  53. end
  54. end
  55. PositiveExpectationHandler.singleton_class.send(:prepend, VCRHelper)
  56. NegativeExpectationHandler.singleton_class.send(:prepend, VCRHelper)
  57. end
  58. end
  59. RSpec.configure do |config|
  60. config.around(:each, use_vcr: true) do |example|
  61. vcr_options = Array(example.metadata[:use_vcr])
  62. spec_path = Pathname.new(example.file_path).realpath
  63. cassette_path = spec_path.relative_path_from(Rails.root.join('spec')).sub(%r{_spec\.rb$}, '')
  64. cassette_name = "#{example.example_group.description} #{example.description}".gsub(%r{[^0-9A-Za-z.\-]+}, '_').downcase
  65. request_profile = [
  66. :method,
  67. :uri,
  68. vcr_options.include?(:with_oauth_headers) ? :oauth_headers : nil
  69. ].compact
  70. puts cassette_path.join(cassette_name)
  71. VCR.use_cassette(cassette_path.join(cassette_name), match_requests_on: request_profile) do |cassette|
  72. if vcr_options.include?(:time_sensitive) && !cassette.recording?
  73. travel_to(cassette.http_interactions.interactions.first.recorded_at)
  74. end
  75. example.run
  76. end
  77. end
  78. config.around(:each, use_vcr: true) do |example|
  79. RSpec::Support::VCRHelper.inject_advisory(example)
  80. end
  81. config.around(:each, use_vcr: true) do |example|
  82. RSpec::Expectations::VCRHelper.inject_advisory(example)
  83. end
  84. end