diff --git a/Gemfile b/Gemfile index 4aa1e315536..67c6bda7bd5 100644 --- a/Gemfile +++ b/Gemfile @@ -158,6 +158,8 @@ group :test, :development do gem "syntax_tree" gem "syntax_tree-disable_ternary" + + gem "rspec-multi-mock" end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 8e11f3123cc..02e2443997a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -426,6 +426,8 @@ GEM rspec-mocks (3.13.1) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) + rspec-multi-mock (0.3.1) + rspec (>= 3.7.0) rspec-rails (6.1.3) actionpack (>= 6.1) activesupport (>= 6.1) @@ -699,6 +701,7 @@ DEPENDENCIES rrule rspec rspec-html-matchers + rspec-multi-mock rspec-rails rss rswag-specs diff --git a/spec/lib/cache_spec.rb b/spec/lib/cache_spec.rb index 4f08048a64d..0e547b0cae0 100644 --- a/spec/lib/cache_spec.rb +++ b/spec/lib/cache_spec.rb @@ -122,14 +122,16 @@ RSpec.describe Cache do end end - it "isn't prone to a race condition due to key expiring between GET calls" do - key = cache.normalize_key("my_key") + context "when there is a race condition due to key expiring between GET calls" do + before do + allow(Discourse.redis).to receive(:get).and_wrap_original do |original_method, *args| + original_method.call(*args).tap { Discourse.redis.del(*args) } + end + end - # while this is not technically testing the race condition, it's - # ensuring we're only calling redis.get once, which is a good enough proxy - Discourse.redis.stubs(:get).with(key).returns(Marshal.dump("bob")).once - - expect(fetch_value).to eq("bob") + it "isn't prone to that race condition" do + expect(fetch_value).to eq("bob") + end end end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index c9cbce441c3..5d30b3ea639 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -186,7 +186,18 @@ end PER_SPEC_TIMEOUT_SECONDS = 45 BROWSER_READ_TIMEOUT = 30 +# To avoid erasing `any_instance` from Mocha +require "rspec/mocks/syntax" +RSpec::Mocks::Syntax.singleton_class.define_method(:enable_should) { |*| nil } +RSpec::Mocks::Syntax.singleton_class.define_method(:disable_should) { |*| nil } + +RSpec::Mocks::ArgumentMatchers.remove_method(:hash_including) # We’re currently relying on the version from Webmock + RSpec.configure do |config| + config.expect_with :rspec do |c| + c.syntax = :expect + end + config.fail_fast = ENV["RSPEC_FAIL_FAST"] == "1" config.silence_filter_announcements = ENV["RSPEC_SILENCE_FILTER_ANNOUNCEMENTS"] == "1" config.extend RedisSnapshotHelper @@ -206,10 +217,18 @@ RSpec.configure do |config| config.include ServiceMatchers config.include I18nHelpers - config.mock_framework = :mocha config.order = "random" config.infer_spec_type_from_file_location! + config.mock_with :rspec do |mocks| + mocks.verify_partial_doubles = true + mocks.verify_doubled_constant_names = true + mocks.syntax = :expect + end + config.mock_with MultiMock::Adapter.for(:mocha, :rspec) + + config.include Mocha::API + if ENV["GITHUB_ACTIONS"] # Enable color output in GitHub Actions # This eventually will be `config.color_mode = :on` in RSpec 4?