How would I mock `request.xhr?` in a Rails 5 helper spec? - ruby-on-rails-5

I'm testing Rails 5 helpers in rspec. We have a block in a helper which is wrapped in a conditional:
if request.xhr?
# do stuff
end
In the specs, I'm unable to force that request.xhr? test to return true. I've tried allow_any_instance_of(ActionController::Request).to receive(:xhr?).and_return(true) but that says Undefined Constant ActionController::Request (which sort of makes sense). I also tried allow(request).to receive(:xhr?).and_return(true) but that just failed silently.
How can I test this - both that the #do stuff code is executed when we want it to be, and that it does what we expect?

The answer turned out to be allow_any_instance_of(ActionDispatch::Request).to receive(:xhr?).and_return(true). I had missed that the Request object had moved out of the ActionController module and into ActionDispatch.

Related

Rails 3.2.5 in `eval': wrong number of arguments (0 for 2..3) (ArgumentError)

I wrote a runner (saved in lib folder). When starting the runner with: rails runner lib/test.rb
def aaa
puts "aaa"
end
aaa
it dumps:
in `eval': wrong number of arguments (0 for 2..3) (ArgumentError)
why?
rails runner is intended to run code from your app codebase as in
(from the guide)
rails runner "Model.long_running_method" # parses the string and executes
# the (hypothetical) method [long_running_method]
# from (hypothetical) model [app/models/model.rb]
the error raises from the fact that in your call you don't provide a string to evaluate
anyway to make it work this way (with a function from lib) you should
enclose your method in some class and
make the class available requiring it someway during application boot
! pay attention: if you call rails runner 'MyClass.my_method' you're calling a class method which has to be defined properly
def self.my_method
# your code
end
if you want to call an instance method you need to do rails runner 'MyClass.new.my_method'
All that said, rails runner boots all the rails app.
If that is not required, may I suggest to investigate whether a rake task could be suited for your needs ?

populate_page_with method gives an error "Undefined method send_keys" when used with selenium web-driver

