Karol Selak
Karol Selak

Reputation: 4774

How to make shared example with RSpec with parametrized code to test without using eval method?

I have a shared example in RSpec, which tests SMS sending. In my app I have few methods which send an SMS, so I'd like to parametrize the code I test, so that I can use my shared example for all my methods. The only way to do that which I discovered is using eval function:

RSpec.shared_examples "sending an sms" do |action_code|
  it "sends an sms" do
    eval(action_code)
    expect(WebMock).to have_requested(**my_request**).with(**my_body**)
  end
end

So I can use this example like that:

it_behaves_like "sending an sms",
  "post :accept, params: { id: reservation.id }"

it_behaves_like "sending an sms",
  "post :create, params: reservation_attributes"

How can I achieve this without using eval function? I tried to use the pattern with yield command, but it doesn't work because of scope:

Failure/Error: post :create, params: reservation_attributes reservation_attributes is not available on an example group (e.g. a describe or context block). It is only available from within individual examples (e.g. it blocks) or from constructs that run in the scope of an example (e.g. before, let, etc).

Upvotes: 4

Views: 2669

Answers (1)

Igor Drozdov
Igor Drozdov

Reputation: 15045

Actually in your case, action and params can be passed as arguments into shared examples:

RSpec.shared_examples "sending an sms" do |action, params|
  it "sends an sms" do
    post action, params: params
    expect(WebMock).to have_requested(**my_request**).with(**my_body**)
  end
end

And called as:

it_behaves_like "sending an sms", :accept, { id: reservation.id }

it_behaves_like "sending an sms", :create, reservation_attributes

Or you can define separate action for every block

RSpec.shared_examples "sending an sms" do
  it "sends an sms" do
    action
    expect(WebMock).to have_requested(**my_request**).with(**my_body**)
  end
end

it_behaves_like "sending an sms" do
  let(:action) { post :accept, params: { id: reservation.id } }
end

it_behaves_like "sending an sms" do
  let(:action) { post :create, params: reservation_attributes }
end

Upvotes: 5

Related Questions