Getting a wrong argument type RSpec::Matchers::Matcher (expected Proc) error in Rspec when testing responses in Rails - ruby

I am trying to test my Rails 3.0.9 controller with Rspec 2.6.4 and Webrat 0.7.3. My controller looks like this:
#metrics_controller.rb
class MetricsController < ApplicationController
def show
#metric = Metric.all(:msrun_id => params[:id]).first
end
def index
#metrics = Metric.all
end
end
And my controller spec looks like this:
#metrics_controller_spec.rb
require 'spec_helper'
describe MetricsController do
describe "GET #index" do
it "should be successful" do
get :index
response.should be_success
end
end
describe "GET show" do
it 'contains an overview of a metric' do
get :show, :id => 1
response.should have_selector('title', :content => "Metric Overview")
end
end
end
This looks very similar to other examples I have seen in documentation, but when I run bundle exec rspec spec/controllers/metrics_controller_spec.rb I am getting some strange errors:
1) MetricsController GET #index should be successful
Failure/Error: response.should be_success
TypeError:
wrong argument type RSpec::Matchers::BePredicate (expected Proc)
# ./spec/controllers/metrics_controller_spec.rb:8
2) MetricsController GET show contains an overview of a metric
Failure/Error: response.should have_selector('title')
TypeError:
wrong argument type Webrat::Matchers::HaveSelector (expected Proc)
# ./spec/controllers/metrics_controller_spec.rb:16
It looks like something weird is going on with the response.should method. If I change the first example to something more verbose that doesn't call should on response like this:
response.success?.should == true
then the example works fine, but why would should be expecting a Proc? Any ideas about how I can fix this?

This is not an especially helpful answer, but I will put it in here in case someone else gets stuck on the same thing. I inherited the project from someone else, and they set it up to use both railties and rails. Changing the Gemfile to look like this:
source 'http://rubygems.org'
RAILS_VERSION = '~> 3.0.7'
DM_VERSION = '~> 1.1.0'
gem 'railties', RAILS_VERSION, :require => 'rails'
gem 'activesupport', RAILS_VERSION
gem 'actionpack', RAILS_VERSION
gem 'actionmailer', RAILS_VERSION
gem 'dm-rails', DM_VERSION
gem 'rspec-rails'
#other gems below
Instead of something like this:
source 'http://rubygems.org'
gem 'rails'
gem 'dm-rails', '~> 1.1.0'
gem 'rspec-rails'
#other gems below
along with changing the config/application.rb to require the railties instead of rails seemed to fix it. The key seemed to be using railties instead of all of rails along with dm-rails.

Related

Ruby: Strange string comparison assertion behaviour

