How to give a unique id to a test object in Rspec? - ruby-on-rails

context 'with dish available to pre-order' do
let!(:dish) { create :dish, chef: chef }
let!(:dish2) { create :dish, chef: chef2}
it 'should show dish' do
Time.zone = 'Asia/Kuala_Lumpur'
t = Time.zone.local(2016, 7, 25, 20, 30, 0)
Timecop.travel(t)
visit '/'
set_delivery_time
select_delivery_area_by_chef dish.chef
visit '/preorders'
expect(page).to have_content('PREORDER MENU')
within('div#dishes-container') do
expect(page).to have_xpath("//img[#src=\"#{dish.image.small}\"]")
expect(page).to have_content(dish.description)
expect(page).to have_content(dish.name)
expect(page).to have_content(dish.price)
expect(dish).to have_content("Add to Cart")
expect(dish2).to have_content("Pre-Order")
expect(current_path).to eq(preorders_path)
end
end
1) Visitor can see preorders with dish available to add to cart, preparation time over 1 hour should show dish
Failure/Error: expect(dish).to have_content("Add to Cart")
expected to find text "Add to Cart" in "Dock Bogisich"
# ./spec/features/visitor/preorders/list_of_preorders_spec.rb:129:in `block (4 levels) in <top (required)>'
# ./spec/features/visitor/preorders/list_of_preorders_spec.rb:124:in `block (3 levels) in <top (required)>'
I am trying to get rspec to check if specifically dish has 'add to cart' content and dish 2 to have 'pre-order' content. How can I get Rspec to check it? Is it possible to give them both a unique id and call it out here?

In your view assign ids to both the buttons. Something like:
<button id="add_to_cart-{dish.id}"> ADD to Cart </button>
<button id="pre-order-{dish2.id}"> Pre-Order </button>
Than in spec:
add-cart-btn = "button#add_to_cart-#{dish.id}"
with_in add-cart-btn do
page.should have_content 'Add to Cart'
end
Same for the Pre-order!

Related

Rails, Capybara - click_link on remote links doesnt work

I'm using Capybara to test my project. But i have a problem.
I have some remote forms on my project. They add records via ajax. When i'm testing with capybara it works well on development environment. It visits the page, fills in the form and submits. Booom, record has been added and test didnt fail.
But when i run rspec with test environments i'm getting unknown format exception.
1) add new address user adds new address
Failure/Error: find("input[value='Adres Ekle']").click
ActionController::UnknownFormat:
Account::AddressesController#create is missing a template for this request format and variant.
request.formats: ["text/html"]
request.variant: []
# ./spec/features/user_add_new_address_spec.rb:28:in `block (2 levels) in <top (required)>'
I've also tried to respond via js from controller like;
def create
request.format = :js
end
Then it returns;
1) add new address user adds new address
Failure/Error: find("input[value='Adres Ekle']").click
ActionController::UnknownFormat:
Account::AddressesController#create is missing a template for this request format and variant.
request.formats: ["text/javascript"]
request.variant: []
# ./spec/features/user_add_new_address_spec.rb:28:in `block (2 levels) in <top (required)>'
And my scenario if u want more info;
scenario 'user adds new address' do
expect(page).to have_content 'Kayıtlı Adreslerim'
find("a[title='Adres Ekle']").click
expect(page).to have_content 'Yeni Adres Ekle'
expect(page).to have_content 'Adres Başlığı'
fill_in 'address[name]', with:'Izmir Ofisi'
select('Izmir', :from => 'address[city_id]')
fill_in 'address[address]', with: 'Lorem ipsum dolor sit amet.'
find("input[value='Adres Ekle']").click # It submits remote: true form.
expect(page).to have_content 'Success!'
end
PS: my create action doesnt render something like that.
its like;
def create
#new_address = Address.new
#address = #current_account.addresses.new(address_params)
if #address.save
#check = true
else
#check = false
end
end
it renders: create.js.erb
<% if #check %>
if($('.addresses').length) {
$('.addresses').append('<%= j(render('account/addresses/address', address: #address)) %>');
}
if($('#did-addresses').length){
$('#did-addresses').append("<%= "<option selected='true' value='#{#address.id}'>#{#address.name}</option>".html_safe %>").selectpicker('refresh');
}
$('#new-address').html('<%= j(render('account/addresses/form', new_address: #new_address)) %>');
swal({
type: 'success',
title: "<%= t('response.success') %>",
text: "<%= t('flash.actions.create.notice', resource_name: Address.model_name.human) %>",
timer: 2000
});
quickview.close('#new-address');
<% else %>
<% #address.errors.each do |error| %>
<% end %>
<% end %>
$('.preloader').fadeOut();
I was facing the same case in rails 6 but I fixed it be adding js: true to the scenario and it automatically worked well.
scenario 'Should delete the feature', js: true do
# Your logic
# Your expectations
end
Since copying your development config over your test config fixed your issue, it sounds like you probably an error in one of your JS files. Normally in the test and production environment all of your JS assets get concatenated into one file which means an error in any one of them can prevent the code in the others from being executed. In the development environment each JS file is loaded separately which means an error in any file can only affect the rest of the code in that file. Check your the console in your browser for any JS errors when going to the page in question and fix them.

Rspec testing view test fails but HTML is OK?

With Rspec, I'm testing the presence of the logo in the navnar:
#spec/views/_header_spec.html.erb
require 'spec_helper'
describe "layouts/_header.html.erb" do
subject{rendered}
it "should have the clickable logo" do
render
should have_selector("img")
should have_link("/")
end
end
This is my generated HTML:
<a href="/" class="navbar-brand">
<img alt="Logo" src="/assets/logo.png">
</a>
The page is OK, but the test fails:
$rspec spec/views/_header_spec.rb
F
Failures:
1) layouts/_header.html.erb should have the clickable logo
Failure/Error: should have_link("/")
Capybara::ExpectationNotMet:
expected to find link "/" but there were no matches
# ./spec/views/_header_spec.rb:10:in `block (2 levels) in <top (required)>'
Finished in 0.13914 seconds
1 example, 1 failure
Failed examples:
rspec ./spec/views/_header_spec.rb:7 # layouts/_header.html.erb should have the clickable logo
Randomized with seed 37707
The test fails, but the HTML behaviour page is correct, so I think my test is not working properly. Can you help me?
Replace
should have_link("/")
With
should have_link("Logo", href: "/")
have_link takes the display text of the link or alt attribute value of an image, and using the href option you can specify the corresponding path.

