I have some large end-to-end integration tests that for CI purposes I don't want in my spec/features folder in Capybara. Instead I have them in a spec/integration folder. Knowing that Capybara loads differently based on the folder, I put the :type=>:feature option on my describe, like so:
describe 'Recurring Contract Orders', :type=>:feature, :js=>true, :focus=>true do
it "satisifies the use case" do
....
But no luck, I am still getting the:
NameError:
undefined local variable or method `page' for #<RSpec::Core::ExampleGroup::Nested_1:0x007fd396bd2998>
error when I run the test. Is there something else I'm missing?
I don't know if it's something you are still trying to solve, but I was having the same problem. You are able to use the specific Capybara commands if you just include the DSL:
include Capybara::DSL
I haven't found out how to just have Capybara include my /integration folder yet, but this has worked for now.
For future ref, I think the right thing (according to https://github.com/jnicklas/capybara) is to tag the specs with :type => :feature, e.g.
describe "Some pages", :type => :feature do
specify "some behaviour"
end
Related
I have a test that I want to run only when I specifically indicate that I want to run it.
Say I have a test that does a whack load.. It's a test that takes a user through all the steps necessary to purchase something from when the user signs up to when they bid on something and then when they pay for it, and even when they later get a refund for the purchase.
Now typically a massive test is a really bad idea. Tests should be small and discrete. I'm all for that. And I have those tests in place. But I also think that one omni-test is a good idea. Especially for something as significant as payments.
I expect the test to be slow and all over the database... so I don't really want to run it all that often. (only when I specifically ask for it)
So I'm wondering if there is a way to have a test only run when I specifically ask for. If I type "rspec' in my terminal then this massive test won't run.
Sounds like you are looking to isolate certain 'features' to be run. Cucumber and Capybara use rspec underneath the covers to just this. Using this structure will be skipped unless specifically called. From the rspec core, use the tag options.
Example from https://www.relishapp.com/rspec/rspec-core/v/2-4/docs/command-line/tag-option
describe "group with tagged specs" do
it "example I'm working now", :focus => true do; end
it "special example", :type => 'special' do; end
it "slow example", :skip => true do; end
it "ordinary example", :speed => 'slow' do; end
it "untagged example" do; end
end
Then, to test:
When I run "rspec . --tag mytag"
Features Specs
Furthermore, using cucumber allows for feature tags for view testing.
You can use ENV variables to conditionally change your configuration. For example, I use the following in my spec_helper.rb for disabling feature tests by default:
config.filter_run_excluding :type => 'feature' unless ENV['FEATURE']
Then, if you want to run the full test suite from your console, simply:
FEATURE=true rspec
You should be able to tweak this to suit your needs. Just remember to set the environment variable on your CI server if you want the feature specs to be run there.
require "spec_helper"
require "rails_helper"
include Capybara::RSpecMatchers
include Capybara::DSL
Capybara.javascript_driver = :webkit
feature "Course", :type => :feature do
scenario "Get index and search for course types", js: true do
visit "/courses"
within("//body") do
find(:xpath, "//input[#id='course_type_id_1']").click
find(:xpath, "//div[#class='course-right-sec']")
expect(page).to have_content('65,171 courses')
expect(page).to have_content('Fundamentals of Design')
end
end
end
The problem i am facing with the above code is that when i find a specific div inside a within block, whether the id of the div is correct or not it passes the test.
Whoa, this is a lot of expectations for one test. While some testing purists would say one expectation per test, feature tests that need to load js are time consuming, but you might be doing too much here. One logical way would be to have one feature test for each of your courses; that way you have a couple expectations for each.
This isn't the exact solution to your problem, but it will help debugging in the future.
All of your expectations are based on the have_content matcher. Basically, if it's in the DOM on load, all of these expectations are going to pass, regardless of your find and click events. Ie. find(id).click
I might be able to help more if you give more context to whats going on here and what you are trying to test for and against. Attaching your js would help also.
I'm just getting started with feature specs using RSpec (and Capybara). I'm testing my ActiveAdmin dashboard and I want to check that all panels have an orders table as shown in this snippet:
feature 'admin dashboard', type: :feature do
def panels
page.all('.column .panel')
end
describe 'all panels' do
it 'have an orders table' do
expect(panels).to all(have_css('table.orders tbody'))
end
end
end
I've used the all matcher a lot in my unit tests but it doesn't appear to work when wrapping Capybara's have_css matcher because I'm getting the following error:
Failure/Error: expect(panels).to all(have_css('table.orders tbody'))
TypeError:
no implicit conversion of Capybara::RackTest::CSSHandlers into String
Am I correct in my assumption that RSpec's built-in all matcher should work with other matchers as well?
Note: I'm using describe and it instead of feature and scenario in this instance because I'm testing output rather than user interaction scenarios (see my other question).
Unfortunately there is a conflict between RSpec's all and Capybara's all see Capybara Issue 1396. The all that you are calling is actually Capybara's all.
Solution 1 - Call BuiltIn::All Directly
The quickest solution would be to call RSpec's all method directly (or at least that code that it executes.
The expectation will work if you use RSpec::Matchers::BuiltIn::All.new instead of all:
expect(panels).to RSpec::Matchers::BuiltIn::All.new(have_css('table.orders tbody'))
Solution 2 - Redefine all
Calling the BuiltIn:All directly does not read nicely so might get annoying if used often. An alternative would be to re-define the all method to be RSpec's all method. To do this, add the module and configuration:
module FixAll
def all(expected)
RSpec::Matchers::BuiltIn::All.new(expected)
end
end
RSpec.configure do |c|
c.include FixAll
end
With the change, the all in the following line will behave like RSpec's all method.
expect(panels).to all(have_css('table.orders tbody'))
Note that if you want to use Capybara's all method, you would now always need to call it using the session (ie page):
# This will work because "page.all" is used
expect(page.all('table').length).to eq(2)
# This will throw an exception since "all" is used
expect(all('table').length).to eq(2)
I used a very similar approach to the accepted answer, but in a Cucumber environment I was getting errors about RSpec.configure not existing. Also, I wanted to call the matcher something besides all so that I could use them both without conflicts. This is what I ended up with
# features/support/rspec_each.rb
module RSpecEach
def each(expected)
RSpec::Matchers::BuiltIn::All.new(expected)
end
end
World(RSpecEach) # extends the Cucumber World environment
Now I can do things like:
expect(page.all('#employees_by_dept td.counts')).to each(have_text('1'))
I've been searching around for a while, and did not find a clear explanation about testing structure in RoR. (I'm learning with Michael Hartl's book).
Since I'm using rspec for testing, do I need to keep the "test" folder anymore ?
Is the "spec" folder structure strictly assigned to specific test purposes ?
When "generating" a test script, does it do something else than creating the script file ? (i.e. could I create it by hand ?)
The 2nd question comes from this error:
undefined method `visit' for #<RSpec::Core::ExampleGroup: ...
which occurs as soon as my very simple test file is not in /spec/requests (but in /spec/views):
require 'spec_helper'
describe "Home page" do
subject { page }
###1
describe "title" do
before { visit root_path }
it { should have_selector('h1', text: 'Welcome') }
it { should have_selector('title', text: 'Home') }
end
end
1) No, you don't need the test folder. Only spec, unless you're using Test::Unit.
2) You can order spec however you want. The general suggested format is
spec/
controllers/
views/
models/
lib/ #Only if you have stuff in lib you need to test
spec_helper.rb
with names like spec/controllers/items_controller_spec.rb, and spec/models/item_spec.rb
3) I'm not sure what you mean. For RSpec, you just need to make a file that uses its syntax to test certain pieces of your Ruby code. It doesn't create a script -- you do.
For your last question about visit:
It seems like you're trying to use a Capybara method (visit). Capybara takes care of visiting your site in a browser, not RSpec.
No
See Below
No, only create the file
There is one specific folder structure you need to use in order to run Capybara acceptance tests. These are tests that have "visit" in them
Capybara 1.0
spec/requests
Capybara 2.0
spec/features
No, my understanding is that the test folder is generally used for Test::Unit stuff. You can delete or keep it; doesn't hurt to leave it.
There's a pretty specific way they want you to organize that stuff. If you have app/models/user.rb, for example, your spec should be in spec/models/user_spec.rb.
I don't know of anything else it does besides creating the test script. You can totally create those by hand, and I do all the time.
I'm having a hard time getting any consistant behavior from Mocha and the regexp_matches method. If autotest runs my entire test suite everything works fine. If I purposely cause the test containing the regexp_matches call to fail and then fix it I get a method_missing error on regexp_matches. If I then run the entire test suite again, everything is fine. The bigger problem is coming from Hudson (continuous integration). It runs the entire test suite but always says regexp_matches is missing and I don't know how to fix it.
My test:
test "if token is set during Account creation the long url should be created correctly" do
Account.any_instance.expects(:http_get).with("api.server.com", regexp_matches(%r(^http://.*/accounts/\d+/jobs$)))
account = Account.create name: "New Account", token: "NewToken"
end
The error:
test_if_token_is_set_during_Account_creation_the_long_url_should_be_created_correctly(AccountTest):
NoMethodError: undefined method `regexp_matches' for #<AccountTest:0x0000010162d0c0>
test/unit/account_test.rb:158:in `block in <class:AccountTest>'
I don't even know what other code to add here as I can't imagine what the cause is. For giggles I pasted require 'mocha' at the top of the test file but that didn't change anything.
I ran into this problem on a rails project when removing
require 'spec_helper'
I did this so that running the spec would not load the whole rails environment. This means that external dependencies have to be required or mocked. Mocha obviously needs to be required.
But even after specifying
require 'mocha'
I ran into the same method missing issue.
Ultimately, I solved it by including the parameter matchers module directly:
require_relative "../../../lib/some_class"
require "mocha"
include Mocha::ParameterMatchers
describe SomeClass do
it "should do things" do
...