I want to mock custom devise strategies to authenticate user in my feature specs. To stub request to 3th party app I'm using WebMock with the implementation below:
spec/utility/stub_methods.rb
def stub_aware_auth(creds, returns_token, _valid)
stub_request(:post, "http://example.com/oauth/token").
with(body: {"grant_type" => "password", "password" => creds.password, "username" => creds.email},
headers: {'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/x-www-form-urlencoded'}).
to_return(status: 200, body: {'access_token' => returns_token, 'token_type' => 'bearer', 'expires_in' => 1200}.to_json, headers: {})
end
Which is called in the spec by:
context 'AWARxE authenticated user' do
before do
stub_aware_auth(creds, return_token, valid)
end
let(:creds) do
OpenStruct.new(email: '[email protected]', password: "Ican'tb3li3v3itsn0tbutt3r")
end
let(:return_token) { SecureRandom.hex(32) }
let(:valid) { true }
# other logic (...)
end
spec_helper.rb
WebMock.disable_net_connect!(allow_localhost: true)
Which works quite surprisingly wired because if in one test example it has to use stub_aware_auth
twice, the first request returns the defined result but the second throws an error:
WebMock::NetConnectNotAllowedError: Real HTTP connections are disabled. Unregistered request: POST http://example.com/oauth/token with body 'grant_type=password&password=Ican%27tb3li3v3itsn0tbutt3r&username=PHYSICIANSREALLYSHOULDONLYAUTOAUTH%40EXAMPLE.COM' with headers {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type'=>'application/x-www-form-urlencoded', 'User-Agent'=>'Faraday v0.12.1'}
You can stub this request with the following snippet:
stub_request(:post, "http://example.com/oauth/token").
with(body: {"grant_type"=>"password", "password"=>"Ican'tb3li3v3itsn0tbutt3r", "username"=>"[email protected]"},
headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type'=>'application/x-www-form-urlencoded', 'User-Agent'=>'Faraday v0.12.1'}).
to_return(status: 200, body: "", headers: {})
registered request stubs:
stub_request(:get, "http://example.com/api/v1/user").
with(headers: {'Authorization'=>'Bearer dc2dcf4c5b47ffcfea28c26490ed2a0e2580f152dfb18dbfc97670028d24ecaa'})
stub_request(:post, "http://example.com/oauth/token").
with(body: {"grant_type"=>"password", "password"=>"Ican'tb3li3v3itsn0tbutt3r", "username"=>"[email protected]"},
headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type'=>'application/x-www-form-urlencoded'})
Which is surprised because WebMock.disable_net_connect!(allow_localhost: true)
is defined in spec_helper.
[EDIT]
Full failed example if it helps:
spec/features/login_strategies_spec.rb
context 'AWARxE authenticated user' do
before do
stub_aware_auth(creds, return_token, valid)
end
let(:return_token) { SecureRandom.hex(32) }
let(:valid) { true }
context 'physician' do
let(:creds) do
OpenStruct.new(email: '[email protected]', password: "Ican'tb3li3v3itsn0tbutt3r")
end
let(:user) { build(:physician) }
before do
stub_aware_user_info(user, 'Physician (MD, DO)', return_token, valid, 1)
end
# some other it block (...)
context 'case insensitive' do
let(:valid) { true }
let(:uppercase_email_creds) {
OpenStruct.new(email: creds.email.upcase, password: creds.password)
}
scenario 'logging in with upper case email' do
expect { subject }.to change(Login, :count)
logout
expect {
login(uppercase_email_creds)
}.to_not change(Login, :count)
expect(page).to have_current_path(name_search_registrants_url, url: true)
end
end
end
The stub you are creating is still on the original creds
with the lowercase email. There is no possibility for webmock to mock the call unless you actually call something like
stub_aware_auth(uppercase_email_creds, return_token, valid)
If you actualy expect the app to call out with lowercase email in body, then the test fails because it should fail, it is calling out with the email in uppercase:
You can stub this request with the following snippet:
stub_request(:post, "http://example.com/oauth/token").
with(body: {..., "username"=>"[email protected]"},
...).
to_return(status: 200, body: "", headers: {})