0

I've got some job that updates records, and I want something like:

  it 'updates each record' do
    expect {
      described_class.perform_now
    }.to(change_all_of{
      Record.pluck(:updated_at)
    })
  end

Only I can't find anything that looks like how to accomplish this, or what I can recognize as the docs for how to write a custom matcher.

The issue is that change, on an array, will return true if any element has changed; I only want to return true if every element has changed.

Can anyone point me either at whatever I missed that would let me do this, OR, whatever docs/info I need to write my own change matcher?

Narfanator
  • 5,595
  • 3
  • 39
  • 71

1 Answers1

0

Alright, thanks to this answer on another question, and staring at the actual code, here's what I've got -

module RSpec
  module Matchers
    def change_all &block
      BuiltIn::ChangeAll.new(nil, nil, &block)
    end

    module BuiltIn
      class ChangeAll < Change
        def initialize receiver=nil, message=nil, &block
          @change_details = ChangeAllDetails.new(receiver, message, &block)
        end

        def failure_message
          "expected all elements to change, but " + (
            @change_details.actual_after & @change_details.actual_before
          ).collect do |unchanged|
            "before[#{@change_details.actual_before.find_index(unchanged)}] " \
            "after[#{@change_details.actual_after.find_index(unchanged)}] " \
            "#{unchanged}"
          end.join(",") + " remained the same"
        end
      end

      class ChangeAllDetails < ChangeDetails
        attr_accessor :actual_before

        def changed?
          !(@actual_after & @actual_before).any?
        end
      end
    end
  end
end

Suggestions welcome!

Narfanator
  • 5,595
  • 3
  • 39
  • 71