diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f41d4c..b1c82ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ ### Development [Full Changelog](https://github.com/rspec/rspec-activemodel-mocks/compare/v1.2.0...main) +Bug fixes: + +* Fix `===` to work with multiple mocks. (@bquorning, #61) + ### 1.2.0 / 2023-12-10 [Full Changelog](https://github.com/rspec/rspec-activemodel-mocks/compare/v1.1.0...v1.2.0) diff --git a/lib/rspec/active_model/mocks/mocks.rb b/lib/rspec/active_model/mocks/mocks.rb index 6c42f53..fa70939 100644 --- a/lib/rspec/active_model/mocks/mocks.rb +++ b/lib/rspec/active_model/mocks/mocks.rb @@ -94,6 +94,8 @@ def association(association_name) # * A String representing a Class that extends ActiveModel::Naming # * A Class that extends ActiveModel::Naming def mock_model(string_or_model_class, stubs={}) + @__rspec_active_model_mocks ||= Hash.new { |h, k| h[k] = [] } + if String === string_or_model_class if Object.const_defined?(string_or_model_class) model_class = Object.const_get(string_or_model_class) @@ -137,9 +139,10 @@ def self.param_delimiter; "-"; end double("#{model_class.name}_#{stubs[:id]}", stubs).tap do |m| if model_class.method(:===).owner == Module && !stubs.key?(:===) allow(model_class).to receive(:===).and_wrap_original do |original, other| - m === other || original.call(other) + @__rspec_active_model_mocks[model_class].include?(other) || original.call(other) end end + @__rspec_active_model_mocks[model_class] << m msingleton = class << m; self; end msingleton.class_eval do include ActiveModelInstanceMethods diff --git a/spec/rspec/active_model/mocks/mock_model_spec.rb b/spec/rspec/active_model/mocks/mock_model_spec.rb index 1603f6b..d936aa0 100644 --- a/spec/rspec/active_model/mocks/mock_model_spec.rb +++ b/spec/rspec/active_model/mocks/mock_model_spec.rb @@ -209,6 +209,19 @@ def self.===(_other) end # rubocop:enable Lint/LiteralAsCondition end + + it "works for multiple mocks of the same model" do + foo = mock_model(MockableModel) + bar = mock_model(MockableModel) + baz = mock_model(MockableModelNoPrimaryKey) + quz = mock_model(MockableModel) + + expect(MockableModel === foo).to be(true) + expect(MockableModel === bar).to be(true) + expect(MockableModel === baz).to be(false) + expect(MockableModelNoPrimaryKey === baz).to be(true) + expect(MockableModel === quz).to be(true) + end end describe "#kind_of?" do diff --git a/spec/rspec/active_model/mocks/stub_model_spec.rb b/spec/rspec/active_model/mocks/stub_model_spec.rb index 97c5819..a5f5adf 100644 --- a/spec/rspec/active_model/mocks/stub_model_spec.rb +++ b/spec/rspec/active_model/mocks/stub_model_spec.rb @@ -181,5 +181,18 @@ def model_class end # rubocop:enable Lint/LiteralAsCondition end + + it "works for multiple mocks of the same model" do + foo = stub_model(MockableModel) + bar = stub_model(MockableModel) + baz = stub_model(MockableModelNoPrimaryKey) + qux = stub_model(MockableModel) + + expect(MockableModel === foo).to be(true) + expect(MockableModel === bar).to be(true) + expect(MockableModel === baz).to be(false) + expect(MockableModelNoPrimaryKey === baz).to be(true) + expect(MockableModel === qux).to be(true) + end end end