Why does an rspec feature spec with javascript not do test teardown? - ruby-on-rails

I have several non-javascript specs that use the ui to create and edit records.
When I run these specs the test database records are automatically removed for me by the rspec teardown for each test.
However the test below which is the first one to have :js => true for some ajax stuff isn't doing tear down of the records afterwards and then tests start to break because the database is no longer empty correctly when they start. The link and the group rows still exist in the test database.
# spec/features/verifying_link_spec.rb
require 'spec_helper'
describe "verification", :js => true, :type => :feature do
before :all do
User.create(:username => 'r#google.com', :password => 'esceptio')
end
before :each do
visit '/ladmin/login'
fill_in 'username', :with => 'r#google.com'
fill_in 'password', :with => 'esceptio'
find('input[value="Login"]').click
end
it "lets me verify a link" do
find('div#side div a', text: 'New Group').click
fill_in 'group[group_name]', with: 'Group Add'
click_button 'Save'
find('div#side div a', text: 'New Link').click
fill_in 'link[url_address]', with: 'http://www.a.com/newtest9876link'
fill_in 'link[alt_text]', with: 'abcd9876'
click_button 'Save'
this_year=Time.now.strftime('%Y')
l=Link.first
l.update_attribute(:verified_date, nil)
expect(Link.count).to eq 1
visit links_path
find('a', text: "verify")
click_link("verify", match: :first)
sleep(3)
expect(page).to have_content(this_year)
end
end
Right now I am using a workaround solution of using the ui to delete the records (below) but this should not be necessary
# added at bottom of spec
click_link('Details')
click_link('Delete')
page.driver.browser.switch_to.alert.accept
click_link('Groups')
click_link('Delete')
page.driver.browser.switch_to.alert.accept
None of my other unit tests or feature tests (except this one with js) have this problem. They all create records that get removed automatically.

I highly recommend using the database_cleaner gem to clean your database out between tests. Rspec wraps everything in a transaction and rolling it back once the example is finished. However, when you start using javascript you might be saving the data outside of the rspec transaction and then the database never reverts to its original state.
Truncation is slower than the transaction strategy. However you may only need the truncation strategy with JS tests. You could follow this guide to setup the database cleaner gem in that manner: http://devblog.avdi.org/2012/08/31/configuring-database_cleaner-with-rails-rspec-capybara-and-selenium/
If you find your tests taking eons, you might want to investigate some time looking at a gem that preloads your environment. I highly recommend zeus

Related

VCR: "There is currently no cassette in use." when creating a second cassette

I'm attempting to do RSpec feature tests on an external API.
My VCR config is as follows:
VCR.configure do |config|
config.cassette_library_dir = 'spec/vcr'
config.hook_into :webmock
config.ignore_localhost = true
end
My test looks like this:
feature 'Visitor' do
scenario 'performs an archival', :clean => false, :js => true do
mock_login
visit '/dashboard'
click_link 'Test Company'
VCR.use_cassette('feature/archive') do
within '.nav-app' do
click_button 'Quicksave'
end
end
end
scenario 'performs a restore', :js => true do
mock_login
visit '/dashboard'
click_link 'Test Company'
VCR.use_cassette('feature/restore') do
within '.nav-app' do
click_button 'Quickload'
end
end
end
end
The archive cassette is created just fine, however the restore cassette throws an error:
An HTTP request has been made that VCR does not know how to handle:
GET http://SomeApiUrl/...
There is currently no cassette in use.
I've obviously told VCR to create and use another cassette with:
VCR.use_cassette('feature/restore')
So what gives?
It's also worth mentioning that I still receive this error even when I clean out my cassette folder and start fresh.
Try passing , :record => :new_episodes as an argument to use_cassete. If you don’t use the record new episodes. It thinks they are the same request.
Turns out I'm dumb. The issue seemed to be that I was using the filename vcr.rb to configure VCR; I figured it wouldn't matter being that it was in my spec/support folder, but that was not the case.
A simple rename to vcr_config.rb fixed the problem right up...

Rake test not picking up capybara tests in minitest

