Setting Sessions Using Rspec/ Rack::Test in Sinatra Tests - ruby

I am trying to test a Sinatra application that is using oauth that has the following code being run before every route for the callback:
before do
unless session.has_key?(:oauth_token) || request.path == '/auth/callback'
access_url = oauth_client.auth_code.authorize_url(redirect_uri: ENV['CALLBACK'])
puts "Redirecting to #{access_url}"
redirect "#{access_url}"
end
end
For my tests, I simply just want to set the session[:oauth_token] to anything so that I get past this block and move onto the test. However, after hours of searches and experimentation, I haven't been able to figure it out.
I've tried Rack::Test to try and set it this way:
describe "Visit home page", js: true do
before { get '/', {}, { 'rack.session' => { oauth_token: 'blahblahblah' } } }
it "has a list of products" do
get "/"
expect(page).to have_link("Clear & Mild Foam Handwash Refill, Fragrance-Free, 1250mL Refill, 3/Carton")
expect(page).to have_link("Coffee Portion Packs, 1.5oz Packs, Hazelnut Crème, 24/Carton")
end
end
end
and my spec_helper.rb looks like this:
require File.expand_path '../../server.rb', __FILE__
require 'rspec'
require 'capybara/rspec'
require 'rack/test'
require 'capybara-screenshot/rspec'
require 'capybara/poltergeist'
Capybara.javascript_driver = :poltergeist
set :environment, :test
Capybara.app = Sinatra::Application
ENV['RACK_ENV'] = 'test'
module RSpecMixin
include Rack::Test::Methods
def app() Sinatra::Application end
def setup_session(session = {})
Rack::Session::Abstract::SessionHash.stub(:new).and_return(session)
end
end
RSpec.configure do |c|
c.include RSpecMixin
end
What is the best way to go about actually setting a session before every route?

Try this:
env "rack.session", { oauth_token: 'blahblahblah' }
get '/'
Taken from here.

Related

Errno::ENOENT at / no such file or directory

I'm currently working on a sinatra app and im having a little problem.
i'm trying to load my index.erb but sinatra cannot find the index.erb.
Here is my app.rb
require 'rubygems'
require 'sinatra'
module Registration
class HelloWorldApp < Sinatra::Base
get '/' do
erb :index
end
end
end
and this is my Code hierarchy.
It keeps on looking in the directory: Sinatra-Intro/app/views/index.erb
but my views is in the: Sinatra-Intro/views/index.erb
You need to configure your application instance, something like this should work:
require 'rubygems'
require 'sinatra'
module Registration
class HelloWorldApp < Sinatra::Base
configure do
set :public_folder , File.expand_path('../public', __FILE__)
set :views , File.expand_path('../views', __FILE__)
set :root , File.dirname(__FILE__)
set :show_exceptions, development?
# Optional: Load from external file
#YAML.load_file('path/to/config.yml').each do |k, v|
# set(k.to_sym, v)
#end
end
get '/' do
erb :index
end
end
end
Then:
bundle exec rackup
You can change the default location with the view setting. Like this:
set :views, Proc.new { File.join(root, "views") }

How to test if some specific rack middleware is being used?

