I am trying to get best in place's
test helpers
working in my app. I am using
Capybara with Test::Unit
I have written a test like this.
class CompaniesTest < ActionDispatch::IntegrationTest
include BestInPlace::TestHelpers
def setup
#company = companies(:public)
end
test "should have best in place fields on show" do
get company_path(#company)
assert_response :success
assert_match #company.name, response.body
bip_text( #company, :name, "new name" )
end
end
I am getting an error like this
Capybara::ElementNotFound: Unable to find css "#best_in_place_company_1001664029_name"
I tried adding a sleep(0.5) before bip_text to see if it is a timing issue this did not change the error.
EDIT:
<span data-bip-type="input"
data-bip-attribute="name"
data-bip-object="company"
data-bip-original-content="Lightbulbs Corp."
data-bip-skip-blur="false"
data-bip-url="/companies/1001664029"
data-bip-value="Lightbulbs Corp."
class="best_in_place"
id="best_in_place_company_1001664029_name">Lightbulbs Corp.</span>
Here is what the css element for the page in the test env looks like. It looks like the id is correct. Any help would be appreciated.
I just reread your question and noticed you're using get. That's not a Capybara method and you can't mix the two different APIs and expect things to work. To implement what you're doing using Capybara it would be something like
test "should have best in place fields on show" do
visit company_path(#company)
assert_text #company.name
bip_text( #company, :name, "new name" )
end
Related
I have never dabbled outside of model testing when it comes to testing, and I am currently learning how to create my own user authentication instead of relying on Devise. It has been a little bit of time since I have worked with RSpec and not only would I like a little sanity check for syntax, but I can not figure out a way to confirm that my log in and sign up is indeed disappearing when a user logs in.
Here is my current users_logins_spec.rb
require 'rails_helper'
RSpec.describe "UsersLogins", type: :request do
before(:each) do
#user = FactoryGirl.build(:user)
end
it "login with invalid information" do
get login_path
expect(response).to render_template(:new)
post login_path, session: { email: "", password: "" }
expect(response).to render_template(:new)
expect(flash).to be_present
get root_path
expect(flash).not_to be_present
end
it "login with valid information" do
get login_path
post login_path, session: { email: #user.email, password: "password"}
expect(response).to redirect_to(#user)
follow_redirect!
expect(response).to render_template('users/show')
# expect(page).to have_selector('a', login_path)
end
end
Emphasizing the last test because that is the one that fails. I believe that if I were to put ID's on the tags that I want to check I would be able to circumvent the problem that I am having with methods that I understand. My intention is to learn how to manipulate my tests without having to find workarounds that change my code outside of the test, despite how little of a change that would be.
The other question is dealing with redirects. When I want to redirect to the #user url_path of #user, how does RSpec different when interpreting the call? I know that in Rails if I had something like
= link_to "Profile", current_user
it would automatically interpret it as
= link_to "Profile", user_path(current_user)
assuming my user resources within routes.rb.
If anyone can recommend some good tutorials for Rspec with Capybara for Integration and Feature testing that would be awesome, and any help/advice would be greatly appreciated. I am trying to make this as a Integration test instead of a feature test (which to my understanding those are kept within the requests directory and are "less readable" because they aren't so much as user stories but still are checking functionality of the site)
EDIT:
So I figured out part of my problem. I put in a debugger and was able to figure out that my user wasn't actually logging in correctly.
Here is the method that I am using to digest a password within the factory.
user.rb
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
factories.rb
FactoryGirl.define do
factory :user do
sequence(:id) { |n| n }
sequence(:name) { |n| "foo#{n}" }
email { "#{name}#example.com" }
password_digest User.digest('password')
end
end
The problem seems to be that my user login credentials are invalid and I am not exactly sure why.
FINAL EDIT - SOLVED
Okay, so I got it working. My problem with the user being incorrect was an easy fix. Instead of using password_digest within the factory I just did changed it to password and password_confirmation and it began the redirect. I originally had FactoryGirl.create(user) and have been switching between the two throughout testing, but in order for this to work with the confirmation it had to be create.
The next issue was actually with assert_select.
Here is the error:
NotImplementedError:
Implementing document_root_element makes assert_select work without needing to specify an element to select from.
I did end up finding a solution. Apparently this is with the latest version of RSpec and the solution that I had found was to set the document_root_element.
Within my spec/support I created a module
**spec/support/assert_select_root.rb
module AssertSelectRoot
def document_root_element
html_document.root
end
end
RSpec.configure do |config|
config.include AssertSelectRoot, :type => :request
end
I guess this was required for tests within spec/requests tests
Joe. You should keep in mind that FactoryGirl.build do not create database instance. So your Users table may be empty if you don't seed it before test.
I suggest you to use .create instead of .build.
I found this in one demo app:
it "should be able to use bip_text to update a text field" do
#user.save!
visit user_path(#user)
within("#email") do
page.should have_content("lucianapoli#gmail.com")
end
bip_text #user, :email, "new#email.com"
visit user_path(#user)
within("#email") do
page.should have_content("new#email.com")
end
end
https://github.com/dougc84/best_in_place/blob/master/spec/integration/js_spec.rb
Seems easy.
So I copied it to my Capybara spec:
before (:each) do
#report = FactoryGirl.create(:report)
visit report_path(#report)
end
it "name", :focus do
within("#name") do
page.should have_content #report.name
end
bip_text #report, :name, "new name"
visit report_path(#report)
within("#name") do
page.should have_content "new name"
end
end
It's so fast I can barely see anything, but it looks like it does do something with #name field. Then page reloads and it's still old value.
Any help?
Oh btw it does work in the browser. Just can't get tests pass.
I've added sleep 1 before and after bip_ helper, and it worked.
The problem here is the Javascript run by bip_text is asynchronous, but in your next line you immediately go to a different page, cutting off that Javascript from ever finishing. This is why your sleep 1 fixes it. You could also fix it by making Capybara wait for some new content before visit report_path, but then you'd need to write something like a success message to the page (e.g. with the ajax:success JS callback).
I'd like to isolate specific nodes to test on.
e.g. instead of
get :show
response.should have_content(#user.name)
it would be more descriptive/correct to be able to write something like
get :show
profile = response.find_selector("div.user-profile")
profile.should have_content(#user.name)
is it possible?
UPDATE
Got a bit further with this after reading Peter's answer but still not finding elements.
in app\views\users\index.html.erb
<h1>Users</h1>
<div id="test"></div>
in spec\controllers\users_controller_spec.rb
require 'spec_helper'
describe UsersController do
render_views
it "should should have header" do
get :index
response.should have_selector("h1", content: "Users")
end
it "should show user profile" do
get :index
node = page.find_by_id("test")
p node
end
end
The first test passes, the second test gives ElementNotFound error. I'm possibly just doing something stupid as this is my first go at Rails.
Yes, it is possible. Capybara doesn't have find_selector, but it does have find and derivatives which take a locator and behave as you imply above. See http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Finders
For example, instead of:
page.should have_selector('foo', text: 'bar')
you can say:
node = page.find('foo')
node.should have_content('bar')
I am using rspec and webrat for behavior driven development. This is the first time I am using webrat.
I followed webrat's instructions on how to use the gem, so I think it is installed correctly (the gem shows when I use bundle show).
The problem occurs when I just want to test whether my rendered view (welcome/index.html.erb) has an h1 tag. Should be fairly simple.
My code looks like this:
require 'spec_helper'
describe "welcome/index.html.erb" do
render :template => "welcome/index", :layout => "layouts/application"
it "displays a welcome message" do
rendered.should have_selector "h1"
end
end
I got there because of this question, but maybe it is a little old. When I run the test it gives me
undefined method `render'
What am I doing wrong? How can I fix this?
Found a way to solve it. Apparently this is much easier than I thought:
describe "welcome/index.html.erb" do
it "displays a welcome message" do
render
rendered.should have_selector "h1"
end
end
Apparently I just have to say render inside the "it" block. This solves the problem for me.
I'm doing some tests here using Rspec and I would like to assure that the controller is calling the log method in some actions. I'm also using mocha.
I would like something like this:
it "update action should redirect when model is valid" do
Tag.any_instance.stubs(:valid?).returns(true)
put :update, :id => Tag.first
controller.expects(:add_team_log).at_least_once
response.should redirect_to(edit_admin_tag_url(assigns[:tag]))
end
is there something to use as the 'controller' variable? I tried self, the controller class name...
I just got helped with this. For testing controllers, you'd nest your specs inside a describe which names the controller. (The spec should also be in the Controllers folder)
describe ArticlesController do
integrate_views
describe "GET index" do
...
it "update action should redirect when model is valid" do
...
controller.expects(:add_team_log).at_least_once
...
end
end
end
I think you want #controller instead of controller. Here's an example from my test suite:
it "delegates to the pricing web service" do
isbn = "an_isbn"
#controller.expects(:lookup)
.with(isbn, anything)
.returns({asin: "an_asin"})
get :results, isbn: isbn
assert_response :success
end