I am setting up a basic template for having a capybara feature test in a rails application. I'm also using MiniTest instead of RSPEC.
Running Rake Test does not seem to be picking up my feature tests. I have one test in the file, running rake test does not change the number of assertions. Skipping the test does not show up either when I run rake test.
Here is a link to the repository: https://github.com/rrgayhart/rails_template
Here are the steps that I followed
I added this to the Gemfile and ran bundle
group :development, :test do
gem 'capybara'
gem 'capybara_minitest_spec'
gem 'launchy'
end
I added this to the test_helper
require 'capybara/rails'
I created a folder test/features
I created a file called drink_creation_test.rb
Here is the code from that feature test file
require 'test_helper'
class DrinkCreationTest < MiniTest::Unit::TestCase
def test_it_creates_an_drink_with_a_title_and_body
visit drinks_path
click_on 'new-drink'
fill_in 'name', :with => "PBR"
fill_in 'description', :with => "This is a great beer."
fill_in 'price', :with => 7.99
fill_in 'category_id', :with => 1
click_on 'save-drink'
within('#title') do
assert page.has_content?("PBR")
end
within('#description') do
assert page.has_content?("td", text: "This is a great beer")
end
end
end
I think I am having an issue with not connecting something correctly.
Please let me know if there is anything else I can provide which may help with diagnosing this issue.
Multiple things going on here. First, the default rake test task won't pick up tests not in the default test directories. So you need to either move the test file or add a new rake task to test files in test/features.
Since you are using capybara_minitest_spec you need to include Capybara::DSL and Capybara::RSpecMatchers into your test. And because you aren't using ActiveSupport::TestCase or one of the other Rails test classes in this test, you may see inconsistencies in the database because this test is executing outside of the standard rails test transactions.
require 'test_helper'
class DrinkCreationTest < MiniTest::Unit::TestCase
include Capybara::DSL
include Capybara::RSpecMatchers
def test_it_creates_an_drink_with_a_title_and_body
visit drinks_path
click_on 'new-drink'
fill_in 'name', :with => "PBR"
fill_in 'description', :with => "This is a great beer."
fill_in 'price', :with => 7.99
fill_in 'category_id', :with => 1
click_on 'save-drink'
within('#title') do
assert page.has_content?("PBR")
end
within('#description') do
assert page.has_content?("td", text: "This is a great beer")
end
end
end
Or, you could use minitest-rails and minitest-rails-capybara to generate and run these tests.
$ rails generate mini_test:feature DrinkCreation
$ rake minitest:features
I believe minitest has it's own gem for rails when using capybara: minitest-rails-capybara
Following the instructions over there might help, but I've never set up capybara with mini test before.

Testing javascript on subdomain with capybara, phantomjs and rails

Solution
This worked. The main essence is that I have to set the Capybara.server_port and Capybara.app_host and sign in manually in the sign in form. Capybara.app_host cannot be set with a dynamic subdomain unless its declared in a variable. All urls has to be hard coded.
require 'spec_helper'
feature 'customer' do
let(:user) {FactoryGirl.create(:user)}
let(:firm) {user.firm}
let(:customers) {"http://#{firm.subdomain}.lvh.me:31234/customers"}
let(:root_url) {"http://#{firm.subdomain}.lvh.me:31234/"}
before(:all) do
Capybara.server_port = 31234
sub = firm.subdomain
Capybara.app_host = root_url
end
def sign_in_on_js
visit root_url
fill_in "Email", :with => user.email
fill_in "Password", :with => "password"
click_button "Sign in"
page.should have_content("Signed in successfully.")
end
scenario "make new", js: true do
sign_in_on_js
visit customers
page.should have_content("Add new customer")
find("#dialog_customer").click
page.should have_content("Create new customer")
end
end
Original question
I am making a multitenant app in rails. There is going to be a lot of javascript. But, I cant get the testing to work.
When not running :js = true every thing works. The problem arises in specs like this one
let(:customers) {"http://#{firm.subdomain}.lvh.me:3003/customers"}
scenario "Statistics select", :js => true do
visit customers
page.should have_content("Add new customer")
end
The poltergeist web driver for capybara cannot find the url and returns a blank page
Failure/Error: page.should have_content("Add new customer")
expected there to be text "Add new customer" in ""
I have this in my spec_helper.rb
require 'capybara/rspec'
require 'capybara/poltergeist'
Capybara.javascript_driver = :poltergeist
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, :debug => true)
end
Poltergeist and phantomjs try to deliver. I get this output
{"name"=>"set_debug", "args"=>[true]}
{"response"=>true}
{"name"=>"visit", "args"=>["http://subdomain2.lvh.me:3003/statistics"]}
poltergeist [1362522132943] state default -> loading
{"response"=>{"status"=>"fail"}}
Do I need to have a server running during testing to make this work?
I've tried selenium and capybara-webkit, but phantomjs has gotten closest to success.
I have also tried to change the hosts file in different ways( maybe not correct )
Any tips on setup are welcome!
Update
Starting to get desperate. I now start the rails server
rails s -e test -p 3001
and then run my tests.
Now I get redirected to the sign in page. I have this in the specs
before(:each) do
login_as(user, :scope => :user)
end
How can I sign in the test user on the rails test server without going trough the sign in process manually for every spec
Capybara already starts a server for you, to quote the docs:
Some Capybara drivers need to run against an actual HTTP server. Capybara takes care of this and starts one for you in the same process as your test, but on another thread. Selenium is one of those drivers, whereas RackTest is not.
Within your test you can use the visit method with a relative url, for example:
visit("/statistics")
Capybara will direct this request to the server it just started for this test.
When your want to use an absolute url within your test, you can, but you should also specify the port the server is running on. This port is being randomly chosen during the test. Some drivers have a method available to retrieve the port number.
For example when you use the Capybara-Webkit driver:
Capybara.current_session.driver.server_port
To visit an absolute url you can then use:
port_number = Capybara.current_session.driver.server_port
visit("http://127.0.0.1:#{port_number}/statistics")
Within the test specs probably a method login_as won't work. You have to log in with a few simple steps. For example:
before(:each) do
visit "/login"
fill_in "Email", :with => "my#email.com"
fill_in "Password", :with => "secret"
click_button "Login"
end
To test multiple subdomains you can set the Capybara.app_host. Take a look at this question for a detailed explanation.
UPDATE
Capybara 2 includes a nice feature called always_include_port which will automatically add the port number the server is running on.
Capybara.always_include_port = true
So instead of
visit("http://127.0.0.1:#{port_number}/statistics")
you can now use
visit("/statistics")
and it will automatically connect to http://127.0.0.1:#{port_number}/statistics.
If you want to test multiple subdomains with Capybara.app_host, you could use a domain name which always resolves to 127.0.0.1 for example lvh.me.
For example, if you specify Capybara.app_host = "http://example.lvh.me" it will run the tests using the example subdomain.

