Capybara/Cucumber : RoutingError for nested resources in a namespace - ruby-on-rails

I'm using Capybara/Cucumber on Rails 3.2 and I'm facing a weird routing error.
I have the following routes defined :
#routes.rb
namespace :super_user do
...
resources :events do
resources :invites
end
end
...
resources :invites
and the following Cucumber feature :
#in_progress #current
Scenario: I can invite a USER by email
Given the following event exists:
| Name |
| The Event |
And I go to the event page for "The Event"
And I follow "Invite new user"
And I fill in "invite_email" with "user#domain.com"
...
The event page (EventsController#show) contains a link to the invites#new action :
#app/views/super_user/events/show.html.erb
...
<%= content_for :button_bar do %>
<%= link_to( 'Invite new user', new_super_user_event_invite_path(#event) ) %>
<% end %>
Everything is working properly when I test the /super_user/events/1 action manually, but whenever I run cucumber I get :
And I follow "Invite new user" # features/step_definitions/web_steps.rb:45
uninitialized constant SuperUser::InvitesController (ActionController::RoutingError)
(eval):2:in `click_link'
./features/step_definitions/web_steps.rb:46:in `/^(?:|I )follow "([^"]*)"$/'
features/create_casino_super_user.feature:24:in `And I follow "Invite new user"'
Why does routing behave differently when using Cucumber/Capybara ? How could I fix this feature ?
Relevant parts of bundle list :
* cucumber (1.0.6)
* cucumber-rails (1.0.2)
* capybara (1.0.1)
* capybara-webkit (0.6.1 dfa0624)
* rails (3.2.1)
EDIT
Side note : the InvitesController class is not in the SuperUser module but as I said previously it works when testing manually.

I'm on Rails 3 (not 3.2), coming from 2.3 and just jumping to the new routing DSL. I came across a very similar issue where our resource-in-a-namespace routes work when hit directly but not from inside Cucumber/Capybara.
In the end, I pulled the default routes from Rails 2.3 and made them active only inside cucumber, which seems to work:
# Cucumber doesn't understand the Rails 3 default route, above, so use the old way to make that work
# TODO remove this when we can/must, and hope that Cucumber is smarter by then
if File.basename($0) == "cucumber"
map.connect ':controller/:action/:id.:format'
map.connect ':controller/:action/:id'
end
Not sure that's an option for you (map.connect is part of the old API, which I think disappears in 3.1), but I wanted to put it on the internet somewhere for those who come looking.

Related

Rails Rspec Controller return 'undefined method Sinatra::Application:Class'

Typically I avoid controller tests and stick to Model & Cucumber, but i find myself needing one and I cant seem to get moving.
The following code is simplistic.. i have ripped out just about everything
1 require 'spec_helper'
2
3 describe ExperiencesController do
4 describe "GET #show" do
5 context "experience item" do
6 it "redirects to the success url" do
7 experience = build(:experience)
8 get :show, :id => experience.id
9 #should be a test here :)
10 end
11 end
12 end
13 end
Yields the following
Failures:
1) ExperiencesController GET #show experience item redirects to the success url
Failure/Error: get :show, :id => experience.id
NoMethodError:
undefined method `id' for Sinatra::Application:Class
# (__DELEGATE__):2:in `get'
# ./spec/controller_spec/experiences_controller_spec.rb:8:in `block (4 levels) in <top (required)>'
$ rake routes|grep experience
experiences GET /experiences(.:format) experiences#index
POST /experiences(.:format) experiences#create
new_experience GET /experiences/new(.:format) experiences#new
edit_experience GET /experiences/:id/edit(.:format) experiences#edit
experience GET /experiences/:id(.:format) experiences#show
PUT /experiences/:id(.:format) experiences#update
DELETE /experiences/:id(.:format) experiences#destroy
Really feels like a config type of thing
I dont understand why it would be yielding a Sinatra error
Any help appreciated
** Update **
SideKiq and its dependency sinatra is installed in the Gemfile for this rails app.
And I believe that sinatra may be interfering with controller test.
Ok.. so the problem was a collision of mistakes
1.) Because Im using Sidekiq I had the following in my config route
require 'sidekiq/web'
mount Sidekiq::Web => '/sidekiq'
That awesome piece of code mounts a Sinatra based web interface to monitor Sidekiq
2.) If you notice above my directory above is wrong
It was incorrectly spec/controller_spec instead of spec/controller
When that happens rspec doesnt know you are intending to test controllers and doesnt
load all the Get/post helpers , instead in the loaded stack the only thing it
found was sinatra which has a get method..
Solution ..
Move the spec to the proper directory so it properly infers the right dependencies
IT10T error..

mail_room with Ruby on Rails

