Added Rspec and Webrat plugins and started porting Selenium on Rails tests to Rspec Plain Text Stories driving Webrat driving Selenium.

This commit is contained in:
Luke Melia 2008-06-18 02:57:57 -04:00
parent 0600756bbf
commit 0f7d6f7a1d
602 changed files with 47788 additions and 29 deletions

View file

@ -0,0 +1,34 @@
require 'singleton'
require 'selenium'
class SeleniumDriverManager
include Singleton
def running_selenium_driver
start
driver
end
def start
return if running?
driver.start
@running = true
end
def stop
return unless running?
driver.stop
@running = false
end
def running?
@running
end
protected
def driver
@driver ||= Selenium::SeleniumDriver.new("localhost", 4444, "*chrome", "http://localhost", 15000)
end
end

4
script/spec Executable file
View file

@ -0,0 +1,4 @@
#!/usr/bin/env ruby
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../vendor/plugins/rspec/lib"))
require 'spec'
exit ::Spec::Runner::CommandLine.run(::Spec::Runner::OptionParser.parse(ARGV, STDERR, STDOUT))

116
script/spec_server Executable file
View file

@ -0,0 +1,116 @@
#!/usr/bin/env ruby
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../vendor/plugins/rspec/lib' # For rspec installed as plugin
require 'rubygems'
require 'drb/drb'
require 'rbconfig'
require 'spec'
require 'optparse'
# This is based on Florian Weber's TDDMate
module Spec
module Runner
class RailsSpecServer
def run(argv, stderr, stdout)
$stdout = stdout
$stderr = stderr
base = ActiveRecord::Base
def base.clear_reloadable_connections!
active_connections.each do |name, conn|
if conn.requires_reloading?
conn.disconnect!
active_connections.delete(name)
end
end
end
if ActionController.const_defined?(:Dispatcher)
dispatcher = ::ActionController::Dispatcher.new($stdout)
dispatcher.cleanup_application
elsif ::Dispatcher.respond_to?(:reset_application!)
::Dispatcher.reset_application!
else
raise "Application reloading failed"
end
if Object.const_defined?(:Fixtures) && Fixtures.respond_to?(:reset_cache)
Fixtures.reset_cache
end
::Dependencies.mechanism = :load
require_dependency('application.rb') unless Object.const_defined?(:ApplicationController)
load File.dirname(__FILE__) + '/../spec/spec_helper.rb'
if in_memory_database?
load "#{RAILS_ROOT}/db/schema.rb" # use db agnostic schema by default
ActiveRecord::Migrator.up('db/migrate') # use migrations
end
::Spec::Runner::CommandLine.run(
::Spec::Runner::OptionParser.parse(
argv,
$stderr,
$stdout
)
)
end
def in_memory_database?
ENV["RAILS_ENV"] == "test" and
::ActiveRecord::Base.connection.class.to_s == "ActiveRecord::ConnectionAdapters::SQLite3Adapter" and
::Rails::Configuration.new.database_configuration['test']['database'] == ':memory:'
end
end
end
end
puts "Loading Rails environment"
ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'dispatcher'
def restart_test_server
puts "restarting"
config = ::Config::CONFIG
ruby = File::join(config['bindir'], config['ruby_install_name']) + config['EXEEXT']
command_line = [ruby, $0, ARGV].flatten.join(' ')
exec(command_line)
end
def daemonize(pid_file = nil)
return yield if $DEBUG
pid = Process.fork{
Process.setsid
Dir.chdir(RAILS_ROOT)
trap("SIGINT"){ exit! 0 }
trap("SIGTERM"){ exit! 0 }
trap("SIGHUP"){ restart_test_server }
File.open("/dev/null"){|f|
STDERR.reopen f
STDIN.reopen f
STDOUT.reopen f
}
yield
}
puts "spec_server launched. (PID: %d)" % pid
File.open(pid_file,"w"){|f| f.puts pid } if pid_file
exit! 0
end
options = Hash.new
opts = OptionParser.new
opts.on("-d", "--daemon"){|v| options[:daemon] = true }
opts.on("-p", "--pid PIDFILE"){|v| options[:pid] = v }
opts.parse!(ARGV)
puts "Ready"
exec_server = lambda {
trap("USR2") { restart_test_server } if Signal.list.has_key?("USR2")
DRb.start_service("druby://127.0.0.1:8989", Spec::Runner::RailsSpecServer.new)
DRb.thread.join
}
if options[:daemon]
daemonize(options[:pid], &exec_server)
else
exec_server.call
end

77
script/story Executable file
View file