Trying to test omniauth with rspec & Capybara, failing

Using Rails 3.2 and the latest Rspec and Capybara, which means my Capybara specs live in spec/features.
I'm really new to Rails and testing, but I want to get used to testing. I ended up implementing OAuth before testing it. I finally got it working, and now I'm trying to retroactively test it (so I at least know if it breaks in the future). I'm trying to follow this tutorial, but things aren't working. Here's what I did:
1) Created spec/support/integration_spec_helper.rb with:
module IntegrationSpecHelper
def login_with_oauth(service = :google)
visit "/auth/#{service}"
end
end
2) Modified spec/spec_helper to include config.include IntegrationSpecHelper, :type => :request inside the Rspec.configure do block.
3) Created spec/features/omniauth_spec.rb with:
require 'spec_helper'
feature 'testing oauth' do
scenario 'should create a new tiger' do
login_with_oauth
visit new_tiger_path
fill_in 'tiger_name', :with => 'Charlie'
fill_in 'tiger_blood', :with => 'yes'
click_on 'Create Tiger'
page.should have_content("Thanks! You are a winner!")
end
end
Of course it's going to fail (I don't have tigers in my app) but I want it to fail on visit new_tiger_path. Instead, running the spec, I get:
1) testing oauth should create a new tiger
Failure/Error: login_with_oauth
NameError:
undefined local variable or method `login_with_oauth' for #<RSpec::Core::ExampleGroup::Nested_3:0x83355d8>
# ./spec/features/omniauth_spec.rb:4:in `block (2 levels) in <top (required)>'
So basically, it says there's no such thing login_with_oauth. This must be a really basic error, as my code isn't included for some reason.
I'm not using spork (trying to keep things simple).
Any idea what the problem might be? Thanks in advance!
If you are trying to use oauth from google, you'll want to change:
def login_with_oauth(service = :google)
to:
def login_with_oauth(service = :google_oauth2)
:google_oauth2 should also be the first argument to OmniAuth.config.add_mock, i.e.:
OmniAuth.config.add_mock(
:google_oauth2,
{
:info => {
:email => 'test#some_test_domain.com',
:name=>'Test User'
}
})
Don't forget to change:
config.include(IntegrationSpecHelper, :type => :request)
to:
config.include(IntegrationSpecHelper, :type => :feature)
inside the RSpec.configure block, as Christoph noted above.
A little late, but maybe I can help.
Got the same problem. It's caused by
config.include IntegrationSpecHelper, :type => :request
The paramater ':type' needs to be changed to ':feature' because you write a rspec feature test.
Solution:
config.include IntegrationSpecHelper, :type => :feature
Unfortunately this causes further problems, I couldn't solve yet.
Regards,
C-

Testing purchase process in RSpec request spec

I'm trying to test the order process in a request spec by filling out the purchase form:
describe "CC order" do
before do
visit order_path "product"
fill_in "full_name", with: "test name"
fill_in "email", with: "test#email.com"
fill_in "card_number", with: "4242424242424242"
fill_in "card_cvc", with: "123"
# etc...
click_on "complete-button"
end
it "should display confirmation message" do
page.should have_content "Thanks for your order!"
end
end
A new User and Order should be saved after the purchase form is submitted and does so correctly in development. However, my test fails because instead of processing the order it tells me that the database is locked:
I do have transactional fixtures turned on and some of my other tests use them. Is there another way I should be testing my order process?
EDIT: It seems like it open happens when I use page in the it block. If I just make the test block empty, everything works fine.
I was running out of ideas so I switched from sqlite to postgresql in development + test. That fixed the problem.

Resources