Capybara has_content? block - ruby-on-rails

Sometime I really need to check something in the database,
But if I immediate will go to database with u = User.last there is a chance that AJAX request wont finished and in the User.last - I'll find old record.
So for this I need some workaround, for example,
assert has_content? 'Success' do
# here we access to database
end
We check for Success message, which server response, and this is the sign, that we can go to our database.
How can I achive this?
Thanks all in advance.

You don't need a block for this just do one then the other. The content assertion will wait for the content to exist which will confirm the AJAX has completed and then you can check for the User
assert_content 'Success' # will wait for 'Success' to appear
u = User.last # won't happen until after 'Success has appeared and therefor the AJAX has completed'
Note also the use of the Capybara provided assert_content (rather than assert has_content? ...). You generally want to prefer using the Capybara provided assertions rather than asserting on the result of a Capybara boolean method since the error messages on failure will be a lot clearer.

Related

RSpec - How to test the if-else block in update method of controller

Let's say I have a database to store the data of people (name, email). And there's an update method in the controller. The method is like:
def update
#people = People.find(params[:id])
if #people.update(people_params)
redirect_to people_path
else
render 'edit'
end
end
I wonder how can I test the situation that the update failed? Or do I really need to test it? I have searched it on StackOverflow, there is a link about it, but it not says if I should or should not to test it. Could anyone give me some help about it? If it can be test, how? Thank you so much!
You don’t need to test Ruby and Rails internals. Either you trust both of them do work as expected, or you’d better switch to some other language / framework.
Whether you still want to test it, mock everything unrelated. Here is an example of doing this with rspec and flexmock.
describe '#update' do
let(:person) { build(:people) }
before do
flexmock(People).should_receive(:find).once.returns person
flexmock(person).should_receive(:update).once.returns false
end
it 'redirects to `edit` page' do
...
end
end
Typically the update failure would be due to object to be saved not being valid, according to its validation criteria. You would normally test the validation criteria in the model specs, but when testing the controller, or in integration tests, you might want to ensure that the #edit render occurs when the user tries to save an invalid model.
If the model does not have any validation criteria, you can probably skip the else render :edit altogether. It's part of the Rails scaffold that may not apply in all cases.
You can test your update fail scenario by trying to save an invalid model. You would typically confirm that the user was correctly informed of the validity problem (flash message).
There's no right or wrong as to whether or not to test. Personally, I would test it, b/c I like TDD, and I prefer to over-test rather than under-test. Many would not.

Cucumber, Rails: has_content? test passes even though the string isn't there

Scenario is:
Scenario: View welcome page
Given I am on the home page
Then I should see 'Welcome'
And definition of the step is
Then("I should see {string}") do |string|
page.has_content?(string)
end
The test passes whether the word "welcome" is in the home page or not. What am I doing wrong?
A step will only fail if it throws an exception. By its naming convention, the has_content? method returns false if the content is not in the page, and thus does not throw an exception. This will cause your step to "pass" when you intend it to fail.
You need to make an assertion with some sort of unit testing library (my Ruby is a little rusty)
Then("I should see {string}") do |string|
page.has_content?(string).should_be true
end
You'll need something like RSpec to gain access to a library allowing you to make assertions.
Doing this the way shown in the other answer will work but will not give useful error messages. Instead you want
For RSpec
expect(page).to have_content(string)
For minitest
assert_content(string)
For others
page.assert_content(string)
Note that assert_content/assert_text and have_content/have_text are aliases of each other so use whichever reads better.

How to assert url was called from javascript using rspec and capybara

Scenario:
We use capybara integration tests to test that our frontend plumbing (javascript) is connected properly.
Sometimes all we need to validate the test is:
has content rendered properly on the page
has the js called the correct url open interaction
Problem:
Item 1 above is easy. However, with item 2 I can't seem to find an easy way to say:
Assert that url was called from js in browser.
Example:
it "should call coorect url with correct query string" do
visit widgets_path
# THIS IS WHAT I NEED TO KNOW
expect(something).to receive(:some_method).with(url: "my/test/url", params: {per_page: 2})
# In other words, I don't want the controller action to run. I don't care about the result since the controller is being tested elsewhere.
# I just need to know that the correct URL was called with the correct params.
within 'ul.pagination' do
click_on '2'
end
end
I've tried mocking the controller action, but there's no way to inspect the params. Or is there? Without inspecting the params, how can I know if the correct stuff was sent? All I know it's the correct route, which isn't enough.
If I could inspect the params then this would be solved... but otherwise?
If you are looking for the Rails solution, here it is! Tested with Rails 5.1.3.
1) Create a request params matcher spec/support/matchers/request_with_params.rb
RSpec::Matchers.define :request_with_params do |params|
match { |request| request.params.symbolize_keys.slice(*params.keys) == params }
end
2) Create a helper method for your acceptance tests (you can use some logics to pass symbol instead of class UsersController -> :users if needed)
def expect_request(controller, action, params = {})
expect_any_instance_of(ActionDispatch::Routing::RouteSet::Dispatcher)
.to receive(:dispatch)
.with(controller, action.to_s, request_with_params(params), anything)
end
end
3) Use it!
expect_request(UsersController, :index)
or with params
expect_request(UsersController, :show, { id: 1 })
OR
4) There is another way in using https://github.com/oesmith/puffing-billy Check this gem for intercepting requests sent by your browser. But it can be an overkill if you need to mock only certain requests to your backend app.
Capybara integration tests intentionally don't support that. They are end-to-end blackbox tests, shouldn't generally be mocked, and really only support checking for things visible to the user in the browser. In your example case that would mean expecting on whatever visible change is caused by the JS call to the specific URL. Something like
expect(page).to have_css('div.widget', count: 2)