Can anyone explain what is happening here? I have this simple class with some static methods, and I want to test them.
yaqueline/build/converters/asciidocconverter.rb
# encoding: UTF-8
require 'asciidoctor'
module Yaqueline
module Build
module Converters
class AsciiDocConverter < Converter
class << self
def matches path
path =~ /\.(asciidoc|adoc|ascii|ad)$/
end
def convert content
html = Asciidoctor.convert content, to_file: false, safe: :safe
html = get_guts_out_of_body html
puts "asciidoc #{html}"
html
end
def get_guts_out_of_body html
if html =~ /<body>/
puts "get guts: #{html}"
return html.match(%r{(?<=<body>).*(?=</body>)})
end
html
end
end # class << self
end # class
end
end
end
and the test in test/build/converters/asciidocconverter_test.rb:
# encoding: utf-8
require 'helper'
require 'yaqueline/build/converters/asciidocconverter'
class TestAsciidocConverter < Test::Unit::TestCase
should "be able to get body html from a document" do
value = %q{SUCCESS}
html = %Q{
<html>
<head>
<title>Hej värld</title>
</head>
<body>#{value}</body>
</html>}
guts = Yaqueline::Build::Converters::AsciiDocConverter.get_guts_out_of_body html
puts "guts was '#{guts}'"
assert value.eql?(guts), "guts was '#{guts}', expected '#{value}'"
end
end
When running the test with
$ rake test TEST=test/build/converters/asciidocconverter_test.rb
The results looks good to me:
Started
get guts:
<html>
<head>
<title>Hej värld</title>
</head>
<body>SUCCESS</body>
</html>
guts was 'SUCCESS'
F
===============================================================================================================================================================================
Failure:
guts was 'SUCCESS', expected 'SUCCESS'.
<false> is not true.
test: AsciidocConverter should be able to get body html from a document. (TestAsciidocConverter)
/Users/mats/src/examples/yaqueline/test/build/converters/asciidocconverter_test.rb:37:in `block in <class:TestAsciidocConverter>'
/Users/mats/src/examples/yaqueline/test/build/converters/asciidocconverter_test.rb:39:in `instance_exec'
/Users/mats/src/examples/yaqueline/test/build/converters/asciidocconverter_test.rb:39:in `block in create_test_from_should_hash'
===============================================================================================================================================================================
but the assertion fails which seems odd to me and I'll need some help.
I'm running ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-darwin15]
and my Gemfilelooks like
# Add dependencies required to use your gem here.
# Example:
# gem "activesupport", ">= 2.3.5"
gem 'mercenary'
gem 'safe_yaml'
gem 'kramdown'
gem 'colorator'
gem 'pathutil'
gem 'nokogiri'
gem 'sass'
gem 'listen', '~> 3.0'
gem 'asciidoctor'
gem 'tilt'
gem 'erubis'
# Add dependencies to develop your gem here.
# Include everything needed to run rake, tests, features, etc.
group :development do
gem "rdoc", "~> 3.12"
gem "bundler", "~> 1.0"
gem "juwelier", "~> 2.1.0"
gem "simplecov", ">= 0"
gem 'rubocop', '~> 0.48.1', require: false
gem 'thin' # or whatever I end up with
gem 'minitest'
gem 'test-unit'
gem 'shoulda'
end
Maybe this helps to realize hat test harness I'm using.
Can anyone see the mistake or explain what's going on?
Cheers
Inspect the types of values being compared. One of them is not a string. (Thus, it can't be equal to a string).
guts = html.match(%r{(?<=<body>).*(?=</body>)})
guts # => #<MatchData "SUCCESS">
guts.to_s # => "SUCCESS"

How to use Kaminari pagination gem with Sinatra and Mongoid?

Presumably, not a whole lot of configuration is required - docs. The gem doesn't seem to work. Relevant code:
Gemfile:
source 'https://rubygems.org'
ruby '2.2.4'
gem 'sinatra'
gem 'thin'
gem 'slim'
gem 'json'
gem 'mongoid'
gem 'kaminari'
web.rb:
require 'sinatra'
require 'json'
require 'mongoid'
require 'kaminari'
# Mongoid class
class Affiliate
include Mongoid::Document
field :name, type: String
end
# MongoDB connection info and whatnot
Mongoid.load!('mongoid.yml', :development)
get '/kaminari' do
puts Affiliate.page(1).count
end
Error:
NoMethodError - undefined method `page' for Affiliate:Class
The error message states you can't page a class. Also, calling count on paginated data set isn't a correct use. Instead, first add some selection criteria to the class and then try to page the results. With respect to Mongoid, an example would be:
#paginated_users = User.where(:age.gte => 10).page(10)
By default, kaminari returns 25 items per page, you can change that by appending a per(desired number of items per page) method like so,
#paginated_users = User.where(:age.gte => 10).page(10).per(5)
Lastly, make sure you add a <%= paginate #paginated_users %> (the same variable name declared in your web.rb that contains the dataset to be paginated in the view) in your corresponding view file.
The following worked for me:
require 'mongoid'
require 'kaminari/sinatra'
require 'kaminari/mongoid'
get '/rest/1.0/post' do
# matches "GET /rest/1.0/post?page=1"
page_id = params[:page].to_i
redirect '/rest/1.0/post?page=1' if page_id == 0
page = Post.page(page_id)
json(size: Post.count,
total_pages: page.total_pages,
per_page: page.limit_value,
prev_page: page.prev_page,
current_page: page_id,
next_page: page.next_page,
data: page)
end
And in the Gemfile:
gem 'mongoid'
gem 'kaminari-mongoid'
gem 'kaminari-sinatra'

Rails 4, Strong Parameters, Unpermitted parameters on fields belonging to associated model

This is my first try at using models with associations with Rails 4 and for some reason I'm not able to get at the parameters POST'ed in due to a "Unpermitted parameters" error. I have tried to permit the associated fields several different ways with no success.
Basically, I have an Adoption Request with an associated Person.
class AdoptionRequest < ActiveRecord::Base
has_one :person
accepts_nested_attributes_for :person
end
and
class Person < ActiveRecord::Base
belongs_to :adoption_request
end
Here are the relevant sections from adoption_requests_controller.rb:
def create
#adoption_request = AdoptionRequest.new(adoption_request_params)
respond_to do |format|
if #adoption_request.save
format.html { redirect_to #adoption_request, notice: 'Adoption request was successfully created.' }
format.json { render action: 'show', status: :created, location: #adoption_request }
else
format.html { render action: 'new' }
format.json { render json: #adoption_request.errors, status: :unprocessable_entity }
end
end
end
private
def adoption_request_params
params.require(:adoption_request).permit(person_attributes: [:first_name, :last_name])
end
The form in the view is generated using rails-bootstrap-forms:
= bootstrap_form_for #adoption_request do |f|
= f.fields_for #adoption_request.person do |owner_fields|
= owner_fields.text_field :first_name
= owner_fields.text_field :last_name
= f.submit
Here is an example of the HTML generated by this for the first name field:
<input class="form-control" id="adoption_request_person_first_name" name="adoption_request[person][first_name]" type="text">
Now when I submit the following POST payload:
{"utf8"=>"✓", "authenticity_token"=>"kE1Q222VzXRsuLnhiO0X3mijW1TGTWSAOVgVDz/rxsE=", "adoption_request"=>{"person"=>{"first_name"=>"John", "last_name"=>"Smith"}}, "commit"=>"Create Adoption request"}
The adoption request is created, but the associated person is not. This is appears to be happening because strong parameters is not allowing the person parameters to come through. Case in point, I see this in the rails console output:
Unpermitted parameters: person
According to the strong parameters documentation, this configuration should work, but I have also tried:
params.require(:adoption_request).permit(:person, person_attributes: [:first_name, :last_name])
which results in the same error ("Unpermitted parameters: person"), and
params.require(:adoption_request).permit!
works to allow the parameters through, but this is not an acceptable solution as it negates the whole purpose of using strong parameters.
What am I doing wrong?
Here is my Gemfile, in case it is helpful:
source 'https://rubygems.org'
ruby '2.0.0'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.0.3'
# Use postgresql as the database for Active Record
gem 'pg'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 4.0.0'
# Use jquery as the JavaScript library
gem 'jquery-rails'
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 1.2'
group :doc do
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', require: false
end
# Use Bootstrap
gem 'bootstrap-sass', '~> 3.3.4'
# Use Figaro to make using environment variables easier
gem 'figaro'
# Use Slim templating engine
gem "slim-rails"
# User authlogic for authentication system
gem 'authlogic'
# Use rails-bootstrap-forms to integrate rails form builder with bootstrap
gem 'bootstrap_form'
group :test do
# use MiniTest::Spec::DSL
gem 'minitest-spec-rails', '~> 4.7'
end
The app itself is more complex than this. I've simplified it to illustrate the problem.
Thanks in advance for your help!
You need to change this line
= f.fields_for #adoption_request.person do |owner_fields|
to
= f.fields_for :person do |owner_fields|
I would simply try building the Person object on save. Pass the first and last names up as hidden fields.
Otherwise I would give strong parameters a read.
if #adoption_request.save
#adoption_request.persons.build(first_name: #first_name, last_name: #last_name)

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.

Acceptance testing of sinatra app using webrat fails

I am trying to test a ruby authentication app using minitest and webrat but get errors.
Tests like visit '/' fail with an error Status 200 expected but was 404.
Tests containing code like fill_in :email, :with => "first#company.com" fail with error Could not find field: :email.
I read several sinatra, testing and webrat documents and forums. Some of them were old and suggested stuff like Sinatra::Default, but github.com/brynary/webrat/wiki/sinatra, Building a Sinatra App Driven By Webrat Tests and Learning From the Masters: Sinatra Internals are new, yet they still fail.
Basically, I didn't like sentence-like syntax of rspec, cucumber etc but do want to do behaviour driven development. I really like the minitest syntax, both tests and output and that is why I choose webrat for BDD. If I'm wrong about expecting webrat to fulfill acceptance testing requirements, please simply tell me that I should use this framework or that one.
Apart from that, the first parts of the main file and test file are below. I hope someone can explain me, what I am missing?
test_file
require "test/unit"
require "minitest/autorun"
require "rack/test"
require 'webrat'
require_relative "../lib/kimsin.rb"
Webrat.configure do |config|
config.mode = :rack
end
ENV["RACK_ENV"] = "test"
class KimsinTests < Test::Unit::TestCase
include Rack::Test::Methods
include Webrat::Methods
include Webrat::Matchers
def app
Sinatra::Application.new
end
def test_create_user
visit "/user/new"
fill_in :username, :with => "first#company.com"
fill_in :password, :with => "abC123?*"
fill_in :confirm_password, :with => "abC123?*"
click_link "Register"
assert 201, last_response.status, "Status 201 expected but was #{last_response.status}.\n#{error}"
assert_contain /Logged in as first#company.com./, "No user created"
assert_contain /Logout/, "Logout link not present"
end
main_file
require "sinatra"
require "erb"
require_relative "../lib/kimsin/version"
require_relative "../lib/kimsin/user"
class Kimsin < Sinatra::Application
use Rack::Session::Pool, :expire_after => 2592000
set :session_secret, BCrypt::Engine.generate_salt
configure :development do
DataMapper.auto_migrate!
end
get "/" do
if session[:user_id]
user = User.get session[:user_id]
email = user.email
erb :index, :locals => { :email => email }
else
email = nil
erb :index, :locals => { :email => email }
end
end
Using Sinatra with Webrat should work fine. I think that the errors that you are seeing are caused by the following method (around line 18 in your test file):
def app
Sinatra::Application.new
end
This is setting up the Sinatra::Application base class to run your tests against when you really need to set up your own subclass Kimsin (because you are creating a modular style Sinatra app), i.e.
def app
Kimsin.new
end
The 404 errors and missing fields are happening because Sinatra::Application doesn't define any of the routes you are testing.
You might also like to take a look at Capybara if you are looking for similar alternatives to Webrat.

Resources