capybara matchers always eval to TRUE in rspec. Why? - ruby

Something strange is going on with capybara and rspec, which I'm setting up on Ruby 1.9.3, Padrino 0.10.7, rspec 2.11.0, capybara 2.0.2.
A basic Padrino project set up haml and rspec (no custom code, yet!) other than just enough to load a "/" page (which I verified does render as expected by "puts page.content" within the specs below). Here's the simple spec. "Bogus" doesn't exist, but "Home" does...note that when I puts to console, the expected true/false are CORRECT, but for some reason, the matchers aren't seeing the true/false correctly.
The one clue I have so far lies in the 2nd spec using should have_content('Bogus') which is reporting that Proc is expected...
./spec/controllers/hello_world_spec.rb
require 'spec_helper'
require 'capybara'
require 'capybara/rspec'
describe 'The HelloWorld App', :type => :feature do
context "per documentation" do
it "has bogus content" do
visit '/'
page.has_content?('Bogus')
end
it "does not have bogus content" do
visit '/'
page.should have_content("Bogus")
end
end
context "should tests" do
it "has bogus content" do
visit '/'
page.has_content?('Bogus').should == true
end
it "does not have bogus content" do
visit '/'
page.has_content?('Bogus').should == false
end
end
context "variables" do
it "has bogus content" do
visit '/'
result = page.has_content?('Bogus')
puts result
result.should == true
end
it "has Home content (expect TRUE!)" do
visit '/'
result = page.has_content?('Home')
puts result
result.should == true
end
it "does not have bogus content" do
visit '/'
result = page.has_content?('Bogus')
puts result
result.should == false
end
end
end
spec_helper.rb
PADRINO_ENV = 'test' unless defined?(PADRINO_ENV)
require File.expand_path(File.dirname(__FILE__) + "/../config/boot")
def app
##
# You can handle all padrino applications using instead:
Padrino.application
# Askme.tap do |app|
# end
end
RSpec.configure do |conf|
conf.include Rack::Test::Methods
Capybara.app = app
end
Output:
11:40:57:website >> bundle exec rspec spec/app/controllers/hello_world_controller_spec.rb
WARNING: Nokogiri was built against LibXML version 2.8.0, but has dynamically loaded 2.7.8
The HelloWorld App
per documentation
has bogus content
does not have bogus content (FAILED - 1)
should tests
has bogus content
does not have bogus content
variables
false
has bogus content
true
has Home content (expect TRUE!)
false
does not have bogus content
Failures:
1) The HelloWorld App per documentation does not have bogus content
Failure/Error: page.should have_content("Bogus")
TypeError:
wrong argument type Capybara::RSpecMatchers::HaveText (expected Proc)
# ./spec/app/controllers/hello_world_controller_spec.rb:16:in `block (3 levels) in <top (required)>'
Finished in 1.66 seconds
7 examples, 1 failure
Failed examples:
rspec ./spec/app/controllers/hello_world_controller_spec.rb:14 # The HelloWorld App per documentation does not have bogus content

Turns out the culprit was having both "bacon" and "rspec" in the Gemfile. Capybara was being introduced to a project that utilized bacon for the test suite and examples being tried were rspec. Once bacon was removed from the bundled gems, the capybara specs ran per documentation.
Since the bacon scripts run more or less as-is under rspec, the project decision is to remove bacon and go with rspec for the test suite and make the minor tweaks to the bacon scripts to run all specs under rspec.

Related

How to hook after example has execution result and status with :aggregated_failures flag