I am using page object gem with selenium web-driver. I am trying to automate gmail sign in page. So to enter mail_id and password I am using populate_page_with method.
I am storing my login credentials in a variable "data"
data = { :mail_id => 'abc#abc.com', :mail_password=> '12345' }
And calling populate_page_with method like below
populate_page_with data
When I am trying run the script it gives an error Undefined method send_keys.
But the implementation working fine when I am trying to automate yahoo mail sign in page.
My page object class is
class GmailSignInPage
include PageObject
button :gsubmit, :id => 'signIn'
text_field :mail_id, :id => 'Email'
text_field :mail_password, :id => 'Passwd'
def log_in_to_gmail(data = {})
self.mail_password_element.when_visible
populate_page_with data
self.gsubmit
end
end
My step-definition is
Given /^I navigate to gmail page$/ do
data = { :mail_id => 'abc#abc.com', :mail_password=> '12345' }
on(GmailSignInPage).log_in_to_gmail data
end
In supports/env.rb, I have added PageFactory class also
World(PageObject::PageFactory)
If I modify my log_in_to_gmail method like below then also I am getting same exception
undefined method 'send_keys' for #<NoMethodError: undefined method 'current' for Time:Class> (NoMethodError)
def log_in_to_gmail(data = {})
self.mail_password = data['mail_id']
self.mail_password = data['mail_password']
self.gsubmit
end
But if I use send_keys method its working fine except warning message
def log_in_to_gmail(data = {})
mail_id_element.send_keys data['mail_id']
mail_password_element.send_keys data['mail_password']
self.gsubmit
end
And the warning message is
*** DEPRECATION WARNING
*** You are calling a method named bridge at C:/jruby-1.7.6/lib/ruby/gems/shared/gems/page-object-0.9.2/lib/page-object/elements/element.rb:27:in 'wait_for_document_ready'.
*** This method does not exist in page-object so it is being passed to the driver.
*** This feature will be removed in the near future.
*** Please change your code to call the correct page-object method.
*** If you are using functionality that does not exist in page-object please request it be added.
So I think, this is not the issue with populate_page_with method because even assignment operator = gives same exception. This may be due to page_object gem unable handle gmail sign-in page.
Ok, lets try this again.
I have created a test and copy pasted all of the sample code you have above (Using the populate_page_with() method). I did make one key change to my code compared to yours:
Yours
on(GmailSignInPage).log_in_to_gmail data
Mine
GmailSignInPage.new(#browser).log_in_to_gmail data
I don't know what gem the on() method from your code is from. I could guess, but I want to make this answer more fact based that my previous one. :)
Once I did this, I was able to successfully sign in to Google. So there is nothing unusual about the Google sign in page or any limitation I can come across in the page-object gem or anything wrong with your approach.
So the only things that are different between us is the one line of code I put above, our dev environments, other dependent gems each of us are using.
Try replacing the above line and see if that works.
If not, I would recommend seeing if you have a gem conflict of some sort. Reason I suspect this is due to the strange exception methods you are getting:
undefined method 'send_keys' for # (NoMethodError)
The send_keys part I get, but 'current'? No 'current' method is being called and the Time class is no where to be seen in this example. That's one issue to look at isolating and seeing if you can clean up.

undefined method 'path' for nil:NilClass using chargify_api_ares gem

I feel like this should be a simple problem, but I'm pulling my hair out trying to track it down. I'm installed the chargify_api_ares gem, but can't do even basic things such as
Chargify::Subscription.create
As I get this path error. I feel like this must be a gem issue somehow but don't know where to go from here.
UPDATE: bundle show chargify_api_ares shows the correct path, I just somehow can't access it. Still trying random environment related things.
Looks like this is the source of the problem, in active_resource\base.rb:
# Gets the \prefix for a resource's nested URL (e.g., <tt>prefix/collectionname/1.json</tt>)
# This method is regenerated at runtime based on what the \prefix is set to.
def prefix(options={})
default = site.path
default << '/' unless default[-1..-1] == '/'
# generate the actual method based on the current site path
self.prefix = default
prefix(options)
end
As I understand it, Chargify.subdomain should be setting the site.path, but I don't understand activeresource well enough yet to know what's happening and will continue to dig.
I too had the same issue.
I executed the following on the console
Chargify.configure do |c|
c.api_key = "<<api_key>>"
c.subdomain = "<<subdomain>>"
end
After that performing any Chargify console commands went through fine.

Ruby on Rails - Suppress an error message

I am using Rails 3 and AJAX and have a parent object which is being created through and AJAX request. This parent is sent with children and saves them all. However, if a child has an error, Rails will stop the request. Is there any way to tell Rails to ignore this? I understand the proper thing to do is find the problem within the Javascript sending the request and fix it. However, for the sake of learning, is there a way to tell Rails that some errors might be ignorable?
To save without validating use:
#parent.save(:validate => false)
Also, don't forget you can create conditional validation rules if needs be. For example, add a virtual attribute (an instance variable that is not persisted to the DB) accessible via bare_bones?. Then modify a validator like so:
validates_presence_of :nickname, :unless => "bare_bones?"
Then, in your controller you would do something like this:
#parent = Parent.new params[:parent]
#parent.bare_bones = true
#parent.save()
Hope this helps.
You are looking for exception handling.
begin
#code that may contain errors
rescue
#what to do if an error is encountered
end

change rails environment in the mid of testing

How to change the environment variable of rails in testing
You could do
Rails.stub(env: ActiveSupport::StringInquirer.new("production"))
Then Rails.env, Rails.development? etc will work as expected.
With RSpec 3 or later you may want to use the new "zero monkeypatching" syntax (as mentioned by #AnkitG in another answer) to avoid deprecation warnings:
allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new("production"))
I usually define a stub_env method in a spec helper so I don't have to put all that stuff inline in my tests.
An option to consider (as suggested in a comment here) is to instead rely on some more targeted configuration that you can set in your environment files and change in tests.
Rspec 3 onwards you can do
it "should do something specific for production" do
allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new("production"))
#other assertions
end
Sometimes returning a different environment variable can be a headache (required production environment variables, warning messages, etc).
Depending on your case, as an alternate you may be able to simply return the value you need for your test to think it's in another environment. Such as if you wanted Rails to believe it is in production for code that checks Rails.env.production? you could do something like this:
it "does something specific when in production" do
allow(Rails.env).to receive(:production?).and_return(true)
##other assertions
end
You could do the same for other environments, such as :development?, :staging?, etc. If you don't need the full capacity of returning a full environment, this could be another option.
As a simpler variation on several answers above, this is working for me:
allow(Rails).to receive(:env).and_return('production')
Or, for as I'm doing in shared_examples, pass that in a variable:
allow(Rails).to receive(:env).and_return(target_env)
I suspect this falls short of the ...StringInquirer... solution as your app uses additional methods to inspect the environment (e.g. env.production?, but if you code just asks for Rails.env, this is a lot more readable. YMMV.
If you're using something like rspec, you can stub Rails.env to return a different value for the specific test example you're running:
it "should log something in production" do
Rails.stub(:env).and_return('production')
Rails.logger.should_receive(:warning).with("message")
run_your_code
end