RSpec で RSpec::Matchers.define 使ってカスタムマッチャを作成した。

擬似コード

こんな感じで。

RSpec::Matchers.define :send_message do |object, message|
  match do |block|
    allow(object).to receive(message)
      .tap { |m| m.with(*@with) if @with }

    block.call

    expect(object).to have_received(message)
      .tap { |m| m.with(*@with) if @with }
  end

  chain :with do |*with|
    @with = with
  end

  description do
    "#{object}.#{message}"
  end

  failure_message do
    "expected to #{description}"
  end

  supports_block_expectations
end

classで定義

classを使ってマッチャーを定義することもできる。

def have_enqueued_job(job = nil)
  check_active_job_adapter
  ActiveJob::HaveEnqueuedJob.new(job)
end

https://github.com/rspec/rspec-rails/blob/5cd1679c82c764e00500290bb60b8185cc3f48b1/lib/rspec/rails/matchers/active_job.rb#L371-L374

参考

あわせて読みたい