I'm maintaining a standalone test automation suite written in Rspec & Capybara and SitePrism (No Rails).
Recently I started integrating it with Testrail for reporting - I used rspec-testrail gem for that but I had to modify it a bit, because I also wanted to send Slack notifications with test progress and report.
Anyway, the integration works smoothly, except the fact that example processing is relying on example having an exception and lack of exception causes setting the test status as Passed on Testrail.
As it appears, after :each nor after :example in Rspec.configure doesn't guarantee that the example has finished running.
I also tried around :example and around :each as described here, but to no avail.
I inspected contents of example.metadata and it looks that example.metadata[:execution_result] has only started_at variable, but a finished example would have also finished_at and status variables, according to the docs
My suspicion (after reading the relish docs) is that :aggregated_failures is the cause of different metadata structure and multiple expects running in threads that are later merged into one backtrace.
Do you know how can I wait for the example to finish or how to hook into the state where it's finished?
Or maybe I should create a custom formatter where I would hook after example notifications printed to the console (I would like to keep the stacktrace there).
My code is as follows:
Test (both assertions are failing):
require 'spec_helper'
feature 'Sign in' do
let(:login_page) { LoginPage.new }
let(:user) { { email: ENV['ADMIN_EMAIL'], password: ENV['ADMIN_PASSWORD'] } }
scenario 'is successful and user is redirected to dashboard for user with correct credentials', testrail_id: 5694 do
login_page.load
login_page.form.email.set(user[:email])
login_page.form.password.set(user[:password])
login_page.form.submit_btn.click
expect(login_page.sidebar).to have_jobs(text: "some_nonexistenttext")
login_page.logout
expect(current_url).to have_content "google.com"
end
end
Console output from the above test:
Failures:
1) Sign in is successful and user is redirected to dashboard for user with correct credentials
Got 2 failures:
1.1) Failure/Error: expect(login_page.sidebar).to have_jobs(text: "blala")
expected #has_jobs?({:text=>"some_nonexistenttext"}) to return true, got false
# ./spec/auth/login_spec.rb:13:in `block (3 levels) in <top (required)>'
1.2) Failure/Error: expect(current_url).to have_content "google.com"
expected to find text "google.com" in "https://example.com/"
# ./spec/auth/login_spec.rb:15:in `block (3 levels) in <top (required)>'
Finished in 53.91 seconds (files took 1.45 seconds to load)
4 examples, 1 failure
Failed examples:
rspec ./spec/auth/login_spec.rb:8 # Sign in is successful and user is redirected to dashboard for user with correct credentials
Spec helper:
require 'rubygems'
require 'capybara/rspec'
require 'selenium-webdriver'
require 'site_prism'
require 'slack-notifier'
require_relative '../config'
require_relative '../lib/testrail'
...
RSpec.configure do |config|
config.define_derived_metadata do |meta|
meta[:aggregate_failures] = true
end
config.example_status_persistence_file_path = 'examples.txt'
config.before :all do
testrail_initialize_test_run!
end
config.after :example, testrail_id: proc { |value| !value.nil? } do |example|
RSpec::Testrail.process(example)
end
end
processing method (slightly modified from original)
def process(example)
if example.exception
status = 5
message = example.exception.message
slack_notifier.publish(message_text "Failed")
elsif example.skipped? || example.pending?
puts 'Example skipped or pending'
status = 10
message = 'Pending or not implemented'
else
status = 1
message = ''
end
client.send_post("add_result_for_case/#{testrun['id']}/#{example.metadata[:testrail_id]}",
status_id: status,
comment: message)
end
So basically all I had to was to use a reporter listener and process notifications inside it :)
config.reporter.register_listener RSpec::Testrail::Listener.new, :start, :example_failed, :example_passed, :example_pending, :stop

Set Up for RSpec in a Sinatra modular app

This is my first attempt with Sinatra. I built a simple classic app, set up RSpec for it, and got it working. Then, I tried to go modular, in a MVC fashion. Even though the app works in the browser, RSpec throws a NoMethodError. I've read Sinatra docs regarding RSpec, also searched a lot here in SO, but I can't find where the bug is. Any clue?
Thank you very much in advance.
Here are my relevant files:
config.ru
require 'sinatra/base'
Dir.glob('./{app/controllers}/*.rb') { |file| require file }
map('/') { run ApplicationController }
app.rb
require 'sinatra/base'
class ZerifApp < Sinatra::Base
# Only start the server if this file has been
# executed directly
run! if __FILE__ == $0
end
app/controllers/application_controller.rb
class ApplicationController < Sinatra::Base
set :views, File.expand_path('../../views', __FILE__)
set :public_dir, File.expand_path('../../../public', __FILE__)
get '/' do
erb :index
end
end
spec/spec_helper.rb
require 'rack/test'
# Also tried this
# Rack::Builder.parse_file(File.expand_path('../../config.ru', __FILE__))
require File.expand_path '../../app.rb', __FILE__
ENV['RACK_ENV'] = 'test'
module RSpecMixin
include Rack::Test::Methods
def app() described_class end
end
RSpec.configure { |c| c.include RSpecMixin }
spec/app_spec.rb
require File.expand_path '../spec_helper.rb', __FILE__
describe "My Sinatra Application" do
it "should allow accessing the home page" do
get '/'
expect(last_response).to be_ok
end
end
The error
My Sinatra Application should allow accessing the home page
Failure/Error: get '/'
NoMethodError:
undefined method `call' for nil:NilClass
# ./spec/app_spec.rb:5:in `block (2 levels) in <top (required)>'
I'm guessing you're following this recipe, correct?
The described_class in this line:
def app() described_class end
is meant to be the class under test, in this case ZerifApp. Try it like so:
def app() ZerifApp end
EDIT
It turns out the above answer is not correct about what described_class does. I assumed it was a placeholder -- actually it is an RSpec method that returns the class of the implicit subject, that is to say, the thing being tested.
The recipe at the link is misleading because of the way it recommends writing the describe block:
describe "My Sinatra Application" do
This is valid RSpec, but it does not define the subject class. Executing described_class in an example for this block will return nil. To make it work, replace the describe block:
describe ZerifApp do
Now described_class will return the expected value (ZerifApp)
https://pragprog.com/book/7web/seven-web-frameworks-in-seven-weeks
It has some source code to get some ideas from.
This has code example too. https://github.com/laser/sinatra-best-practices

prepare called on a closed database rails rspec

