diff --git a/README.rdoc b/README.rdoc index 761bd170..7c9f1e1e 100644 --- a/README.rdoc +++ b/README.rdoc @@ -90,19 +90,6 @@ Macros to test the most common controller patterns... end end -Test entire controllers in a few lines... - - class PostsControllerTest < Test::Unit::TestCase - should_be_restful do |resource| - resource.parent = :user - - resource.create.params = { :title => "first post", :body => 'blah blah blah'} - resource.update.params = { :title => "changed" } - end - end - -should_be_restful generates 40 tests on the fly, for both html and xml requests. - === Helpful Assertions (ThoughtBot::Shoulda::Assertions) More to come here, but have fun with what's there. diff --git a/lib/shoulda/controller/macros.rb b/lib/shoulda/controller/macros.rb index 2df5121d..1dd77155 100644 --- a/lib/shoulda/controller/macros.rb +++ b/lib/shoulda/controller/macros.rb @@ -22,53 +22,7 @@ module ThoughtBot # :nodoc: # end # # Would produce 5 tests for the +show+ action - # - # Furthermore, the should_be_restful helper will create an entire set of tests which will verify that your - # controller responds restfully to a variety of requested formats. module Macros - # :section: should_be_restful - # Generates a full suite of tests for a restful controller. - # - # The following definition will generate tests for the +index+, +show+, +new+, - # +edit+, +create+, +update+ and +destroy+ actions, in both +html+ and +xml+ formats: - # - # should_be_restful do |resource| - # resource.parent = :user - # - # resource.create.params = { :title => "first post", :body => 'blah blah blah'} - # resource.update.params = { :title => "changed" } - # end - # - # This generates about 40 tests, all of the format: - # "on GET to :show should assign @user." - # "on GET to :show should not set the flash." - # "on GET to :show should render 'show' template." - # "on GET to :show should respond with success." - # "on GET to :show as xml should assign @user." - # "on GET to :show as xml should have ContentType set to 'application/xml'." - # "on GET to :show as xml should respond with success." - # "on GET to :show as xml should return as the root element." - # The +resource+ parameter passed into the block is a ResourceOptions object, and - # is used to configure the tests for the details of your resources. - # - def should_be_restful(&blk) # :yields: resource - resource = ResourceOptions.new - blk.call(resource) - resource.normalize!(self) - - resource.formats.each do |format| - resource.actions.each do |action| - if self.respond_to? :"make_#{action}_#{format}_tests" - self.send(:"make_#{action}_#{format}_tests", resource) - else - should "test #{action} #{format}" do - flunk "Test for #{action} as #{format} not implemented" - end - end - end - end - end - # :section: Test macros # Macro that creates a test asserting that the flash contains the given value. # val can be a String, a Regex, or nil (indicating that the flash should not be set) diff --git a/lib/shoulda/controller/resource_options.rb b/lib/shoulda/controller/resource_options.rb index e094f3a8..ee935a33 100644 --- a/lib/shoulda/controller/resource_options.rb +++ b/lib/shoulda/controller/resource_options.rb @@ -1,234 +1,10 @@ module ThoughtBot # :nodoc: module Shoulda # :nodoc: module Controller - # Formats tested by #should_be_restful. Defaults to [:html, :xml] VALID_FORMATS = Dir.glob(File.join(File.dirname(__FILE__), 'formats', '*.rb')).map { |f| File.basename(f, '.rb') }.map(&:to_sym) # :doc: VALID_FORMATS.each {|f| require "shoulda/controller/formats/#{f}"} - # Actions tested by #should_be_restful VALID_ACTIONS = [:index, :show, :new, :edit, :create, :update, :destroy] # :doc: - - # A ResourceOptions object is passed into should_be_restful in order to configure the tests for your controller. - # - # Example: - # class UsersControllerTest < Test::Unit::TestCase - # fixtures :all - # - # def setup - # ...normal setup code... - # @user = User.find(:first) - # end - # - # should_be_restful do |resource| - # resource.identifier = :id - # resource.klass = User - # resource.object = :user - # resource.parent = [] - # resource.actions = [:index, :show, :new, :edit, :update, :create, :destroy] - # resource.formats = [:html, :xml] - # - # resource.create.params = { :name => "bob", :email => 'bob@bob.com', :age => 13} - # resource.update.params = { :name => "sue" } - # - # resource.create.redirect = "user_url(@user)" - # resource.update.redirect = "user_url(@user)" - # resource.destroy.redirect = "users_url" - # - # resource.create.flash = /created/i - # resource.update.flash = /updated/i - # resource.destroy.flash = /removed/i - # end - # end - # - # Whenever possible, the resource attributes will be set to sensible defaults. - # - class ResourceOptions - # Configuration options for the create, update, destroy actions under should_be_restful - class ActionOptions - # String evaled to get the target of the redirection. - # All of the instance variables set by the controller will be available to the - # evaled code. - # - # Example: - # resource.create.redirect = "user_url(@user.company, @user)" - # - # Defaults to a generated url based on the name of the controller, the action, and the resource.parents list. - attr_accessor :redirect - - # String or Regexp describing a value expected in the flash. Will match against any flash key. - # - # Defaults: - # destroy:: /removed/ - # create:: /created/ - # update:: /updated/ - attr_accessor :flash - - # Hash describing the params that should be sent in with this action. - attr_accessor :params - end - - # Configuration options for the denied actions under should_be_restful - # - # Example: - # context "The public" do - # setup do - # @request.session[:logged_in] = false - # end - # - # should_be_restful do |resource| - # resource.parent = :user - # - # resource.denied.actions = [:index, :show, :edit, :new, :create, :update, :destroy] - # resource.denied.flash = /get outta here/i - # resource.denied.redirect = 'new_session_url' - # end - # end - # - class DeniedOptions - # String evaled to get the target of the redirection. - # All of the instance variables set by the controller will be available to the - # evaled code. - # - # Example: - # resource.create.redirect = "user_url(@user.company, @user)" - attr_accessor :redirect - - # String or Regexp describing a value expected in the flash. Will match against any flash key. - # - # Example: - # resource.create.flash = /created/ - attr_accessor :flash - - # Actions that should be denied (only used by resource.denied). Note that these actions will - # only be tested if they are also listed in +resource.actions+ - # The special value of :all will deny all of the REST actions. - attr_accessor :actions - end - - # Name of key in params that references the primary key. - # Will almost always be :id (default), unless you are using a plugin or have patched rails. - attr_accessor :identifier - - # Name of the ActiveRecord class this resource is responsible for. Automatically determined from - # test class if not explicitly set. UserTest => "User" - attr_accessor :klass - - # Name of the instantiated ActiveRecord object that should be used by some of the tests. - # Defaults to the underscored name of the AR class. CompanyManager => :company_manager - attr_accessor :object - - # Name of the parent AR objects. Can be set as parent= or parents=, and can take either - # the name of the parent resource (if there's only one), or an array of names (if there's - # more than one). - # - # Example: - # # in the routes... - # map.resources :companies do - # map.resources :people do - # map.resources :limbs - # end - # end - # - # # in the tests... - # class PeopleControllerTest < Test::Unit::TestCase - # should_be_restful do |resource| - # resource.parent = :companies - # end - # end - # - # class LimbsControllerTest < Test::Unit::TestCase - # should_be_restful do |resource| - # resource.parents = [:companies, :people] - # end - # end - attr_accessor :parent - alias parents parent - alias parents= parent= - - # Actions that should be tested. Must be a subset of VALID_ACTIONS (default). - # Tests for each actionw will only be generated if the action is listed here. - # The special value of :all will test all of the REST actions. - # - # Example (for a read-only controller): - # resource.actions = [:show, :index] - attr_accessor :actions - - # Formats that should be tested. Must be a subset of VALID_FORMATS (default). - # Each action will be tested against the formats listed here. The special value - # of :all will test all of the supported formats. - # - # Example: - # resource.actions = [:html, :xml] - attr_accessor :formats - - # ActionOptions object specifying options for the create action. - attr_accessor :create - - # ActionOptions object specifying options for the update action. - attr_accessor :update - - # ActionOptions object specifying options for the desrtoy action. - attr_accessor :destroy - - # DeniedOptions object specifying which actions should return deny a request, and what should happen in that case. - attr_accessor :denied - - def initialize # :nodoc: - @create = ActionOptions.new - @update = ActionOptions.new - @destroy = ActionOptions.new - @denied = DeniedOptions.new - - @create.flash ||= /created/i - @update.flash ||= /updated/i - @destroy.flash ||= /removed/i - @denied.flash ||= /denied/i - - @create.params ||= {} - @update.params ||= {} - - @actions = VALID_ACTIONS - @formats = VALID_FORMATS - @denied.actions = [] - end - - def normalize!(target) # :nodoc: - @denied.actions = VALID_ACTIONS if @denied.actions == :all - @actions = VALID_ACTIONS if @actions == :all - @formats = VALID_FORMATS if @formats == :all - - @denied.actions = @denied.actions.map(&:to_sym) - @actions = @actions.map(&:to_sym) - @formats = @formats.map(&:to_sym) - - ensure_valid_members(@actions, VALID_ACTIONS, 'actions') - ensure_valid_members(@denied.actions, VALID_ACTIONS, 'denied.actions') - ensure_valid_members(@formats, VALID_FORMATS, 'formats') - - @identifier ||= :id - @klass ||= target.name.gsub(/ControllerTest$/, '').singularize.constantize - @object ||= @klass.name.tableize.singularize - @parent ||= [] - @parent = [@parent] unless @parent.is_a? Array - - collection_helper = [@parent, @object.to_s.pluralize, 'url'].flatten.join('_') - collection_args = @parent.map {|n| "@#{object}.#{n}"}.join(', ') - @destroy.redirect ||= "#{collection_helper}(#{collection_args})" - - member_helper = [@parent, @object, 'url'].flatten.join('_') - member_args = [@parent.map {|n| "@#{object}.#{n}"}, "@#{object}"].flatten.join(', ') - @create.redirect ||= "#{member_helper}(#{member_args})" - @update.redirect ||= "#{member_helper}(#{member_args})" - @denied.redirect ||= "new_session_url" - end - - private - - def ensure_valid_members(ary, valid_members, name) # :nodoc: - invalid = ary - valid_members - raise ArgumentError, "Unsupported #{name}: #{invalid.inspect}" unless invalid.empty? - end - end end end end diff --git a/test/functional/posts_controller_test.rb b/test/functional/posts_controller_test.rb index 9e34b031..1cf0f282 100644 --- a/test/functional/posts_controller_test.rb +++ b/test/functional/posts_controller_test.rb @@ -33,32 +33,11 @@ class PostsControllerTest < Test::Unit::TestCase should_route :get, '/users/5/posts/new', :action => :new, :user_id => 5 should_route :put, '/users/5/posts/1', :action => :update, :id => 1, :user_id => 5 - context "The public" do - setup do - @request.session[:logged_in] = false - end - - should_be_restful do |resource| - resource.parent = :user - - resource.denied.actions = [:index, :show, :edit, :new, :create, :update, :destroy] - resource.denied.flash = /what/i - resource.denied.redirect = '"/"' - end - end - context "Logged in" do setup do @request.session[:logged_in] = true end - should_be_restful do |resource| - resource.parent = :user - - resource.create.params = { :title => "first post", :body => 'blah blah blah'} - resource.update.params = { :title => "changed" } - end - context "viewing posts for a user" do setup do get :index, :user_id => users(:first) diff --git a/test/functional/users_controller_test.rb b/test/functional/users_controller_test.rb index b34bd284..d162c1e0 100644 --- a/test/functional/users_controller_test.rb +++ b/test/functional/users_controller_test.rb @@ -14,23 +14,21 @@ class UsersControllerTest < Test::Unit::TestCase @user = User.find(:first) end - should_be_restful do |resource| - resource.identifier = :id - resource.klass = User - resource.object = :user - resource.parent = [] - resource.actions = [:index, :show, :new, :edit, :update, :create, :destroy] - resource.formats = [:html, :xml] + context "on GET to #index" do + setup { get :index } - resource.create.params = { :name => "bob", :email => 'bob@bob.com', :age => 13, :ssn => "123456789"} - resource.update.params = { :name => "sue" } - - resource.create.redirect = "user_url(@user)" - resource.update.redirect = "user_url(@user)" - resource.destroy.redirect = "users_url" - - resource.create.flash = /created/i - resource.update.flash = /updated/i - resource.destroy.flash = /removed/i + should_respond_with :success + should_render_with_layout 'users' + should_render_template :index + should_assign_to :users end + + context "on GET to #index.xml" do + setup { get :index, :format => 'xml' } + + should_respond_with :success + should_respond_with_xml_for + should_assign_to :users + end + end