mdesantis
mdesantis

Reputation: 8517

RSpec: use `receive ... exactly ... with ... and_return ...` with different `with` arguments

I'm writing an expectation which checks whether a method is called two times with different arguments and returns different values. At the moment I'm just writing the expectation twice:

expect(ctx[:helpers]).to receive(:sanitize_strip).with(
  %{String\n<a href="http://localhost:3000/">description</a> <br/>and newline\n<br>},
  length: nil
).and_return('String description and newline')

expect(ctx[:helpers]).to receive(:sanitize_strip).with(
  %{String\n<a href="http://localhost:3000/">description</a> <br/>and newline\n<br>},
  length: 15
).and_return('String descr...')

I wonder if I can use receive ... exactly ... with ... and_return ... instead; something like:

expect(ctx[:helpers]).to receive(:sanitize_strip).exactly(2).times.with(
  %{String\n<a href="http://localhost:3000/">description</a> <br/>and newline\n<br>},
  length: nil
).with(
  %{String\n<a href="http://localhost:3000/">description</a> <br/>and newline\n<br>},
  length: 15
).and_return('String descr...', 'String description and newline')

The code above doesn't work, it raises the following error:

1) Types::Collection fields succeeds
   Failure/Error: context[:helpers].sanitize_strip(text, length: truncate_at)

     #<Double :helpers> received :sanitize_strip with unexpected arguments
       expected: ("String\n<a href=\"http://localhost:3000/\">description</a> <br/>and newline\n<br>", {:length=>15})
            got: ("String\n<a href=\"http://localhost:3000/\">description</a> <br/>and newline\n<br>", {:length=>nil})
     Diff:
     @@ -1,3 +1,3 @@
      ["String\n<a href=\"http://localhost:3000/\">description</a> <br/>and newline\n<br>",
     - {:length=>15}]
     + {:length=>nil}]

Is there a way to use receive ... exactly ... with ... and_return ... with different with arguments?

Upvotes: 2

Views: 1803

Answers (2)

Alan Gabbianelli
Alan Gabbianelli

Reputation: 75

Without using an extra gem, you could call the normal expect ... to receive ... with ... and_return ... with variables from inside an each block:

describe '#sanitize_strip' do
  let(:html) do
    %{String\n<a href="http://localhost:3000/">description</a> <br/>and newline\n<br>}
  end
  let(:test_data) do
    [
      [[html, length: nil], 'String description and newline'],
      [[html, length: 15], 'String descr...']
    ]
  end

  it 'returns sanitized strings stripped to the number of characters provided' do
    test_data.each do |args, result|
      expect(ctx[:helpers]).to receive(:sanitize_strip).with(*args).and_return(result)
    end

    # Trigger the calls to sanitize_strip
  end
end

Upvotes: 1

phil pirozhkov
phil pirozhkov

Reputation: 4900

There's an rspec-any_of gem that allows for the following syntax by prodiding all_of argument matcher:

expect(ctx[:helpers]).to receive(:sanitize_strip).with(
  %{String\n<a href="http://localhost:3000/">description</a> <br/>and newline\n<br>}
  all_of({length: 15}, {length: nil})
)
.and_return('String descr...', 'String description and newline')
.twice

Upvotes: 1

Related Questions