I can't seem to get mail_room working in a Rails app.
When testing the logger delivery method, it works correctly with this
config/mail_room.yml
---
:mailboxes:
-
:email: "some#gmail.com"
:password: "password"
:name: "inbox"
:delivery_method: logger
:log_path: "email.log"
but the postback delivery method doesn't seem to work at all
config/mail_room.yml
---
:mailboxes:
-
:email: "some#gmail.com"
:password: "password"
:name: "inbox"
:delivery_method: postback
:delivery_url: "http://global-or-local-ip/inbox"
:delivery_token: "abcdefg"
config/routes.rb
post 'inbox', :to => 'users#inbox', :as => :users_inbox
app/controllers/users_controller.rb
class UsersController < ApplicationController
def inbox
puts "Check your inbox..."
end
end
Not sure if it's because of mail_room or something missing from the Rails app. I've tried different verbs in the routes. Using Rails 4.0.2 and tried both 0.1.0 and github source for the gem.
After some research, we found that Faraday 0.8.8 was having some issues with ruby 2.0 as we were using it in mail_room. Released a new gem, and made notes in the README that users should install >= 0.8.9 of Faraday.

Test BrainTree with rspec and capybara in Rails 4

I'm working on a Rails 4 app and i want to write some tests for BrainTree:
using rspec-rails (2.14.0) and capybara (2.1.0) in Rails 4.0.0
The problem is with on the route, in the form for Braintree i pass a :url
<%= form_for :customer, :url => Braintree::TransparentRedirect.url do |f| %>
Now when i run a feature test like this one:
it 'should make new payment info' do
login
visit new_customer_path
page.fill_in 'customer_credit_card_number', :with => '4111111111111111'
page.fill_in 'customer_credit_card_expiration_date', :with => '01/25'
page.fill_in 'customer_credit_card_cvv', :with => '400'
page.click_button 'Save Payment Info'
page.should have_content('Payment Info Confirmation')
page.should have_content('411111******1111')
end
i get a error on the route:
Failure/Error: page.click_button 'Save Payment Info'
ActionController::RoutingError:
No route matches [POST] "/merchants/fvn6vfc5ptyg2xrp/transparent_redirect_requests"
I've also tried this in a controller test (with render_views):
it 'should make new payment info' do
sign_in_as_user
visit new_customer_path
page.fill_in 'customer_credit_card_number', :with => '4111111111111111'
page.fill_in 'customer_credit_card_expiration_date', :with => '01/25'
page.fill_in 'customer_credit_card_cvv', :with => '400'
page.click_button 'Save Payment Info'
save_and_open_page
page.should have_content('Payment Info Confirmation')
page.should have_content('411111******1111')
end
Same error on the route...
In development env in the browser it works fine, i looks like the :url option in my form gets ignored by capybara? I wonder if anybody can help me with this?
I've also found these examples apps for Braintree with Rails: https://github.com/braintree/braintree_ruby_examples/blob/master/rails3_tr_devise/spec/controllers/customer_controller_spec.rb when i run the tests on that project it works.. maybe my problem has to do with the version of Rails and rspec?
many thanks in advance!!
I actually cover this exact scenario in my Multitenancy with Rails book.
The difference between your tests and Braintree's project's tests are that your tests are Capybara features and theirs' are controller specs.
I mention this relevant part of Capybara's README within the book:
RackTest is Capybara's default driver. It is written in pure Ruby and does not
have any support for executing JavaScript. Since the RackTest driver interacts
directly with Rack interfaces, it does not require a server to be started.
However, this means that if your application is not a Rack application (Rails,
Sinatra and most other Ruby frameworks are Rack applications) then you cannot
use this driver. Furthermore, you cannot use the RackTest driver to test a
remote application, or to access remote URLs (e.g., redirects to external sites,
external APIs, or OAuth services) that your application might interact with.
The way I get around it is that I wrote a gem called fake_braintree_redirect which inserts a piece of middleware into the request stack during the test environment to capture these requests and respond appropriately. The middleware is added to the stack using an initializer block defined within application.rb, like this:
initializer 'middleware.fake_braintree_redirect' do
if Rails.env.test?
require 'fake_braintree_redirect'
config.middleware.use FakeBraintreeRedirect
end
end
This takes Braintree out of the equation completely and returns a successful response whenever you send data to it.
Alternatively, if you really want to test against Braintree's sandbox, you could switch to the JavaScript driver by tagging your scenario as:
scenario "foo", :js => true

Do routing specs support redirect routes? [RSpec]