@ -0,0 +1,77 @@
#!/usr/bin/env ruby
require 'rubygems'
class StoryCommand
ROOT_PATH = File.expand_path(File.dirname(__FILE__) + "/..")
STORIES_PATH = "#{ROOT_PATH}/stories"
STEP_MATCHERS_PATH = "#{ROOT_PATH}/stories/steps"
HELPER_PATH = "#{ROOT_PATH}/stories/helper"
DRIVER_MANAGER_PATH = "#{ROOT_PATH}/lib/selenium_driver_manager"
require DRIVER_MANAGER_PATH
def self.run
self.new.run
end
def run
if ARGV.reject { |a| a =~ /^-/ }.any?
run_story_files(ARGV.dup)
else
run_story_files(all_story_files)
end
ensure
SeleniumDriverManager.instance.stop
end
def all_story_files
Dir["#{STORIES_PATH}/**/*.story"].uniq
end
def clean_story_paths(paths)
paths.reject! { |path| path =~ /^-/ }
paths.map! { |path| File.expand_path(path) }
paths.map! { |path| path.gsub(/\.story$/, "") }
paths.map! { |path| path.gsub(/#{STORIES_PATH}\//, "") }
end
def run_story_files(stories)
clean_story_paths(stories).each do |story|
setup_and_run_story(File.readlines("#{STORIES_PATH}/#{story}.story"), story)
end
end
def setup_and_run_story(lines, story_name)
require HELPER_PATH
steps = steps_for_story(lines, story_name)
steps.reject! { |step| !File.exist?("#{STEP_MATCHERS_PATH}/#{step}.rb") }
steps.each { |step| require "#{STEP_MATCHERS_PATH}/#{step}" }
run_story(lines, steps)
end
def steps_for_story(lines, story_name)
if lines.first =~ /^# steps: /
lines.first.gsub(/^# steps: /, "").split(",").map(&:strip)
else
story_name.to_s.split("/")
end
end
def run_story(lines, steps)
tempfile = Tempfile.new("story")
lines.each do |line|
tempfile.puts line
end
tempfile.close
with_steps_for(*steps.map(&:to_sym)) do
run tempfile.path, :type => SeleniumRailsStory
end
end
end
StoryCommand.run

2
spec/rcov.opts Normal file
View file

@ -0,0 +1,2 @@
--exclude "spec/*,gems/*"
--rails

4
spec/spec.opts Normal file
View file

@ -0,0 +1,4 @@
--colour
--format progress
--loadby mtime
--reverse

47
spec/spec_helper.rb Normal file
View file

@ -0,0 +1,47 @@
# This file is copied to ~/spec when you run 'ruby script/generate rspec'
# from the project root directory.
ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'spec'
require 'spec/rails'
Spec::Runner.configure do |config|
# If you're not using ActiveRecord you should remove these
# lines, delete config/database.yml and disable :active_record
# in your config/boot.rb
config.use_transactional_fixtures = true
config.use_instantiated_fixtures = false
config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
# == Fixtures
#
# You can declare fixtures for each example_group like this:
# describe "...." do
# fixtures :table_a, :table_b
#
# Alternatively, if you prefer to declare them only once, you can
# do so right here. Just uncomment the next line and replace the fixture
# names with your fixtures.
#
# config.global_fixtures = :table_a, :table_b
#
# If you declare global fixtures, be aware that they will be declared
# for all of your examples, even those that don't use them.
#
# You can also declare which fixtures to use (for example fixtures for test/fixtures):
#
# config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
#
# == Mock Framework
#
# RSpec uses it's own mocking framework by default. If you prefer to
# use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
#
# == Notes
#
# For more information take a look at Spec::Example::Configuration and Spec::Runner
end

115
stories/helper.rb Normal file
View file

@ -0,0 +1,115 @@
ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
$:.unshift File.join(File.dirname(__FILE__), *%w[.. vendor plugings rspec lib])
require 'test_help'
require 'test/unit/testresult'
require 'spec'
require 'spec/rails'
require 'spec/story'
require 'webrat/selenium'
module Spec
module Story
class StepGroup
def include_steps_for(name)
require File.expand_path(File.dirname(__FILE__) + "/steps/#{name}")
step_matchers = rspec_story_steps[name.to_sym]
warn "WARNING: 0 step matchers found for include_steps_for(:#{name}). Are you missing an include?" if step_matchers.empty?
self << step_matchers
end
end
end
end
Test::Unit.run = true
class SeleniumRailsStory < Test::Unit::TestCase
include Spec::Matchers
include Spec::Rails::Matchers
def initialize #:nodoc:
# TODO - eliminate this hack, which is here to stop
# Rails Stories from dumping the example summary.
Spec::Runner::Options.class_eval do
def examples_should_be_run?
false
end
end
@_result = Test::Unit::TestResult.new
end
def should_see(text_or_regexp)
if text_or_regexp.is_a?(Regexp)
response.should have_tag("*", text_or_regexp)
else
response.should have_tag("*", /#{Regexp.escape(text_or_regexp)}/i)
end
end
def response
webrat_session.response_body
end
def method_missing(name, *args)
if webrat_session.respond_to?(name)
webrat_session.send(name, *args)
else
super
end
end
protected
def webrat_session
@webrat_session ||= begin
Webrat::SeleniumSession.new(SeleniumDriverManager.instance.running_selenium_driver)
end
end
end
class DatabaseResetListener
include Singleton
def scenario_started(*args)
if defined?(ActiveRecord::Base)
connection = ActiveRecord::Base.connection
%w[users].each do |table|
connection.execute "DELETE FROM #{table}"
end
end
end
def scenario_succeeded(*args)
end
alias :scenario_pending :scenario_succeeded
alias :scenario_failed :scenario_succeeded
end
class CookieResetListener
include Singleton
def scenario_started(*args)
%w[tracks_login auth_token _session_id].each do |cookie_name|
SeleniumDriverManager.instance.running_selenium_driver.get_eval("window.document.cookie = '#{cookie_name}=;expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/';")
end
end
def scenario_succeeded(*args)
end
alias :scenario_pending :scenario_succeeded
alias :scenario_failed :scenario_succeeded
end
class Spec::Story::Runner::ScenarioRunner
def initialize
@listeners = [DatabaseResetListener.instance, CookieResetListener.instance]
end
end
class Spec::Story::GivenScenario
def perform(instance, name = nil)
scenario = Spec::Story::Runner::StoryRunner.scenario_from_current_story @name
runner = Spec::Story::Runner::ScenarioRunner.new
runner.instance_variable_set(:@listeners,[])
runner.run(scenario, instance)
end
end

View file

@ -0,0 +1,15 @@
Story: First run shows admin signup
As a user who just installed Tracks
I want to create an admin account
So that I have control over all preferences and users
Scenario: Successful signup
Given no users exist
And a visitor named Reinier
When Reinier visits the site
Then he should see a signup form
When Reinier successfully submits the signup form
Then Reinier should see the tasks listing page
And Reinier should be an admin

View file

@ -0,0 +1,22 @@
Story: Existing user logging in
As an existing user
I want to log in with my username and password
So that I can securely get things done
Scenario: Login success
Given an admin user Reinier with the password abracadabra
And Reinier is not logged in
When Reinier visits the login page
And Reinier successfully submits the login form
Then Reinier should see the tasks listing page
And Reinier should see the message Login successful
Scenario: Login failure
Given an admin user Reinier with the password abracadabra
And Reinier is not logged in
When Reinier visits the login page
And Reinier submits the login form with an incorrect password
Then Reinier should see the login page again
And Reinier should see the message Login unsuccessful

68
stories/steps/login.rb Normal file
View file

@ -0,0 +1,68 @@
steps_for :login do
Given "an admin user Reinier with the password abracadabra" do
@reinier = User.create!(:login => 'reinier', :password => 'abracadabra', :password_confirmation => 'abracadabra', :is_admin => true)
@reinier.create_preference
end
Given "Reinier is not logged in" do
end
Given "no users exist" do
User.delete_all
end
Given "a visitor named Reinier" do
end
When "Reinier submits the login form with an incorrect password" do
fills_in 'Login', :with => 'reinier'
fills_in 'Password', :with => 'incorrectpass'
clicks_button
end
When "Reinier visits the login page" do
visits '/login'
end
When "Reinier successfully submits the login form" do
fills_in 'Login', :with => 'reinier'
fills_in 'Password', :with => 'abracadabra'
clicks_button
end
When "Reinier visits the site" do
visits '/'
end
When "Reinier successfully submits the signup form" do
fills_in 'Desired login', :with => 'reinier'
fills_in 'Choose password', :with => 'abracadabra'
fills_in 'Confirm password', :with => 'abracadabra'
clicks_button
end
Then "he should see a signup form" do
should_see 'create an admin account'
end
Then "Reinier should see the tasks listing page" do
response.should have_tag('title', /list tasks/i)
end
Then "Reinier should be an admin" do
response.should have_tag('a', /Admin/i)
end
Then "Reinier should see the message Login successful" do
should_see 'Login successful'
end
Then "Reinier should see the login page again" do
response.should have_tag('title', /login/i)
end
Then "Reinier should see the message Login unsuccessful" do
should_see 'Login unsuccessful'
end
end

View file

@ -1,8 +0,0 @@
setup :clear_tables => [:users, :preferences]
open '/'
assert_title 'exact:TRACKS::Sign up as the admin user'
type "user_login", "admin"
type "user_password", "abracadabra"
type "user_password_confirmation", "abracadabra"
click_and_wait "signup"
assert_title 'exact:TRACKS::List tasks'

View file

@ -1,9 +0,0 @@
setup :fixtures => :all
open :controller => 'login', :action => 'logout'
open :controller => 'login'
assert_title 'exact:TRACKS::Login'
type "user_login", "admin"
type "user_password", "incorrect_password"
click_and_wait "login"
assert_title 'exact:TRACKS::Login'
verify_text_present 'Login unsuccessful'

View file

@ -1,12 +0,0 @@
setup :fixtures => :all
open :controller => 'login', :action => 'logout'
open :controller => 'login'
assert_title 'exact:TRACKS::Login'
type "user_login", "admin"
type "user_password", "abracadabra"
click_and_wait "login"
assert_title 'exact:TRACKS::List tasks'
wait_for_visible "flash"
wait_for_text "flash", "Login successful: session will not expire."
#next line slows down the test unacceptably, but is useful in ensuring that the message disappears.
#wait_for_not_visible "flash"

4
vendor/plugins/rspec-rails/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
tmtags
.DS_Store
.emacs-project
*~

26
vendor/plugins/rspec-rails/CHANGES vendored Normal file
View file

@ -0,0 +1,26 @@
== Version 1.1.5
* Add conditional so Rails 2.1.0 doesn't warn about cache_template_extensions (patch from James Herdman)
* Fixed stub_model examples to work with Rails 2.1.0 (the code was fine, just the spec needed patching)
== Version 1.1.4
Maintenance release.
* Moved mock_model and stub_model to their own module: Spec::Rails::Mocks
* Setting mock_model object id with stubs hash - patch from Adam Meehan
* Added as_new_record to stub_model e.g. stub_model(Foo).as_new_record
* Improved stub_model such that new_record? does "the right thing"
* Patch from Pat Maddox to get integrate_views to work in nested example groups.
* Patch from Pat Maddox to get controller_name to work in nested example groups.
* Patch from Corey Haines to add include_text matcher
* Added stub_model method which creates a real model instance with :id stubbed and data access prohibited.
* Applied patch from Pat Maddox to handle redirect_to w/ SSL. Closes #320.
* Added #helper and #assigns to helper specs.
* Applied patch from Bryan Helmkamp to tweak format of generated spec.opts to be more obvious. Closes #162.
* Tweaked list of exceptions (ignores) for autotest
* Applied patch from Rick Olson to get rspec_on_rails working with rails edge (>= 8862)
* Applied patch from Wincent Colaiuta to invert sense of "spec --diff". Closes #281.
* Allow any type of render in view specs. Closes #57.
* Applied patch from Ian White to get rspec working with edge rails (8804). Closes #271.
* Applied patch from Jon Strother to have spec_server reload fixtures. Closes #344.

31
vendor/plugins/rspec-rails/MIT-LICENSE vendored Normal file
View file

@ -0,0 +1,31 @@
====================================================================
== RSpec
Copyright (c) 2005-2007 The RSpec Development Team
====================================================================
== ARTS
Copyright (c) 2006 Kevin Clark, Jake Howerton
====================================================================
== ZenTest
Copyright (c) 2001-2006 Ryan Davis, Eric Hodel, Zen Spider Software
====================================================================
== AssertSelect
Copyright (c) 2006 Assaf Arkin
====================================================================
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

3
vendor/plugins/rspec-rails/README vendored Normal file
View file

@ -0,0 +1,3 @@
See the rdoc for Spec::Rails for usage documentation.
See ~/rspec/README for instructions on running rspec_on_rails' examples.

9
vendor/plugins/rspec-rails/Rakefile vendored Normal file
View file

@ -0,0 +1,9 @@
require 'rake'
require 'rake/rdoctask'
desc 'Generate RDoc'
rd = Rake::RDocTask.new do |rdoc|
rdoc.rdoc_dir = '../doc/output/rdoc-rails'
rdoc.options << '--title' << 'Spec::Rails' << '--line-numbers' << '--inline-source' << '--main' << 'Spec::Rails'
rdoc.rdoc_files.include('MIT-LICENSE', 'lib/**/*.rb')
end

View file

@ -0,0 +1 @@
Please refer to the CHANGES file for RSpec's core

View file

@ -0,0 +1,35 @@
require 'rbconfig'
# This generator bootstraps a Rails project for use with RSpec
class RspecGenerator < Rails::Generator::Base
DEFAULT_SHEBANG = File.join(Config::CONFIG['bindir'],
Config::CONFIG['ruby_install_name'])
def initialize(runtime_args, runtime_options = {})
super
end
def manifest
record do |m|
script_options = { :chmod => 0755, :shebang => options[:shebang] == DEFAULT_SHEBANG ? nil : options[:shebang] }
m.directory 'spec'
m.template 'spec_helper.rb', 'spec/spec_helper.rb'
m.file 'spec.opts', 'spec/spec.opts'
m.file 'rcov.opts', 'spec/rcov.opts'
m.file 'script/spec_server', 'script/spec_server', script_options
m.file 'script/spec', 'script/spec', script_options
m.directory 'stories'
m.file 'all_stories.rb', 'stories/all.rb'
m.file 'stories_helper.rb', 'stories/helper.rb'
end
end
protected
def banner
"Usage: #{$0} rspec"
end
end

View file

@ -0,0 +1,4 @@
dir = File.dirname(__FILE__)
Dir[File.expand_path("#{dir}/**/*.rb")].uniq.each do |file|
require file
end

View file

@ -0,0 +1,2 @@
--exclude "spec/*,gems/*"
--rails

View file

@ -0,0 +1,4 @@
#!/usr/bin/env ruby
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../vendor/plugins/rspec/lib"))
require 'spec'
exit ::Spec::Runner::CommandLine.run(::Spec::Runner::OptionParser.parse(ARGV, STDERR, STDOUT))

View file

@ -0,0 +1,116 @@
#!/usr/bin/env ruby
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../vendor/plugins/rspec/lib' # For rspec installed as plugin
require 'rubygems'
require 'drb/drb'
require 'rbconfig'
require 'spec'
require 'optparse'
# This is based on Florian Weber's TDDMate
module Spec
module Runner
class RailsSpecServer
def run(argv, stderr, stdout)
$stdout = stdout
$stderr = stderr
base = ActiveRecord::Base
def base.clear_reloadable_connections!
active_connections.each do |name, conn|
if conn.requires_reloading?
conn.disconnect!
active_connections.delete(name)
end
end
end
if ActionController.const_defined?(:Dispatcher)
dispatcher = ::ActionController::Dispatcher.new($stdout)
dispatcher.cleanup_application
elsif ::Dispatcher.respond_to?(:reset_application!)
::Dispatcher.reset_application!
else
raise "Application reloading failed"
end
if Object.const_defined?(:Fixtures) && Fixtures.respond_to?(:reset_cache)
Fixtures.reset_cache
end
::Dependencies.mechanism = :load
require_dependency('application.rb') unless Object.const_defined?(:ApplicationController)
load File.dirname(__FILE__) + '/../spec/spec_helper.rb'
if in_memory_database?
load "#{RAILS_ROOT}/db/schema.rb" # use db agnostic schema by default
ActiveRecord::Migrator.up('db/migrate') # use migrations
end
::Spec::Runner::CommandLine.run(
::Spec::Runner::OptionParser.parse(
argv,
$stderr,
$stdout
)
)
end
def in_memory_database?
ENV["RAILS_ENV"] == "test" and
::ActiveRecord::Base.connection.class.to_s == "ActiveRecord::ConnectionAdapters::SQLite3Adapter" and
::Rails::Configuration.new.database_configuration['test']['database'] == ':memory:'
end
end
end
end
puts "Loading Rails environment"
ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'dispatcher'
def restart_test_server
puts "restarting"
config = ::Config::CONFIG
ruby = File::join(config['bindir'], config['ruby_install_name']) + config['EXEEXT']
command_line = [ruby, $0, ARGV].flatten.join(' ')
exec(command_line)
end
def daemonize(pid_file = nil)
return yield if $DEBUG
pid = Process.fork{
Process.setsid
Dir.chdir(RAILS_ROOT)
trap("SIGINT"){ exit! 0 }
trap("SIGTERM"){ exit! 0 }
trap("SIGHUP"){ restart_test_server }
File.open("/dev/null"){|f|
STDERR.reopen f
STDIN.reopen f
STDOUT.reopen f
}
yield
}
puts "spec_server launched. (PID: %d)" % pid
File.open(pid_file,"w"){|f| f.puts pid } if pid_file
exit! 0
end
options = Hash.new
opts = OptionParser.new
opts.on("-d", "--daemon"){|v| options[:daemon] = true }
opts.on("-p", "--pid PIDFILE"){|v| options[:pid] = v }
opts.parse!(ARGV)
puts "Ready"
exec_server = lambda {
trap("USR2") { restart_test_server } if Signal.list.has_key?("USR2")
DRb.start_service("druby://127.0.0.1:8989", Spec::Runner::RailsSpecServer.new)
DRb.thread.join
}
if options[:daemon]
daemonize(options[:pid], &exec_server)
else
exec_server.call
end

View file

@ -0,0 +1,4 @@
--colour
--format progress
--loadby mtime
--reverse

View file

@ -0,0 +1,47 @@
# This file is copied to ~/spec when you run 'ruby script/generate rspec'
# from the project root directory.
ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'spec'
require 'spec/rails'
Spec::Runner.configure do |config|
# If you're not using ActiveRecord you should remove these
# lines, delete config/database.yml and disable :active_record
# in your config/boot.rb
config.use_transactional_fixtures = true
config.use_instantiated_fixtures = false
config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
# == Fixtures
#
# You can declare fixtures for each example_group like this:
# describe "...." do
# fixtures :table_a, :table_b
#
# Alternatively, if you prefer to declare them only once, you can
# do so right here. Just uncomment the next line and replace the fixture
# names with your fixtures.
#
# config.global_fixtures = :table_a, :table_b
#
# If you declare global fixtures, be aware that they will be declared
# for all of your examples, even those that don't use them.
#
# You can also declare which fixtures to use (for example fixtures for test/fixtures):
#
# config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
#
# == Mock Framework
#
# RSpec uses it's own mocking framework by default. If you prefer to
# use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
#
# == Notes
#
# For more information take a look at Spec::Example::Configuration and Spec::Runner
end

View file

@ -0,0 +1,3 @@
ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'spec/rails/story_adapter'

View file

@ -0,0 +1,33 @@
Description:
The rspec_controller generator creates stub specs and files for a new
controller and its views.
The generator takes a controller name and a list of views as arguments.
The controller name may be given in CamelCase or under_score and should
not be suffixed with 'Controller'. To create a controller within a
module, specify the controller name as 'module/controller'.
The generator creates stubs for a controller (and spec), a view (and spec)
for each view in the argument list, plus a helper.
Example:
./script/generate rspec_controller dog bark fetch
...
create spec/controllers/dog_controller_spec.rb
create app/controllers/dog_controller.rb
create app/helpers/dog_helper.rb
create spec/views/dog/bark_view_spec.rb
create app/views/dog/bark.rhtml
create spec/views/dog/fetch_view_spec.rb
create app/views/dog/fetch.rhtml
Modules Example:
./script/generate rspec_controller 'pets/dog' bark fetch
...
create spec/controllers/pets/dog_controller_spec.rb
create app/controllers/pets/dog_controller.rb
create app/helpers/pets/dog_helper.rb
create spec/views/pets/dog/bark_view_spec.rb
create app/views/pets/dog/bark.rhtml
create spec/views/pets/dog/fetch_view_spec.rb
create app/views/pets/dog/fetch.rhtml

View file

@ -0,0 +1,49 @@
require 'rails_generator/generators/components/controller/controller_generator'
class RspecControllerGenerator < ControllerGenerator
def manifest
record do |m|
# Check for class naming collisions.
m.class_collisions class_path, "#{class_name}Controller", "#{class_name}Helper"
# Controller, helper, views, and spec directories.
m.directory File.join('app/controllers', class_path)
m.directory File.join('app/helpers', class_path)
m.directory File.join('app/views', class_path, file_name)
m.directory File.join('spec/controllers', class_path)
m.directory File.join('spec/helpers', class_path)
m.directory File.join('spec/views', class_path, file_name)
if Rails::VERSION::STRING < "2.0.0"
@default_file_extension = "rhtml"
else
@default_file_extension = "html.erb"
end
# Controller spec, class, and helper.
m.template 'controller_spec.rb',
File.join('spec/controllers', class_path, "#{file_name}_controller_spec.rb")
m.template 'helper_spec.rb',
File.join('spec/helpers', class_path, "#{file_name}_helper_spec.rb")
m.template 'controller:controller.rb',
File.join('app/controllers', class_path, "#{file_name}_controller.rb")
m.template 'controller:helper.rb',
File.join('app/helpers', class_path, "#{file_name}_helper.rb")
# Spec and view template for each action.
actions.each do |action|
m.template 'view_spec.rb',
File.join('spec/views', class_path, file_name, "#{action}.#{@default_file_extension}_spec.rb"),
:assigns => { :action => action, :model => file_name }
path = File.join('app/views', class_path, file_name, "#{action}.#{@default_file_extension}")
m.template "controller:view.#{@default_file_extension}",
path,
:assigns => { :action => action, :path => path }
end
end
end
end

View file

@ -0,0 +1,25 @@
require File.expand_path(File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../spec_helper')
describe <%= class_name %>Controller do
<% if actions.empty? -%>
#Delete this example and add some real ones
<% else -%>
#Delete these examples and add some real ones
<% end -%>
it "should use <%= class_name %>Controller" do
controller.should be_an_instance_of(<%= class_name %>Controller)
end
<% unless actions.empty? -%>
<% for action in actions -%>
describe "GET '<%= action %>'" do
it "should be successful" do
get '<%= action %>'
response.should be_success
end
end
<% end -%>
<% end -%>
end

View file

@ -0,0 +1,11 @@
require File.expand_path(File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../spec_helper')
describe <%= class_name %>Helper do
#Delete this example and add some real ones or delete this file
it "should be included in the object returned by #helper" do
included_modules = (class << helper; self; end).send :included_modules
included_modules.should include(<%= class_name %>Helper)
end
end

View file

@ -0,0 +1,12 @@
require File.expand_path(File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../../spec_helper')
describe "/<%= class_name.underscore %>/<%= action %>" do
before(:each) do
render '<%= class_name.underscore %>/<%= action %>'
end
#Delete this example and add some real ones or delete this file
it "should tell you where to find the file" do
response.should have_tag('p', %r[Find me in app/views/<%= class_name.underscore %>/<%= action %>])
end
end

View file

@ -0,0 +1,18 @@
Description:
The rspec_model generator creates stubs for a new model.
The generator takes a model name as its argument. The model name may be
given in CamelCase or under_score and should not be suffixed with 'Model'.
The generator creates a model class in app/models, an RSpec spec in
spec/models, database fixtures in spec/fixtures/plural_name.yml, and a migration
in db/migrate.
Example:
./script/generate rspec_model Account
This will create an Account model:
Model: app/models/account.rb
Spec: spec/models/account_spec.rb
Fixtures: spec/fixtures/accounts.yml
Migration: db/migrate/XXX_add_accounts.rb

View file

@ -0,0 +1,30 @@
require 'rails_generator/generators/components/model/model_generator'
class RspecModelGenerator < ModelGenerator
def manifest
record do |m|
# Check for class naming collisions.
m.class_collisions class_path, class_name
# Model, spec, and fixture directories.
m.directory File.join('app/models', class_path)
m.directory File.join('spec/models', class_path)
m.directory File.join('spec/fixtures', class_path)
# Model class, spec and fixtures.
m.template 'model:model.rb', File.join('app/models', class_path, "#{file_name}.rb")
m.template 'model:fixtures.yml', File.join('spec/fixtures', class_path, "#{table_name}.yml")
m.template 'model_spec.rb', File.join('spec/models', class_path, "#{file_name}_spec.rb")
unless options[:skip_migration]
m.migration_template 'model:migration.rb', 'db/migrate', :assigns => {
:migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}"
}, :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}"
end
end
end
end

View file

@ -0,0 +1,11 @@
require File.expand_path(File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../spec_helper')
describe <%= class_name %> do
before(:each) do
@<%= file_name %> = <%= class_name %>.new
end
it "should be valid" do
@<%= file_name %>.should be_valid
end
end

View file

@ -0,0 +1,167 @@
class RspecScaffoldGenerator < Rails::Generator::NamedBase
default_options :skip_migration => false
attr_reader :controller_name,
:controller_class_path,
:controller_file_path,
:controller_class_nesting,
:controller_class_nesting_depth,
:controller_class_name,
:controller_singular_name,
:controller_plural_name,
:resource_edit_path,
:default_file_extension
alias_method :controller_file_name, :controller_singular_name
alias_method :controller_table_name, :controller_plural_name
def initialize(runtime_args, runtime_options = {})
super
@controller_name = @name.pluralize
base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name)
@controller_class_name_without_nesting, @controller_singular_name, @controller_plural_name = inflect_names(base_name)
if @controller_class_nesting.empty?
@controller_class_name = @controller_class_name_without_nesting
else
@controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}"
end
if Rails::VERSION::STRING < "2.0.0"
@resource_generator = "scaffold_resource"
@default_file_extension = "rhtml"
else
@resource_generator = "scaffold"
@default_file_extension = "html.erb"
end
if ActionController::Base.respond_to?(:resource_action_separator)
@resource_edit_path = "/edit"
else
@resource_edit_path = ";edit"
end
end
def manifest
record do |m|
# Check for class naming collisions.
m.class_collisions(controller_class_path, "#{controller_class_name}Controller", "#{controller_class_name}Helper")
m.class_collisions(class_path, "#{class_name}")
# Controller, helper, views, and spec directories.
m.directory(File.join('app/models', class_path))
m.directory(File.join('app/controllers', controller_class_path))
m.directory(File.join('app/helpers', controller_class_path))
m.directory(File.join('app/views', controller_class_path, controller_file_name))
m.directory(File.join('spec/controllers', controller_class_path))
m.directory(File.join('spec/models', class_path))
m.directory(File.join('spec/helpers', class_path))
m.directory File.join('spec/fixtures', class_path)
m.directory File.join('spec/views', controller_class_path, controller_file_name)
# Controller spec, class, and helper.
m.template 'rspec_scaffold:routing_spec.rb',
File.join('spec/controllers', controller_class_path, "#{controller_file_name}_routing_spec.rb")
m.template 'rspec_scaffold:controller_spec.rb',
File.join('spec/controllers', controller_class_path, "#{controller_file_name}_controller_spec.rb")
m.template "#{@resource_generator}:controller.rb",
File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb")
m.template 'rspec_scaffold:helper_spec.rb',
File.join('spec/helpers', class_path, "#{controller_file_name}_helper_spec.rb")
m.template "#{@resource_generator}:helper.rb",
File.join('app/helpers', controller_class_path, "#{controller_file_name}_helper.rb")
for action in scaffold_views
m.template(
"#{@resource_generator}:view_#{action}.#{@default_file_extension}",
File.join('app/views', controller_class_path, controller_file_name, "#{action}.#{default_file_extension}")
)
end
# Model class, unit test, and fixtures.
m.template 'model:model.rb', File.join('app/models', class_path, "#{file_name}.rb")
m.template 'model:fixtures.yml', File.join('spec/fixtures', class_path, "#{table_name}.yml")
m.template 'rspec_model:model_spec.rb', File.join('spec/models', class_path, "#{file_name}_spec.rb")
# View specs
m.template "rspec_scaffold:edit_erb_spec.rb",
File.join('spec/views', controller_class_path, controller_file_name, "edit.#{default_file_extension}_spec.rb")
m.template "rspec_scaffold:index_erb_spec.rb",
File.join('spec/views', controller_class_path, controller_file_name, "index.#{default_file_extension}_spec.rb")
m.template "rspec_scaffold:new_erb_spec.rb",
File.join('spec/views', controller_class_path, controller_file_name, "new.#{default_file_extension}_spec.rb")
m.template "rspec_scaffold:show_erb_spec.rb",
File.join('spec/views', controller_class_path, controller_file_name, "show.#{default_file_extension}_spec.rb")
unless options[:skip_migration]
m.migration_template(
'model:migration.rb', 'db/migrate',
:assigns => {
:migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}",
:attributes => attributes
},
:migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}"
)
end
m.route_resources controller_file_name
end
end
protected
# Override with your own usage banner.
def banner
"Usage: #{$0} rspec_scaffold ModelName [field:type field:type]"
end
def add_options!(opt)
opt.separator ''
opt.separator 'Options:'
opt.on("--skip-migration",
"Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
end
def scaffold_views
%w[ index show new edit ]
end
def model_name
class_name.demodulize
end
end
module Rails
module Generator
class GeneratedAttribute
def default_value
@default_value ||= case type
when :int, :integer then "\"1\""
when :float then "\"1.5\""
when :decimal then "\"9.99\""
when :datetime, :timestamp, :time then "Time.now"
when :date then "Date.today"
when :string then "\"MyString\""
when :text then "\"MyText\""
when :boolean then "false"
else
""
end
end
def input_type
@input_type ||= case type
when :text then "textarea"
else
"input"
end
end
end
end
end

View file

@ -0,0 +1,313 @@
require File.expand_path(File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../spec_helper')
describe <%= controller_class_name %>Controller do
describe "handling GET /<%= table_name %>" do
before(:each) do
@<%= file_name %> = mock_model(<%= class_name %>)
<%= class_name %>.stub!(:find).and_return([@<%= file_name %>])
end
def do_get
get :index
end
it "should be successful" do
do_get
response.should be_success
end
it "should render index template" do
do_get
response.should render_template('index')
end
it "should find all <%= table_name %>" do
<%= class_name %>.should_receive(:find).with(:all).and_return([@<%= file_name %>])
do_get
end
it "should assign the found <%= table_name %> for the view" do
do_get
assigns[:<%= table_name %>].should == [@<%= file_name %>]
end
end
describe "handling GET /<%= table_name %>.xml" do
before(:each) do
@<%= file_name.pluralize %> = mock("Array of <%= class_name.pluralize %>", :to_xml => "XML")
<%= class_name %>.stub!(:find).and_return(@<%= file_name.pluralize %>)
end
def do_get
@request.env["HTTP_ACCEPT"] = "application/xml"
get :index
end
it "should be successful" do
do_get
response.should be_success
end
it "should find all <%= table_name %>" do
<%= class_name %>.should_receive(:find).with(:all).and_return(@<%= file_name.pluralize %>)
do_get
end
it "should render the found <%= table_name %> as xml" do
@<%= file_name.pluralize %>.should_receive(:to_xml).and_return("XML")
do_get
response.body.should == "XML"
end
end
describe "handling GET /<%= table_name %>/1" do
before(:each) do
@<%= file_name %> = mock_model(<%= class_name %>)
<%= class_name %>.stub!(:find).and_return(@<%= file_name %>)
end
def do_get
get :show, :id => "1"
end
it "should be successful" do
do_get
response.should be_success
end
it "should render show template" do
do_get
response.should render_template('show')
end
it "should find the <%= file_name %> requested" do
<%= class_name %>.should_receive(:find).with("1").and_return(@<%= file_name %>)
do_get
end
it "should assign the found <%= file_name %> for the view" do
do_get
assigns[:<%= file_name %>].should equal(@<%= file_name %>)
end
end
describe "handling GET /<%= table_name %>/1.xml" do
before(:each) do
@<%= file_name %> = mock_model(<%= class_name %>, :to_xml => "XML")
<%= class_name %>.stub!(:find).and_return(@<%= file_name %>)
end
def do_get
@request.env["HTTP_ACCEPT"] = "application/xml"
get :show, :id => "1"
end
it "should be successful" do
do_get
response.should be_success
end
it "should find the <%= file_name %> requested" do
<%= class_name %>.should_receive(:find).with("1").and_return(@<%= file_name %>)
do_get
end
it "should render the found <%= file_name %> as xml" do
@<%= file_name %>.should_receive(:to_xml).and_return("XML")
do_get
response.body.should == "XML"
end
end
describe "handling GET /<%= table_name %>/new" do
before(:each) do
@<%= file_name %> = mock_model(<%= class_name %>)
<%= class_name %>.stub!(:new).and_return(@<%= file_name %>)
end
def do_get
get :new
end
it "should be successful" do
do_get
response.should be_success
end
it "should render new template" do
do_get
response.should render_template('new')
end
it "should create an new <%= file_name %>" do
<%= class_name %>.should_receive(:new).and_return(@<%= file_name %>)
do_get
end
it "should not save the new <%= file_name %>" do
@<%= file_name %>.should_not_receive(:save)
do_get
end
it "should assign the new <%= file_name %> for the view" do
do_get
assigns[:<%= file_name %>].should equal(@<%= file_name %>)
end
end
describe "handling GET /<%= table_name %>/1/edit" do
before(:each) do
@<%= file_name %> = mock_model(<%= class_name %>)
<%= class_name %>.stub!(:find).and_return(@<%= file_name %>)
end
def do_get
get :edit, :id => "1"
end
it "should be successful" do
do_get
response.should be_success
end
it "should render edit template" do
do_get
response.should render_template('edit')
end
it "should find the <%= file_name %> requested" do
<%= class_name %>.should_receive(:find).and_return(@<%= file_name %>)
do_get
end
it "should assign the found <%= class_name %> for the view" do
do_get
assigns[:<%= file_name %>].should equal(@<%= file_name %>)
end
end
describe "handling POST /<%= table_name %>" do
before(:each) do
@<%= file_name %> = mock_model(<%= class_name %>, :to_param => "1")
<%= class_name %>.stub!(:new).and_return(@<%= file_name %>)
end
describe "with successful save" do
def do_post
@<%= file_name %>.should_receive(:save).and_return(true)
post :create, :<%= file_name %> => {}
end
it "should create a new <%= file_name %>" do
<%= class_name %>.should_receive(:new).with({}).and_return(@<%= file_name %>)
do_post
end
it "should redirect to the new <%= file_name %>" do
do_post
response.should redirect_to(<%= table_name.singularize %>_url("1"))
end
end
describe "with failed save" do
def do_post
@<%= file_name %>.should_receive(:save).and_return(false)
post :create, :<%= file_name %> => {}
end
it "should re-render 'new'" do
do_post
response.should render_template('new')
end
end
end
describe "handling PUT /<%= table_name %>/1" do
before(:each) do
@<%= file_name %> = mock_model(<%= class_name %>, :to_param => "1")
<%= class_name %>.stub!(:find).and_return(@<%= file_name %>)
end
describe "with successful update" do
def do_put
@<%= file_name %>.should_receive(:update_attributes).and_return(true)
put :update, :id => "1"
end
it "should find the <%= file_name %> requested" do
<%= class_name %>.should_receive(:find).with("1").and_return(@<%= file_name %>)
do_put
end
it "should update the found <%= file_name %>" do
do_put
assigns(:<%= file_name %>).should equal(@<%= file_name %>)
end
it "should assign the found <%= file_name %> for the view" do
do_put
assigns(:<%= file_name %>).should equal(@<%= file_name %>)
end
it "should redirect to the <%= file_name %>" do
do_put
response.should redirect_to(<%= table_name.singularize %>_url("1"))
end
end
describe "with failed update" do
def do_put
@<%= file_name %>.should_receive(:update_attributes).and_return(false)
put :update, :id => "1"
end
it "should re-render 'edit'" do
do_put
response.should render_template('edit')
end
end
end
describe "handling DELETE /<%= table_name %>/1" do
before(:each) do
@<%= file_name %> = mock_model(<%= class_name %>, :destroy => true)
<%= class_name %>.stub!(:find).and_return(@<%= file_name %>)
end
def do_delete
delete :destroy, :id => "1"
end
it "should find the <%= file_name %> requested" do
<%= class_name %>.should_receive(:find).with("1").and_return(@<%= file_name %>)
do_delete
end
it "should call destroy on the found <%= file_name %>" do
@<%= file_name %>.should_receive(:destroy)
do_delete
end
it "should redirect to the <%= table_name %> list" do
do_delete
response.should redirect_to(<%= table_name %>_url)
end
end
end

View file

@ -0,0 +1,25 @@
require File.expand_path(File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../../spec_helper')
describe "/<%= table_name %>/edit.<%= default_file_extension %>" do
include <%= controller_class_name %>Helper
before do
@<%= file_name %> = mock_model(<%= class_name %>)
<% for attribute in attributes -%>
@<%= file_name %>.stub!(:<%= attribute.name %>).and_return(<%= attribute.default_value %>)
<% end -%>
assigns[:<%= file_name %>] = @<%= file_name %>
end
it "should render edit form" do
render "/<%= table_name %>/edit.<%= default_file_extension %>"
response.should have_tag("form[action=#{<%= file_name %>_path(@<%= file_name %>)}][method=post]") do
<% for attribute in attributes -%><% unless attribute.name =~ /_id/ || [:datetime, :timestamp, :time, :date].index(attribute.type) -%>
with_tag('<%= attribute.input_type -%>#<%= file_name %>_<%= attribute.name %>[name=?]', "<%= file_name %>[<%= attribute.name %>]")
<% end -%><% end -%>
end
end
end

View file

@ -0,0 +1,11 @@
require File.expand_path(File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../spec_helper')
describe <%= controller_class_name %>Helper do
#Delete this example and add some real ones or delete this file
it "should be included in the object returned by #helper" do
included_modules = (class << helper; self; end).send :included_modules
included_modules.should include(<%= controller_class_name %>Helper)
end
end

View file

@ -0,0 +1,22 @@
require File.expand_path(File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../../spec_helper')
describe "/<%= table_name %>/index.<%= default_file_extension %>" do
include <%= controller_class_name %>Helper
before(:each) do
<% [98,99].each do |id| -%>
<%= file_name %>_<%= id %> = mock_model(<%= class_name %>)
<% for attribute in attributes -%>
<%= file_name %>_<%= id %>.should_receive(:<%= attribute.name %>).and_return(<%= attribute.default_value %>)
<% end -%><% end %>
assigns[:<%= table_name %>] = [<%= file_name %>_98, <%= file_name %>_99]
end
it "should render list of <%= table_name %>" do
render "/<%= table_name %>/index.<%= default_file_extension %>"
<% for attribute in attributes -%><% unless attribute.name =~ /_id/ || [:datetime, :timestamp, :time, :date].index(attribute.type) -%>
response.should have_tag("tr>td", <%= attribute.default_value %>, 2)
<% end -%><% end -%>
end
end

View file

@ -0,0 +1,26 @@
require File.expand_path(File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../../spec_helper')
describe "/<%= table_name %>/new.<%= default_file_extension %>" do
include <%= controller_class_name %>Helper
before(:each) do
@<%= file_name %> = mock_model(<%= class_name %>)
@<%= file_name %>.stub!(:new_record?).and_return(true)
<% for attribute in attributes -%>
@<%= file_name %>.stub!(:<%= attribute.name %>).and_return(<%= attribute.default_value %>)
<% end -%>
assigns[:<%= file_name %>] = @<%= file_name %>
end
it "should render new form" do
render "/<%= table_name %>/new.<%= default_file_extension %>"
response.should have_tag("form[action=?][method=post]", <%= table_name %>_path) do
<% for attribute in attributes -%><% unless attribute.name =~ /_id/ || [:datetime, :timestamp, :time, :date].index(attribute.type) -%>
with_tag("<%= attribute.input_type -%>#<%= file_name %>_<%= attribute.name %>[name=?]", "<%= file_name %>[<%= attribute.name %>]")
<% end -%><% end -%>
end
end
end

View file

@ -0,0 +1,61 @@
require File.expand_path(File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../spec_helper')
describe <%= controller_class_name %>Controller do
describe "route generation" do
it "should map { :controller => '<%= table_name %>', :action => 'index' } to /<%= table_name %>" do
route_for(:controller => "<%= table_name %>", :action => "index").should == "/<%= table_name %>"
end
it "should map { :controller => '<%= table_name %>', :action => 'new' } to /<%= table_name %>/new" do
route_for(:controller => "<%= table_name %>", :action => "new").should == "/<%= table_name %>/new"
end
it "should map { :controller => '<%= table_name %>', :action => 'show', :id => 1 } to /<%= table_name %>/1" do
route_for(:controller => "<%= table_name %>", :action => "show", :id => 1).should == "/<%= table_name %>/1"
end
it "should map { :controller => '<%= table_name %>', :action => 'edit', :id => 1 } to /<%= table_name %>/1<%= resource_edit_path %>" do
route_for(:controller => "<%= table_name %>", :action => "edit", :id => 1).should == "/<%= table_name %>/1<%= resource_edit_path %>"
end
it "should map { :controller => '<%= table_name %>', :action => 'update', :id => 1} to /<%= table_name %>/1" do
route_for(:controller => "<%= table_name %>", :action => "update", :id => 1).should == "/<%= table_name %>/1"
end
it "should map { :controller => '<%= table_name %>', :action => 'destroy', :id => 1} to /<%= table_name %>/1" do
route_for(:controller => "<%= table_name %>", :action => "destroy", :id => 1).should == "/<%= table_name %>/1"
end
end
describe "route recognition" do
it "should generate params { :controller => '<%= table_name %>', action => 'index' } from GET /<%= table_name %>" do
params_from(:get, "/<%= table_name %>").should == {:controller => "<%= table_name %>", :action => "index"}
end
it "should generate params { :controller => '<%= table_name %>', action => 'new' } from GET /<%= table_name %>/new" do
params_from(:get, "/<%= table_name %>/new").should == {:controller => "<%= table_name %>", :action => "new"}
end
it "should generate params { :controller => '<%= table_name %>', action => 'create' } from POST /<%= table_name %>" do
params_from(:post, "/<%= table_name %>").should == {:controller => "<%= table_name %>", :action => "create"}
end
it "should generate params { :controller => '<%= table_name %>', action => 'show', id => '1' } from GET /<%= table_name %>/1" do
params_from(:get, "/<%= table_name %>/1").should == {:controller => "<%= table_name %>", :action => "show", :id => "1"}
end
it "should generate params { :controller => '<%= table_name %>', action => 'edit', id => '1' } from GET /<%= table_name %>/1;edit" do
params_from(:get, "/<%= table_name %>/1<%= resource_edit_path %>").should == {:controller => "<%= table_name %>", :action => "edit", :id => "1"}
end
it "should generate params { :controller => '<%= table_name %>', action => 'update', id => '1' } from PUT /<%= table_name %>/1" do
params_from(:put, "/<%= table_name %>/1").should == {:controller => "<%= table_name %>", :action => "update", :id => "1"}
end
it "should generate params { :controller => '<%= table_name %>', action => 'destroy', id => '1' } from DELETE /<%= table_name %>/1" do
params_from(:delete, "/<%= table_name %>/1").should == {:controller => "<%= table_name %>", :action => "destroy", :id => "1"}
end
end
end

View file

@ -0,0 +1,22 @@
require File.expand_path(File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../../spec_helper')
describe "/<%= table_name %>/show.<%= default_file_extension %>" do
include <%= controller_class_name %>Helper
before(:each) do
@<%= file_name %> = mock_model(<%= class_name %>)
<% for attribute in attributes -%>
@<%= file_name %>.stub!(:<%= attribute.name %>).and_return(<%= attribute.default_value %>)
<% end -%>
assigns[:<%= file_name %>] = @<%= file_name %>
end
it "should render attributes in <p>" do
render "/<%= table_name %>/show.<%= default_file_extension %>"
<% for attribute in attributes -%><% unless attribute.name =~ /_id/ || [:datetime, :timestamp, :time, :date].index(attribute.type) -%>
response.should have_text(/<%= Regexp.escape(attribute.default_value)[1..-2]%>/)
<% end -%><% end -%>
end
end

9
vendor/plugins/rspec-rails/init.rb vendored Normal file
View file

@ -0,0 +1,9 @@
# Placeholder to satisfy Rails.
#
# Do NOT add any require statements to this file. Doing
# so will cause Rails to load this plugin all of the time.
#
# Running 'ruby script/generate rspec' will
# generate spec/spec_helper.rb, which includes the necessary
# require statements and configuration. This file should
# be required by all of your spec files.

View file

@ -0,0 +1 @@
# This needs to be here for >= ZenTest-3.9.0 to add this directory to the load path.

View file

@ -0,0 +1,81 @@
# (c) Copyright 2006 Nick Sieger <nicksieger@gmail.com>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
$:.push(*Dir["vendor/rails/*/lib"])
require 'active_support'
require 'autotest/rspec'
Autotest.add_hook :initialize do |at|
%w{config/ coverage/ db/ doc/ log/ public/ script/ tmp/ vendor/rails vendor/plugins previous_failures.txt}.each do |exception|
at.add_exception(exception)
end
at.clear_mappings
at.add_mapping(%r%^(test|spec)/fixtures/(.*).yml$%) { |_, m|
["spec/models/#{m[2].singularize}_spec.rb"] + at.files_matching(%r%^spec\/views\/#{m[2]}/.*_spec\.rb$%)
}
at.add_mapping(%r%^spec/(models|controllers|views|helpers|lib)/.*rb$%) { |filename, _|
filename
}
at.add_mapping(%r%^app/models/(.*)\.rb$%) { |_, m|
["spec/models/#{m[1]}_spec.rb"]
}
at.add_mapping(%r%^app/views/(.*)$%) { |_, m|
at.files_matching %r%^spec/views/#{m[1]}_spec.rb$%
}
at.add_mapping(%r%^app/controllers/(.*)\.rb$%) { |_, m|
if m[1] == "application"
at.files_matching %r%^spec/controllers/.*_spec\.rb$%
else
["spec/controllers/#{m[1]}_spec.rb"]
end
}
at.add_mapping(%r%^app/helpers/(.*)_helper\.rb$%) { |_, m|
if m[1] == "application" then
at.files_matching(%r%^spec/(views|helpers)/.*_spec\.rb$%)
else
["spec/helpers/#{m[1]}_helper_spec.rb"] + at.files_matching(%r%^spec\/views\/#{m[1]}/.*_spec\.rb$%)
end
}
at.add_mapping(%r%^config/routes\.rb$%) {
at.files_matching %r%^spec/(controllers|views|helpers)/.*_spec\.rb$%
}
at.add_mapping(%r%^config/database\.yml$%) { |_, m|
at.files_matching %r%^spec/models/.*_spec\.rb$%
}
at.add_mapping(%r%^(spec/(spec_helper|shared/.*)|config/(boot|environment(s/test)?))\.rb$%) {
at.files_matching %r%^spec/(models|controllers|views|helpers)/.*_spec\.rb$%
}
at.add_mapping(%r%^lib/(.*)\.rb$%) { |_, m|
["spec/lib/#{m[1]}_spec.rb"]
}
end
class Autotest::RailsRspec < Autotest::Rspec
def spec_command
"script/spec"
end
end

View file

@ -0,0 +1,52 @@
silence_warnings { RAILS_ENV = "test" }
require 'application'
require 'action_controller/test_process'
require 'action_controller/integration'
require 'active_record/fixtures' if defined?(ActiveRecord::Base)
require 'test/unit'
require 'spec'
require 'spec/rails/matchers'
require 'spec/rails/mocks'
require 'spec/rails/example'
require 'spec/rails/extensions'
require 'spec/rails/version'
module Spec
# = Spec::Rails
#
# Spec::Rails (a.k.a. RSpec on Rails) is a Ruby on Rails plugin that allows you to drive the development
# of your RoR application using RSpec, a framework that aims to enable Example Driven Development
# in Ruby.
#
# == Features
#
# * Use RSpec to independently specify Rails Models, Views, Controllers and Helpers
# * Integrated fixture loading
# * Special generators for Resources, Models, Views and Controllers that generate Specs instead of Tests.
#
# == Vision
#
# For people for whom TDD is a brand new concept, the testing support built into Ruby on Rails
# is a huge leap forward. The fact that it is built right in is fantastic, and Ruby on Rails
# apps are generally much easier to maintain than they might have been without such support.
#
# For those of us coming from a history with TDD, and now BDD, the existing support presents some problems related to dependencies across specs. To that end, RSpec on Rails supports 4 types of specs. Weve also built in first class mocking and stubbing support in order to break dependencies across these different concerns.
#
# == More Information
#
# See Spec::Rails::Runner for information about the different kinds of contexts
# you can use to spec the different Rails components
#
# See Spec::Rails::Expectations for information about Rails-specific expectations
# you can set on responses and models, etc.
#
# == License
#
# RSpec on Rails is licensed under the same license as RSpec itself,
# the MIT-LICENSE.
module Rails
end
end

View file

@ -0,0 +1,46 @@
dir = File.dirname(__FILE__)
require 'spec/rails/example/assigns_hash_proxy'
require "spec/rails/example/render_observer"
require "spec/rails/example/rails_example_group"
require "spec/rails/example/model_example_group"
require "spec/rails/example/functional_example_group"
require "spec/rails/example/controller_example_group"
require "spec/rails/example/helper_example_group"
require "spec/rails/example/view_example_group"
module Spec
module Rails
# Spec::Rails::Example extends Spec::Example (RSpec's core Example module) to provide
# Rails-specific contexts for describing Rails Models, Views, Controllers and Helpers.
#
# == Model Examples
#
# These are the equivalent of unit tests in Rails' built in testing. Ironically (for the traditional TDD'er) these are the only specs that we feel should actually interact with the database.
#
# See Spec::Rails::Example::ModelExampleGroup
#
# == Controller Examples
#
# These align somewhat with functional tests in rails, except that they do not actually render views (though you can force rendering of views if you prefer). Instead of setting expectations about what goes on a page, you set expectations about what templates get rendered.
#
# See Spec::Rails::Example::ControllerExampleGroup
#
# == View Examples
#
# This is the other half of Rails functional testing. View specs allow you to set up assigns and render
# a template. By assigning mock model data, you can specify view behaviour with no dependency on a database
# or your real models.
#
# See Spec::Rails::Example::ViewExampleGroup
#
# == Helper Examples
#
# These let you specify directly methods that live in your helpers.
#
# See Spec::Rails::Example::HelperExampleGroup
module Example
end
end
end

View file

@ -0,0 +1,43 @@
module Spec
module Rails
module Example
class AssignsHashProxy #:nodoc:
def initialize(object)
@object = object
end
def [](ivar)
if assigns.include?(ivar.to_s)
assigns[ivar.to_s]
elsif assigns.include?(ivar)
assigns[ivar]
else
nil
end
end
def []=(ivar, val)
@object.instance_variable_set "@#{ivar}", val
assigns[ivar.to_s] = val
end
def delete(name)
assigns.delete(name.to_s)
end
def each(&block)
assigns.each &block
end
def has_key?(key)
assigns.key?(key.to_s)
end
protected
def assigns
@object.assigns
end
end
end
end
end

View file

@ -0,0 +1,271 @@
module Spec
module Rails
module Example
# Controller Examples live in $RAILS_ROOT/spec/controllers/.
#
# Controller Examples use Spec::Rails::Example::ControllerExampleGroup, which supports running specs for
# Controllers in two modes, which represent the tension between the more granular
# testing common in TDD and the more high level testing built into
# rails. BDD sits somewhere in between: we want to a balance between
# specs that are close enough to the code to enable quick fault
# isolation and far enough away from the code to enable refactoring
# with minimal changes to the existing specs.
#
# == Isolation mode (default)
#
# No dependencies on views because none are ever rendered. The
# benefit of this mode is that can spec the controller completely
# independent of the view, allowing that responsibility to be
# handled later, or by somebody else. Combined w/ separate view
# specs, this also provides better fault isolation.
#
# == Integration mode
#
# To run in this mode, include the +integrate_views+ declaration
# in your controller context:
#
# describe ThingController do
# integrate_views
# ...
#
# In this mode, controller specs are run in the same way that
# rails functional tests run - one set of tests for both the
# controllers and the views. The benefit of this approach is that
# you get wider coverage from each spec. Experienced rails
# developers may find this an easier approach to begin with, however
# we encourage you to explore using the isolation mode and revel
# in its benefits.
#
# == Expecting Errors
#
# Rspec on Rails will raise errors that occur in controller actions.
# In contrast, Rails will swallow errors that are raised in controller
# actions and return an error code in the header. If you wish to override
# Rspec and have Rail's default behaviour,tell the controller to use
# rails error handling ...
#
# before(:each) do
# controller.use_rails_error_handling!
# end
#
# When using Rail's error handling, you can expect error codes in headers ...
#
# it "should return an error in the header" do
# response.should be_error
# end
#
# it "should return a 501" do
# response.response_code.should == 501
# end
#
# it "should return a 501" do
# response.code.should == "501"
# end
class ControllerExampleGroup < FunctionalExampleGroup
class << self
# Use this to instruct RSpec to render views in your controller examples (Integration Mode).
#
# describe ThingController do
# integrate_views
# ...
#
# See Spec::Rails::Example::ControllerExampleGroup for more information about
# Integration and Isolation modes.
def integrate_views(integrate_views = true)
@integrate_views = integrate_views
end
def integrate_views? # :nodoc:
@integrate_views
end
def inherited(klass) # :nodoc:
klass.controller_class_name = controller_class_name
klass.integrate_views(integrate_views?)
super
end
# You MUST provide a controller_name within the context of
# your controller specs:
#
# describe "ThingController" do
# controller_name :thing
# ...
def controller_name(name)
@controller_class_name = "#{name}_controller".camelize
end
attr_accessor :controller_class_name # :nodoc:
end
before(:each) do
# Some Rails apps explicitly disable ActionMailer in environment.rb
if defined?(ActionMailer)
@deliveries = []
ActionMailer::Base.deliveries = @deliveries
end
unless @controller.class.ancestors.include?(ActionController::Base)
Spec::Expectations.fail_with <<-EOE
You have to declare the controller name in controller specs. For example:
describe "The ExampleController" do
controller_name "example" #invokes the ExampleController
end
EOE
end
(class << @controller; self; end).class_eval do
def controller_path #:nodoc:
self.class.name.underscore.gsub('_controller', '')
end
include ControllerInstanceMethods
end
@controller.integrate_views! if @integrate_views
@controller.session = session
end
attr_reader :response, :request, :controller
def initialize(defined_description, &implementation) #:nodoc:
super
controller_class_name = self.class.controller_class_name
if controller_class_name
@controller_class_name = controller_class_name.to_s
else
@controller_class_name = self.class.described_type.to_s
end
@integrate_views = self.class.integrate_views?
end
# Uses ActionController::Routing::Routes to generate
# the correct route for a given set of options.
# == Example
# route_for(:controller => 'registrations', :action => 'edit', :id => 1)
# => '/registrations/1;edit'
def route_for(options)
ensure_that_routes_are_loaded
ActionController::Routing::Routes.generate(options)
end
# Uses ActionController::Routing::Routes to parse
# an incoming path so the parameters it generates can be checked
# == Example
# params_from(:get, '/registrations/1;edit')
# => :controller => 'registrations', :action => 'edit', :id => 1
def params_from(method, path)
ensure_that_routes_are_loaded
ActionController::Routing::Routes.recognize_path(path, :method => method)
end
protected
def _assigns_hash_proxy
@_assigns_hash_proxy ||= AssignsHashProxy.new @controller
end
private
def ensure_that_routes_are_loaded
ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
end
module ControllerInstanceMethods #:nodoc:
include Spec::Rails::Example::RenderObserver
# === render(options = nil, deprecated_status_or_extra_options = nil, &block)
#
# This gets added to the controller's singleton meta class,
# allowing Controller Examples to run in two modes, freely switching
# from context to context.
def render(options=nil, deprecated_status_or_extra_options=nil, &block)
if ::Rails::VERSION::STRING >= '2.0.0' && deprecated_status_or_extra_options.nil?
deprecated_status_or_extra_options = {}
end
unless block_given?
unless integrate_views?
if @template.respond_to?(:finder)
(class << @template.finder; self; end).class_eval do
define_method :file_exists? do
true
end
end
else
(class << @template; self; end).class_eval do
define_method :file_exists? do
true
end
end
end
(class << @template; self; end).class_eval do
define_method :render_file do |*args|
@first_render ||= args[0]
end
end
end
end
if matching_message_expectation_exists(options)
expect_render_mock_proxy.render(options, &block)
@performed_render = true
else
unless matching_stub_exists(options)
super(options, deprecated_status_or_extra_options, &block)
end
end
end
def raise_with_disable_message(old_method, new_method)
raise %Q|
controller.#{old_method}(:render) has been disabled because it
can often produce unexpected results. Instead, you should
use the following (before the action):
controller.#{new_method}(*args)
See the rdoc for #{new_method} for more information.
|
end
def should_receive(*args)
if args[0] == :render
raise_with_disable_message("should_receive", "expect_render")
else
super
end
end
def stub!(*args)
if args[0] == :render
raise_with_disable_message("stub!", "stub_render")
else
super
end
end
def response(&block)
# NOTE - we're setting @update for the assert_select_spec - kinda weird, huh?
@update = block
@_response || @response
end
def integrate_views!
@integrate_views = true
end
private
def integrate_views?
@integrate_views
end
def matching_message_expectation_exists(options)
expect_render_mock_proxy.send(:__mock_proxy).send(:find_matching_expectation, :render, options)
end
def matching_stub_exists(options)
expect_render_mock_proxy.send(:__mock_proxy).send(:find_matching_method_stub, :render, options)
end
end
Spec::Example::ExampleGroupFactory.register(:controller, self)
end
end
end
end

View file

@ -0,0 +1,59 @@
module Spec
module Rails
module Example
class FunctionalExampleGroup < RailsExampleGroup
include ActionController::TestProcess
include ActionController::Assertions
attr_reader :request, :response
before(:each) do
@controller_class = Object.path2class @controller_class_name
raise "Can't determine controller class for #{@controller_class_name}" if @controller_class.nil?
@controller = @controller_class.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@response.session = @request.session
end
def params
request.parameters
end
def flash
response.flash
end
def session
response.session
end
# :call-seq:
# assigns()
#
# Hash of instance variables to values that are made available to
# views. == Examples
#
# #in thing_controller.rb
# def new
# @thing = Thing.new
# end
#
# #in thing_controller_spec
# get 'new'
# assigns[:registration].should == Thing.new
#--
# NOTE - Even though docs only use assigns[:key] format, this supports
# assigns(:key) in order to avoid breaking old specs.
#++
def assigns(key = nil)
if key.nil?
_assigns_hash_proxy
else
_assigns_hash_proxy[key]
end
end
end
end
end
end

View file

@ -0,0 +1,164 @@
module Spec
module Rails
module Example
# Helper Specs live in $RAILS_ROOT/spec/helpers/.
#
# Helper Specs use Spec::Rails::Example::HelperExampleGroup, which allows you to
# include your Helper directly in the context and write specs directly
# against its methods.
#
# HelperExampleGroup also includes the standard lot of ActionView::Helpers in case your
# helpers rely on any of those.
#
# == Example
#
# class ThingHelper
# def number_of_things
# Thing.count
# end
# end
#
# describe "ThingHelper example_group" do
# include ThingHelper
# it "should tell you the number of things" do
# Thing.should_receive(:count).and_return(37)
# number_of_things.should == 37
# end
# end
class HelperExampleGroup < FunctionalExampleGroup
class HelperObject < ActionView::Base
def protect_against_forgery?
false
end
def session=(session)
@session = session
end
def request=(request)
@request = request
end
def flash=(flash)
@flash = flash
end
def params=(params)
@params = params
end
def controller=(controller)
@controller = controller
end
private
attr_reader :session, :request, :flash, :params, :controller
end
class << self
# The helper name....
def helper_name(name=nil)
@helper_being_described = "#{name}_helper".camelize.constantize
send :include, @helper_being_described
end
def helper
@helper_object ||= returning HelperObject.new do |helper_object|
if @helper_being_described.nil?
if described_type.class == Module
helper_object.extend described_type
end
else
helper_object.extend @helper_being_described
end
end
end
end
# Returns an instance of ActionView::Base with the helper being spec'd
# included.
#
# == Example
#
# describe PersonHelper do
# it "should write a link to person with the name" do
# assigns[:person] = mock_model(Person, :full_name => "Full Name", :id => 37, :new_record? => false)
# helper.link_to_person.should == %{<a href="/people/37">Full Name</a>}
# end
# end
#
# module PersonHelper
# def link_to_person
# link_to person.full_name, url_for(person)
# end
# end
#
def helper
self.class.helper
end
# Reverse the load order so that custom helpers which are defined last
# are also loaded last.
ActionView::Base.included_modules.reverse.each do |mod|
include mod if mod.parents.include?(ActionView::Helpers)
end
before(:all) do
@controller_class_name = 'Spec::Rails::Example::HelperExampleGroupController'
end
before(:each) do
@controller.request = @request
@controller.url = ActionController::UrlRewriter.new @request, {} # url_for
@flash = ActionController::Flash::FlashHash.new
session['flash'] = @flash
ActionView::Helpers::AssetTagHelper::reset_javascript_include_default
helper.session = session
helper.request = @request
helper.flash = flash
helper.params = params
helper.controller = @controller
end
def flash
@flash
end
def eval_erb(text)
erb_args = [text]
if helper.respond_to?(:output_buffer)
erb_args += [nil, nil, '@output_buffer']
end
helper.instance_eval do
ERB.new(*erb_args).result(binding)
end
end
# TODO: BT - Helper Examples should proxy method_missing to a Rails View instance.
# When that is done, remove this method
def protect_against_forgery?
false
end
Spec::Example::ExampleGroupFactory.register(:helper, self)
protected
def _assigns_hash_proxy
@_assigns_hash_proxy ||= AssignsHashProxy.new helper
end
end
class HelperExampleGroupController < ApplicationController #:nodoc:
attr_accessor :request, :url
# Re-raise errors
def rescue_action(e); raise e; end
end
end
end
end

View file

@ -0,0 +1,14 @@
module Spec
module Rails
module Example
# Model examples live in $RAILS_ROOT/spec/models/.
#
# Model examples use Spec::Rails::Example::ModelExampleGroup, which
# provides support for fixtures and some custom expectations via extensions
# to ActiveRecord::Base.
class ModelExampleGroup < RailsExampleGroup
Spec::Example::ExampleGroupFactory.register(:model, self)
end
end
end
end

View file

@ -0,0 +1,29 @@
require 'spec/interop/test'
if ActionView::Base.respond_to?(:cache_template_extension)
ActionView::Base.cache_template_extensions = false
end
module Spec
module Rails
module Example
class RailsExampleGroup < Test::Unit::TestCase
# Rails >= r8570 uses setup/teardown_fixtures explicitly
before(:each) do
setup_fixtures if self.respond_to?(:setup_fixtures)
end
after(:each) do
teardown_fixtures if self.respond_to?(:teardown_fixtures)
end
include Spec::Rails::Matchers
include Spec::Rails::Mocks
Spec::Example::ExampleGroupFactory.default(self)
end
end
end
end

View file

@ -0,0 +1,90 @@
require 'spec/mocks/framework'
module Spec
module Rails
module Example
# Provides specialized mock-like behaviour for controller and view examples,
# allowing you to mock or stub calls to render with specific arguments while
# ignoring all other calls.
module RenderObserver
# Similar to mocking +render+ with the exception that calls to +render+ with
# any other options are passed on to the receiver (i.e. controller in
# controller examples, template in view examples).
#
# This is necessary because Rails uses the +render+ method on both
# controllers and templates as a dispatcher to render different kinds of
# things, sometimes resulting in many calls to the render method within one
# request. This approach makes it impossible to use a normal mock object, which
# is designed to observe all incoming messages with a given name.
#
# +expect_render+ is auto-verifying, so failures will be reported without
# requiring you to explicitly request verification.
#
# Also, +expect_render+ uses parts of RSpec's mock expectation framework. Because
# it wraps only a subset of the framework, using this will create no conflict with
# other mock frameworks if you choose to use them. Additionally, the object returned
# by expect_render is an RSpec mock object, which means that you can call any of the
# chained methods available in RSpec's mocks.
#
# == Controller Examples
#
# controller.expect_render(:partial => 'thing', :object => thing)
# controller.expect_render(:partial => 'thing', :collection => things).once
#
# controller.stub_render(:partial => 'thing', :object => thing)
# controller.stub_render(:partial => 'thing', :collection => things).twice
#
# == View Examples
#
# template.expect_render(:partial => 'thing', :object => thing)
# template.expect_render(:partial => 'thing', :collection => things)
#
# template.stub_render(:partial => 'thing', :object => thing)
# template.stub_render(:partial => 'thing', :collection => things)
#
def expect_render(opts={})
register_verify_after_each
expect_render_mock_proxy.should_receive(:render, :expected_from => caller(1)[0]).with(opts)
end
# This is exactly like expect_render, with the exception that the call to render will not
# be verified. Use this if you are trying to isolate your example from a complicated render
# operation but don't care whether it is called or not.
def stub_render(opts={})
register_verify_after_each
expect_render_mock_proxy.stub!(:render, :expected_from => caller(1)[0]).with(opts)
end
def verify_rendered # :nodoc:
expect_render_mock_proxy.rspec_verify
end
def unregister_verify_after_each #:nodoc:
proc = verify_rendered_proc
Spec::Example::ExampleGroup.remove_after(:each, &proc)
end
protected
def verify_rendered_proc #:nodoc:
template = self
@verify_rendered_proc ||= Proc.new do
template.verify_rendered
template.unregister_verify_after_each
end
end
def register_verify_after_each #:nodoc:
proc = verify_rendered_proc
Spec::Example::ExampleGroup.after(:each, &proc)
end
def expect_render_mock_proxy #:nodoc:
@expect_render_mock_proxy ||= Spec::Mocks::Mock.new("expect_render_mock_proxy")
end
end
end
end
end

View file

@ -0,0 +1,178 @@
module Spec
module Rails
module Example
# View Examples live in $RAILS_ROOT/spec/views/.
#
# View Specs use Spec::Rails::Example::ViewExampleGroup,
# which provides access to views without invoking any of your controllers.
# See Spec::Rails::Expectations::Matchers for information about specific
# expectations that you can set on views.
#
# == Example
#
# describe "login/login" do
# before do
# render 'login/login'
# end
#
# it "should display login form" do
# response.should have_tag("form[action=/login]") do
# with_tag("input[type=text][name=email]")
# with_tag("input[type=password][name=password]")
# with_tag("input[type=submit][value=Login]")
# end
# end
# end
class ViewExampleGroup < FunctionalExampleGroup
before(:each) do
ensure_that_flash_and_session_work_properly
end
after(:each) do
ensure_that_base_view_path_is_not_set_across_example_groups
end
def initialize(defined_description, &implementation) #:nodoc:
super
@controller_class_name = "Spec::Rails::Example::ViewExampleGroupController"
end
def ensure_that_flash_and_session_work_properly #:nodoc:
@controller.send :initialize_template_class, @response
@controller.send :assign_shortcuts, @request, @response
@session = @controller.session
@controller.class.send :public, :flash
end
def ensure_that_base_view_path_is_not_set_across_example_groups #:nodoc:
ActionView::Base.base_view_path = nil
end
def set_base_view_path(options) #:nodoc:
ActionView::Base.base_view_path = base_view_path(options)
end
def base_view_path(options) #:nodoc:
"/#{derived_controller_name(options)}/"
end
def derived_controller_name(options) #:nodoc:
parts = subject_of_render(options).split('/').reject { |part| part.empty? }
"#{parts[0..-2].join('/')}"
end
def derived_action_name(options) #:nodoc:
parts = subject_of_render(options).split('/').reject { |part| part.empty? }
"#{parts.last}"
end
def subject_of_render(options) #:nodoc:
[:template, :partial, :file].each do |render_type|
if options.has_key?(render_type)
return options[render_type]
end
end
return ""
end
def add_helpers(options) #:nodoc:
@controller.add_helper("application")
@controller.add_helper(derived_controller_name(options))
@controller.add_helper(options[:helper]) if options[:helper]
options[:helpers].each { |helper| @controller.add_helper(helper) } if options[:helpers]
end
# Renders a template for a View Spec, which then provides access to the result
# through the +response+. Also supports render with :inline, which you can
# use to spec custom form builders, helpers, etc, in the context of a view.
#
# == Examples
#
# render('/people/list')
# render('/people/list', :helper => MyHelper)
# render('/people/list', :helpers => [MyHelper, MyOtherHelper])
# render(:partial => '/people/_address')
# render(:inline => "<% custom_helper 'argument', 'another argument' %>")
#
# See Spec::Rails::Example::ViewExampleGroup for more information.
def render(*args)
options = Hash === args.last ? args.pop : {}
options[:template] = args.first.to_s unless args.empty?
set_base_view_path(options)
add_helpers(options)
assigns[:action_name] = @action_name
@request.path_parameters = {
:controller => derived_controller_name(options),
:action => derived_action_name(options)
}
defaults = { :layout => false }
options = defaults.merge options
@controller.send(:params).reverse_merge! @request.parameters
@controller.send :initialize_current_url
@controller.class.instance_eval %{
def controller_path
"#{derived_controller_name(options)}"
end
def controller_name
"#{derived_controller_name(options).split('/').last}"
end
}
@controller.send :forget_variables_added_to_assigns
@controller.send :render, options
@controller.send :process_cleanup
end
# This provides the template. Use this to set mock
# expectations for dealing with partials
#
# == Example
#
# describe "/person/new" do
# it "should use the form partial" do
# template.should_receive(:render).with(:partial => 'form')
# render "/person/new"
# end
# end
def template
@controller.template
end
Spec::Example::ExampleGroupFactory.register(:view, self)
protected
def _assigns_hash_proxy
@_assigns_hash_proxy ||= AssignsHashProxy.new @controller
end
end
class ViewExampleGroupController < ApplicationController #:nodoc:
include Spec::Rails::Example::RenderObserver
attr_reader :template
def add_helper_for(template_path)
add_helper(template_path.split('/')[0])
end
def add_helper(name)
begin
helper_module = "#{name}_helper".camelize.constantize
rescue
return
end
(class << template; self; end).class_eval do
include helper_module
end
end
end
end
end
end

View file

@ -0,0 +1,12 @@
require 'spec'
require 'spec/rails/extensions/object'
require 'spec/rails/extensions/spec/example/configuration'
require 'spec/rails/extensions/spec/matchers/have'
require 'spec/rails/extensions/active_record/base'
require 'spec/rails/extensions/action_controller/base'
require 'spec/rails/extensions/action_controller/rescue'
require 'spec/rails/extensions/action_controller/test_response'
require 'spec/rails/extensions/action_view/base'

View file

@ -0,0 +1,14 @@
module ActionController
class Base
class << self
def set_view_path(path)
[:append_view_path, :view_paths=, :template_root=].each do |method|
if respond_to?(method)
return send(method, path)
end
end
end
end
end
end

View file

@ -0,0 +1,21 @@
module ActionController
module Rescue
def use_rails_error_handling!
@use_rails_error_handling = true
end
def use_rails_error_handling?
@use_rails_error_handling ||= false
end
protected
def rescue_action_with_fast_errors(exception)
if use_rails_error_handling?
rescue_action_without_fast_errors exception
else
raise exception
end
end
alias_method_chain :rescue_action, :fast_errors
end
end

View file

@ -0,0 +1,11 @@
module ActionController #:nodoc:
class TestResponse #:nodoc:
attr_writer :controller_path
def capture(name)
template.instance_variable_get "@content_for_#{name.to_s}"
end
alias [] capture
end
end

View file

@ -0,0 +1,27 @@
module ActionView #:nodoc:
class Base #:nodoc:
include Spec::Rails::Example::RenderObserver
cattr_accessor :base_view_path
def render_partial(partial_path, local_assigns = nil, deprecated_local_assigns = nil) #:nodoc:
if partial_path.is_a?(String)
unless partial_path.include?("/")
unless self.class.base_view_path.nil?
partial_path = "#{self.class.base_view_path}/#{partial_path}"
end
end
end
super(partial_path, local_assigns, deprecated_local_assigns)
end
alias_method :orig_render, :render
def render(options = {}, old_local_assigns = {}, &block)
if expect_render_mock_proxy.send(:__mock_proxy).send(:find_matching_expectation, :render, options)
expect_render_mock_proxy.render(options)
else
unless expect_render_mock_proxy.send(:__mock_proxy).send(:find_matching_method_stub, :render, options)
orig_render(options, old_local_assigns, &block)
end
end
end
end
end

View file

@ -0,0 +1,30 @@
if defined?(ActiveRecord::Base)
module ActiveRecord #:nodoc:
class Base
(class << self; self; end).class_eval do
# Extension for <tt>should have</tt> on AR Model classes
#
# ModelClass.should have(:no).records
# ModelClass.should have(1).record
# ModelClass.should have(n).records
def records
find(:all)
end
alias :record :records
end
# Extension for <tt>should have</tt> on AR Model instances
#
# model.should have(:no).errors_on(:attribute)
# model.should have(1).error_on(:attribute)
# model.should have(n).errors_on(:attribute)
def errors_on(attribute)
self.valid?
[self.errors.on(attribute)].flatten.compact
end
alias :error_on :errors_on
end
end
end

View file

@ -0,0 +1,5 @@
class Object # :nodoc:
def self.path2class(klassname)
klassname.split('::').inject(Object) { |k,n| k.const_get n }
end
end

View file

@ -0,0 +1,71 @@
require 'spec/example/configuration'
begin
module Spec
module Example
class Configuration
# Rails 1.2.3 does a copy of the @inheritable_attributes to the subclass when the subclass is
# created. This causes an ordering issue when setting state on Configuration because the data is
# already copied.
# Iterating over EXAMPLE_GROUP_CLASSES causes the base ExampleGroup classes to have their
# @inheritable_attributes updated.
# TODO: BT - When we no longer support Rails 1.2.3, we can remove this functionality
EXAMPLE_GROUP_CLASSES = [
::Test::Unit::TestCase,
::Spec::Rails::Example::RailsExampleGroup,
::Spec::Rails::Example::FunctionalExampleGroup,
::Spec::Rails::Example::ControllerExampleGroup,
::Spec::Rails::Example::ViewExampleGroup,
::Spec::Rails::Example::HelperExampleGroup,
::Spec::Rails::Example::ModelExampleGroup
]
# All of this is ActiveRecord related and makes no sense if it's not used by the app
if defined?(ActiveRecord::Base)
def initialize
super
self.fixture_path = RAILS_ROOT + '/spec/fixtures'
end
def use_transactional_fixtures
Test::Unit::TestCase.use_transactional_fixtures
end
def use_transactional_fixtures=(value)
EXAMPLE_GROUP_CLASSES.each do |example_group|
example_group.use_transactional_fixtures = value
end
end
def use_instantiated_fixtures
Test::Unit::TestCase.use_instantiated_fixtures
end
def use_instantiated_fixtures=(value)
EXAMPLE_GROUP_CLASSES.each do |example_group|
example_group.use_instantiated_fixtures = value
end
end
def fixture_path
Test::Unit::TestCase.fixture_path
end
def fixture_path=(path)
EXAMPLE_GROUP_CLASSES.each do |example_group|
example_group.fixture_path = path
end
end
def global_fixtures
::Test::Unit::TestCase.fixture_table_names
end
def global_fixtures=(fixtures)
EXAMPLE_GROUP_CLASSES.each do |example_group|
example_group.fixtures(*fixtures)
end
end
end
end
end
end
rescue Exception => e
puts e.message
puts e.backtrace
raise e
end

View file

@ -0,0 +1,21 @@
require 'spec/matchers/have'
module Spec #:nodoc:
module Matchers #:nodoc:
class Have #:nodoc:
alias_method :__original_failure_message, :failure_message
def failure_message
return "expected #{relativities[@relativity]}#{@expected} errors on :#{@args[0]}, got #{@actual}" if @collection_name == :errors_on
return "expected #{relativities[@relativity]}#{@expected} error on :#{@args[0]}, got #{@actual}" if @collection_name == :error_on
return __original_failure_message
end
alias_method :__original_description, :description
def description
return "should have #{relativities[@relativity]}#{@expected} errors on :#{@args[0]}" if @collection_name == :errors_on
return "should have #{relativities[@relativity]}#{@expected} error on :#{@args[0]}" if @collection_name == :error_on
return __original_description
end
end
end
end

View file

@ -0,0 +1,30 @@
dir = File.dirname(__FILE__)
require 'spec/rails/matchers/assert_select'
require 'spec/rails/matchers/have_text'
require 'spec/rails/matchers/include_text'
require 'spec/rails/matchers/redirect_to'
require 'spec/rails/matchers/render_template'
module Spec
module Rails
# Spec::Rails::Expectations::Matchers provides several expectation matchers
# intended to work with Rails components like models and responses. For example:
#
# response.should redirect_to("some/url") #redirect_to(url) is the matcher.
#
# In addition to those you see below, the arbitrary predicate feature of RSpec
# makes the following available as well:
#
# response.should be_success #passes if response.success?
# response.should be_redirect #passes if response.redirect?
#
# Note that many of these matchers are part of a wrapper of <tt>assert_select</tt>, so
# the documentation comes straight from that with some slight modifications.
# <tt>assert_select</tt> is a Test::Unit extension originally contributed to the
# Rails community as a plugin by Assaf Arkin and eventually shipped as part of Rails.
#
# For more info on <tt>assert_select</tt>, see the relevant Rails documentation.
module Matchers
end
end
end

View file

@ -0,0 +1,130 @@
# This is a wrapper of assert_select for rspec.
module Spec # :nodoc:
module Rails
module Matchers
class AssertSelect #:nodoc:
def initialize(assertion, spec_scope, *args, &block)
@assertion = assertion
@spec_scope = spec_scope
@args = args
@block = block
end
def matches?(response_or_text, &block)
if ActionController::TestResponse === response_or_text and
response_or_text.headers.key?('Content-Type') and
response_or_text.headers['Content-Type'].to_sym == :xml
@args.unshift(HTML::Document.new(response_or_text.body, false, true).root)
elsif String === response_or_text
@args.unshift(HTML::Document.new(response_or_text).root)
end
@block = block if block
begin
@spec_scope.send(@assertion, *@args, &@block)
rescue ::Test::Unit::AssertionFailedError => @error
end
@error.nil?
end
def failure_message; @error.message; end
def negative_failure_message; "should not #{description}, but did"; end
def description
{
:assert_select => "have tag#{format_args(*@args)}",
:assert_select_email => "send email#{format_args(*@args)}",
}[@assertion]
end
private
def format_args(*args)
return "" if args.empty?
return "(#{arg_list(*args)})"
end
def arg_list(*args)
args.collect do |arg|
arg.respond_to?(:description) ? arg.description : arg.inspect
end.join(", ")
end
end
# :call-seq:
# response.should have_tag(*args, &block)
# string.should have_tag(*args, &block)
#
# wrapper for assert_select with additional support for using
# css selectors to set expectation on Strings. Use this in
# helper specs, for example, to set expectations on the results
# of helper methods.
#
# == Examples
#
# # in a controller spec
# response.should have_tag("div", "some text")
#
# # in a helper spec (person_address_tag is a method in the helper)
# person_address_tag.should have_tag("input#person_address")
#
# see documentation for assert_select at http://api.rubyonrails.org/
def have_tag(*args, &block)
AssertSelect.new(:assert_select, self, *args, &block)
end
# wrapper for a nested assert_select
#
# response.should have_tag("div#form") do
# with_tag("input#person_name[name=?]", "person[name]")
# end
#
# see documentation for assert_select at http://api.rubyonrails.org/
def with_tag(*args, &block)
should have_tag(*args, &block)
end
# wrapper for a nested assert_select with false
#
# response.should have_tag("div#1") do
# without_tag("span", "some text that shouldn't be there")
# end
#
# see documentation for assert_select at http://api.rubyonrails.org/
def without_tag(*args, &block)
should_not have_tag(*args, &block)
end
# :call-seq:
# response.should have_rjs(*args, &block)
#
# wrapper for assert_select_rjs
#
# see documentation for assert_select_rjs at http://api.rubyonrails.org/
def have_rjs(*args, &block)
AssertSelect.new(:assert_select_rjs, self, *args, &block)
end
# :call-seq:
# response.should send_email(*args, &block)
#
# wrapper for assert_select_email
#
# see documentation for assert_select_email at http://api.rubyonrails.org/
def send_email(*args, &block)
AssertSelect.new(:assert_select_email, self, *args, &block)
end
# wrapper for assert_select_encoded
#
# see documentation for assert_select_encoded at http://api.rubyonrails.org/
def with_encoded(*args, &block)
should AssertSelect.new(:assert_select_encoded, self, *args, &block)
end
end
end
end

View file

@ -0,0 +1,57 @@
module Spec
module Rails
module Matchers
class HaveText #:nodoc:
def initialize(expected)
@expected = expected
end
def matches?(response_or_text)
@actual = response_or_text.respond_to?(:body) ? response_or_text.body : response_or_text
return actual =~ expected if Regexp === expected
return actual == expected unless Regexp === expected
end
def failure_message
"expected #{expected.inspect}, got #{actual.inspect}"
end
def negative_failure_message
"expected not to have text #{expected.inspect}"
end
def to_s
"have text #{expected.inspect}"
end
private
attr_reader :expected
attr_reader :actual
end
# :call-seq:
# response.should have_text(expected)
# response.should_not have_text(expected)
#
# Accepts a String or a Regexp, matching a String using ==
# and a Regexp using =~.
#
# If response_or_text has a #body, then that is used as to match against
# else it uses response_or_text
#
# Use this instead of <tt>response.should have_tag()</tt>
# when you want to match the whole string or whole body
#
# == Examples
#
# response.should have_text("This is the expected text")
def have_text(text)
HaveText.new(text)
end
end
end
end

View file

@ -0,0 +1,54 @@
module Spec
module Rails
module Matchers
class IncludeText #:nodoc:
def initialize(expected)
@expected = expected
end
def matches?(response_or_text)
@actual = response_or_text.respond_to?(:body) ? response_or_text.body : response_or_text
return actual.include?(expected)
end
def failure_message
"expected to find #{expected.inspect} in #{actual.inspect}"
end
def negative_failure_message
"expected not to include text #{expected.inspect}"
end
def to_s
"include text #{expected.inspect}"
end
private
attr_reader :expected
attr_reader :actual
end
# :call-seq:
# response.should include_text(expected)
# response.should_not include_text(expected)
#
# Accepts a String, matching using include?
#
# Use this instead of <tt>response.should have_text()</tt>
# when you either don't know or don't care where on the page
# this text appears.
#
# == Examples
#
# response.should include_text("This text will be in the actual string")
def include_text(text)
IncludeText.new(text)
end
end
end
end

View file

@ -0,0 +1,113 @@
module Spec
module Rails
module Matchers
class RedirectTo #:nodoc:
def initialize(request, expected)
@expected = expected
@request = request
end
def matches?(response)
@redirected = response.redirect?
@actual = response.redirect_url
return false unless @redirected
if @expected.instance_of? Hash
return false unless @actual =~ %r{^\w+://#{@request.host}}
return false unless actual_redirect_to_valid_route
return actual_hash == expected_hash
else
return @actual == expected_url
end
end
def actual_hash
hash_from_url @actual
end
def expected_hash
hash_from_url expected_url
end
def actual_redirect_to_valid_route
actual_hash
end
def hash_from_url(url)
query_hash(url).merge(path_hash(url)).with_indifferent_access
end
def path_hash(url)
path = url.sub(%r{^\w+://#{@request.host}(?::\d+)?}, "").split("?", 2)[0]
ActionController::Routing::Routes.recognize_path path
end
def query_hash(url)
query = url.split("?", 2)[1] || ""
QueryParameterParser.parse_query_parameters(query, @request)
end
def expected_url
case @expected
when Hash
return ActionController::UrlRewriter.new(@request, {}).rewrite(@expected)
when :back
return @request.env['HTTP_REFERER']
when %r{^\w+://.*}
return @expected
else
return "http://#{@request.host}" + (@expected.split('')[0] == '/' ? '' : '/') + @expected
end
end
def failure_message
if @redirected
return %Q{expected redirect to #{@expected.inspect}, got redirect to #{@actual.inspect}}
else
return %Q{expected redirect to #{@expected.inspect}, got no redirect}
end
end
def negative_failure_message
return %Q{expected not to be redirected to #{@expected.inspect}, but was} if @redirected
end
def description
"redirect to #{@actual.inspect}"
end
class QueryParameterParser
def self.parse_query_parameters(query, request)
if defined?(CGIMethods)
CGIMethods.parse_query_parameters(query)
else
request.class.parse_query_parameters(query)
end
end
end
end
# :call-seq:
# response.should redirect_to(url)
# response.should redirect_to(:action => action_name)
# response.should redirect_to(:controller => controller_name, :action => action_name)
# response.should_not redirect_to(url)
# response.should_not redirect_to(:action => action_name)
# response.should_not redirect_to(:controller => controller_name, :action => action_name)
#
# Passes if the response is a redirect to the url, action or controller/action.
# Useful in controller specs (integration or isolation mode).
#
# == Examples
#
# response.should redirect_to("path/to/action")
# response.should redirect_to("http://test.host/path/to/action")
# response.should redirect_to(:action => 'list')
def redirect_to(opts)
RedirectTo.new(request, opts)
end
end
end
end

View file

@ -0,0 +1,70 @@
module Spec
module Rails
module Matchers
class RenderTemplate #:nodoc:
def initialize(expected, controller)
@controller = controller
@expected = expected
end
def matches?(response)
@actual = response.rendered_file
full_path(@actual) == full_path(@expected)
end
def failure_message
"expected #{@expected.inspect}, got #{@actual.inspect}"
end
def negative_failure_message
"expected not to render #{@expected.inspect}, but did"
end
def description
"render template #{@expected.inspect}"
end
private
def full_path(path)
return nil if path.nil?
path.include?('/') ? path : "#{@controller.class.to_s.underscore.gsub('_controller','')}/#{path}"
end
end
# :call-seq:
# response.should render_template(path)
# response.should_not render_template(path)
#
# Passes if the specified template is rendered by the response.
# Useful in controller specs (integration or isolation mode).
#
# <code>path</code> can include the controller path or not. It
# can also include an optional extension (no extension assumes .rhtml).
#
# Note that partials must be spelled with the preceding underscore.
#
# == Examples
#
# response.should render_template('list')
# response.should render_template('same_controller/list')
# response.should render_template('other_controller/list')
#
# #rjs
# response.should render_template('list.rjs')
# response.should render_template('same_controller/list.rjs')
# response.should render_template('other_controller/list.rjs')
#
# #partials
# response.should render_template('_a_partial')
# response.should render_template('same_controller/_a_partial')
# response.should render_template('other_controller/_a_partial')
def render_template(path)
RenderTemplate.new(path.to_s, @controller)
end
end
end
end

View file

@ -0,0 +1,117 @@
module Spec
module Rails
class IllegalDataAccessException < StandardError; end
module Mocks
# Creates a mock object instance for a +model_class+ with common
# methods stubbed out. Additional methods may be easily stubbed (via
# add_stubs) if +stubs+ is passed.
def mock_model(model_class, options_and_stubs = {})
id = next_id
options_and_stubs.reverse_merge!({
:id => id,
:to_param => id.to_s,
:new_record? => false,
:errors => stub("errors", :count => 0)
})
m = mock("#{model_class.name}_#{options_and_stubs[:id]}", options_and_stubs)
m.send(:__mock_proxy).instance_eval <<-CODE
def @target.is_a?(other)
#{model_class}.ancestors.include?(other)
end
def @target.kind_of?(other)
#{model_class}.ancestors.include?(other)
end
def @target.instance_of?(other)
other == #{model_class}
end
def @target.class
#{model_class}
end
CODE
yield m if block_given?
m
end
module ModelStubber
def connection
raise Spec::Rails::IllegalDataAccessException.new("stubbed models are not allowed to access the database")
end
def new_record?
id.nil?
end
def as_new_record
self.id = nil
self
end
end
# :call-seq:
# stub_model(Model)
# stub_model(Model).as_new_record
# stub_model(Model, hash_of_stubs)
#
# Creates an instance of +Model+ that is prohibited from accessing the
# database. For each key in +hash_of_stubs+, if the model has a
# matching attribute (determined by asking it, which it answers based
# on schema.rb) are simply assigned the submitted values. If the model
# does not have a matching attribute, the key/value pair is assigned
# as a stub return value using RSpec's mocking/stubbing framework.
#
# new_record? is overridden to return the result of id.nil? This means
# that by default new_record? will return false. If you want the
# object to behave as a new record, sending it +as_new_record+ will
# set the id to nil. You can also explicitly set :id => nil, in which
# case new_record? will return true, but using +as_new_record+ makes
# the example a bit more descriptive.
#
# While you can use stub_model in any example (model, view,
# controller, helper), it is especially useful in view examples,
# which are inherently more state-based than interaction-based.
#
# == Examples
#
# stub_model(Person)
# stub_model(Person).as_new_record
# stub_model(Person, :id => 37)
# stub_model(Person) do |person|
# model.first_name = "David"
# end
def stub_model(model_class, stubs = {})
stubs = {:id => next_id}.merge(stubs)
returning model_class.new do |model|
model.id = stubs.delete(:id)
model.extend ModelStubber
stubs.each do |k,v|
if model.has_attribute?(k)
model[k] = stubs.delete(k)
end
end
add_stubs(model, stubs)
yield model if block_given?
end
end
#--
# TODO - Shouldn't this just be an extension of stub! ??
# - object.stub!(:method => return_value, :method2 => return_value2, :etc => etc)
#++
# Stubs methods on +object+ (if +object+ is a symbol or string a new mock
# with that name will be created). +stubs+ is a Hash of <tt>method=>value</tt>
def add_stubs(object, stubs = {}) #:nodoc:
m = [String, Symbol].index(object.class) ? mock(object.to_s) : object
stubs.each {|k,v| m.stub!(k).and_return(v)}
m
end
private
@@model_id = 1000
def next_id
@@model_id += 1
end
end
end
end

View file

@ -0,0 +1,71 @@
# WARNING - THIS IS PURELY EXPERIMENTAL AT THIS POINT
# Courtesy of Brian Takita and Yurii Rashkovskii
$:.unshift File.join(File.dirname(__FILE__), *%w[.. .. .. .. rspec lib])
if defined?(ActiveRecord::Base)
require 'test_help'
else
require 'action_controller/test_process'
require 'action_controller/integration'
end
require 'test/unit/testresult'
require 'spec'
require 'spec/rails'
Test::Unit.run = true
ActionController::Integration::Session.send(:include, Spec::Matchers)
ActionController::Integration::Session.send(:include, Spec::Rails::Matchers)
class RailsStory < ActionController::IntegrationTest
if defined?(ActiveRecord::Base)
self.use_transactional_fixtures = true
else
def self.fixture_table_names; []; end # Workaround for projects that don't use ActiveRecord
end
def initialize #:nodoc:
# TODO - eliminate this hack, which is here to stop
# Rails Stories from dumping the example summary.
Spec::Runner::Options.class_eval do
def examples_should_be_run?
false
end
end
@_result = Test::Unit::TestResult.new
end
end
class ActiveRecordSafetyListener
include Singleton
def scenario_started(*args)
if defined?(ActiveRecord::Base)
ActiveRecord::Base.send :increment_open_transactions unless Rails::VERSION::STRING == "1.1.6"
ActiveRecord::Base.connection.begin_db_transaction
end
end
def scenario_succeeded(*args)
if defined?(ActiveRecord::Base)
ActiveRecord::Base.connection.rollback_db_transaction
ActiveRecord::Base.send :decrement_open_transactions unless Rails::VERSION::STRING == "1.1.6"
end
end
alias :scenario_pending :scenario_succeeded
alias :scenario_failed :scenario_succeeded
end
class Spec::Story::Runner::ScenarioRunner
def initialize
@listeners = [ActiveRecordSafetyListener.instance]
end
end
class Spec::Story::GivenScenario
def perform(instance, name = nil)
scenario = Spec::Story::Runner::StoryRunner.scenario_from_current_story @name
runner = Spec::Story::Runner::ScenarioRunner.new
runner.instance_variable_set(:@listeners,[])
runner.run(scenario, instance)
end
end

View file

@ -0,0 +1,23 @@
module Spec
module Rails
module VERSION #:nodoc:
BUILD_TIME_UTC = 20080615141040
end
end
end
# Verify that the plugin has the same revision as RSpec
if Spec::Rails::VERSION::BUILD_TIME_UTC != Spec::VERSION::BUILD_TIME_UTC
raise <<-EOF
############################################################################
Your RSpec on Rails plugin is incompatible with your installed RSpec.
RSpec : #{Spec::VERSION::BUILD_TIME_UTC}
RSpec on Rails : #{Spec::Rails::VERSION::BUILD_TIME_UTC}
Make sure your RSpec on Rails plugin is compatible with your RSpec gem.
See http://rspec.rubyforge.org/documentation/rails/install.html for details.
############################################################################
EOF
end

View file

@ -0,0 +1,36 @@
require File.dirname(__FILE__) + '/../../spec_helper'
require File.join(File.dirname(__FILE__), *%w[.. .. .. lib autotest rails_rspec])
require File.join(File.dirname(__FILE__), *%w[.. .. .. .. rspec spec autotest_matchers])
describe Autotest::RailsRspec, "file mapping" do
before(:each) do
@autotest = Autotest::RailsRspec.new
@autotest.hook :initialize
end
it "should map model example to model" do
@autotest.should map_specs(['spec/models/thing_spec.rb']).
to('app/models/thing.rb')
end
it "should map controller example to controller" do
@autotest.should map_specs(['spec/controllers/things_controller_spec.rb']).
to('app/controllers/things_controller.rb')
end
it "should map view.rhtml" do
@autotest.should map_specs(['spec/views/things/index.rhtml_spec.rb']).
to('app/views/things/index.rhtml')
end
it "should map view.rhtml with underscores in example filename" do
@autotest.should map_specs(['spec/views/things/index_rhtml_spec.rb']).
to('app/views/things/index.rhtml')
end
it "should map view.html.erb" do
@autotest.should map_specs(['spec/views/things/index.html.erb_spec.rb']).
to('app/views/things/index.html.erb')
end
end

View file

@ -0,0 +1,8 @@
require File.dirname(__FILE__) + '/../../spec_helper'
require File.join(File.dirname(__FILE__), "..", "..", "..", "lib", "autotest", "rails_rspec")
describe Autotest::RailsRspec do
it "should provide the correct spec_command" do
Autotest::RailsRspec.new.spec_command.should == "script/spec"
end
end

View file

@ -0,0 +1,60 @@
require File.dirname(__FILE__) + '/../../spec_helper'
describe "AssignsHashProxy" do
before(:each) do
@object = Object.new
@assigns = Hash.new
@object.stub!(:assigns).and_return(@assigns)
@proxy = Spec::Rails::Example::AssignsHashProxy.new(@object)
end
it "has [] accessor" do
@proxy['foo'] = 'bar'
@assigns['foo'].should == 'bar'
@proxy['foo'].should == 'bar'
end
it "works for symbol key" do
@assigns[:foo] = 2
@proxy[:foo].should == 2
end
it "checks for string key before symbol key" do
@assigns['foo'] = false
@assigns[:foo] = 2
@proxy[:foo].should == false
end
it "each method iterates through each element like a Hash" do
values = {
'foo' => 1,
'bar' => 2,
'baz' => 3
}
@proxy['foo'] = values['foo']
@proxy['bar'] = values['bar']
@proxy['baz'] = values['baz']
@proxy.each do |key, value|
key.should == key
value.should == values[key]
end
end
it "delete method deletes the element of passed in key" do
@proxy['foo'] = 'bar'
@proxy.delete('foo').should == 'bar'
@proxy['foo'].should be_nil
end
it "has_key? detects the presence of a key" do
@proxy['foo'] = 'bar'
@proxy.has_key?('foo').should == true
@proxy.has_key?('bar').should == false
end
it "should sets an instance var" do
@proxy['foo'] = 'bar'
@object.instance_eval { @foo }.should == 'bar'
end
end

View file

@ -0,0 +1,83 @@
require File.dirname(__FILE__) + '/../../spec_helper'
module Spec
module Example
describe Configuration, :shared => true do
before(:each) { @config = Configuration.new }
end
describe Configuration, "#use_transactional_fixtures" do
it_should_behave_like "Spec::Example::Configuration"
it "should return Test::Unit::TestCase.use_transactional_fixtures" do
@config.use_transactional_fixtures.should == Test::Unit::TestCase.use_transactional_fixtures
end
it "should set Test::Unit::TestCase.use_transactional_fixtures to false" do
Configuration::EXAMPLE_GROUP_CLASSES.each do |example_group|
example_group.should_receive(:use_transactional_fixtures=).with(false)
end
@config.use_transactional_fixtures = false
end
it "should set Test::Unit::TestCase.use_transactional_fixtures to true" do
Configuration::EXAMPLE_GROUP_CLASSES.each do |example_group|
example_group.should_receive(:use_transactional_fixtures=).with(true)
end
@config.use_transactional_fixtures = true
end
end
describe Configuration, "#use_instantiated_fixtures" do
it_should_behave_like "Spec::Example::Configuration"
it "should return Test::Unit::TestCase.use_transactional_fixtures" do
@config.use_instantiated_fixtures.should == Test::Unit::TestCase.use_instantiated_fixtures
end
it "should set Test::Unit::TestCase.use_instantiated_fixtures to false" do
Configuration::EXAMPLE_GROUP_CLASSES.each do |example_group|
example_group.should_receive(:use_instantiated_fixtures=).with(false)
end
@config.use_instantiated_fixtures = false
end
it "should set Test::Unit::TestCase.use_instantiated_fixtures to true" do
Configuration::EXAMPLE_GROUP_CLASSES.each do |example_group|
example_group.should_receive(:use_instantiated_fixtures=).with(true)
end
@config.use_instantiated_fixtures = true
end
end
describe Configuration, "#fixture_path" do
it_should_behave_like "Spec::Example::Configuration"
it "should default to RAILS_ROOT + '/spec/fixtures'" do
@config.fixture_path.should == RAILS_ROOT + '/spec/fixtures'
Configuration::EXAMPLE_GROUP_CLASSES.each do |example_group|
example_group.fixture_path.should == RAILS_ROOT + '/spec/fixtures'
end
end
it "should set fixture_path" do
@config.fixture_path = "/new/path"
@config.fixture_path.should == "/new/path"
Configuration::EXAMPLE_GROUP_CLASSES.each do |example_group|
example_group.fixture_path.should == "/new/path"
end
end
end
describe Configuration, "#global_fixtures" do
it_should_behave_like "Spec::Example::Configuration"
it "should set fixtures on TestCase" do
Configuration::EXAMPLE_GROUP_CLASSES.each do |example_group|
example_group.should_receive(:fixtures).with(:blah)
end
@config.global_fixtures = [:blah]
end
end
end
end

View file

@ -0,0 +1,62 @@
require File.dirname(__FILE__) + '/../../spec_helper'
require 'controller_spec_controller'
describe "a controller spec running in isolation mode", :type => :controller do
controller_name :controller_spec
it "should not care if the template doesn't exist" do
get 'some_action'
response.should be_success
response.should render_template("template/that/does/not/actually/exist")
end
it "should not care if the template has errors" do
get 'action_with_errors_in_template'
response.should be_success
response.should render_template("action_with_errors_in_template")
end
end
describe "a controller spec running in integration mode", :type => :controller do
controller_name :controller_spec
integrate_views
before(:each) do
controller.class.send(:define_method, :rescue_action) { |e| raise e }
end
it "should render a template" do
get 'action_with_template'
response.should be_success
response.should have_tag('div', 'This is action_with_template.rhtml')
end
it "should choke if the template doesn't exist" do
error = defined?(ActionController::MissingTemplate) ? ActionController::MissingTemplate : ActionView::MissingTemplate
lambda { get 'some_action' }.should raise_error(error)
response.should_not be_success
end
it "should choke if the template has errors" do
lambda { get 'action_with_errors_in_template' }.should raise_error(ActionView::TemplateError)
response.should_not be_success
end
describe "nested" do
it "should render a template" do
get 'action_with_template'
response.should be_success
response.should have_tag('div', 'This is action_with_template.rhtml')
end
describe "with integrate_views turned off" do
integrate_views false
it "should not care if the template doesn't exist" do
get 'some_action'
response.should be_success
response.should render_template("template/that/does/not/actually/exist")
end
end
end
end

View file

@ -0,0 +1,206 @@
require File.dirname(__FILE__) + '/../../spec_helper'
require 'controller_spec_controller'
['integration', 'isolation'].each do |mode|
describe "A controller example running in #{mode} mode", :type => :controller do
controller_name :controller_spec
integrate_views if mode == 'integration'
it "should provide controller.session as session" do
get 'action_with_template'
session.should equal(controller.session)
end
it "should provide the same session object before and after the action" do
session_before = session
get 'action_with_template'
session.should equal(session_before)
end
it "should keep the same data in the session before and after the action" do
session[:foo] = :bar
get 'action_with_template'
session[:foo].should == :bar
end
it "should ensure controller.session is NOT nil before the action" do
controller.session.should_not be_nil
get 'action_with_template'
end
it "should ensure controller.session is NOT nil after the action" do
get 'action_with_template'
controller.session.should_not be_nil
end
it "should allow specifying a partial with partial name only" do
get 'action_with_partial'
response.should render_template("_partial")
end
it "should allow specifying a partial with expect_render" do
controller.expect_render(:partial => "controller_spec/partial")
get 'action_with_partial'
end
it "should allow specifying a partial with expect_render with object" do
controller.expect_render(:partial => "controller_spec/partial", :object => "something")
get 'action_with_partial_with_object', :thing => "something"
end
it "should allow specifying a partial with expect_render with locals" do
controller.expect_render(:partial => "controller_spec/partial", :locals => {:thing => "something"})
get 'action_with_partial_with_locals', :thing => "something"
end
it "should yield to render :update" do
template = stub("template")
controller.expect_render(:update).and_yield(template)
template.should_receive(:replace).with(:bottom, "replace_me", :partial => "non_existent_partial")
get 'action_with_render_update'
end
it "should allow a path relative to RAILS_ROOT/app/views/ when specifying a partial" do
get 'action_with_partial'
response.should render_template("controller_spec/_partial")
end
it "should provide access to flash" do
get 'action_which_sets_flash'
flash[:flash_key].should == "flash value"
end
it "should provide access to flash values set after a session reset" do
get 'action_setting_flash_after_session_reset'
flash[:after_reset].should == "available"
end
it "should not provide access to flash values set before a session reset" do
get 'action_setting_flash_before_session_reset'
flash[:before_reset].should_not == "available"
end
it "should provide access to session" do
session[:session_key] = "session value"
lambda do
get 'action_which_gets_session', :expected => "session value"
end.should_not raise_error
end
it "should support custom routes" do
route_for(:controller => "custom_route_spec", :action => "custom_route").should == "/custom_route"
end
it "should support existing routes" do
route_for(:controller => "controller_spec", :action => "some_action").should == "/controller_spec/some_action"
end
it "should generate params for custom routes" do
params_from(:get, '/custom_route').should == {:controller => "custom_route_spec", :action => "custom_route"}
end
it "should generate params for existing routes" do
params_from(:get, '/controller_spec/some_action').should == {:controller => "controller_spec", :action => "some_action"}
end
it "should expose instance vars through the assigns hash" do
get 'action_setting_the_assigns_hash'
assigns[:indirect_assigns_key].should == :indirect_assigns_key_value
end
it "should expose the assigns hash directly" do
get 'action_setting_the_assigns_hash'
assigns[:direct_assigns_key].should == :direct_assigns_key_value
end
it "should complain when calling should_receive(:render) on the controller" do
lambda {
controller.should_receive(:render)
}.should raise_error(RuntimeError, /should_receive\(:render\) has been disabled/)
end
it "should complain when calling stub!(:render) on the controller" do
controller.extend Spec::Mocks::Methods
lambda {
controller.stub!(:render)
}.should raise_error(RuntimeError, /stub!\(:render\) has been disabled/)
end
it "should NOT complain when calling should_receive with arguments other than :render" do
controller.should_receive(:anything_besides_render)
lambda {
controller.rspec_verify
}.should raise_error(Exception, /expected :anything_besides_render/)
end
end
describe "Given a controller spec for RedirectSpecController running in #{mode} mode", :type => :controller do
controller_name :redirect_spec
integrate_views if mode == 'integration'
it "a redirect should ignore the absence of a template" do
get 'action_with_redirect_to_somewhere'
response.should be_redirect
response.redirect_url.should == "http://test.host/redirect_spec/somewhere"
response.should redirect_to("http://test.host/redirect_spec/somewhere")
end
it "a call to response.should redirect_to should fail if no redirect" do
get 'action_with_no_redirect'
lambda {
response.redirect?.should be_true
}.should fail
lambda {
response.should redirect_to("http://test.host/redirect_spec/somewhere")
}.should fail_with("expected redirect to \"http://test.host/redirect_spec/somewhere\", got no redirect")
end
end
describe "Given a controller spec running in #{mode} mode" do
example_group = describe "A controller spec"
# , :type => :controller do
# integrate_views if mode == 'integration'
it "a spec in a context without controller_name set should fail with a useful warning" do
pending("need a new way to deal with examples that should_raise")
# ,
# :should_raise => [
# Spec::Expectations::ExpectationNotMetError,
# /You have to declare the controller name in controller specs/
# ] do
end
end
end
describe ControllerSpecController, :type => :controller do
it "should not require naming the controller if describe is passed a type" do
end
end
describe "A controller spec with controller_name set", :type => :controller do
controller_name :controller_spec
describe "nested" do
it "should inherit the controller name" do
get 'action_with_template'
response.should be_success
end
end
end
module Spec
module Rails
module Example
describe ControllerExampleGroup do
it "should clear its name from the description" do
group = describe("foo", :type => :controller) do
$nested_group = describe("bar") do
end
end
group.description.to_s.should == "foo"
$nested_group.description.to_s.should == "foo bar"
end
end
end
end
end

View file

@ -0,0 +1,112 @@
require File.dirname(__FILE__) + '/../../spec_helper'
module Spec
module Example
describe ExampleGroupFactory do
it "should return a ModelExampleGroup when given :type => :model" do
example_group = Spec::Example::ExampleGroupFactory.create_example_group(
"name", :type => :model
) {}
example_group.superclass.should == Spec::Rails::Example::ModelExampleGroup
end
it "should return a ModelExampleGroup when given :spec_path => '/blah/spec/models/'" do
example_group = Spec::Example::ExampleGroupFactory.create_example_group(
"name", :spec_path => '/blah/spec/models/blah.rb'
) {}
example_group.superclass.should == Spec::Rails::Example::ModelExampleGroup
end
it "should return a ModelExampleGroup when given :spec_path => '\\blah\\spec\\models\\' (windows format)" do
example_group = Spec::Example::ExampleGroupFactory.create_example_group(
"name", :spec_path => '\\blah\\spec\\models\\blah.rb'
) {}
example_group.superclass.should == Spec::Rails::Example::ModelExampleGroup
end
it "should return a RailsExampleGroup when given :spec_path => '/blah/spec/foo/' (anything other than controllers, views and helpers)" do
example_group = Spec::Example::ExampleGroupFactory.create_example_group(
"name", :spec_path => '/blah/spec/foo/blah.rb'
) {}
example_group.superclass.should == Spec::Rails::Example::RailsExampleGroup
end
it "should return a RailsExampleGroup when given :spec_path => '\\blah\\spec\\foo\\' (windows format) (anything other than controllers, views and helpers)" do
example_group = Spec::Example::ExampleGroupFactory.create_example_group(
"name", :spec_path => '\\blah\\spec\\foo\\blah.rb'
) {}
example_group.superclass.should == Spec::Rails::Example::RailsExampleGroup
end
it "should return a ViewExampleGroup when given :type => :model" do
example_group = Spec::Example::ExampleGroupFactory.create_example_group(
"name", :type => :view
) {}
example_group.superclass.should == Spec::Rails::Example::ViewExampleGroup
end
it "should return a ViewExampleGroup when given :spec_path => '/blah/spec/views/'" do
example_group = Spec::Example::ExampleGroupFactory.create_example_group(
"name", :spec_path => '/blah/spec/views/blah.rb'
) {}
example_group.superclass.should == Spec::Rails::Example::ViewExampleGroup
end
it "should return a ModelExampleGroup when given :spec_path => '\\blah\\spec\\views\\' (windows format)" do
example_group = Spec::Example::ExampleGroupFactory.create_example_group(
"name", :spec_path => '\\blah\\spec\\views\\blah.rb'
) {}
example_group.superclass.should == Spec::Rails::Example::ViewExampleGroup
end
it "should return a HelperExampleGroup when given :type => :helper" do
example_group = Spec::Example::ExampleGroupFactory.create_example_group(
"name", :type => :helper
) {}
example_group.superclass.should == Spec::Rails::Example::HelperExampleGroup
end
it "should return a HelperExampleGroup when given :spec_path => '/blah/spec/helpers/'" do
example_group = Spec::Example::ExampleGroupFactory.create_example_group(
"name", :spec_path => '/blah/spec/helpers/blah.rb'
) {}
example_group.superclass.should == Spec::Rails::Example::HelperExampleGroup
end
it "should return a ModelExampleGroup when given :spec_path => '\\blah\\spec\\helpers\\' (windows format)" do
example_group = Spec::Example::ExampleGroupFactory.create_example_group(
"name", :spec_path => '\\blah\\spec\\helpers\\blah.rb'
) {}
example_group.superclass.should == Spec::Rails::Example::HelperExampleGroup
end
it "should return a ControllerExampleGroup when given :type => :controller" do
example_group = Spec::Example::ExampleGroupFactory.create_example_group(
"name", :type => :controller
) {}
example_group.superclass.should == Spec::Rails::Example::ControllerExampleGroup
end
it "should return a ControllerExampleGroup when given :spec_path => '/blah/spec/controllers/'" do
example_group = Spec::Example::ExampleGroupFactory.create_example_group(
"name", :spec_path => '/blah/spec/controllers/blah.rb'
) {}
example_group.superclass.should == Spec::Rails::Example::ControllerExampleGroup
end
it "should return a ModelExampleGroup when given :spec_path => '\\blah\\spec\\controllers\\' (windows format)" do
example_group = Spec::Example::ExampleGroupFactory.create_example_group(
"name", :spec_path => '\\blah\\spec\\controllers\\blah.rb'
) {}
example_group.superclass.should == Spec::Rails::Example::ControllerExampleGroup
end
it "should favor the :type over the :spec_path" do
example_group = Spec::Example::ExampleGroupFactory.create_example_group(
"name", :spec_path => '/blah/spec/models/blah.rb', :type => :controller
) {}
example_group.superclass.should == Spec::Rails::Example::ControllerExampleGroup
end
end
end
end

View file

@ -0,0 +1,161 @@
require File.dirname(__FILE__) + '/../../spec_helper'
Spec::Runner.configuration.global_fixtures = :people
describe ExplicitHelper, :type => :helper do
include ExplicitHelper
it "should not require naming the helper if describe is passed a type" do
method_in_explicit_helper.should match(/text from a method/)
helper.method_in_explicit_helper.should match(/text from a method/)
end
end
module Spec
module Rails
module Example
describe HelperExampleGroup, :type => :helper do
helper_name :explicit
it "DEPRECATED should have direct access to methods defined in helpers" do
method_in_explicit_helper.should =~ /text from a method/
end
it "should expose the helper with the #helper method" do
helper.method_in_explicit_helper.should =~ /text from a method/
end
it "should have access to named routes" do
rspec_on_rails_specs_url.should == "http://test.host/rspec_on_rails_specs"
rspec_on_rails_specs_path.should == "/rspec_on_rails_specs"
helper.named_url.should == "http://test.host/rspec_on_rails_specs"
helper.named_path.should == "/rspec_on_rails_specs"
end
it "should fail if the helper method deson't exist" do
lambda { non_existent_helper_method }.should raise_error(NameError)
lambda { helper.non_existent_helper_method }.should raise_error(NameError)
end
it "should have access to session" do
session[:foo] = 'bar'
session_foo.should == 'bar'
helper.session_foo.should == 'bar'
end
it "should have access to params" do
params[:foo] = 'bar'
params_foo.should == 'bar'
helper.params_foo.should == 'bar'
end
it "should have access to request" do
request.stub!(:thing).and_return('bar')
request_thing.should == 'bar'
helper.request_thing.should == 'bar'
end
it "should have access to flash" do
flash[:thing] = 'camera'
flash_thing.should == 'camera'
helper.flash_thing.should == 'camera'
end
end
describe HelperExampleGroup, "#eval_erb", :type => :helper do
helper_name :explicit
it "should support methods that accept blocks" do
eval_erb("<% prepend 'foo' do %>bar<% end %>").should == "foobar"
end
end
describe HelperExampleGroup, ".fixtures", :type => :helper do
helper_name :explicit
fixtures :animals
it "should load fixtures" do
pig = animals(:pig)
pig.class.should == Animal
end
it "should load global fixtures" do
lachie = people(:lachie)
lachie.class.should == Person
end
end
describe "methods from standard helpers", :type => :helper do
helper_name :explicit
it "should be exposed to the helper" do
helper.link_to("Foo","http://bar").should have_tag("a")
end
end
describe HelperExampleGroup, "included modules", :type => :helper do
helpers = [
ActionView::Helpers::ActiveRecordHelper,
ActionView::Helpers::AssetTagHelper,
ActionView::Helpers::BenchmarkHelper,
ActionView::Helpers::CacheHelper,
ActionView::Helpers::CaptureHelper,
ActionView::Helpers::DateHelper,
ActionView::Helpers::DebugHelper,
ActionView::Helpers::FormHelper,
ActionView::Helpers::FormOptionsHelper,
ActionView::Helpers::FormTagHelper,
ActionView::Helpers::JavaScriptHelper,
ActionView::Helpers::NumberHelper,
ActionView::Helpers::PrototypeHelper,
ActionView::Helpers::ScriptaculousHelper,
ActionView::Helpers::TagHelper,
ActionView::Helpers::TextHelper,
ActionView::Helpers::UrlHelper
]
helpers << ActionView::Helpers::PaginationHelper rescue nil #removed for 2.0
helpers << ActionView::Helpers::JavaScriptMacrosHelper rescue nil #removed for 2.0
helpers.each do |helper_module|
it "should include #{helper_module}" do
self.class.ancestors.should include(helper_module)
helper.class.ancestors.should include(helper_module)
end
end
end
# TODO: BT - Helper Examples should proxy method_missing to a Rails View instance.
# When that is done, remove this method
describe HelperExampleGroup, "#protect_against_forgery?", :type => :helper do
it "should return false" do
protect_against_forgery?.should be_false
helper.protect_against_forgery?.should be_false
end
end
end
end
end
module Bug11223
# see http://rubyforge.org/tracker/index.php?func=detail&aid=11223&group_id=797&atid=3149
describe 'Accessing flash from helper spec', :type => :helper do
it 'should not raise an error' do
lambda { flash['test'] }.should_not raise_error
end
end
end
module Spec
module Rails
module Example
describe HelperExampleGroup do
it "should clear its name from the description" do
group = describe("foo", :type => :helper) do
$nested_group = describe("bar") do
end
end
group.description.to_s.should == "foo"
$nested_group.description.to_s.should == "foo bar"
end
end
end
end
end

View file

@ -0,0 +1,18 @@
require File.dirname(__FILE__) + '/../../spec_helper'
module Spec
module Rails
module Example
describe ModelExampleGroup do
it "should clear its name from the description" do
group = describe("foo", :type => :model) do
$nested_group = describe("bar") do
end
end
group.description.to_s.should == "foo"
$nested_group.description.to_s.should == "foo bar"
end
end
end
end
end

View file

@ -0,0 +1,16 @@
require File.dirname(__FILE__) + '/../../spec_helper'
describe "A shared view example_group", :shared => true do
it "should have some tag with some text" do
response.should have_tag('div', 'This is text from a method in the ViewSpecHelper')
end
end
describe "A view example_group", :type => :view do
it_should_behave_like "A shared view example_group"
before(:each) do
render "view_spec/implicit_helper"
end
end

View file

@ -0,0 +1,33 @@
require File.dirname(__FILE__) + '/../../spec_helper'
describe "assert_equal", :shared => true do
it "like assert_equal" do
assert_equal 1, 1
lambda {
assert_equal 1, 2
}.should raise_error(Test::Unit::AssertionFailedError)
end
end
describe "A model spec should be able to access 'test/unit' assertions", :type => :model do
it_should_behave_like "assert_equal"
end
describe "A view spec should be able to access 'test/unit' assertions", :type => :view do
it_should_behave_like "assert_equal"
end
describe "A helper spec should be able to access 'test/unit' assertions", :type => :helper do
it_should_behave_like "assert_equal"
end
describe "A controller spec with integrated views should be able to access 'test/unit' assertions", :type => :controller do
controller_name :controller_spec
integrate_views
it_should_behave_like "assert_equal"
end
describe "A controller spec should be able to access 'test/unit' assertions", :type => :controller do
controller_name :controller_spec
it_should_behave_like "assert_equal"
end

View file

@ -0,0 +1,272 @@
require File.dirname(__FILE__) + '/../../spec_helper'
describe "A template with an implicit helper", :type => :view do
before(:each) do
render "view_spec/implicit_helper"
end
it "should include the helper" do
response.should have_tag('div', :content => "This is text from a method in the ViewSpecHelper")
end
it "should include the application helper" do
response.should have_tag('div', :content => "This is text from a method in the ApplicationHelper")
end
it "should have access to named routes" do
rspec_on_rails_specs_url.should == "http://test.host/rspec_on_rails_specs"
rspec_on_rails_specs_path.should == "/rspec_on_rails_specs"
end
end
describe "A template requiring an explicit helper", :type => :view do
before(:each) do
render "view_spec/explicit_helper", :helper => 'explicit'
end
it "should include the helper if specified" do
response.should have_tag('div', :content => "This is text from a method in the ExplicitHelper")
end
it "should include the application helper" do
response.should have_tag('div', :content => "This is text from a method in the ApplicationHelper")
end
end
describe "A template requiring multiple explicit helpers", :type => :view do
before(:each) do
render "view_spec/multiple_helpers", :helpers => ['explicit', 'more_explicit']
end
it "should include all specified helpers" do
response.should have_tag('div', :content => "This is text from a method in the ExplicitHelper")
response.should have_tag('div', :content => "This is text from a method in the MoreExplicitHelper")
end
it "should include the application helper" do
response.should have_tag('div', :content => "This is text from a method in the ApplicationHelper")
end
end
describe "Message Expectations on helper methods", :type => :view do
it "should work" do
template.should_receive(:method_in_plugin_application_helper).and_return('alternate message 1')
render "view_spec/implicit_helper"
response.body.should =~ /alternate message 1/
end
it "should work twice" do
template.should_receive(:method_in_plugin_application_helper).and_return('alternate message 2')
render "view_spec/implicit_helper"
response.body.should =~ /alternate message 2/
end
end
describe "A template that includes a partial", :type => :view do
def render!
render "view_spec/template_with_partial"
end
it "should render the enclosing template" do
render!
response.should have_tag('div', "method_in_partial in ViewSpecHelper")
end
it "should render the partial" do
render!
response.should have_tag('div', "method_in_template_with_partial in ViewSpecHelper")
end
it "should include the application helper" do
render!
response.should have_tag('div', "This is text from a method in the ApplicationHelper")
end
it "should pass expect_render with the right partial" do
template.expect_render(:partial => 'partial')
render!
template.verify_rendered
end
it "should fail expect_render with the wrong partial" do
template.expect_render(:partial => 'non_existent')
render!
begin
template.verify_rendered
rescue Spec::Mocks::MockExpectationError => e
ensure
e.backtrace.find{|line| line =~ /view_spec_spec\.rb\:92/}.should_not be_nil
end
end
it "should pass expect_render when a partial is expected twice and happens twice" do
template.expect_render(:partial => 'partial_used_twice').twice
render!
template.verify_rendered
end
it "should pass expect_render when a partial is expected once and happens twice" do
template.expect_render(:partial => 'partial_used_twice')
render!
begin
template.verify_rendered
rescue Spec::Mocks::MockExpectationError => e
ensure
e.backtrace.find{|line| line =~ /view_spec_spec\.rb\:109/}.should_not be_nil
end
end
it "should fail expect_render with the right partial but wrong options" do
template.expect_render(:partial => 'partial', :locals => {:thing => Object.new})
render!
lambda {template.verify_rendered}.should raise_error(Spec::Mocks::MockExpectationError)
end
end
describe "A partial that includes a partial", :type => :view do
it "should support expect_render with nested partial" do
obj = Object.new
template.expect_render(:partial => 'partial', :object => obj)
render :partial => "view_spec/partial_with_sub_partial", :locals => { :partial => obj }
end
end
describe "A view that includes a partial using :collection and :spacer_template", :type => :view do
it "should render the partial w/ spacer_tamplate" do
render "view_spec/template_with_partial_using_collection"
response.should have_tag('div',/method_in_partial/)
response.should have_tag('div',/ApplicationHelper/)
response.should have_tag('div',/ViewSpecHelper/)
response.should have_tag('hr#spacer')
end
it "should render the partial" do
template.expect_render(:partial => 'partial',
:collection => ['Alice', 'Bob'],
:spacer_template => 'spacer')
render "view_spec/template_with_partial_using_collection"
end
end
describe "A view that includes a partial using an array as partial_path", :type => :view do
before(:each) do
module ActionView::Partials
def render_template_with_partial_with_array_support(partial_path, local_assigns = nil, deprecated_local_assigns = nil)
if partial_path.is_a?(Array)
"Array Partial"
else
render_partial_without_array_support(partial_path, local_assigns, deprecated_local_assigns)
end
end
alias :render_partial_without_array_support :render_partial
alias :render_partial :render_template_with_partial_with_array_support
end
@array = ['Alice', 'Bob']
assigns[:array] = @array
end
after(:each) do
module ActionView::Partials
alias :render_template_with_partial_with_array_support :render_partial
alias :render_partial :render_partial_without_array_support
undef render_template_with_partial_with_array_support
end
end
it "should render have the array passed through to render_partial without modification" do
render "view_spec/template_with_partial_with_array"
response.body.should match(/^Array Partial$/)
end
end
describe "Different types of renders (not :template)", :type => :view do
it "should render partial with local" do
render :partial => "view_spec/partial_with_local_variable", :locals => {:x => "Ender"}
response.should have_tag('div', :content => "Ender")
end
end
describe "A view", :type => :view do
before(:each) do
session[:key] = "session"
params[:key] = "params"
flash[:key] = "flash"
render "view_spec/accessor"
end
it "should have access to session data" do
response.should have_tag("div#session", "session")
end
specify "should have access to params data" do
response.should have_tag("div#params", "params")
end
it "should have access to flash data" do
response.should have_tag("div#flash", "flash")
end
it "should have a controller param" do
response.should have_tag("div#controller", "view_spec")
end
it "should have an action param" do
response.should have_tag("div#action", "accessor")
end
end
describe "A view with a form_tag", :type => :view do
it "should render the right action" do
render "view_spec/entry_form"
response.should have_tag("form[action=?]","/view_spec/entry_form")
end
end
describe "An instantiated ViewExampleGroupController", :type => :view do
before do
render "view_spec/foo/show"
end
it "should return the name of the real controller that it replaces" do
@controller.controller_name.should == 'foo'
end
it "should return the path of the real controller that it replaces" do
@controller.controller_path.should == 'view_spec/foo'
end
end
describe "render :inline => ...", :type => :view do
it "should render ERB right in the spec" do
render :inline => %|<%= text_field_tag('field_name', 'Value') %>|
response.should have_tag("input[type=?][name=?][value=?]","text","field_name","Value")
end
end
module Spec
module Rails
module Example
describe ViewExampleGroup do
it "should clear its name from the description" do
group = describe("foo", :type => :view) do
$nested_group = describe("bar") do
end
end
group.description.to_s.should == "foo"
$nested_group.description.to_s.should == "foo bar"
end
it "should clear ActionView::Base.base_view_path on teardown" do
group = describe("base_view_path_cleared flag", :type => :view) {}
example = group.it{}
ActionView::Base.should_receive(:base_view_path=).with(nil)
group.run_after_each(example)
end
end
end
end
end

View file

@ -0,0 +1,54 @@
require File.dirname(__FILE__) + '/../../spec_helper'
module ActionController
describe "Rescue", "#rescue_action in default mode" do
before(:each) do
@fixture = Object.new
@fixture.extend ActionController::Rescue
class << @fixture
public :rescue_action
end
end
it "should raise the passed in exception so examples fail fast" do
proc {@fixture.rescue_action(RuntimeError.new("Foobar"))}.should raise_error(RuntimeError, "Foobar")
end
end
class RescueOverriddenController < ActionController::Base
def rescue_action(error)
"successfully overridden"
end
end
describe "Rescue", "#rescue_action, when overridden" do
before(:each) do
@fixture = RescueOverriddenController.new
end
it "should do whatever the overridden method does" do
@fixture.rescue_action(RuntimeError.new("Foobar")).should == "successfully overridden"
end
end
class SearchController < ActionController::Base
end
describe "Rescue", "#rescue_action when told to use rails error handling" do
before(:each) do
@controller = SearchController.new
@controller.use_rails_error_handling!
class << @controller
public :rescue_action
end
end
it "should use Rails exception handling" do
exception = RuntimeError.new("The Error")
exception.stub!(:backtrace).and_return(caller)
@controller.should_receive(:rescue_action_locally).with(exception)
@controller.rescue_action(exception)
end
end
end

View file

@ -0,0 +1,48 @@
require File.dirname(__FILE__) + '/../../spec_helper'
require 'spec/mocks/errors'
describe ActionView::Base, "with RSpec extensions:", :type => :view do
describe "expect_render" do
it "should not raise when render has been received" do
template.expect_render(:partial => "name")
template.render :partial => "name"
end
it "should raise when render has NOT been received" do
template.expect_render(:partial => "name")
lambda {
template.verify_rendered
}.should raise_error
end
it "should return something (like a normal mock)" do
template.expect_render(:partial => "name").and_return("Little Johnny")
result = template.render :partial => "name"
result.should == "Little Johnny"
end
end
describe "stub_render" do
it "should not raise when stubbing and render has been received" do
template.stub_render(:partial => "name")
template.render :partial => "name"
end
it "should not raise when stubbing and render has NOT been received" do
template.stub_render(:partial => "name")
end
it "should not raise when stubbing and render has been received with different options" do
template.stub_render(:partial => "name")
template.render :partial => "view_spec/spacer"
end
it "should not raise when stubbing and expecting and render has been received" do
template.stub_render(:partial => "name")
template.expect_render(:partial => "name")
template.render(:partial => "name")
end
end
end

View file

@ -0,0 +1,14 @@
require File.dirname(__FILE__) + '/../../spec_helper'
describe "A model" do
fixtures :things
it "should tell you its required fields" do
Thing.new.should have(1).error_on(:name)
end
it "should tell you how many records it has" do
Thing.should have(:no).records
Thing.create(:name => "THE THING")
Thing.should have(1).record
end
end

View file

@ -0,0 +1,806 @@
require File.dirname(__FILE__) + '/../../spec_helper'
# assert_select plugins for Rails
#
# Copyright (c) 2006 Assaf Arkin, under Creative Commons Attribution and/or MIT License
# Developed for http://co.mments.com
# Code and documention: http://labnotes.org
class AssertSelectController < ActionController::Base
def response=(content)
@content = content
end
#NOTE - this is commented because response is implemented in lib/spec/rails/context/controller
# def response(&block)
# @update = block
# end
#
def html()
render :text=>@content, :layout=>false, :content_type=>Mime::HTML
@content = nil
end
def rjs()
update = @update
render :update do |page|
update.call page
end
@update = nil
end
def xml()
render :text=>@content, :layout=>false, :content_type=>Mime::XML
@content = nil
end
def rescue_action(e)
raise e
end
end
class AssertSelectMailer < ActionMailer::Base
def test(html)
recipients "test <test@test.host>"
from "test@test.host"
subject "Test e-mail"
part :content_type=>"text/html", :body=>html
end
end
module AssertSelectSpecHelpers
def render_html(html)
@controller.response = html
get :html
end
def render_rjs(&block)
clear_response
@controller.response &block
get :rjs
end
def render_xml(xml)
@controller.response = xml
get :xml
end
def first_non_rspec_line_in_backtrace_of(error)
rspec_path = File.join('rspec', 'lib', 'spec')
error.backtrace.reject { |line|
line =~ /#{rspec_path}/
}.first
end
private
# necessary for 1.2.1
def clear_response
render_html("")
end
end
unless defined?(SpecFailed)
SpecFailed = Spec::Expectations::ExpectationNotMetError
end
describe "should have_tag", :type => :controller do
include AssertSelectSpecHelpers
controller_name :assert_select
integrate_views
it "should find specific numbers of elements" do
render_html %Q{<div id="1"></div><div id="2"></div>}
response.should have_tag( "div" )
response.should have_tag("div", 2)
lambda { response.should_not have_tag("div") }.should raise_error(SpecFailed, "should not have tag(\"div\"), but did")
lambda { response.should have_tag("div", 3) }.should raise_error(SpecFailed)
lambda { response.should have_tag("p") }.should raise_error(SpecFailed)
end
it "should expect to find elements when using true" do
render_html %Q{<div id="1"></div><div id="2"></div>}
response.should have_tag( "div", true )
lambda { response.should have_tag( "p", true )}.should raise_error(SpecFailed)
end
it "should expect to not find elements when using false" do
render_html %Q{<div id="1"></div><div id="2"></div>}
response.should have_tag( "p", false )
lambda { response.should have_tag( "div", false )}.should raise_error(SpecFailed)
end
it "should match submitted text using text or regexp" do
render_html %Q{<div id="1">foo</div><div id="2">foo</div>}
response.should have_tag("div", "foo")
response.should have_tag("div", /(foo|bar)/)
response.should have_tag("div", :text=>"foo")
response.should have_tag("div", :text=>/(foo|bar)/)
lambda { response.should have_tag("div", "bar") }.should raise_error(SpecFailed)
lambda { response.should have_tag("div", :text=>"bar") }.should raise_error(SpecFailed)
lambda { response.should have_tag("p", :text=>"foo") }.should raise_error(SpecFailed)
lambda { response.should have_tag("div", /foobar/) }.should raise_error(SpecFailed)
lambda { response.should have_tag("div", :text=>/foobar/) }.should raise_error(SpecFailed)
lambda { response.should have_tag("p", :text=>/foo/) }.should raise_error(SpecFailed)
end
it "should use submitted message" do
render_html %Q{nothing here}
lambda {
response.should have_tag("div", {}, "custom message")
}.should raise_error(SpecFailed, /custom message/)
end
it "should match submitted html" do
render_html %Q{<p>\n<em>"This is <strong>not</strong> a big problem,"</em> he said.\n</p>}
text = "\"This is not a big problem,\" he said."
html = "<em>\"This is <strong>not</strong> a big problem,\"</em> he said."
response.should have_tag("p", text)
lambda { response.should have_tag("p", html) }.should raise_error(SpecFailed)
response.should have_tag("p", :html=>html)
lambda { response.should have_tag("p", :html=>text) }.should raise_error(SpecFailed)
# # No stripping for pre.
render_html %Q{<pre>\n<em>"This is <strong>not</strong> a big problem,"</em> he said.\n</pre>}
text = "\n\"This is not a big problem,\" he said.\n"
html = "\n<em>\"This is <strong>not</strong> a big problem,\"</em> he said.\n"
response.should have_tag("pre", text)
lambda { response.should have_tag("pre", html) }.should raise_error(SpecFailed)
response.should have_tag("pre", :html=>html)
lambda { response.should have_tag("pre", :html=>text) }.should raise_error(SpecFailed)
end
it "should match number of instances" do
render_html %Q{<div id="1">foo</div><div id="2">foo</div>}
response.should have_tag("div", 2)
lambda { response.should have_tag("div", 3) }.should raise_error(SpecFailed)
response.should have_tag("div", 1..2)
lambda { response.should have_tag("div", 3..4) }.should raise_error(SpecFailed)
response.should have_tag("div", :count=>2)
lambda { response.should have_tag("div", :count=>3) }.should raise_error(SpecFailed)
response.should have_tag("div", :minimum=>1)
response.should have_tag("div", :minimum=>2)
lambda { response.should have_tag("div", :minimum=>3) }.should raise_error(SpecFailed)
response.should have_tag("div", :maximum=>2)
response.should have_tag("div", :maximum=>3)
lambda { response.should have_tag("div", :maximum=>1) }.should raise_error(SpecFailed)
response.should have_tag("div", :minimum=>1, :maximum=>2)
lambda { response.should have_tag("div", :minimum=>3, :maximum=>4) }.should raise_error(SpecFailed)
end
it "substitution values" do
render_html %Q{<div id="1">foo</div><div id="2">foo</div><span id="3"></span>}
response.should have_tag("div#?", /\d+/) do |elements| #using do/end
elements.size.should == 2
end
response.should have_tag("div#?", /\d+/) { |elements| #using {}
elements.size.should == 2
}
lambda {
response.should have_tag("div#?", /\d+/) do |elements|
elements.size.should == 3
end
}.should raise_error(SpecFailed, "expected: 3,\n got: 2 (using ==)")
lambda {
response.should have_tag("div#?", /\d+/) { |elements|
elements.size.should == 3
}
}.should raise_error(SpecFailed, "expected: 3,\n got: 2 (using ==)")
response.should have_tag("div#?", /\d+/) do |elements|
elements.size.should == 2
with_tag("#1")
with_tag("#2")
without_tag("#3")
end
end
#added for RSpec
it "nested tags in form" do
render_html %Q{
<form action="test">
<input type="text" name="email">
</form>
<form action="other">
<input type="text" name="other_input">
</form>
}
response.should have_tag("form[action=test]") { |form|
with_tag("input[type=text][name=email]")
}
response.should have_tag("form[action=test]") { |form|
with_tag("input[type=text][name=email]")
}
lambda {
response.should have_tag("form[action=test]") { |form|
with_tag("input[type=text][name=other_input]")
}
}.should raise_error(SpecFailed)
lambda {
response.should have_tag("form[action=test]") {
with_tag("input[type=text][name=other_input]")
}
}.should raise_error(SpecFailed)
end
it "should report the correct line number for a nested failed expectation" do
render_html %Q{
<form action="test">
<input type="text" name="email">
</form>
}
begin
response.should have_tag("form[action=test]") {
@expected_error_line = __LINE__; should have_tag("input[type=text][name=other_input]")
}
rescue => e
first_non_rspec_line_in_backtrace_of(e).should =~
/#{File.basename(__FILE__)}:#{@expected_error_line}/
else
fail
end
end
it "should report the correct line number for a nested raised exception" do
render_html %Q{
<form action="test">
<input type="text" name="email">
</form>
}
begin
response.should have_tag("form[action=test]") {
@expected_error_line = __LINE__; raise "Failed!"
}
rescue => e
first_non_rspec_line_in_backtrace_of(e).should =~
/#{File.basename(__FILE__)}:#{@expected_error_line}/
else
fail
end
end
it "should report the correct line number for a nested failed test/unit assertion" do
pending "Doesn't work at the moment. Do we want to support this?" do
render_html %Q{
<form action="test">
<input type="text" name="email">
</form>
}
begin
response.should have_tag("form[action=test]") {
@expected_error_line = __LINE__; assert false
}
rescue => e
first_non_rspec_line_in_backtrace_of(e).should =~
/#{File.basename(__FILE__)}:#{@expected_error_line}/
else
fail
end
end
end
it "beatles" do
unless defined?(BEATLES)
BEATLES = [
["John", "Guitar"],
["George", "Guitar"],
["Paul", "Bass"],
["Ringo", "Drums"]
]
end
render_html %Q{
<div id="beatles">
<div class="beatle">
<h2>John</h2><p>Guitar</p>
</div>
<div class="beatle">
<h2>George</h2><p>Guitar</p>
</div>
<div class="beatle">
<h2>Paul</h2><p>Bass</p>
</div>
<div class="beatle">
<h2>Ringo</h2><p>Drums</p>
</div>
</div>
}
response.should have_tag("div#beatles>div[class=\"beatle\"]", 4)
response.should have_tag("div#beatles>div.beatle") {
BEATLES.each { |name, instrument|
with_tag("div.beatle>h2", name)
with_tag("div.beatle>p", instrument)
without_tag("div.beatle>span")
}
}
end
it "assert_select_text_match" do
render_html %Q{<div id="1"><span>foo</span></div><div id="2"><span>bar</span></div>}
response.should have_tag("div") do |divs|
with_tag("div", "foo")
with_tag("div", "bar")
with_tag("div", /\w*/)
with_tag("div", /\w*/, :count=>2)
without_tag("div", :text=>"foo", :count=>2)
with_tag("div", :html=>"<span>bar</span>")
with_tag("div", :html=>"<span>bar</span>")
with_tag("div", :html=>/\w*/)
with_tag("div", :html=>/\w*/, :count=>2)
without_tag("div", :html=>"<span>foo</span>", :count=>2)
end
end
it "assert_select_from_rjs with one item" do
render_rjs do |page|
page.replace_html "test", "<div id=\"1\">foo</div>\n<div id=\"2\">foo</div>"
end
response.should have_tag("div") { |elements|
elements.size.should == 2
with_tag("#1")
with_tag("#2")
}
lambda {
response.should have_tag("div") { |elements|
elements.size.should == 2
with_tag("#1")
with_tag("#3")
}
}.should raise_error(SpecFailed)
lambda {
response.should have_tag("div") { |elements|
elements.size.should == 2
with_tag("#1")
without_tag("#2")
}
}.should raise_error(SpecFailed, "should not have tag(\"#2\"), but did")
lambda {
response.should have_tag("div") { |elements|
elements.size.should == 3
with_tag("#1")
with_tag("#2")
}
}.should raise_error(SpecFailed)
response.should have_tag("div#?", /\d+/) { |elements|
with_tag("#1")
with_tag("#2")
}
end
it "assert_select_from_rjs with multiple items" do
render_rjs do |page|
page.replace_html "test", "<div id=\"1\">foo</div>"
page.replace_html "test2", "<div id=\"2\">foo</div>"
end
response.should have_tag("div")
response.should have_tag("div") { |elements|
elements.size.should == 2
with_tag("#1")
with_tag("#2")
}
lambda {
response.should have_tag("div") { |elements|
with_tag("#3")
}
}.should raise_error(SpecFailed)
end
end
describe "css_select", :type => :controller do
include AssertSelectSpecHelpers
controller_name :assert_select
integrate_views
it "can select tags from html" do
render_html %Q{<div id="1"></div><div id="2"></div>}
css_select("div").size.should == 2
css_select("p").size.should == 0
end
it "can select nested tags from html" do
render_html %Q{<div id="1">foo</div><div id="2">foo</div>}
response.should have_tag("div#?", /\d+/) { |elements|
css_select(elements[0], "div").should have(1).element
css_select(elements[1], "div").should have(1).element
}
response.should have_tag("div") {
css_select("div").should have(2).elements
css_select("div").each { |element|
# Testing as a group is one thing
css_select("#1,#2").should have(2).elements
# Testing individually is another
css_select("#1").should have(1).element
css_select("#2").should have(1).element
}
}
end
it "can select nested tags from rjs (one result)" do
render_rjs do |page|
page.replace_html "test", "<div id=\"1\">foo</div>\n<div id=\"2\">foo</div>"
end
css_select("div").should have(2).elements
css_select("#1").should have(1).element
css_select("#2").should have(1).element
end
it "can select nested tags from rjs (two results)" do
render_rjs do |page|
page.replace_html "test", "<div id=\"1\">foo</div>"
page.replace_html "test2", "<div id=\"2\">foo</div>"
end
css_select("div").should have(2).elements
css_select("#1").should have(1).element
css_select("#2").should have(1).element
end
end
describe "have_rjs behaviour_type", :type => :controller do
include AssertSelectSpecHelpers
controller_name :assert_select
integrate_views
before(:each) do
render_rjs do |page|
page.replace "test1", "<div id=\"1\">foo</div>"
page.replace_html "test2", "<div id=\"2\">bar</div><div id=\"3\">none</div>"
page.insert_html :top, "test3", "<div id=\"4\">loopy</div>"
page.hide "test4"
page["test5"].hide
end
end
it "should pass if any rjs exists" do
response.should have_rjs
end
it "should fail if no rjs exists" do
render_rjs do |page|
end
lambda do
response.should have_rjs
end.should raise_error(SpecFailed)
end
it "should find all rjs from multiple statements" do
response.should have_rjs do
with_tag("#1")
with_tag("#2")
with_tag("#3")
# with_tag("#4")
# with_tag("#5")
end
end
it "should find by id" do
response.should have_rjs("test1") { |rjs|
rjs.size.should == 1
with_tag("div", 1)
with_tag("div#1", "foo")
}
lambda do
response.should have_rjs("test1") { |rjs|
rjs.size.should == 1
without_tag("div#1", "foo")
}
end.should raise_error(SpecFailed, "should not have tag(\"div#1\", \"foo\"), but did")
response.should have_rjs("test2") { |rjs|
rjs.size.should == 2
with_tag("div", 2)
with_tag("div#2", "bar")
with_tag("div#3", "none")
}
# response.should have_rjs("test4")
# response.should have_rjs("test5")
end
# specify "should find rjs using :hide" do
# response.should have_rjs(:hide)
# response.should have_rjs(:hide, "test4")
# response.should have_rjs(:hide, "test5")
# lambda do
# response.should have_rjs(:hide, "test3")
# end.should raise_error(SpecFailed)
# end
it "should find rjs using :replace" do
response.should have_rjs(:replace) { |rjs|
with_tag("div", 1)
with_tag("div#1", "foo")
}
response.should have_rjs(:replace, "test1") { |rjs|
with_tag("div", 1)
with_tag("div#1", "foo")
}
lambda {
response.should have_rjs(:replace, "test2")
}.should raise_error(SpecFailed)
lambda {
response.should have_rjs(:replace, "test3")
}.should raise_error(SpecFailed)
end
it "should find rjs using :replace_html" do
response.should have_rjs(:replace_html) { |rjs|
with_tag("div", 2)
with_tag("div#2", "bar")
with_tag("div#3", "none")
}
response.should have_rjs(:replace_html, "test2") { |rjs|
with_tag("div", 2)
with_tag("div#2", "bar")
with_tag("div#3", "none")
}
lambda {
response.should have_rjs(:replace_html, "test1")
}.should raise_error(SpecFailed)
lambda {
response.should have_rjs(:replace_html, "test3")
}.should raise_error(SpecFailed)
end
it "should find rjs using :insert_html (non-positioned)" do
response.should have_rjs(:insert_html) { |rjs|
with_tag("div", 1)
with_tag("div#4", "loopy")
}
response.should have_rjs(:insert_html, "test3") { |rjs|
with_tag("div", 1)
with_tag("div#4", "loopy")
}
lambda {
response.should have_rjs(:insert_html, "test1")
}.should raise_error(SpecFailed)
lambda {
response.should have_rjs(:insert_html, "test2")
}.should raise_error(SpecFailed)
end
it "should find rjs using :insert (positioned)" do
render_rjs do |page|
page.insert_html :top, "test1", "<div id=\"1\">foo</div>"
page.insert_html :bottom, "test2", "<div id=\"2\">bar</div>"
page.insert_html :before, "test3", "<div id=\"3\">none</div>"
page.insert_html :after, "test4", "<div id=\"4\">loopy</div>"
end
response.should have_rjs(:insert, :top) do
with_tag("div", 1)
with_tag("#1")
end
response.should have_rjs(:insert, :top, "test1") do
with_tag("div", 1)
with_tag("#1")
end
lambda {
response.should have_rjs(:insert, :top, "test2")
}.should raise_error(SpecFailed)
response.should have_rjs(:insert, :bottom) {|rjs|
with_tag("div", 1)
with_tag("#2")
}
response.should have_rjs(:insert, :bottom, "test2") {|rjs|
with_tag("div", 1)
with_tag("#2")
}
response.should have_rjs(:insert, :before) {|rjs|
with_tag("div", 1)
with_tag("#3")
}
response.should have_rjs(:insert, :before, "test3") {|rjs|
with_tag("div", 1)
with_tag("#3")
}
response.should have_rjs(:insert, :after) {|rjs|
with_tag("div", 1)
with_tag("#4")
}
response.should have_rjs(:insert, :after, "test4") {|rjs|
with_tag("div", 1)
with_tag("#4")
}
end
end
describe "send_email behaviour_type", :type => :controller do
include AssertSelectSpecHelpers
controller_name :assert_select
integrate_views
before(:each) do
ActionMailer::Base.delivery_method = :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries = []
end
after(:each) do
ActionMailer::Base.deliveries.clear
end
it "should fail with nothing sent" do
response.should_not send_email
lambda {
response.should send_email{}
}.should raise_error(SpecFailed, /No e-mail in delivery list./)
end
it "should pass otherwise" do
AssertSelectMailer.deliver_test "<div><p>foo</p><p>bar</p></div>"
response.should send_email
lambda {
response.should_not send_email
}.should raise_error(SpecFailed)
response.should send_email{}
response.should send_email {
with_tag("div:root") {
with_tag("p:first-child", "foo")
with_tag("p:last-child", "bar")
}
}
lambda {
response.should_not send_email
}.should raise_error(SpecFailed, "should not send email, but did")
end
end
# describe "An rjs call to :visual_effect, a 'should have_rjs' spec with",
# :type => :view do
#
# before do
# render 'rjs_spec/visual_effect'
# end
#
# it "should pass with the correct element name" do
# response.should have_rjs(:effect, :fade, 'mydiv')
# end
#
# it "should fail the wrong element name" do
# lambda {
# response.should have_rjs(:effect, :fade, 'wrongname')
# }.should raise_error(SpecFailed)
# end
#
# it "should fail with the correct element but the wrong command" do
# lambda {
# response.should have_rjs(:effect, :puff, 'mydiv')
# }.should raise_error(SpecFailed)
# end
#
# end
#
# describe "An rjs call to :visual_effect for a toggle, a 'should have_rjs' spec with",
# :type => :view do
#
# before do
# render 'rjs_spec/visual_toggle_effect'
# end
#
# it "should pass with the correct element name" do
# response.should have_rjs(:effect, :toggle_blind, 'mydiv')
# end
#
# it "should fail with the wrong element name" do
# lambda {
# response.should have_rjs(:effect, :toggle_blind, 'wrongname')
# }.should raise_error(SpecFailed)
# end
#
# it "should fail the correct element but the wrong command" do
# lambda {
# response.should have_rjs(:effect, :puff, 'mydiv')
# }.should raise_error(SpecFailed)
# end
#
# end
describe "string.should have_tag", :type => :helper do
include AssertSelectSpecHelpers
it "should find root element" do
"<p>a paragraph</p>".should have_tag("p", "a paragraph")
end
it "should not find non-existent element" do
lambda do
"<p>a paragraph</p>".should have_tag("p", "wrong text")
end.should raise_error(SpecFailed)
end
it "should find child element" do
"<div><p>a paragraph</p></div>".should have_tag("p", "a paragraph")
end
it "should find nested element" do
"<div><p>a paragraph</p></div>".should have_tag("div") do
with_tag("p", "a paragraph")
end
end
it "should not find wrong nested element" do
lambda do
"<div><p>a paragraph</p></div>".should have_tag("div") do
with_tag("p", "wrong text")
end
end.should raise_error(SpecFailed)
end
end
describe "have_tag", :type => :controller do
include AssertSelectSpecHelpers
controller_name :assert_select
integrate_views
it "should work exactly the same as assert_select" do
render_html %Q{
<div id="wrapper">foo
<div class="piece">
<h3>Text</h3>
</div>
<div class="piece">
<h3>Another</h3>
</div>
</div>
}
assert_select "#wrapper .piece h3", :text => "Text"
assert_select "#wrapper .piece h3", :text => "Another"
response.should have_tag("#wrapper .piece h3", :text => "Text")
response.should have_tag("#wrapper .piece h3", :text => "Another")
end
end
describe 'selecting in HTML that contains a mock with null_object' do
module HTML
class Document
def initialize_with_strict_error_checking(text, strict=false, xml=false)
initialize_without_strict_error_checking(text, true, xml)
end
alias_method :initialize_without_strict_error_checking, :initialize
alias_method :initialize, :initialize_with_strict_error_checking
end
end
describe 'modified HTML::Document' do
it 'should raise error on valid HTML even though false is specified' do
lambda {HTML::Document.new("<b>#<Spec::Mocks::Mock:0x267b4f0></b>", false, false)}.should raise_error
end
end
it 'should not print errors from assert_select' do
mock = mock("Dog", :null_object => true)
html = "<b>#{mock.colour}</b>"
lambda {html.should have_tag('b')}.should_not raise_error
end
end

View file

@ -0,0 +1,37 @@
require File.dirname(__FILE__) + '/../../spec_helper'
class DescriptionGenerationSpecController < ActionController::Base
def render_action
end
def redirect_action
redirect_to :action => :render_action
end
end
describe "Description generation", :type => :controller do
controller_name :description_generation_spec
after(:each) do
Spec::Matchers.clear_generated_description
end
it "should generate description for render_template" do
get 'render_action'
response.should render_template("render_action")
Spec::Matchers.generated_description.should == "should render template \"render_action\""
end
it "should generate description for render_template with full path" do
get 'render_action'
response.should render_template("description_generation_spec/render_action")
Spec::Matchers.generated_description.should == "should render template \"description_generation_spec/render_action\""
end
it "should generate description for redirect_to" do
get 'redirect_action'
response.should redirect_to("http://test.host/description_generation_spec/render_action")
Spec::Matchers.generated_description.should == "should redirect to \"http://test.host/description_generation_spec/render_action\""
end
end

View file

@ -0,0 +1,13 @@
require File.dirname(__FILE__) + '/../../spec_helper'
describe "error_on" do
it "should provide a message including the name of what the error is on" do
have(1).error_on(:whatever).description.should == "should have 1 error on :whatever"
end
end
describe "errors_on" do
it "should provide a message including the name of what the error is on" do
have(2).errors_on(:whatever).description.should == "should have 2 errors on :whatever"
end
end

View file

@ -0,0 +1,62 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
describe "have_text" do
describe "where target is a Regexp" do
it 'should should match submitted text using a regexp' do
string = 'foo'
string.should have_text(/fo*/)
end
end
describe "where target is a String" do
it 'should match submitted text using a string' do
string = 'foo'
string.should have_text('foo')
end
end
end
describe "have_text",
:type => :controller do
['isolation','integration'].each do |mode|
if mode == 'integration'
integrate_views
end
describe "where target is a response (in #{mode} mode)" do
controller_name :render_spec
it "should pass with exactly matching text" do
post 'text_action'
response.should have_text("this is the text for this action")
end
it "should pass with matching text (using Regexp)" do
post 'text_action'
response.should have_text(/is the text/)
end
it "should fail with matching text" do
post 'text_action'
lambda {
response.should have_text("this is NOT the text for this action")
}.should fail_with("expected \"this is NOT the text for this action\", got \"this is the text for this action\"")
end
it "should fail when a template is rendered" do
post 'some_action'
lambda {
response.should have_text("this is the text for this action")
}.should fail_with(/expected \"this is the text for this action\", got .*/)
end
it "should pass using should_not with incorrect text" do
post 'text_action'
response.should_not have_text("the accordian guy")
end
end
end
end

View file

@ -0,0 +1,70 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
describe "include_text" do
describe "where target is a String" do
it 'should match submitted text using a string' do
string = 'foo'
string.should include_text('foo')
end
it 'should match if the text is contained' do
string = 'I am a big piece of text'
string.should include_text('big piece')
end
it 'should not match if text is not contained' do
string = 'I am a big piece of text'
string.should_not include_text('corey')
end
end
end
describe "include_text", :type => :controller do
['isolation','integration'].each do |mode|
if mode == 'integration'
integrate_views
end
describe "where target is a response (in #{mode} mode)" do
controller_name :render_spec
it "should pass with exactly matching text" do
post 'text_action'
response.should include_text("this is the text for this action")
end
it 'should pass with substring matching text' do
post 'text_action'
response.should include_text('text for this')
end
it "should fail with matching text" do
post 'text_action'
lambda {
response.should include_text("this is NOT the text for this action")
}.should fail_with("expected to find \"this is NOT the text for this action\" in \"this is the text for this action\"")
end
it "should fail when a template is rendered" do
post 'some_action'
failure_message = case mode
when 'isolation'
/expected to find \"this is the text for this action\" in \"render_spec\/some_action\"/
when 'integration'
/expected to find \"this is the text for this action\" in \"\"/
end
lambda {
response.should include_text("this is the text for this action")
}.should fail_with(failure_message)
end
it "should pass using should_not with incorrect text" do
post 'text_action'
response.should_not include_text("the accordian guy")
end
end
end
end

View file

@ -0,0 +1,209 @@
require File.dirname(__FILE__) + '/../../spec_helper'
['isolation','integration'].each do |mode|
describe "redirect_to behaviour", :type => :controller do
if mode == 'integration'
integrate_views
end
controller_name :redirect_spec
it "redirected to another action" do
get 'action_with_redirect_to_somewhere'
response.should redirect_to(:action => 'somewhere')
end
it "redirected to another controller and action" do
get 'action_with_redirect_to_other_somewhere'
response.should redirect_to(:controller => 'render_spec', :action => 'text_action')
end
it "redirected to another action (with 'and return')" do
get 'action_with_redirect_to_somewhere_and_return'
response.should redirect_to(:action => 'somewhere')
end
it "redirected from an SSL action to a non-SSL action" do
request.stub!(:ssl?).and_return true
get 'action_with_redirect_to_somewhere'
response.should redirect_to(:action => 'somewhere')
end
it "redirected to correct path with leading /" do
get 'action_with_redirect_to_somewhere'
response.should redirect_to('/redirect_spec/somewhere')
end
it "redirected to correct path without leading /" do
get 'action_with_redirect_to_somewhere'
response.should redirect_to('redirect_spec/somewhere')
end
it "redirected to correct internal URL" do
get 'action_with_redirect_to_somewhere'
response.should redirect_to("http://test.host/redirect_spec/somewhere")
end
it "redirected to correct external URL" do
get 'action_with_redirect_to_rspec_site'
response.should redirect_to("http://rspec.rubyforge.org")
end
it "redirected :back" do
request.env['HTTP_REFERER'] = "http://test.host/previous/page"
get 'action_with_redirect_back'
response.should redirect_to(:back)
end
it "redirected :back and should redirect_to URL matches" do
request.env['HTTP_REFERER'] = "http://test.host/previous/page"
get 'action_with_redirect_back'
response.should redirect_to("http://test.host/previous/page")
end
it "redirected from within a respond_to block" do
get 'action_with_redirect_in_respond_to'
response.should redirect_to('redirect_spec/somewhere')
end
params_as_hash = {:action => "somewhere", :id => 1111, :param1 => "value1", :param2 => "value2"}
it "redirected to an internal URL containing a query string" do
get "action_with_redirect_which_creates_query_string"
response.should redirect_to(params_as_hash)
end
it "redirected to an internal URL containing a query string, one way it might be generated" do
get "action_with_redirect_with_query_string_order1"
response.should redirect_to(params_as_hash)
end
it "redirected to an internal URL containing a query string, another way it might be generated" do
get "action_with_redirect_with_query_string_order2"
response.should redirect_to(params_as_hash)
end
it "redirected to an internal URL which is unroutable but matched via a string" do
get "action_with_redirect_to_unroutable_url_inside_app"
response.should redirect_to("http://test.host/nonexistant/none")
end
end
describe "redirect_to with a controller spec in #{mode} mode and a custom request.host", :type => :controller do
if mode == 'integration'
integrate_views
end
controller_name :redirect_spec
before do
request.host = "some.custom.host"
end
it "should pass when redirected to another action" do
get 'action_with_redirect_to_somewhere'
response.should redirect_to(:action => 'somewhere')
end
end
describe "Given a controller spec in #{mode} mode", :type => :controller do
if mode == 'integration'
integrate_views
end
controller_name :redirect_spec
it "an action that redirects should not result in an error if no should redirect_to expectation is called" do
get 'action_with_redirect_to_somewhere'
end
it "an action that redirects should not result in an error if should_not redirect_to expectation was called, but not to that action" do
get 'action_with_redirect_to_somewhere'
response.should_not redirect_to(:action => 'another_destination')
end
it "an action that redirects should result in an error if should_not redirect_to expectation was called to that action" do
get 'action_with_redirect_to_somewhere'
lambda {
response.should_not redirect_to(:action => 'somewhere')
}.should fail_with("expected not to be redirected to {:action=>\"somewhere\"}, but was")
end
it "an action that does not redirects should not result in an error if should_not redirect_to expectation was called" do
get 'action_with_no_redirect'
response.should_not redirect_to(:action => 'any_destination')
end
end
describe "Given a controller spec in #{mode} mode, should redirect_to should fail when", :type => :controller do
if mode == 'integration'
integrate_views
end
controller_name :redirect_spec
it "redirected to wrong action" do
get 'action_with_redirect_to_somewhere'
lambda {
response.should redirect_to(:action => 'somewhere_else')
}.should fail_with("expected redirect to {:action=>\"somewhere_else\"}, got redirect to \"http://test.host/redirect_spec/somewhere\"")
end
it "redirected to incorrect path with leading /" do
get 'action_with_redirect_to_somewhere'
lambda {
response.should redirect_to('/redirect_spec/somewhere_else')
}.should fail_with('expected redirect to "/redirect_spec/somewhere_else", got redirect to "http://test.host/redirect_spec/somewhere"')
end
it "redirected to incorrect path without leading /" do
get 'action_with_redirect_to_somewhere'
lambda {
response.should redirect_to('redirect_spec/somewhere_else')
}.should fail_with('expected redirect to "redirect_spec/somewhere_else", got redirect to "http://test.host/redirect_spec/somewhere"')
end
it "redirected to incorrect internal URL (based on the action)" do
get 'action_with_redirect_to_somewhere'
lambda {
response.should redirect_to("http://test.host/redirect_spec/somewhere_else")
}.should fail_with('expected redirect to "http://test.host/redirect_spec/somewhere_else", got redirect to "http://test.host/redirect_spec/somewhere"')
end
it "redirected to wrong external URL" do
get 'action_with_redirect_to_rspec_site'
lambda {
response.should redirect_to("http://test.unit.rubyforge.org")
}.should fail_with('expected redirect to "http://test.unit.rubyforge.org", got redirect to "http://rspec.rubyforge.org"')
end
it "redirected to incorrect internal URL (based on the directory path)" do
get 'action_with_redirect_to_somewhere'
lambda {
response.should redirect_to("http://test.host/non_existent_controller/somewhere")
}.should fail_with('expected redirect to "http://test.host/non_existent_controller/somewhere", got redirect to "http://test.host/redirect_spec/somewhere"')
end
it "expected redirect :back, but redirected to a new URL" do
get 'action_with_no_redirect'
lambda {
response.should redirect_to(:back)
}.should fail_with('expected redirect to :back, got no redirect')
end
it "no redirect at all" do
get 'action_with_no_redirect'
lambda {
response.should redirect_to(:action => 'nowhere')
}.should fail_with("expected redirect to {:action=>\"nowhere\"}, got no redirect")
end
it "redirected to an internal URL which is unroutable and matched via a hash" do
get "action_with_redirect_to_unroutable_url_inside_app"
route = {:controller => "nonexistant", :action => "none"}
lambda {
response.should redirect_to(route)
}.should raise_error(ActionController::RoutingError, /(no route found to match|No route matches) \"\/nonexistant\/none\" with \{\}/)
end
end
end

View file

@ -0,0 +1,169 @@
require File.dirname(__FILE__) + '/../../spec_helper'
['isolation','integration'].each do |mode|
describe "response.should render_template (in #{mode} mode)",
:type => :controller do
controller_name :render_spec
if mode == 'integration'
integrate_views
end
it "should match a simple path" do
post 'some_action'
response.should render_template('some_action')
end
it "should match a less simple path" do
post 'some_action'
response.should render_template('render_spec/some_action')
end
it "should match a less simple path to another controller" do
post 'action_which_renders_template_from_other_controller'
response.should render_template('controller_spec/action_with_template')
end
it "should match a symbol" do
post 'some_action'
response.should render_template(:some_action)
end
it "should match an rjs template" do
xhr :post, 'some_action'
if Rails::VERSION::STRING < "2.0.0"
response.should render_template('render_spec/some_action.rjs')
else
response.should render_template('render_spec/some_action')
end
end
it "should match a partial template (simple path)" do
get 'action_with_partial'
response.should render_template("_a_partial")
end
it "should match a partial template (complex path)" do
get 'action_with_partial'
response.should render_template("render_spec/_a_partial")
end
it "should fail when the wrong template is rendered" do
post 'some_action'
lambda do
response.should render_template('non_existent_template')
end.should fail_with("expected \"non_existent_template\", got \"render_spec/some_action\"")
end
it "should fail without full path when template is associated with a different controller" do
post 'action_which_renders_template_from_other_controller'
lambda do
response.should render_template('action_with_template')
end.should fail_with(%Q|expected "action_with_template", got "controller_spec/action_with_template"|)
end
it "should fail with incorrect full path when template is associated with a different controller" do
post 'action_which_renders_template_from_other_controller'
lambda do
response.should render_template('render_spec/action_with_template')
end.should fail_with(%Q|expected "render_spec/action_with_template", got "controller_spec/action_with_template"|)
end
it "should fail on the wrong extension (given rhtml)" do
get 'some_action'
lambda {
response.should render_template('render_spec/some_action.rjs')
}.should fail_with("expected \"render_spec/some_action.rjs\", got \"render_spec/some_action\"")
end
it "should fail when TEXT is rendered" do
post 'text_action'
lambda do
response.should render_template('some_action')
end.should fail_with("expected \"some_action\", got nil")
end
end
describe "response.should_not render_template (in #{mode} mode)",
:type => :controller do
controller_name :render_spec
if mode == 'integration'
integrate_views
end
it "should pass when the action renders nothing" do
post 'action_that_renders_nothing'
response.should_not render_template('action_that_renders_nothing')
end
it "should pass when the action renders nothing (symbol)" do
post 'action_that_renders_nothing'
response.should_not render_template(:action_that_renders_nothing)
end
it "should pass when the action does not render the template" do
post 'some_action'
response.should_not render_template('some_other_template')
end
it "should pass when the action does not render the template (symbol)" do
post 'some_action'
response.should_not render_template(:some_other_template)
end
it "should pass when the action does not render the template (named with controller)" do
post 'some_action'
response.should_not render_template('render_spec/some_other_template')
end
it "should pass when the action renders the template with a different controller" do
post 'action_which_renders_template_from_other_controller'
response.should_not render_template('action_with_template')
end
it "should pass when the action renders the template (named with controller) with a different controller" do
post 'action_which_renders_template_from_other_controller'
response.should_not render_template('render_spec/action_with_template')
end
it "should pass when TEXT is rendered" do
post 'text_action'
response.should_not render_template('some_action')
end
it "should fail when the action renders the template" do
post 'some_action'
lambda do
response.should_not render_template('some_action')
end.should fail_with("expected not to render \"some_action\", but did")
end
it "should fail when the action renders the template (symbol)" do
post 'some_action'
lambda do
response.should_not render_template(:some_action)
end.should fail_with("expected not to render \"some_action\", but did")
end
it "should fail when the action renders the template (named with controller)" do
post 'some_action'
lambda do
response.should_not render_template('render_spec/some_action')
end.should fail_with("expected not to render \"render_spec/some_action\", but did")
end
it "should fail when the action renders the partial" do
post 'action_with_partial'
lambda do
response.should_not render_template('_a_partial')
end.should fail_with("expected not to render \"_a_partial\", but did")
end
it "should fail when the action renders the partial (named with controller)" do
post 'action_with_partial'
lambda do
response.should_not render_template('render_spec/_a_partial')
end.should fail_with("expected not to render \"render_spec/_a_partial\", but did")
end
end
end

View file

@ -0,0 +1,10 @@
class MockableModel < ActiveRecord::Base
has_one :associated_model
end
class SubMockableModel < MockableModel
end
class AssociatedModel < ActiveRecord::Base
belongs_to :mockable_model
end

View file

@ -0,0 +1,64 @@
require File.dirname(__FILE__) + '/../../spec_helper'
require File.dirname(__FILE__) + '/ar_classes'
describe "mock_model" do
before(:each) do
@model = mock_model(SubMockableModel)
end
it "should say it is_a? if it is" do
@model.is_a?(SubMockableModel).should be(true)
end
it "should say it is_a? if it's ancestor is" do
@model.is_a?(MockableModel).should be(true)
end
it "should say it is kind_of? if it is" do
@model.kind_of?(SubMockableModel).should be(true)
end
it "should say it is kind_of? if it's ancestor is" do
@model.kind_of?(MockableModel).should be(true)
end
it "should say it is instance_of? if it is" do
@model.instance_of?(SubMockableModel).should be(true)
end
it "should not say it instance_of? if it isn't, even if it's ancestor is" do
@model.instance_of?(MockableModel).should be(false)
end
end
describe "mock_model with stubbed id", :type => :view do
before(:each) do
@model = mock_model(MockableModel, :id => 1)
end
it "should be named using the stubbed id value" do
@model.instance_variable_get(:@name).should == "MockableModel_1"
end
end
describe "mock_model with null_object", :type => :view do
before(:each) do
@model = mock_model(MockableModel, :null_object => true, :mocked_method => "mocked")
end
it "should be able to mock methods" do
@model.mocked_method.should == "mocked"
end
it "should return itself to unmocked methods" do
@model.unmocked_method.should equal(@model)
end
end
describe "mock_model as association", :type => :view do
before(:each) do
@real = AssociatedModel.create!
@mock_model = mock_model(MockableModel)
@real.mockable_model = @mock_model
end
it "should pass associated_model == mock" do
@mock_model.should == @real.mockable_model
end
it "should pass mock == associated_model" do
@real.mockable_model.should == @mock_model
end
end

Some files were not shown because too many files have changed in this diff Show more