RSpec Satisfy Matcher

I've recently discovered (or at least found a good use case for it) the satisfy matcher in RSpec.

My intention was to ensure an attribute contained a string and not another string (within have_attributes).

I tried a few variations of the code below, but none of them worked:

message = Message.first
expect(message).to have_attributes(
  conversation_id: conversation.id,
  customer: "customer@example.com",
  response: include("Hello, world!").and(not_to(include("Subject:")))
)

While inspecting rspec-expectations's source code in search of an exclude matcher or something similar, the satisfy matcher stood out as a good fit:

expect(message).to have_attributes(
  conversation_id: conversation.id,
  message: satisfy do |message|
    message.include?("Hello, world!") && !message.include?("Subject:")
  end
)

It's pretty self-explanatory, isn't it? The test will pass if the block returns true.

Written on January 2, 2026

Share: