Skip to content

Commit

Permalink
Add failing scenarii
Browse files Browse the repository at this point in the history
  • Loading branch information
gonzalo-bulnes committed May 17, 2014
1 parent 9634b21 commit 94f9edd
Show file tree
Hide file tree
Showing 2 changed files with 285 additions and 5 deletions.
203 changes: 203 additions & 0 deletions features/option_fallback_to_devise_is_configurable.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
# See https://github.com/gonzalo-bulnes/simple_token_authentication/pull/#61
Feature: The `acts_as_token_authentication_handler` filter has a fallback_to_devise option
As a developer
In order to build safe API authentication by token
And to keep being able to use token authentication in non-API scnearii
I want the fallback_to_devise option to be available at a controller level

@rspec
Scenario: Fallback to Devise is enabled by default
Given I have a dummy app with a Devise-enabled User
And a scaffolded PrivatePost
And I prepare the test database
And the `authenticate_user!` and `sign_in` methods always raise an exception
And User `acts_as_token_authenticatable`
And PrivatePostsController `acts_as_token_authentication_handler_for` User
And I write to "spec/factories/users.rb" with:
"""
FactoryGirl.define do
sequence :email do |n|
"user#{n}@factory.com"
end
factory :user do
email
password "password"
password_confirmation "password"
end
end
"""
And I write to "spec/requests/private_posts_controller_spec.rb" with:
"""
require 'spec_helper'
describe "PrivatePostsController" do
describe "GET /private_posts" do
context "when the required headers are missing in the request (and no query params are used)" do
it "does fallback to Devise authentication" do
user = FactoryGirl.create(:user \
,email: 'alice@example.com' \
,authentication_token: 'ExaMpLeTokEn' )
# `sign_in` is configured to raise an exception when called,
# see spec/dummy/app/controllers/application_controller.rb
lambda do
# see https://github.com/rspec/rspec-rails/issues/65
# and http://guides.rubyonrails.org/testing.html#helpers-available-for-integration-tests
request_via_redirect 'GET', private_posts_path, nil, { 'X-User-Email' => user.email }
end.should raise_exception(RuntimeError, "`authenticate_user!` was called.")
end
end
end
end
"""

And I silence the PrivatePostsController spec errors

When I run `rspec --format documentation`
Then the exit status should be 0
And the output should match:
"""
PrivatePostsController
GET /private_posts
"""
And the output should contain:
"""
when the required headers are missing in the request (and no query params are used)
does fallback to Devise authentication
"""

@rspec
Scenario: Fallback to Devise can be disabled for a specific controller
Given I have a dummy app with a Devise-enabled User
And a scaffolded PrivatePost
And a scaffolded ApiPrivatePost
And I prepare the test database
And the `authenticate_user!` and `sign_in` methods always raise an exception
And User `acts_as_token_authenticatable`
And PrivatePostsController `acts_as_token_authentication_handler_for` User with options:
"""
fallback_to_devise: true
"""
And ApiPrivatePostsController `acts_as_token_authentication_handler_for` User with options:
"""
fallback_to_devise: false
"""
And I write to "spec/factories/users.rb" with:
"""
FactoryGirl.define do
sequence :email do |n|
"user#{n}@factory.com"
end
factory :user do
email
password "password"
password_confirmation "password"
end
end
"""
And I write to "spec/requests/private_posts_controller_spec.rb" with:
"""
require 'spec_helper'
describe "PrivatePostsController" do
describe "GET /private_posts" do
context "when the required headers are missing in the request (and no query params are used)" do
it "does fallback to Devise authentication" do
user = FactoryGirl.create(:user \
,email: 'alice@example.com' \
,authentication_token: 'ExaMpLeTokEn' )
# `sign_in` is configured to raise an exception when called,
# see spec/dummy/app/controllers/application_controller.rb
lambda do
# see https://github.com/rspec/rspec-rails/issues/65
# and http://guides.rubyonrails.org/testing.html#helpers-available-for-integration-tests
request_via_redirect 'GET', private_posts_path, nil, { 'X-User-Email' => user.email }
end.should raise_exception(RuntimeError, "`authenticate_user!` was called.")
end
end
end
end
"""
And I write to "spec/requests/api_private_posts_controller_spec.rb" with:
"""
require 'spec_helper'
describe "ApiPrivatePostsController" do
describe "GET /api_private_posts" do
context "when the required headers are set in the request" do
it "performs token authentication as usual" do
user = FactoryGirl.create(:user \
,email: 'alice@example.com' \
,authentication_token: 'ExaMpLeTokEn' )
# `sign_in` is configured to raise an exception when called,
# see spec/dummy/app/controllers/application_controller.rb
lambda do
# see https://github.com/rspec/rspec-rails/issues/65
# and http://guides.rubyonrails.org/testing.html#helpers-available-for-integration-tests
request_via_redirect 'GET', api_private_posts_path, nil, { 'X-User-Email' => user.email, 'X-User-Token' => user.authentication_token }
end.should raise_exception(RuntimeError, "`sign_in` was called.")
end
end
context "when the required headers are missing in the request (and no query params are used)" do
it "does not fallback to Devise authentication" do
user = FactoryGirl.create(:user \
,email: 'alice@example.com' \
,authentication_token: 'ExaMpLeTokEn' )
# `sign_in` is configured to raise an exception when called,
# see spec/dummy/app/controllers/application_controller.rb
lambda do
# see https://github.com/rspec/rspec-rails/issues/65
# and http://guides.rubyonrails.org/testing.html#helpers-available-for-integration-tests
request_via_redirect 'GET', api_private_posts_path, nil, { 'X-User-Email' => user.email }
end.should_not raise_exception(RuntimeError, "`authenticate_user!` was called.")
end
end
end
end
"""

And I silence the PrivatePostsController spec errors

When I run `rspec --format documentation`
Then the exit status should be 0
And the output should contain:
"""
PrivatePostsController
GET /private_posts
"""
And the output should contain:
"""
when the required headers are missing in the request (and no query params are used)
does fallback to Devise authentication
"""
And the output should contain:
"""
ApiPrivatePostsController
GET /api_private_posts
"""
And the output should contain:
"""
when the required headers are set in the request
performs token authentication as usual
"""
And the output should contain:
"""
when the required headers are missing in the request (and no query params are used)
does not fallback to Devise authentication
"""
87 changes: 82 additions & 5 deletions features/step_definitions/dummy_app_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,83 @@ def private_post_params
}
end

Given /^(\w+) `acts_as_token_authentication_handler_for` (\w+) with options:$/ do |controller, model, options|
# Caution: model should be a singular camel-cased name but could be pluralized or underscored.
# Caution: controller must be a camel cased name: e.g. CamelCasedController

controller_back = controller
controller = controller.gsub(/Controller/, '').singularize

steps %Q{
And I overwrite "app/controllers/#{controller_back.underscore}.rb" with:
"""
class #{controller_back} < ApplicationController
# Please do notice that this controller DOES call `acts_as_authentication_handler` with options.
# See test/dummy/spec/requests/posts_specs.rb
acts_as_token_authentication_handler_for #{model.singularize.camelize}, #{options}
before_action :set_#{controller.underscore}, only: [:show, :edit, :update, :destroy]
# GET /#{controller.underscore}
def index
@#{controller.pluralize.underscore} = #{controller}.all
end
# GET /#{controller.underscore}/1
def show
end
# GET /#{controller.underscore}/new
def new
@#{controller.underscore} = #{controller}.new
end
# GET /#{controller.underscore}/1/edit
def edit
end
# POST /#{controller.underscore}
def create
@#{controller.underscore} = #{controller}.new(#{controller.underscore}_params)
if @#{controller.underscore}.save
redirect_to @#{controller.underscore}, notice: '#{controller} was successfully created.'
else
render action: 'new'
end
end
# PATCH/PUT /#{controller.underscore}/1
def update
if @#{controller.underscore}.update(#{controller.underscore}_params)
redirect_to @#{controller.underscore}, notice: '#{controller} was successfully updated.'
else
render action: 'edit'
end
end
# DELETE /#{controller.underscore}/1
def destroy
@#{controller.underscore}.destroy
redirect_to #{controller.pluralize.underscore}_url, notice: '#{controller} was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_#{controller.underscore}
@#{controller.underscore} = #{controller}.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def #{controller.underscore}_params
params.require(:#{controller.underscore}).permit(:title, :body)
end
end
"""
}
end

Given /^PrivatePostsController `acts_as_token_authentication_handler_for` (\w+)$/ do |model|
# Caution: model should be a singular camel-cased name but could be pluralized or underscored.

Expand Down Expand Up @@ -380,28 +457,28 @@ def private_post_params
}
end

Given /^I silence the PrivatePostsController spec errors$/ do
Given /^I silence the (\w+) spec errors$/ do |controller|
puts """
Errors should never pass silently.
Unless explicitly silenced.
-- PEP 20, The Zen of Python
"""

steps %Q{
And I overwrite "spec/controllers/private_posts_controller_spec.rb" with:
And I overwrite "spec/controllers/#{controller.underscore}_spec.rb" with:
"""
require 'spec_helper'
describe PrivatePostsController do
describe #{controller} do
# This should return the minimal set of attributes required to create a valid
# PrivatePost. As you add validations to PrivatePost, be sure to
# #{controller}. As you add validations to #{controller}, be sure to
# adjust the attributes here as well.
let(:valid_attributes) { { "title" => "MyString" } }
# This should return the minimal set of values that should be in the session
# in order to pass any filters (e.g. authentication) defined in
# PrivatePostsController. Be sure to keep this updated too.
# #{controller}. Be sure to keep this updated too.
let(:valid_session) { {} }
describe "actions" do
Expand Down

0 comments on commit 94f9edd

Please sign in to comment.