Can't test engine routes under Rails 3.2 + Rspec 2.13 - ruby-on-rails-3

In my engine 'Utilizer', I'm trying to test routes with Rspec 3.2.
Namespace are isolated
# lib/utilizer/engine.rb
module Utilizer
class Engine < ::Rails::Engine
isolate_namespace Utilizer
...
end
end
The engine is mounted to the dummy app:
# spec/dummy/config/routes.rb
Rails.application.routes.draw do
mount Utilizer::Engine => "/utilizer", as: 'utilizer'
end
To the spec_helper.rb I've added a couple of configures as below (from here):
# spec/spec_helper.rb
RSpec.configure do |config|
...
config.before(:each, type: :routing) { #routes = Utilizer::Engine.routes }
...
end
When I defined a route:
# config/routes.rb
Utilizer::Engine.routes.draw do
resources :auths, id: /\d+/, only: [:destroy]
end
Rake shows it properly for the dummy app:
$ spec/dummy > bundle exec rake routes
$ utilizer /utilizer Utilizer::Engine
$ Routes for Utilizer::Engine:
$ auth DELETE /auths/:id(.:format) utilizer/auths#destroy {:id=>/\d+/}
BUT both Rspec tests
# spec/routing/auths_routing_spec.rb
require 'spec_helper'
describe "Auths page routing" do
let!(:auth) { create(:utilizer_auth) } # factory is working properly by itself
describe "#destroy" do
let!(:action) { { controller: "utilizer/auths", action: "destroy", id: auth.id } }
specify { { delete: "/auths/#{ auth.id }" }.should route_to(action) }
specify { { delete: auth_path(auth) }.should route_to(action) }
end
end
fail with errors (for the first and second tests correspondingly):
No route matches "/auths/1"
No route matches "/utilizer/auths/1"
But, Holmes, why?

Since RSpec 2.14 you can use the following:
describe "Auths page routing" do
routes { Utilizer::Engine.routes }
# ...
end
Source: https://github.com/rspec/rspec-rails/pull/668

I've fount a solution in Exoth's comment at the end of this discussion on Github (thanks to Brandan).
In my spec_helper instead of
config.before(:each, type: :routing) { #routes = Utilizer::Engine.routes }
I use
config.before(:each, type: :routing) do
#routes = Utilizer::Engine.routes
assertion_instance.instance_variable_set(:#routes, Utilizer::Engine.routes)
end
and it works.

Related

Running Capybara Specs only works one time; after, problems with factories

I am currently having problems running capybara specs. The first time I run them they work as intended and pass. Every time after that, I get the following error:
Validation failed: Name has already been taken
Here is my sign_in_spec.rb
require 'rails_helper'
RSpec.describe 'Sign in and client creation page' do
let!(:team_all) { FactoryGirl.create(:team_all) }
let!(:development) { FactoryGirl.create(:team_development, parent: team_all) }
let!(:unassigned) { FactoryGirl.create(:team_unassigned, parent: development) }
let!(:product_feed) { FactoryGirl.create(:team_product_feed, parent: development) }
it 'creates a new client' do
user = FactoryGirl.create(:user, team: team_all)
login_as(user, :scope => :user)
visit ('/clients/new')
fill_in 'client_name', with: 'Capybara'
find('#new_client > input.button.bottom').click
expect(page).to have_content('Add Source')
end
end
successful_source_spec.rb
require 'rails_helper'
RSpec.describe 'Successful source' do
let!(:team_all) { FactoryGirl.create(:team_all) }
let!(:development) { FactoryGirl.create(:team_development, parent: team_all) }
let!(:unassigned) { FactoryGirl.create(:team_unassigned, parent: development) }
let!(:product_feed) { FactoryGirl.create(:team_product_feed, parent: development) }
login_user
it 'is created' do
fill_in 'origin_name', with: 'Feed'
find('#origin_feed_option_attributes_primary').click
fill_in 'origin_source', with: 'example_url'
find('#origin_remove_html').click
find('#new_origin > div > div > div > input:nth-child(3)').click
find('#new_origin > div > div > div > a').click
expect(page).to have_content('Feed')
end
end
source_error_spec.rb
require 'rails_helper'
RSpec.describe 'Source creation' do
let!(:team_all) { FactoryGirl.create(:team_all) }
let!(:development) { FactoryGirl.create(:team_development, parent: team_all) }
let!(:unassigned) { FactoryGirl.create(:team_unassigned, parent: development) }
let!(:product_feed) { FactoryGirl.create(:team_product_feed, parent: development) }
login_user
it 'creates bad source' do
fill_in 'origin_name', with: 'Rules'
find('#origin_feed_option_attributes_primary').click
fill_in 'origin_source', with: 'example_url'
find('#origin_remove_html').click
find('#new_origin > div > div > div > input:nth-child(3)').click
expect(page).to have_selector('body > div.off-canvas-wrap.full-width > div > section > section > div > div.flash-wrapper-wrapper > div > div > div')
end
end
Relevant factories
factory :user do
sequence(:email) { |n| "user#{n}#.com" }
password 'p#ssw0rd'
end
factory :team, class: Teams::ProductFeed do
sequence(:name) { |n| "Team #{n}" }
end
factory :team_all, class: Teams::All do
name 'All'
end
factory :team_development, class: Teams::Development do
name 'Development'
end
factory :team_unassigned, class: Teams::Unassigned do
name 'Unassigned'
end
factory :team_product_feed, class: Teams::ProductFeed do
name 'Product Feed'
end
What can I do to prevent issues with factories in the future? If parts of the rails_helper and spec_helper are needed, let me know.
Since you're using Rails < 5.1 you can't use transactional testing when testing with Capybara using any driver other than rack_test. Because of that you need to use database_cleaner to manage the cleaning of the DB between tests. Add the database_cleaner gem to your project and then use the configuration shown for Capybara on the database_cleaner repo - https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example.
You'll also need to ensure you comment out any other mentions of config.use_transactional_fixtures in your spec_helper/rails_helper

Rails 5.1.3 API using Devise Auth Token custom rendering

I'm developing an API using Rails 5.1.3 and I'm using the gem devise_token_auth for authenticate. Everything was working fine until I needed to customize the JSON renderized after an error occurred, like the client sending an request with an invalid email.
So, to do this, I redefined my routes from
mount_devise_token_auth_for 'User', at: 'auth'
to
mount_devise_token_auth_for 'User', at: 'auth', controllers: {
registrations: 'devise/registrations'
}
and created a file app/controllers/devise/registrations_controller.rb as below:
class RegistrationController < DeviseAuthToken::RegistrationController
def render_create_error
render 'devise/registrations/create_error.json'
end
def render_create_success
super
end
end
Now all requests that depends of RegistrationController are getting this error:
ActionView::Template::Error:
undefined method `protect_against_forgery?' for #<#<Class:0x007f84cfab70d8>:0x007f84cec53e10>
What I should do to fix this error?
Thanks in advance!
This is what I did on my rails server (rails 6). I have created folders called overrides where I place all my custom controllers / views
routes.rb
mount_devise_token_auth_for 'User', at: 'auth', controllers: {
registrations: 'overrides/registrations'
}
app/controllers/overrides/registrations_controller.rb
module Overrides
class RegistrationsController < DeviseTokenAuth::RegistrationsController
def render_create_success
render partial: 'overrides/registrations/render_create_success.json.jbuilder'
end
end
end
app/views/overrides/registrations/_render_create_success.json.jbuilder
json.status 'success'
json.data do
json.extract! #resource, :field1, :field2, etc.
end

Airbrake not catching errors for Sidekiq in Rails app on an environment other than development

I'm using Sidekiq and Airbrake in my Rails application. I would like Airbrake to catch any errors that occur during Sidekiq jobs. As per instructions I found online, I've added the following to sidekiq.rb:
config.error_handlers << Proc.new { |ex,context| Airbrake.notify_or_ignore(ex, parameters: context) }
Airbrake then was able to catch errors when they occurred in my development environment. However, once I deployed to a higher environment, Airbrake stopped being able to catch Sidekiq errors. Is there any reason this would happen? Is there anything else I need to configure inside my app?
I'm using sidekiq gem version ~>3.0.2, airbrake gem version ~>4.0.0, and rails 3.2.18
Here is my full sidekiq.rb:
require 'sidekiq'
require 'sidekiq-status'
redis_connection = "redis://127.0.0.1:6379/0"
Sidekiq.configure_server do |config|
config.redis = { :url => redis_connection, :namespace => 'sidekiq' }
config.server_middleware do |chain|
chain.add Sidekiq::Status::ServerMiddleware, expiration: 30.minutes
end
config.client_middleware do |chain|
chain.add Sidekiq::Status::ClientMiddleware
end
config.error_handlers << Proc.new { |ex,context| Airbrake.notify_or_ignore(ex, parameters: context) }
end
Sidekiq.configure_client do |config|
config.redis = { :url => redis_connection, :namespace => 'sidekiq' }
config.client_middleware do |chain|
chain.add Sidekiq::Status::ClientMiddleware
end
end
And here is my full airbrake.rb:
Airbrake.configure do |config|
config.user_attributes = [:id, :email]
config.api_key = '*my_api_key*'
end
It turns out that if your app is also using rubber, then you also have to change your rubber sidekiq initializer (config/rubber/common/initializers/sidekiq) to include the line:
config.error_handlers << Proc.new { |ex,context| Airbrake.notify_or_ignore(ex, parameters: context) }
The rubber sidekiq initializer is used for all non-development environments, whereas the sidekiq.rb file is used for development environment.

ERROR - Could not load 'guard/sass' or find class Guard::Sass

I'm not sure how I've done it, but upon running guard on my project, I'm getting the following error:
WARN: Unresolved specs during Gem::Specification.reset:
thor (>= 0.14.6)
WARN: Clearing out unresolved specs.
Please report a bug if this causes problems.
11:25:16 - ERROR - Could not load 'guard/sass' or find class Guard::Sass
11:25:16 - ERROR - Unable to activate sass-3.3.0.alpha.229, because listen-1.3.0 conflicts with listen (~> 1.1.0)
11:25:16 - ERROR - Invalid Guardfile, original error is:
> [#] undefined method `new' for nil:NilClass
11:25:16 - INFO - Guard is using TerminalTitle to send notifications.
11:25:16 - INFO - Guard is now watching at '/srv/www/unknowntales.net'
11:25:16 - INFO - LiveReload is waiting for a browser to connect.
My Guardfile looks like this (and was generated by Laravel Guard):
guard :concat, :type => "css", :files => %w[foundation normalize], :input_dir => "public/css", :output => "public/css/styles.min"
guard :concat, :type => "js", :files => %w[vendor/jquery vendor/custom.modernizr vendor/zepto foundation/foundation.joyride foundation/foundation.topbar foundation/foundation.placeholder foundation/foundation.tooltips foundation/foundation.magellan foundation/foundation.clearing foundation/foundation.abide foundation/foundation.interchange foundation/foundation.alerts foundation/index foundation/foundation foundation/foundation.cookie foundation/foundation.forms foundation/foundation.dropdown foundation/foundation.orbit foundation/foundation.section foundation/foundation.reveal], :input_dir => "public/js", :output => "public/js/scripts.min"
# Refresh the browser on save
guard 'livereload' do
watch(%r{.+(?<!\.min)\.(css|html|js|blade\.php)$})
end
guard :phpunit, :all_on_start => false, :tests_path => 'app/tests/', :cli => '--colors -c phpunit.xml' do
# Run any test in app/tests upon save.
watch(%r{^.+Test\.php$})
# When a view file is updated, run tests.
# Tip: you probably only want to run your integration tests.
watch(%r{app/views/.+\.php}) { Dir.glob('app/tests/**/*.php') }
# When a file is edited, try to run its associated test.
# Save app/models/User.php, and it will run app/tests/models/UserTest.php
watch(%r{^app/(.+)/(.+)\.php$}) { |m| "app/tests/#{m[1]}/#{m[2]}Test.php"}
end
module ::Guard
class Refresher < Guard
def run_all
# refresh
end
def run_on_additions(paths)
refresh
end
def run_on_removals(paths)
refresh
end
def refresh
`php artisan guard:refresh`
end
end
end
require 'cssmin'
require 'jsmin'
guard :refresher do
watch(%r[public/js/.+])
watch(%r[public/css/.+])
watch(%r{app/config/packages/way/guard-laravel/guard.php}) do |m|
`php artisan guard:refresh`
end
watch('public/css/styles.min.css') do |m|
css = File.read(m[0])
File.open(m[0], 'w') { |file| file.write(CSSMin.minify(css)) }
end
watch('public/js/scripts.min.js') do |m|
js = File.read(m[0])
File.open(m[0], 'w') { |file| file.write(JSMin.minify(js)) }
end
end
guard :sass, :input => 'app/assets/sass', :output => 'public/css'

Can't create a user factory in factory girl when using rspec, devise, guard, and spork

I've seen this issue several places, but none of the solutions seem to work.
I have a Rails 3.1 app with the latest versions of guard, spork, factory girl, rspec, and devise.
Whenever I try to create a user factory (the user model is a devise model) then I get this error:
Could not find a valid mapping for #<User...model attributes...>
I'm not sure what the problem is.
I ran rake db:test:prepare. I followed the instructions in this stackoverflow question: "Could not find a valid mapping for #<User ...>" only on second and successive tests
ALso, I attempted the solution in this answer from google groups:
https://groups.google.com/forum/?fromgroups#!topic/plataformatec-devise/StpbEsDCec0[1-25]
And, here's all the relevant code:
Guardfile
# A sample Guardfile
# More info at https://github.com/guard/guard#readme
require 'capybara/rspec'
guard 'spork', :cucumber_env => { 'RAILS_ENV' => 'test' }, :rspec_env => { 'RAILS_ENV' => 'test' } do
watch('config/application.rb')
watch('config/environment.rb')
watch('config/environments/test.rb')
watch(%r{^config/initializers/.+\.rb$})
watch('Gemfile')
watch('Gemfile.lock')
watch('spec/spec_helper.rb') { :rspec }
watch('test/test_helper.rb') { :test_unit }
watch(%r{features/support/}) { :cucumber }
end
guard 'rspec', :version => 2, :cli => '--drb' do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }
# Rails example
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
watch('config/routes.rb') { "spec/routing" }
watch('app/controllers/application_controller.rb') { "spec/controllers" }
# Capybara request specs
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
# Turnip features and steps
watch(%r{^spec/acceptance/(.+)\.feature$})
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
end
</code>
This is in my spec/factories.rb
FactoryGirl.define do
load "#{Rails.root}/app/models/user.rb"
factory :user, class: User do |user|
email 'owner#example.com'
password '12345678'
password_confirmation '12345678'
companyid 'example_company'
end
end
This is my spec/controllers/api_controller_spec.rb
require 'spec_helper'
describe ApiController do
it 'verifies company_id through POST to api/company_id' do
load "#{Rails.root}/app/models/user.rb"
debugger
user = FactoryGirl.create(:user)
post(:get_company_id, {:company_id => 'example_company'})
response.body.should include('true')
end
end
And I have this at the end of my config/application.rb
ActionDispatch::Callbacks.after do
# Reload the factories
return unless (Rails.env.development? || Rails.env.test?)
unless FactoryGirl.factories.blank? # first init will load factories, this should only run on subsequent reloads
FactoryGirl.factories.clear
FactoryGirl.find_definitions
end
end
I'm really desperate for an answer here because otherwise I won't be able to test my User model (which is the most important model I have).
Feel free to comment and ask any questions.
EDIT: code looked funny in places, so I edited it for clarity
UPDATE:
So I tried simplifying everything to get to the core of the problem, and I'm pretty sure that devise and factory girl don't "like" each other. I'm still getting the exact same error whenever I try and create a user factory.
This is my new setup (I reverted to a previous git commit and I no longer have guard or spork).
My factories.rb is exactly the same as Michael Durant's except I have an extra line:
companyid 'example'
That's just a requirement for my app.
My spec_helper.rb requires rubygems and capybara/rspec and that's it.
And this is my spec/models/user_spec.rb
require 'spec_helper'
describe 'User associations' do
it 'tests creation of user' do
debugger
user = FactoryGirl.create(:user)
User.count.should be(1)
end
end
Also, this is interesting: When I hit that debugger statement and type in
eval User
It shows the mapping of a valid User.
UPDATE:
So, it's not factory girl that's the problem. It's devise.
This is the new api_controller_spec.rb file and it comes up with the same error of not having a valid mapping of the user.
require 'spec_helper'
describe ApiController do
it 'verifies company_id through POST to api/company_id' do
load "#{Rails.root}/app/models/user.rb"
debugger
user = User.new
user.email = 'owner#example.com'
user.password = '12345678'
user.password_confirmation = '12345678'
user.company_id = 'company'
user.save
post(:get_company_id, {:company_id => 'example_company'})
response.body.should include('true')
end
end
THere isn't a problem with any other environment as I can create users fine through the console, while a local server is running, or when the code is pushed up to Heroku. It might be rspec or something else, but I'm just not sure at this point.
I would recommend you simplify things to find the issue. Currently I feel you have too much going on / too many variable factors.
I would recommend the following:
1 Make a new branch. I assume you are using git, if not use it (git init) and make a fork.
2 Remove all the spork and guard stuff. They are helpful in speeding up your tests and running tests in a CI (Continuous Integration), but they are certainly not 'needed' and removing them will help uncover what the real problems are.
3 Set up your user factory correctly. We use this:
FactoryGirl.define do
sequence :email do |n|
"email#{n}#factory.com"
end
factory :user do
email
first_name { 'First' }
last_name { 'Last' }
password { "password" }
password_confirmation { "password" }
association :area
role { 'super_user' }
end
end
4 Set up your spec_help correctly.
We use these requires in our spec_helper.rb:
require 'rubygems'
require 'capybara/rspec'
5 Try to get one user test to pass using spec/models/user_spec.rb, something like:
require 'spec_helper'
describe 'User associations' do
subject { User.new }
it { should validate_presence_of :area }
...
So, the answer had nothing to do with guard, spork, rspec, or factory_girl.
The problem was that I had my devise_for :users routes commented out since I've been doing a huge overhaul of my rails app.
It's always something stupidly simple >.<