Undefined method confusion

I'm a Rails newbie working on my RSpec skills. I'm running into this undefined error that's leaving me scratching my head. Here it is:
1) Veiwing the list of movies shows the movies
Failure/Error: expect(page).to have_text(Movies.location)
NoMethodError:
undefined method `location' for #<Class:0x00000104bbb958>
# ./spec/features/list_movies_spec.rb:26:in `block (2 levels) in <top (required)>
Below is my spec file. Can you please tell me what am I overlooking here?
require "spec_helper"
feature "Veiwing the list of movies" do
it "shows the movies" do
movie1 = Movies.create(name: "The Butler", location: "New York City",
price:15.00)
movie2 = Movies.create(name: "The Grand Master", location: "New Jersey",
price:15.00)
movie3 = Movies.create(name: "Elysium", location: "Los Angeles",
price:15.00 )
movie4 = Movies.create(name:"Pacific Rim", location: "Queens NY",
price:15.00)
visit movies_url
expect(page).to have_text("4 Movies")
expect(page).to have_text(Movies.name)
expect(page).to have_text(Movies.name)
expect(page).to have_text(Movies.name)
expect(page).to have_text(Movies.name)
expect(page).to have_text(Movies.location)
expect(page).to have_text(Movies.description)
expect(page).to have_text("15.00")
end
end
Movies is a class and thus does not have a value for location. You should be checking the location against an instance of Movies: movie1, 2, 3, or 4. For example:
expect(page).to have_text(movie1.location)

Rails Capybara not seeing fields

