Let's say I'm testing the action index of the controller StaticPages. On the controller tests, I need to count the number of links to about_path on this page.
I've Google it and found nothing that could help me. I know this is quite simple and a newbie question but I just started to study RSpec and I stuck here.
First, you need to keep in mind that controller specs don't render views by default. I recommend that you either use a view or request spec.
Second, if you're using builtin assertions then you can check the number of links with:
assert_select %(a[href="#{about_path}"]), 5 # 5 is the expected number of links
If you use expectations then the following should work:
expect(page).to have_selector(%(a[href="#{about_path}"]), count: 5)
I recommend you take a look at the RSpec docs.
You could parse the response body, then count.
doc = Nokogiri::HTML(response.body)
doc.css('a').length
Related
I am new to TDD and really enjoy it. I am using RSpec.
I am trying to learn to write good request specs (in general) and can find very little written on how to test the index method.
I have found this article: https://medium.com/#lcriswell/rails-api-request-specs-with-rspec-effeac468c4e, but I am not interested in testing an API, but an application with views.
What should I include on my index request tests and why?
The first spec in the article is great, you can use it in testing a regular controller for responses.
If you are using any sort of authorization(e.g cancancan), you can test the same request for multiple types of users and check if you get a redirect or a success(you might have to mock the sign-in).
For testing the views that are being rendered, you can try this:
it { is_expected.to render_template(:index) }
If your action assigns instance variables, you can test out that the variable is a certain value like so:
expect(assigns(:foo)).to be true
If your action responds to different formats(HTML, json, ...), you can write different contexts for each of the formats, each time by changing the request(hint: for JS in your specs submit your request like so: get :index, xhr: true)
I'm writing feature specs for my Article form.
In one test, I have RSpec look for certain form inputs using the labels:
expect(find_field("Title")).to_not be_nil
Now I'd like to know if the form was submitted properly. How can I do this using RSpec, if you aren't supposed to check the database from a feature spec?
For example, what if I mistyped the name attribute on the Title input? The label would still be found by my find_field() call, and controller specs would have me specify the title in a hash.
In this case one would assume a Title would be required for an Article so if the name attribute was misspelled the creation of the Article would fail and you'd end up on an error page (Also an unpermitted parameter would raise in the creation by default in test mode with strong parameters). If its a field not required for creation of the Article then the assumption is that the info is displayed in the app somewhere and can be checked for on that page.
As an aside your sample expect would read much clearer if rewritten as
expect(page).to have_field('Title')
There are loads of way to approach this:
expect(page).to have_field('Title')
expect(page).to have_css('#someSelector')
expect(current_path).to eq article_path (for example)
expect(page).to have_content "ABC" (i.e. some content which will be rendered)
The Capybara readme on Github is a really good one full of easy to follow examples - https://github.com/jnicklas/capybara.
Check edit at bottom of page
My boss has a sitemap up- it's basically just every route as a link, with a button to click that says "valid?" or "ignore" which will mark it valid or ignore it on the page.
He asked me to manually go through and click each link, test that page isn't a 500 or 404, and then mark it valid if it isn't.
This seems silly to me, as it is basically just a user facing test for working routes.
I could, in the same time, write out routing specs in Rspec for all those, but I guess he wants some sort of documentation that this is happening on the front end for himself and users.
I was thinking a fun way to work around this boring clicking would be to do it with some programming WHILE writing the specs. Makes him happy, and also adds actual value and test to the app that can be reused.
Is there a way to, in a spec, write something like:
links = page.all('a.routing-links)
link.each do |link|
link.click
if page status != 404 || 500
Link.find(id).update_attribute("verified", true)
end
end
I tried putting that in my spec, but when link.click hits an incorrect route, it stops the test (which makes sense, as that route is broken and this is a test.
What I'd like is to be able to take that error and use it to update the attribute of my model.
Am I going about this completely wrong? Any better ideas or inspiration?
Thanks
Edit
I agree with the poster who said this is better left to a script or rake task.
I'm a bit lost on how to write a script that will go to a page, find every link, record its status_code, and then find and update a model. Any suggestions or tips? Ideally it would be run within in the application, so that I could have access to my models and controllers.
Thanks
Personally I wouldn't actually put this in a spec since you're not actually expecting anything to fail.
Instead I'd create a quick script, or even rake task to run through the links as you described.
That being said, this article: http://agileleague.com/2012/12/rails-3-2-custom-error-pages-the-exceptions_app-and-testing-with-capybara/ details how to bypass the normal fail in these circumstances, namely:
In your config/environments/test.rb
config.consider_all_requests_local = false
config.action_dispatch.show_exceptions = true
Though this would affect all tests, which is quite possibly not what you want.
Also, a minor thing that you'd probably figure out in no time when testing this - you'll either need to revisit the list page after clicking the link, or rather relying on link clicks, you could visit the href instead which would be a bit quicker.
links = page.all('a.routing-links')
link.each do |link|
visit link[:href]
if page.status != 404 || 500
Link.find(id).update_attribute("verified", true)
end
end
I haven't tested that, so not sure if it would work like that, but you should be able to get the idea.
I want to write tests for destroying objects on ruby on rails with cucumber and capybara and rack_test.
I think that I should write a scenario like:
When I try to delete X object
Then I should be on the index page for ...
And I should see "Object deleted successfully"
I don't want to test it by clicking on a link on the index page or the show/edit page because I think I should be testing something different than purely the delete action.
Also, clicking on a link means that the interface is ok, but what happens if someone send a request to delete an object he can't and the interface doesn't show the link?
Given this, I need to send a delete request in the first step and then inspect the response to that request.
I've find troubles trying to do that because when I implement the first step as delete url then when I try page.should have_contain(text) I get the error No response yet. Request a page first. (Rack::Test::Error)
What do you think about it?
check out how-do-you-post-to-a-url-in-capybara (answering another question) but there a several examples of how to use visit in a capybara test like
visit "item/:id/delete"
I'm learning RSpec 2 with Rails 3 and while it's been going along quite nicely so far, I'm having a problem testing the helper link_to_unless_current in a view. What I've been trying to do is use a simple assert_select from a view spec to determine if a link is being generated in the following partial view (HAML):
%article.post{ :id => "post-#{post.id}" }
%header.post-title
%h2= link_to_unless_current post.title, post
.post-content= raw post.body
However, I don't know how to get the view spec to recognize what "current" means because it's a view spec and it only tests the view, not the request. I know this would be a lot simpler in a controller spec, but I think that I should be testing what a view does in its spec and that moving this test out to a controller spec would be confusing things a lot. What I'm asking is: is there any way to tell the view spec, perhaps in a "before" block, what the current page is? Also, am I doing the right thing in respect to organizing my tests? Should this test rightfully reside in a controller spec?
Never mind, I eventually figured it out. You have to stub UrlHelper.current_page? and have it return true if the url options passed match the page you want to act as the current page:
view.stub("current_page?".to_sym) {|options| url_for(options) == post_path(#post) }
I still don't know if this is the way I should be doing RSpec tests, but, whatever, this works. :P