vcr.rb 3.1 KB

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