I feel like I'm going insane here. Doing a routine capybara test of my Post model. Specifically, making sure the new page redirects to the newly created post after a valid submission. So in my spec/requests folder, I've got this:
describe "Valid post submission --" do
it "should log in a user and redirect to new post" do
# Sign in works find, so I won't reproduce it
# Make a blogpost
Post.destroy_all
fill_in :name_here, with: "Post Name Here"
fill_in :content_here, with: "This is the content of a really short post."
screenshot_and_open_image
click_on "Post It"
screenshot_and_open_image
puts current_path
page.should have_selector 'h2', text: "prohibited this post"
page.should have_selector 'h1', text: "Post Name Here"
page.should have_selector '.alert', text: "Post was successfully created."
page.should have_selector 'title', text: full_title('Post Name Here')
end
The screenshots and puts are there to clarify what's going on. There are basically two different cases. In
I just leave the fields be and test for the default IDs ("post_name"
and "post_content"); obviously the above test is for case two:
I change the field ids to "name_here" and "content_here" to test if
the label names or anything else is interfering. That's the one the spec of which is
above.
In case 2 the post is getting rejected because Capybara can't find either field.
In case 1, only the content would be empty, but the name field would be filled with the content.
The precise error in case 1 is:
2) Posts Invalid post - should refresh with error if content empty
Screenshot: /Users/myusername/rails/appname/tmp/capybara/screenshot_2013-03-14-22-37-36.634.png
Failure/Error: fill_in :post_name, with: "Post Name Here"
Capybara::ElementNotFound:
cannot fill in, no text field, text area or password field with id, name, or label 'post_name' found
# (eval):2:in `fill_in'
# ./spec/requests/posts_spec.rb:43:in `block (3 levels) in <top (required)>'
Case 2 doesn't throw an error about not finding the appropriate content, I believe because the label has that id as well.
This is ridiculous, because I took a snapshot of the HTML durin the test, just before it errors. Here's case 2 -- both cases look 90% the same here, apart from that ID difference:
<form accept-charset="UTF-8" action="/posts" class="new_post" id="new_post" method="post">
<div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓"></div>
<div class="field">
<label for="post_name">Name</label>
<br><input id="name_here" name="post[name]" size="30" type="text">
</div>
<div class="field text-area">
<label for="post_content">Content</label>
<br><textarea cols="50" id="content_here" name="post[content]" rows="20"></textarea>
</div>
<div class="actions btn-group">
<input class="btn" name="commit" type="submit" value="Post It">
</div>
</form>
Note the clear existence of the post_content field. In cases where both fail (Case 1), there are both content_here and name_here fields. So the fields are there. And capybara is generally working (this sort of thing works find in other parts of my app). And the problem isn't a conflict with the label name, because putting a different id on the input fields doesn't help capybara find them.
By the way, this all works perfectly in reality.
Any idea at all what's going on here? I'm super frustrated/clueless.
UPDATE -- Following user2172816's advice, I changed my HAML so the HTML looks like this:
<form accept-charset="UTF-8" action="/posts" class="new_post" id="new_post" method="post">
<div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓"></div>
<div class="field">
<label for="post_name">Name</label>
<br><input id="name" name="post[name]" size="30" type="text">
</div>
<div class="field text-area">
<label for="post_content">Content</label>
<br><textarea cols="50" id="content" name="post[content]" rows="20"></textarea>
</div>
<div class="actions btn-group">
<input class="btn" name="commit" type="submit" value="Post It">
</div>
</form>
The test now looks like this:
# Make a blogpost
Post.destroy_all
fill_in "Name", with: "Post Name Here"
fill_in "Content", with: "This is the content of a really short post."
page.should have_selector 'h2', text: "prohibited this post"
page.should have_selector 'h1', text: "Post Name Here"
page.should have_selector '.alert', text: "Post was successfully created."
page.should have_selector 'title', text: full_title('Post Name Here')
But it's still erroring (in new parts of the same spec, too!):
1) Posts Invalid post - should refresh with error if content empty
Screenshot: /Users/username/rails/appname/tmp/capybara/screenshot_2013-03-14-23-54-38.072.png
Failure/Error: fill_in :name, with: "Post Name Here"
Capybara::ElementNotFound:
cannot fill in, no text field, text area or password field with id, name, or label 'name' found
# (eval):2:in `fill_in'
# ./spec/requests/posts_spec.rb:43:in `block (3 levels) in <top (required)>'
2) Posts Invalid post - should refresh with error if name empty
Screenshot: /Users/username/rails/appname/tmp/capybara/screenshot_2013-03-14-23-54-38.274.png
Failure/Error: fill_in :name, with: ""
Capybara::ElementNotFound:
cannot fill in, no text field, text area or password field with id, name, or label 'name' found
# (eval):2:in `fill_in'
# ./spec/requests/posts_spec.rb:33:in `block (3 levels) in <top (required)>'
3) Posts Valid post submission -- should log in a user and redirect to new post
Screenshot: /Users/username/rails/appname/tmp/capybara/screenshot_2013-03-14-23-54-38.459.png
Failure/Error: fill_in :name, with: "Post Name Here"
Capybara::ElementNotFound:
cannot fill in, no text field, text area or password field with id, name, or label 'name' found
# (eval):2:in `fill_in'
# ./spec/requests/posts_spec.rb:67:in `block (3 levels) in <top (required)>'
The attribute "for" of label should be the "id" of the input element, i.e.
<label for="name_here">Name</label>
<br><input id="name_here" name="post[name]" size="30" type="text">
And in the spec you should call:
fill_in 'Name', with: "Post Name Here"

RSpec test link_to inside p tag

Is it possible to have a test for the following html structure?
<p class="all-jobs"><%= link_to "<< Back to all jobs", jobs_path %></p>
I tried doing it this way:
it { should have_selector('p.all-jobs', link: "<< Back to all jobs")}
The error is:
1) JobPages visit a job page
Failure/Error: it { should have_selector('p.all-jobs', link: "<< Back to all jobs")}
expected css "p.all-jobs" to return something
# ./spec/requests/job_pages_spec.rb:78:in `block (3 levels) in <top (required)>'
Okay, I got it to work with the following:
describe "should have a link to index page" do
it { should have_selector('a', title: "<< Back to all jobs", href: jobs_path) }
end

Resources