I was writing a test for my helper which would, if the user is authorised to perform an action, show the actual link, and otherwise show the title or nothing (depending on what is wanted).
I make use of the vigilante gem which I should still write an article about, but this gem allows to store authorisations in the database and can be context-specific (e.g. you you can be assigned different roles for different "contexts", which could translate to organisations, projects, ... whatever applies to your setup). This gem adds a helper method is_allowed_to?
to determine if one has the permissions to perform a certain given action.
When I wanted to mock this in my helper, I assumed a simple
expect(helper).to receive(:is_allowed_to?) { true }
would suffice. However, I got a very strange error:
RSpec::Mocks::MockExpectationError: #<#<Class:0x00007fe2dc84e010>:0x00007fe29c83dc78 ....snip some very long things ... >> does not implement: is_allowed_to?
This is actually a great feature from Rspec: it checks if the thing you want to mock/stub actually exists on the original object, but in this case a helper (or a view) in Rails can access a lot of helper methods which are implicitly loaded.
This behaviour can be controller by setting the RSpec::Mocks.configuration.verify_partial_doubles
to false
. Of course I do not want to disable this for my entire test-suite, but just locally for the single test or single spec file.
So in my spec I temporarily disable the checking for the existence of doubles, as follows
require 'rails_helper'
RSpec.describe MapHelper do
before(:all) do
RSpec::Mocks.configuration.verify_partial_doubles = false
end
after(:all) do
RSpec::Mocks.configuration.verify_partial_doubles = true
end
it "has the correct method" do
expect(helper.respond_to?(:map_checked_link_to)).to eq(true)
end
context "map_checked_link_to" do
context "a reachable feature" do
before do
@pipe = FactoryBot.create(:pipe)
end
it "renders a normal link" do
allow(helper).to receive(:is_allowed_to?).and_return("XXX00")
expect(helper.map_checked_link_to("Pijpstuk 123", @pipe, {})).to eq("<a href=\"/pipes/208\">Pijpstuk 123</a>")
end
end
context "a blocked feature" do
before do
end
it "does not render anything by default" do
allow(helper).to receive(:is_allowed_to?) { false }
expect(helper.map_checked_link_to("Pijpstuk 123", "", {})).to eq("Pijpstuk 123")
end
it "renders the title if so specified" do
allow(helper).to receive(:is_allowed_to?) { false }
expect(helper.map_checked_link_to("Pijpstuk 123", "", {}, true)).to eq("Pijpstuk 123")
end
end
end
end
I also stumbled upon a PR implementing a method without_verifying_partial_doubles
which takes a block which would do exactly the same.
So one would be able to write
it "does something weird with mocks" do
without_verifying_partial_doubles do
...
end
end
But it did not work for me. Not sure if that is because the rspec version I am using in this project is too old, or the example I found was outdated.