IntegrationTest with Mocha, stub HelperMethod (Ruby) - ruby-on-rails

I got a helper method:
has_permission?
In a Module called:
module ApplicationHelper
Inside app/helpers.
I also have an IntegrationTest which includes it:
include ApplicationHelper
My Integration test calls one of my controllers via get request.
On call I want to test if my integration test arrives at a certain method.
On this way is has to pass a few of the methods, one of those being the
has_permission?
In order to make sure this method passes I wanted to stub it.
Object.any_instance.expects(:has_permission?).returns(false)
Doesn't work
ApplicationHelper.expects(:has_permission?).returns(false)
Doesn't work either because it's not a static method.
Is there a way I can stub the helpers non-static method within the test so I can make it return false in all cases?
The test:
test "test try to edit without permission" do
#curr = users(:me)
sign_in #curr
SellingController.expects(:validate).never
post enable_update_user_selling_path(id: #user, params: {user: {sell: "1"}})
end

Stumbled across this when trying to work out how to stub an ApplicationHelper method in an ActionDispatch::IntegrationTest in Rails 5; not sure if that's exactly what you're trying to achieve but I ended up doing something like this
MyController.view_context_class.any_instance.expects(:my_method).returns(true)
It looks as though since Rails 5, helper methods aren't simply mixed into the controller classes directly hence the view_context_class bit.
Seems to work, hopefully this will be helpful to someone!

Forgot to post how I ended up solving this:
SellingController.any_instance.stubs(:has_permission?).returns(false)

Related

Ruby on Rails Rspec undefined method host error

When I try to write test to a method in controller I received undefined method host error. Here is the example code blocks below
In rspec file:
require 'rails_helper'
RSpec.describe FooController, type: :controller do
before do
#controller = FooController.new
#controller.params = ActionController::Parameters.new({ foo_id: foo.id, })
#set_foo = #controller.send(:set_foo_data)
end
and in foo controller:
def set_foo_data
#foo_data = {
table_type: :foo,
.
.
data_url: foos_path,
}
end
data_url part causing this issue.
I checked with byebug and data_url was nil.
The reason this doesn't work is that controllers are Rack middleware and expect to be initialized with a request. Its also just not how you should be coding or testing your code in the first place. Bin it.
Controller specs use the get, post, etc methods that actually create an instance of the controller with a mocked request.
get :foo would then call the foo method directly on the controller instance. You do not initialize controllers directly. If you feel tempted to do this its a very good sign you're doing something very wrong.
Unit testing controllers with controller specs is an extremely flawed approach that's discouraged by both the RSpec and Rails teams - you're mocking out huge parts of the application like the middleware and routes and it lets so many bugs through your tests.
The modern way to test a Rails application is to just test the actions of your controller by sending HTTP requests. This means that you should ONLY test the methods that actually correspond to a route and test your application through the response it provides (the headers and body) and eventually the side effects. In RSpec-Rails this is provided through request, feature and system specs.
Everything else in your controller like this method should be private - and you don't test privates.

Should I create helper methods in test files?

Is it a good practice to create helper method in test file if this method is specific only to tests in this file?
For example, in:
test/integration/post_index_test.rb
among some tests i have defined helper method which is applicable only to tests in this file:
require 'test_helper'
class PostIndexTest < ActionDispatch::IntegrationTest
test 'some test' do
this_file_specific_helper_method
end
def only_this_file_specific_helper_method
# method body
end
end
Can I do this, or it should be avoided. If not, where should I put this method. In generic
test/test_helper.rb
file? Should I create a separate file? Or maybe there is something wrong with my design and I shouldn't have a need for this method at all?
Yes, you can use helper methods within your test files. I don't see why not. If the method performs a routine that you will be using many times within that specific test, using a private helper method would be the way to go.

Rails 3 'request_via_redirect' trouble

I have a trouble with request_via_redirect
How i use this method:
def synchronize
request_via_redirect(:post, synchronize_companies_path, params)
end
And get an error:
NoMethodError (undefined method `request_via_redirect' for #<Companies::ApiController:0x00000006739a00>):
Anybody can explain what is wrong?
Seems like you are using a rspec integration method.
request_via_redirect, post_via_redirect and other methods like that are made to work with testing integration environment. Those functions only work inside a test/spec kind of file.
Try changing your code to the following:
def synchronize
require "uri"
require "net/http"
Net::HTTP.post_form(URI.parse(synchronize_companies_path), params)
end
I am pretty sure that there's a better way of doing what you want to do. Some more information about your intentions should help.

How to mock the redirect to an external URL for a integration/acceptance test?

In my Rails 3 application I have a controller with the following actions (code simplified):
def payment
redirect_to some_url_of_an_external_website
end
# the external website redirects the browser to this action when the payment is done
def payment_callback
#subscription = Subscription.new(:subscription_id => params[:subscription_id])
...
end
In my acceptance test (using steak and RSpec 2), I want to avoid the redirection to this external URL when capybara follows the link pointing to the payment action. Basically I want to mock the route helper payment_path so that it directly points to the payment_call_path with the appropriate subscription_id parameter.
Is this the correct way to do it? If so, how can I mock the payment_path (could not find how to do it)?
Whilst I usually try to avoid mocking in integration tests, here you can do something like this:
MyController.stub!(:payment).and_return('payment received').
Using class_eval as mentioned above will lead to that method being permanently stubbed out across your entire run (if you want this, I'd suggest stubbing it in spec_helper [that's assuming you use a spec_helper]). I find using rspec's mocking/stubbing stuff preferable anyway.
I'm not sure if this is the 'correct' way of doing this, but you can stub any of your application's code to return what you need for your test. So somewhere in your RSpec test you can do something like
MyController.class_eval do
def payment
'payment received'
end
end
Here is an example (see section 'Session Helper Methods') where the #admin? method in ApplicationController is stubbed when a custom RSpec helper module is included into the example group.

Use request helpers outside of controller specs

I'd like to include the request helpers (from ActionDispatch::Integration::RequestHelpers [ApiDock], like post and xhr methods) also in some specs outside of my controller specs. The problem is that these request helpers are only included in spec/controller and when a controller is described.
What do I have to include/require in those specs?
I am using RSpec 2 and Rails 3.
I just solved the problem by including the below code in my acceptance helper. If you are not Steak then just simply put it in spec helper or require it from somewhere else. post and xhr methods are now available in that spec regardless in what spec it is or in what directory you are.
The code is derived from RSpec::Rails::RequestExampleGroup
RSpec::Core::ExampleGroup.class_eval do
include ActiveSupport::Concern
include ActionDispatch::Integration::Runner
include RSpec::Rails::BrowserSimulators
def app
::Rails.application
end
def last_response
response
end
end
I know it's 4 years later and many things have of course changed, but since I stumbled on this question while searching how to make other tests behave like controller tests (and thus have post and get methods and the like) I wanted to point out this solution that works with RSpec 3: if you add this to the spec_helper
config.include RSpec::Rails::RequestExampleGroup, type: :request, example_group: { file_path: /spec\/(api|integration)/
it will make all tests in the given path have support for controller methods.

Resources