How to wait till an element appears after an AJAX call using capybara-webkit?

The capybara method, wait_until doesn't seems to work for capybara-webkit. Is there any alternate solution for that, or any Javascript implementations?
Intentionally need some replacement for sleep, e.g. sleep 2.
If your AJAX call results in a change to the DOM, Capybara will wait for it if you do
page.should have_selector?("some selector")
It is an intentional Capybara feature that it waits (up to Capybara.default_wait_time) for have_selector? and related methods to be true.
If your AJAX call does not result in a change to the DOM, there's no way to wait for it on the browser side using Capybara. You might be able to detect when the AJAX call is complete in Javascript and somehow communicate that to Capybara, but that would couple your test and implementation rather tightly. A common approach in this case is to wait for the server-side effect of your AJAX call (creation or update or deletion of a model object, sending of an email, etc.) to take place. Since Capybara can't see the server side you have to wait for the server-side change yourself.
In Capybara 1 you can use Capybara's wait_until to wait for the server-side change. wait_until was removed from Capybara 2. I posted an implementation of wait_until in my answer to Why does adding "sleep 1" in an after hook cause this Rspec/Capybara test to pass?
I didn't really need the expectation as it wasn't what I needed to test.
This worked for me:
page.has_css?('.my-selector')
# or
page.has_content?('Some text on the page')
# continue with test
Maybe something like this:
# AJAX BEGIN
expect(page).to have_selector('form#new_user_video .submit > .throbber')
expect(page).to_not have_selector('form#new_user_video .submit > .throbber')
# AJAX END
Manually in your js code set 'ajax:send' (append throbber) and 'ajax:success' (remove throbber). This way you'll be able to know when request is finished.
And you should set enough time for ajax to complete:
Capybara.default_max_wait_time = 5

Rails/Capybara- Test that form does not submit

In my Rails app, I used the following jQuery to disable the ability to submit a form by pressing 'enter' in an input field:
$('input').on('keydown', function(e) {
if(e.which == '13') {
return false;
}
})
I wanted to test this with Capybara, but can't figure out how. For example:
# the form being tested creates a new Shift object:
test "enter does not submit form" do
shift_count = Shift.count
# fill in form, etc...
page.driver.browser.execute_script "var e = jQuery.Event('keydown'); e.which = 13; $('#shift_employee').trigger( e );"
assert Shift.count == shift_count
end
This test passes even when the jQuery function is commented out, presumably because it calculates Shift.count before ActiveRecord has had time to save the new the record to the database.
I also tried having the jQuery function do a custom $.get() request, to which the controller responds with simple text, thinking that this would build in enough time for all server-side work to be completed. But this still doesn't work, and I think it's because, no matter how I set up the jQuery function, the submission of the form and saving of the new record will always occur after any AJAX stuff I build in.
Any ideas on how I can reliably test that the form was not submitted?
So the form submission is done via AJAX? This is a common problem that testers run in to with Capybara. What you need to do is wait for the AJAX to complete.
There are two ways to do this. One is very specific and is the preferred method, the other is generic and should only be used if the first method can't be done.
The first way is to wait for content to change on the DOM. In your case nothing might change, but if, for example, you had a warning come up saying "You cannot press Enter, you must click the Save button!" then you could wait for that to come up by doing something like:
page.driver.browser ... # your code
page.should have_css(".info", :text => "You cannot ...etc...")
Of course you don't have to use the :text option though.
The other way is to make a helper method, like wait_for_ajax, that does a generic wait until AJAX is complete.
def wait_for_ajax
start = Time.now
while true
break if (page.evaluate_script('$.active') == 0)
if Time.now > start + Capybara.default_wait_time.seconds
fail "AJAX did not register as complete after #{Capybara.default_wait_time} seconds!"
end
sleep 0.1
end
end
This is based off the old way that people used to check for AJAX, but this new script is preferred for Capybara 2.0.
Then your step would do:
page.driver.etc
wait_for_ajax
That wait_for_ajax method can go in to any file Cucumber will load.
I got it to work by having Capybara revisit the page, and then checking Shift.count. The test now fails when the jQuery function is commented out, and passes when the function is uncommented. I'd still like to know if there's a better way, though.

Resources