To be more particular, I'm talking about sentry-raven and sinatra here. I saw examples testing sinatra applications, or middlewares. But I didn't see ones testing if some particular middleware is present. Or should I be testing behavior, not configuration (or how should I call it)?
The important thing (I'd say) is the behaviour, but if you wish to check for middleware there are 2 ways I'd suggest after taking a delve into the Sinatra source (there are possibly much easier/better ways):
The env
In the Sinatra source there's a method that uses the env to check if a middleware is already present:
# Behaves exactly like Rack::CommonLogger with the notable exception that it does nothing,
# if another CommonLogger is already in the middleware chain.
class CommonLogger < Rack::CommonLogger
def call(env)
env['sinatra.commonlogger'] ? #app.call(env) : super
end
You could do the same thing in a route, e.g.
get "/env-keys" do
env.keys.inspect
end
It'll only show you the middleware if it's inserted something in env hash, e.g.
class MyBad
def initialize app, options={}
#app = app
#options = options
end
def call env
#app.call env.merge("mybad" => "I'm sorry!")
end
end
output:
["SERVER_SOFTWARE", "SERVER_NAME", "rack.input", "rack.version", "rack.errors", "rack.multithread", "rack.multiprocess", "rack.run_once", "REQUEST_METHOD", "REQUEST_PATH", "PATH_INFO", "REQUEST_URI", "HTTP_VERSION", "HTTP_HOST", "HTTP_CONNECTION", "HTTP_CACHE_CONTROL", "HTTP_ACCEPT", "HTTP_USER_AGENT", "HTTP_DNT", "HTTP_ACCEPT_ENCODING", "HTTP_ACCEPT_LANGUAGE", "GATEWAY_INTERFACE", "SERVER_PORT", "QUERY_STRING", "SERVER_PROTOCOL", "rack.url_scheme", "SCRIPT_NAME", "REMOTE_ADDR", "async.callback", "async.close", "rack.logger", "mybad", "rack.request.query_string", "rack.request.query_hash", "sinatra.route"]
It's near the end of that list.
The middleware method
There's also a method called middleware in Sinatra::Base:
# Middleware used in this class and all superclasses.
def middleware
if superclass.respond_to?(:middleware)
superclass.middleware + #middleware
else
#middleware
end
end
Call it in the class definition of a modular app and you can get the middlewares in an array:
require 'sinatra/base'
class AnExample < Sinatra::Base
use MyBad
warn "self.middleware = #{self.middleware}"
output:
self.middleware = [[MyBad, [], nil]]
There may be a way to get it from Sinatra::Application, but I haven't looked.
With help from ruby-raven guys, we've got this:
ENV['RACK_ENV'] = 'test'
# the app: start
require 'sinatra'
require 'sentry-raven'
Raven.configure(true) do |config|
config.dsn = '...'
end
use Raven::Rack
get '/' do
'Hello, world!'
end
# the app: end
require 'rspec'
require 'rack/test'
Raven.configure do |config|
logger = ::Logger.new(STDOUT)
logger.level = ::Logger::WARN
config.logger = logger
end
describe 'app' do
include Rack::Test::Methods
def app
#app || Sinatra::Application
end
class TestRavenError < StandardError; end
it 'sends errors to sentry' do
#app = Class.new Sinatra::Application do
get '/' do
raise TestRavenError
end
end
allow(Raven.client).to receive(:send).and_return(true)
begin
get '/'
rescue TestRavenError
end
expect(Raven.client).to have_received(:send)
end
end
Or if raven sending requests is in the way (when tests fail because of raven sending requests, and not because of the underlying error), one can disable them:
Raven.configure(true) do |config|
config.should_send = Proc.new { false }
end
And mock Raven.send_or_skip instead:
...
allow(Raven).to receive(:send_or_skip).and_return(true)
begin
get '/'
rescue TestRavenError
end
expect(Raven).to have_received(:send_or_skip)
...

Modular Sinatra App using Sinatra Reloader?

Hi if I had a 'main' sinatra file with the following code,
require 'sinatra'
require "sinatra/reloader"
class MyApp < Sinatra::Base
configure do
require "./rest/auth.rb"
register Sinatra::Reloader
also_reload '/rest/auth'
end
get '/' do
erb :home
end
end
And I wanted to put my authentication logic inside of /rest/auth.rb, how can I get /rest/auth.rb to reload in development mode? Must I put the configure block and require sinatra/reloader in every one of my controller files? I'd like for my controllers to inherit the settings of my main class. The code inside of auth.rb is as follows:
class MyApp < Sinatra::Base
set(:auth) do |*roles| # <- notice the splat here
condition do
unless logged_in?
session[:success_url] = request.path_info
redirect '/'
end
end
end
def logged_in?
current_user
end
def current_user
if session[:user_id]
u = User.find(:id=>"#{session[:user_id]}")
else
false
end
end
end
I need to restart the server for my changes to take place but I can throw that reload code in auth.rb's configure block though I wouldn't like to. Any ideas?
Try to rewrite like this
require 'sinatra/base'
require "sinatra/reloader"
class MyApp < Sinatra::Base
configure :development do
register Sinatra::Reloader
also_reload './rest/auth'
end
require "./rest/auth.rb"
get '/' do
erb :home
end
end

Sinatra + Rspec2 - Use Sessions/Helpers?

I am trying to test my Sinatra app using Rspec2 but I can't get access to sessions or helper methods in my tests.
spec_helper:
require File.dirname(__FILE__) + "/../myapp.rb"
require 'rubygems'
require 'sinatra'
require 'rack/test'
require 'rspec'
require 'factory_girl'
set :environment, :test
RSpec.configure do |conf|
conf.include Rack::Test::Methods
end
def app
Sinatra::Application
end
app_spec.rb:
require File.dirname(__FILE__) + "/../spec_helper.rb"
describe 'Something' do
it "should do something" do
session["aa"] = "Test"
end
end
This throws an error, can't find session variables. Similarly I can't use helper methods which are defined in my app.
I run my tests using rspec specs/app_spec/app_spec.rb.
What am I doing wrong?
Assuming you've got your specs and spec helper in the /spec dir, then this line should go at the top of your spec:
require_relative "./spec_helper.rb"
I also like to use File.expand_path and File.join as it's more reliable than doing it yourself, e.g.
require File.dirname(__FILE__) + "/../spec_helper.rb"
becomes
require_relative File.expand_path( File.join File.dirname(__FILE__), "/../spec_helper.rb" )
Also, I don't tend to require "sinatra", the app has that. If you're missing bits from sinatra then maybe, but I add things like this instead through rack:
ENV['RACK_ENV'] = 'test'
Finally, if your Sinatra app is using the modular style then you'll have to include it too. I do this at the top of a spec, for example:
describe "The site" do
include Rack::Test::Methods
include MyApp
let(:app) { MyApp.app }
YMMV. Let us know if any of this works.
A different test to try:
before(:all) { get "/" }
subject { last_response }
it { should be_ok }

Sinatra tests always 404'ing

I have a very simple Sinatra app which I'm having trouble testing.
Basically, every single request test returns a 404 when I know from testing in the browser that the request works fine. Any ideas as to what the problem might be?
test_helper.rb:
ENV["RACK_ENV"] = 'test'
$: << File.expand_path(File.dirname(__FILE__) + '/../lib')
require 'app'
Sinatra::Synchrony.patch_tests!
class Test::Unit::TestCase
include Rack::Test::Methods
end
app_test.rb
require 'test_helper'
class AppTest < Test::Unit::TestCase
def app
#app ||= Sinatra::Application
end
def test_it_says_hello
get "/"
assert_equal 200, last_response.status
end
end
app.rb
$: << 'config'
require "rubygems" require "bundler"
ENV["RACK_ENV"] ||= "development"
Bundler.require(:default, ENV["RACK_ENV"].to_sym)
require ENV["RACK_ENV"]
class App < Sinatra::Base register Sinatra::Synchrony
get '/' do
status 200
'hello, I\'m bat shit crazy and ready to rock'
end
end
Gemfile
source :rubygems
gem 'daemons'
gem 'sinatra'
gem 'sinatra-synchrony', :require => 'sinatra/synchrony'
gem 'resque'
gem 'thin'
group :test do
gem 'rack-test', :require => "rack/test"
gem 'test-unit', :require => "test/unit"
end
Why can I not get this normally very simple thing working?
I had quite the same problem with only HTTP-404 coming in return.
I solved it with giving another return in the "app" function.
class IndexClassTest < Test::Unit::TestCase
def app
#app = Foxydeal #appname NOT Sinatra::Application
end
...
Also
Sinatra::Synchrony.patch_tests!
seems to be obsolete.
Under your app_test.rb do this instead of what you have now:
def app
#app ||= App.new
end
This will work with your your class style like you had it in the beginning, no need to switch to the non-class/modular style.
It may seem logical, but are your routes configured correctly? If a route isn't correctly configured, it'll throw 404 errors left and right.
Figured it out.
app.rb
$: << 'config'
require "rubygems" require "bundler"
ENV["RACK_ENV"] ||= "development" Bundler.require(:default,
ENV["RACK_ENV"].to_sym) require ENV["RACK_ENV"]
class App < Sinatra::Base
register Sinatra::Synchrony
end
get '/' do
status 200
'hello, I\'m bat shit crazy and ready to rock'
end
You may simply do this:
class AppTest < Test::Unit::TestCase
def app
Sinatra::Application
end
You can get a solid understanding of sinatra tests by reading Learning From the Masters: Sinatra Internals and Rack::Test

Resources