I am trying to integrate BDD in my rails app via rspec. I am using guard and spork-rails to speed the monitoring process up. I am getting this error:
An error occurred in an after hook
ActiveRecord::StatementInvalid: ArgumentError: prepare called on a closed database:
rollback transaction occurred at /Users/davidhahn/.rvm/gems/ruby-1.9.3-p286/gems/sqlite3-1.3.6/lib/sqlite3/database.rb:91:in initialize
I ran rake db:test:prepare and it ran without any errors. Since I'm using sqlite I checked to make sure that the user_man_test.sqlite file was in db/. My test is just a simple integration test:
require 'spec_helper'
describe "Authentication" do
describe "Login Page" do
it "should have the h1 'Welcome to User Management'" do
visit '/log_in'
page.should have_selector('h1', text: 'Welcome to User Management')
end
end
describe "Login" do
before { visit '/log_in' }
describe "with invalid information" do
before { click_button "Login" }
it { should have_selector('h1', text: 'Welcome to User Management') }
it { should have_selector('div.alert.alert-error', text: 'Invalid') }
end
end
end
My spec_helper.rb looks like:
require 'rubygems'
require 'spork'
Spork.prefork do
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
config.order = "random"
end
end
Spork.each_run do
# This code will be run each time you run your specs.
end
~
Thanks for the help
Instead of spending hours trying to configure spork properly, I would advise you to look at Zeus. I'm sorry if this doesn't exactly answer your question, but I spent almost one year with spork, had tons of trouble configuring every time that I added a new test gem, and when I made the switch, everything magically worked (and in my experience, Zeus' performance is much better than Spork).

RSpec test fails on Travis-CI but on local machine pass successfully

I'm write some specs to cover my HTML helpers
describe Sinatra::Helpers::HTML do
describe 'tag' do
it 'should retun selfclosed tag' do
Helpers.tag(:br, {}, true).should == '<br />'
end
it 'should have valid attributes' do
Helpers.tag(:div, :class => 'test').should include("class='test'")
end
it 'should contain value returned from block' do
tag = Helpers.tag(:div) { 'Block value' }
tag.should include('Block value')
end
end
describe 'stylesheet_tag' do
it 'should return link tag' do
Helpers.stylesheet_tag('test').should include('link')
end
it 'should contain path to asset' do
end
end
end
When I run it on local machine all is good, everything pass. But after pushing to GitHub repo Travis fails and write that Object::Sinatra is uninitialized (link) and I haven't idea why.
spec_helper.rb looks:
ENV['RACK_ENV'] = "test"
require 'simplecov'
SimpleCov.start
require File.join(File.dirname(__FILE__), '..', 'boot')
require 'rspec'
require 'capybara/rspec'
require 'rack/test'
require 'factory_girl'
FactoryGirl.find_definitions
Capybara.app = Orodruin.rack
RSpec.configure do |config|
config.include Rack::Test::Methods
config.after(:each) do
MongoMapper.database.collections.each do |collection|
collection.remove unless collection.name.match(/^system\./)
end
end
end
class Helpers
extend(*Sinatra::Base.included_modules.map(&:to_s).grep(/Helpers/).map(&:constantize))
end
because http://travis-ci.org/#!/orodruin/orodruin/jobs/2248831/L73 isn't using bundle exec.
the "bundle exec rake" line above it didn't seem to do anything.
you will need to prefix that line with bundle exec.
I don't see that line in your code, but it could be hard coded in one of your gems or in the Travis service.
The real problem is that the sinatra gem isn't found when Travis is running the specs. This is because travis is using an RVM gemset, and you are probably using the "global" gemset.
The result is ruby -s rspec ... isn't being ran in the gem bundle environment and isn't loading Sinatra.
I've forgot to add require 'spec_helper' on top of my specfile.

Using Capybara to test pure JavaScript application

I'm having some problems using Sinatra with Capybara.
I want to test a pure javascript application. It's just a plain index.html that is being served by Sinatra.
require "sinatra"
get "/" do
File.read("public/index.html")
end
Let's say for example that I want to test this code.
$("a.link").click(function(){
$(this).replaceWith("New String");
});
Click me!
Then the test would look something like this.
describe "requests", js: true do
it "should display a message" do
visit "/"
click_link "Click me!"
page.should have_content("New String")
end
end
The problem is that nothing happens. According to Ryan Bates screencast Firefox should start and run the test if js: true is added to the describe block.
Here is my spec_helper file.
require "rspec"
require "capybara"
require "capybara/dsl"
Capybara.javascript_driver = :selenium
require_relative "./../server"
Capybara.app = Sinatra::Application
Capybara.javascript_driver = :selenium
Capybara.default_wait_time = 10
RSpec.configure do |config|
config.mock_with :rspec
config.include Capybara
end
Here is the output when running rspec rspec/request_spec.rb.
requests
should display a message (FAILED - 1)
Failures:
1) requests should display a message
Failure/Error: page.should have_content("New String")
expected #has_content?("New String") to return true, got false
# ./spec/request_spec.rb:5:in `block (2 levels) in <top (required)>'
Finished in 4.38 seconds
1 example, 1 failure
Failed examples:
rspec ./spec/request_spec.rb:2 # requests should display a message
I created an complete example project on Github that can be found here:
https://github.com/oleander/capybara-js-fails
Anyone knows why it fails?
Here is the original answer from Jonas Nicklas.
You need to require 'capybara/rspec' and set :type => :request.
See the Capybara README section on "Using Capybara with RSpec".
/Jonas
Here is a working example on Github.

Resources