After digging fairly deeply on this issue, I've come to an impasse between my understanding of the documentation and my results.
According to https://www.relishapp.com/rspec/rspec-rails/v/2-8/docs/routing-specs/route-to-matcher, we should be able to write the following:
#rspec-rails (2.8.1)
#rspec (>= 1.3.1)
#rspec-core (~> 2.8.0)
# routing spec
require "spec_helper"
describe BusinessUsersController do
describe "routing" do
it "routes to some external url" do
get("/business_users/7/external_url").should route_to("http://www.google.com")
end
end
end
# routes.rb
BizeebeeBilling::Application.routes.draw do
resources :business_users do
member do
get "external_url" => redirect("http://www.google.com")
end
end
end
Running this spec produces the following results:
Failures:
1) BusinessUsersController routing routes to some external url
Failure/Error: assert_routing "/business_users/7/external_url", "http://www.google.com"
ActionController::RoutingError:
No route matches "/business_users/7/external_url"
# ./spec/routing/business_users_routing_spec.rb:19:in `block (3 levels) in <top (required)>'
I have not been able to find anyone reporting this specific issue anywhere.
Added detail: the route is resolved perfectly well when testing manually.
Routing specs/tests specialize in testing whether a route maps to a specific controller and action (and maybe some parameters too).
I dug into the internals of Rails and Journey a bit. RSpec and Rails (basically, some details left out) use Rails.application.routes.recognize_path to answer the question "is this routable?"
For example:
$ rails console
> Rails.application.routes.recognize_path("/business_users/1", method: "GET")
=> {:action=>"show", :controller=>"business_users", :id=>"1"}
However, there's no controller on the other end of /business_users/1/external_url. In fact, to perform the redirect, Rails has created an instance of ActionDispatch::Routing::Redirect, which is a small Rack application. No Rails controller is ever touched. You're basically mounting another Rack application to perform the redirection.
To test the redirect, I recommend using a request spec instead (a file in spec/requests). Something like:
require "spec_helper"
describe "external redirection" do
it "redirects to google.com" do
get "/business_users/1/external_url"
response.should redirect_to("http://www.google.com")
end
end
This tests the route implicitly, and allows you to test against the redirection.
Andy Lindeman has the correct answer. However, you don't have to put the spec in spec/requests, you can keep it in spec/routing and be explicit with the metadata "type": describe 'my route', type: :request do
I was running into a similar case where I was trying to test a series of routes, some which should redirect and some which shouldn't. I wanted to keep them in a single routing spec, since that was the most logical way to group them.
I tried using describe: 'my route', type: request, but found that not to work. However, you can include RSpec::Rails::RequestExampleGroup in your spec context to gain access to the request spec methods. Something like:
describe "My Routes" do
context "Don't Redirect" do
it "gets URL that doesn't redirect" do
get("business_users/internal_url").should route_to(controller: "business_users", action: "internal_url_action")
end
end
context "Redirection" do
include RSpec::Rails::RequestExampleGroup
it "redirects to google.com" do
get "/business_users/1/external_url"
response.should redirect_to("http://www.google.com")
end
end
end
The simplest way to test external redirects is to use an integration test:
test "GET /my_page redirects Google" do
get "/my_page"
assert_redirected_to "https://google.com"
end
You test needs to be under your test/integration directory or the equivalent directory where the integration tests should go.
I think you want the redirect_to matcher.

Sinatra app as Rails 3 subpath

I'm trying to get a sinatra app as a subpath in my rails 3 app.
Specifically, the resque queuing system has a sinatra based web interface that I would like to have accessible through /resque on my usual rails app.
You can see the project here: http://github.com/defunkt/resque
I found some people talking about adding a rackup file and doing this sort of thing:
run Rack::URLMap.new( \
"/" => ActionController::Dispatcher.new,
"/resque" => Resque::Server.new
)
But I don't really know where to put that or how to make it run. My deployment is with passenger, but it would me nice to also have it running when I run 'rails server' too. Any suggestions?
--edit--
I've made some progress by putting the following in config/routes.rb:
match '/resque(/:page)', :to => Rack::URLMap.new("/resque" => Resque::Server.new)
Which seems to work pretty well, however it loses the public folder, (which is defined within the gem I guess), and as a result, there is no styling information, nor images.
You can setup any rack endpoint as a route in rails 3. This guide by wycats goes over what you are looking for and many of the other things you can do in rails3:
http://yehudakatz.com/2009/12/26/the-rails-3-router-rack-it-up/
For example:
class HomeApp < Sinatra::Base
get "/" do
"Hello World!"
end
end
Basecamp::Application.routes do
match "/home", :to => HomeApp
end
Yehuda (/Scott S)'s solution doesn't work for me with Rails 3.0.4 and Sinatra 1.2.1... setting :anchor => false in the matcher is the key:
# in routes.rb
match "/blog" => MySinatraBlogApp, :anchor => false
# Sinatra app
class MySinatraBlogApp < Sinatra::Base
# this now will match /blog/archives
get "/archives" do
"my old posts"
end
end
(answer c/o Michael Raidel - http://inductor.induktiv.at/blog/2010/05/23/mount-rack-apps-in-rails-3/)

Resources