Class: Test::Rails::ViewTestCase
- Inherits:
-
FunctionalTestCase
- Object
- ActiveSupport::TestCase
- TestCase
- FunctionalTestCase
- Test::Rails::ViewTestCase
- Defined in:
- lib/test/rails/view_test_case.rb
Overview
ViewTestCase allows views to be tested independent of their controllers. Testcase implementors must set up the instance variables the view needs to render itself.
Features
-
Allows testing of individual AJAX templates.
-
Allows testing of individual partials.
-
Large library of helpful assertions.
Naming
The test class must be named after your controller class name, so if you’re testing views for the RouteController
you would name your test case RouteViewTest
. The test case will expect to find your view files in app/views/route
.
The test names should be in the form of test_view_edgecase
where ‘view’ corresponds to the name of the view file, and ‘edgecase’ describes the scenario you are testing.
If you are testing a view file named ‘show.rhtml’ your test should be named test_show
. If your view is behaves differently depending upon its parameters then you can make the test name descriptive like test_show_photos
and test_show_no_photos
.
Examples
Typical View Test
class RouteViewTest < Test::Rails::ViewTestCase
fixtures :users, :routes, :points, :photos
def test_delete
# Set up instance variables for template
assigns[:loggedin_user] = users(:herbert)
assigns[:route] = routes(:work)
# render template for the delete action in RouteController
render
# assert that there's a form with an action of "/route/destroy"
assert_form form_url, :post do
# with a hidden id field
assert_input :hidden, :id
# And a submit button that says 'Delete!'
assert_submit 'Delete!'
end
# And a link back to the route so you don't delete it
assert_links_to "/route/show/#{routes(:work).id}", 'No, I do not!'
end
end
Typical Layout Test
require 'test/test_helper'
# Create a dummy controller for layout views. This lets the setup use the
# right path with minimum fuss.
class LayoutsController < ApplicationController; end
class LayoutsViewTest < Test::Rails::ViewTestCase
fixtures :users, :routes, :points, :photos
def test_default
# Template set-up
@request.request_uri = '/foo'
assigns[:action_title] = 'Hello & Goodbye'
# Render an empty string with the 'application' layout.
render :text => '', :layout => 'application'
# Assert content just like a regular view test.
assert_links_to '/', 'Home'
assert_links_to '/user', 'Login'
deny_links_to '/user/logout', 'Logout'
assert_title 'Hello & Goodbye'
assert_h 1, 'Hello & Goodbye'
end
end
Deprecated Features
Form assertions are now using assert_select, so you don’t need to pass URLs around everywhere and can instead use a block. (See above example).
The form assertions will still work using the old syntax, but in a future release they will give warnings, then will be removed.
Instance Attribute Summary
Attributes inherited from FunctionalTestCase
Instance Method Summary collapse
-
#action_name(test) ⇒ Object
Returns the action_name based on a backtrace line passed in as
test
. -
#assert_error_on(field, type) ⇒ Object
Asserts that there is an error on
field
of typetype
. -
#assert_field(*args) ⇒ Object
A wrapper assert that calls both assert_input and assert_label.
-
#assert_form(form_action, method = nil, enctype = nil, &block) ⇒ Object
Asserts that there is a form whose action is
form_action
. -
#assert_h(level, content) ⇒ Object
Asserts a hN tag of level
level
exists and containscontent
. -
#assert_image(src) ⇒ Object
Asserts that an image exists with a src of
src
. -
#assert_input(*args) ⇒ Object
Asserts that an input element of
type
with a name ofname
, and optionally a value ofvalue
exists. -
#assert_label(*args) ⇒ Object
Asserts that a label with a for attribute of
for_attribute
exists. -
#assert_links_to(href, content = nil) ⇒ Object
Asserts that there is an anchor tag with an href of
href
that optionally hascontent
. -
#assert_multipart_form(form_action, &block) ⇒ Object
Asserts that there is a form using the ‘POST’ method whose action is
form_action
and uses the multipart content type. -
#assert_post_form(form_action, &block) ⇒ Object
Asserts that there is a form using the ‘POST’ method whose action is
form_action
. -
#assert_select_in_form(action, &block) ⇒ Object
Utility method for compatibility with old-style assert_tag form assertions.
-
#assert_select_tag(*args) ⇒ Object
Asserts that a select element with a name of “
model
[column
]” andoptions
with specified names and values exists. -
#assert_submit(*args) ⇒ Object
Asserts that a submit element with a value of
value
exists. -
#assert_tag_in_form(form_action, options) ⇒ Object
Asserts that a form with
form_action
has a descendent that matchesoptions
exists. -
#assert_text_area(*args) ⇒ Object
(also: #assert_textarea)
Asserts that a textarea with name
name
and optionallyvalue
exists. -
#assert_title(title) ⇒ Object
Asserts that a title with
title
exists. -
#assigns ⇒ Object
Allows the view instance variables to be set like flash:.
-
#deny_links_to(href, content = nil) ⇒ Object
Denies the existence of an anchor tag with an href of
href
and optionallycontent
. -
#deny_select(selector) ⇒ Object
Opposite of assert_select.
-
#links_to_options_for(href, content = nil) ⇒ Object
Creates an assertion options hash for
href
andcontent
. -
#render(options = {}, *rest_args) ⇒ Object
Renders the template.
-
#setup ⇒ Object
Sets up the test case.
-
#util_make_paginator(item_count, items_per_page, page_number) ⇒ Object
Creates a new Paginator that uses the current controller.
Instance Method Details
#action_name(test) ⇒ Object
Returns the action_name based on a backtrace line passed in as test
.
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 |
# File 'lib/test/rails/view_test_case.rb', line 576 def action_name(test) orig_name = test = test.sub(/.*in `test_(.*)'/, '\1') controller = @controller.class.name.sub('Controller', '').underscore extensions = %w[rhtml rxml rjs mab] while test =~ /_/ do return test if extensions.any? { |ext| File.file? "app/views/#{controller}/#{test}.#{ext}" } test = test.sub(/_[^_]+$/, '') end return test if extensions.any? { |ext| File.file? "app/views/#{controller}/#{test}.#{ext}" } flunk "Couldn't find view for test_#{orig_name}" end |
#assert_error_on(field, type) ⇒ Object
Asserts that there is an error on field
of type type
.
247 248 249 250 251 |
# File 'lib/test/rails/view_test_case.rb', line 247 def assert_error_on(field, type) = ActiveRecord::Errors.[type] assert_select "div.errorExplanation li", :text => /^#{field} #{}/i end |
#assert_field(*args) ⇒ Object
A wrapper assert that calls both assert_input and assert_label.
view:
<%= start_form_tag :controller => 'game', :action => 'save' %>
<label for="game_amount">Amount:</label>
<% text_field 'game', 'amount' %>
test:
assert_field '/game/save', :text, :game, :amount
264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/test/rails/view_test_case.rb', line 264 def assert_field(*args) form_action, type, model, column, value = Symbol === args.first ? [nil, *args] : args if form_action then # HACK deprecate assert_input form_action, type, "#{model}[#{column}]", value assert_label form_action, "#{model}_#{column}" else assert_input type, "#{model}[#{column}]", value assert_label "#{model}_#{column}" end end |
#assert_form(form_action, method = nil, enctype = nil, &block) ⇒ Object
Asserts that there is a form whose action is form_action
. Optionally, method
and enctype
may be specified. If a block is given, assert_form behaves like assert_select, so assert_input and friends may be scoped to the selected form.
view:
<%= start_form_tag :action => 'create_file' %>
# ...
test:
assert_form '/game/save'
or:
assert_form '/game/save' do
# ...
end
295 296 297 298 299 300 |
# File 'lib/test/rails/view_test_case.rb', line 295 def assert_form(form_action, method = nil, enctype = nil, &block) selector = "form[action='#{form_action}']" selector << "[method='#{method}']" if method selector << "[enctype='#{enctype}']" if enctype assert_select selector, &block end |
#assert_h(level, content) ⇒ Object
Asserts a hN tag of level level
exists and contains content
.
view:
<h3>Recent Builds</h3>
test:
assert_h 3, 'Recent Builds'
311 312 313 |
# File 'lib/test/rails/view_test_case.rb', line 311 def assert_h(level, content) assert_select "h#{level}", :text => content end |
#assert_image(src) ⇒ Object
Asserts that an image exists with a src of src
.
view:
<img src="/images/bucket.jpg" alt="Bucket">
test:
assert_image '/images/bucket.jpg'
324 325 326 |
# File 'lib/test/rails/view_test_case.rb', line 324 def assert_image(src) assert_select "img[src='#{src}']" end |
#assert_input(*args) ⇒ Object
Asserts that an input element of type
with a name of name
, and optionally a value of value
exists.
view:
<%= text_field 'game', 'amount' %>
test:
assert_input :text, "game[amount]"
338 339 340 341 342 343 344 345 346 347 |
# File 'lib/test/rails/view_test_case.rb', line 338 def assert_input(*args) action, type, name, value = Symbol === args.first ? [nil, *args] : args raise ArgumentError, 'supply type and name' if type.nil? or name.nil? input_selector = "input[type='#{type}'][name='#{name}']" input_selector << "[value='#{value}']" if value assert_select_in_form action do assert_select input_selector end end |
#assert_label(*args) ⇒ Object
Asserts that a label with a for attribute of for_attribute
exists.
view:
<%= start_form_tag :controller => 'game', :action => 'save' %>
<label for="game_amount">Amount:</label>
test:
assert_label 'game_amount'
359 360 361 362 363 364 365 366 367 |
# File 'lib/test/rails/view_test_case.rb', line 359 def assert_label(*args) action, for_attribute = args.length == 1 ? [nil, *args] : args raise ArgumentError, 'supply for_attribute' if for_attribute.nil? label_selector = "label[for='#{for_attribute}']" assert_select_in_form action do assert_select label_selector end end |
#assert_links_to(href, content = nil) ⇒ Object
Asserts that there is an anchor tag with an href of href
that optionally has content
.
view:
<%= link_to 'drbrain', :model => user %>
test:
assert_links_to '/players/show/1', 'drbrain'
379 380 381 |
# File 'lib/test/rails/view_test_case.rb', line 379 def assert_links_to(href, content = nil) assert_select(*(href, content)) end |
#assert_multipart_form(form_action, &block) ⇒ Object
Asserts that there is a form using the ‘POST’ method whose action is form_action
and uses the multipart content type. If passed a block, works like assert_form.
view:
<%= start_form_tag({ :action => 'create_file' }, :multipart => true) %>
test:
assert_multipart_form '/game/save'
411 412 413 |
# File 'lib/test/rails/view_test_case.rb', line 411 def assert_multipart_form(form_action, &block) assert_form(form_action, :post, 'multipart/form-data', &block) end |
#assert_post_form(form_action, &block) ⇒ Object
Asserts that there is a form using the ‘POST’ method whose action is form_action
. If passed a block, works like assert_form.
view:
<%= start_form_tag :action => 'create_file' %>
test:
assert_post_form '/game/save'
425 426 427 |
# File 'lib/test/rails/view_test_case.rb', line 425 def assert_post_form(form_action, &block) assert_form(form_action, :post, &block) end |
#assert_select_in_form(action, &block) ⇒ Object
Utility method for compatibility with old-style assert_tag form assertions.
556 557 558 559 560 561 562 |
# File 'lib/test/rails/view_test_case.rb', line 556 def assert_select_in_form(action, &block) # :nodoc: if action then assert_form(action, &block) else block.call end end |
#assert_select_tag(*args) ⇒ Object
Asserts that a select element with a name of “model
[column
]” and options
with specified names and values exists.
view:
<%= collection_select :game, :location_id, @locations, :id, :name %>
test:
assert_select_tag :game, :location_id, 'Ballet' => 1, 'Guaymas' => 2
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 |
# File 'lib/test/rails/view_test_case.rb', line 439 def assert_select_tag(*args) action, model, column, = Symbol === args.first ? [nil, *args] : args assert_kind_of Hash, , "options needs to be a Hash" deny .empty?, "options must not be empty" select_selector = "select[name='#{model}[#{column}]']" .each do |option_name, option_value| option_selector = "option[value='#{option_value}']" selector = "#{select_selector} #{option_selector}" assert_select_in_form action do assert_select selector, :text => option_name end end end |
#assert_submit(*args) ⇒ Object
Asserts that a submit element with a value of value
exists.
view:
<input type="submit" value="Create!" %>
test:
assert_submit 'Create!'
466 467 468 469 470 471 472 |
# File 'lib/test/rails/view_test_case.rb', line 466 def assert_submit(*args) action, value = args.length == 1 ? [nil, *args] : args submit_selector = "input[type='submit'][value='#{value}']" assert_select_in_form action do assert_select submit_selector end end |
#assert_tag_in_form(form_action, options) ⇒ Object
Asserts that a form with form_action
has a descendent that matches options
exists.
Typically this is not used directly in tests. Instead use it to build expressive tests that assert which fields are in what form.
view:
<%= start_form_tag :action => 'save' %>
[...]
test:
assert_tag_in_form '/route/save', :tag => 'table'
488 489 490 491 |
# File 'lib/test/rails/view_test_case.rb', line 488 def assert_tag_in_form(form_action, ) assert_tag :tag => 'form', :attributes => { :action => form_action }, :descendant => end |
#assert_text_area(*args) ⇒ Object Also known as: assert_textarea
Asserts that a textarea with name name
and optionally value
exists.
view:
<%= text_area 'post', 'body' %>
test:
assert_text_area 'post[body]'
view:
<textarea id="post_body" name="post[body]">
<%= @post.body %>
</textarea>
test:
assert_text_area 'post[body]', posts(:post).body
510 511 512 513 514 515 516 517 518 519 |
# File 'lib/test/rails/view_test_case.rb', line 510 def assert_text_area(*args) action, name, value = args.first !~ /\A\// ? [nil, *args] : args raise ArgumentError, 'supply name' if name.nil? text_area_selector = ["textarea[name='#{name}']"] text_area_selector << { :text => value } if value assert_select_in_form action do assert_select(*text_area_selector) end end |
#assert_title(title) ⇒ Object
Asserts that a title with title
exists.
view:
<title>some content</title>
test:
assert_title 'some content'
532 533 534 |
# File 'lib/test/rails/view_test_case.rb', line 532 def assert_title(title) assert_select 'title', :text => title end |
#assigns ⇒ Object
Allows the view instance variables to be set like flash:
test:
def test_show
assigns[:route] = routes(:work)
128 129 130 |
# File 'lib/test/rails/view_test_case.rb', line 128 def assigns @ivar_proxy end |
#deny_links_to(href, content = nil) ⇒ Object
Denies the existence of an anchor tag with an href of href
and optionally content
.
view (for /players/show/1):
<%= link_to_unless_current 'drbrain', :model => user %>
test:
deny_links_to '/players/show/1'
393 394 395 396 397 398 |
# File 'lib/test/rails/view_test_case.rb', line 393 def deny_links_to(href, content = nil) selector, = (href, content) [:count] = 0 assert_select selector, end |
#deny_select(selector) ⇒ Object
Opposite of assert_select.
539 540 541 |
# File 'lib/test/rails/view_test_case.rb', line 539 def deny_select(selector) assert_select selector, false end |
#links_to_options_for(href, content = nil) ⇒ Object
Creates an assertion options hash for href
and content
.
567 568 569 570 571 |
# File 'lib/test/rails/view_test_case.rb', line 567 def (href, content = nil) selector = "a[href='#{href}']" equality = content ? { :text => content } : {} return selector, equality end |
#render(options = {}, *rest_args) ⇒ Object
Renders the template. The template is determined from the test name. If you have multiple tests for the same view render will try to Do The Right Thing and remove parts of the name looking for the template file.
By default, render has the added option :layout => false
, so if want to test behavior in your layout add :layout => true
.
The action can be forced by using the options:
render :action => 'new'
render :template => 'profile/index'
A test’s path parameters may be overridden, allowing routes with additional parameters to work.
Working with Routes
By default, a view tests sets the controller and action of a test to the controller name and action name for the test. This may be overriden.
A test involving routes like:
map.workspace '/users/:owner/workspace/:action',
:controller => 'workspace', :action => 'workspace'
Can be invoked by setting @path_parameters like this:
def test__app_entry
@path_parameters[:owner] = 'bob'
@path_parameters[:action] = 'apps'
render :partial => 'apps/app_entry'
# ...
end
View Lookup
render strips off words trailing an _ in the test name one at a time until it finds a matching action. It tries the extensions ‘rhtml’, ‘rxml’, ‘rjs’, and ‘mab’ in order for each action until a view is found.
With this test case:
class RouteViewTest < Test::Rails::ViewTestCase
def test_show_photos
render
end
def test_show_no_photos
render
end
end
In test_show_photos, render will look for:
-
app/views/route/show_photos.rhtml
-
app/views/route/show_photos.rxml
-
app/views/route/show_photos.rjs
-
app/views/route/show_photos.mab
And in test_show_no_photos, render will look for:
-
app/views/route/show_no_photos.rhtml
-
app/views/route/show_no_photos.rxml
-
app/views/route/show_no_photos.rjs
-
app/views/route/show_no_photos.mab
If a view cannot be found the test will flunk.
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
# File 'lib/test/rails/view_test_case.rb', line 204 def render( = {}, *rest_args) @action_name = action_name caller[0] if .empty? assigns[:action_name] = @action_name default_path_parameters = { :controller => @controller.controller_name, :action => @action_name } path_parameters = default_path_parameters.merge(@path_parameters) @request.path_parameters = path_parameters defaults = { :layout => false } = defaults.merge if Test::Rails.rails_version >= Test::Rails.v1_2 then @controller.send :params=, @request.parameters else @controller.instance_variable_set :@params, @request.parameters end @controller.send :initialize_current_url current_url = URI.parse @controller.url_for @request.request_uri = current_url.request_uri # Rails 1.0 @controller.send :assign_names rescue nil @controller.send :fire_flash rescue nil # Rails 1.1 @controller.send :forget_variables_added_to_assigns rescue nil # Do the render [:TR_force] = true @controller.send(:render, , *rest_args) # Rails 1.1 @controller.send :process_cleanup rescue nil end |
#setup ⇒ Object
Sets up the test case.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/test/rails/view_test_case.rb', line 101 def setup return if self.class == Test::Rails::ViewTestCase @path_parameters ||= {} klass_name = self.class.name.sub(/View/, 'Controller') @controller_class_name ||= klass_name.sub 'Test', '' super @ivar_proxy = Test::Rails::IvarProxy.new @controller # these go here so that flash and session work as they should. @controller.send :initialize_template_class, @response @controller.send :assign_shortcuts, @request, @response assigns[:session] = @controller.session @controller.class.send :public, :flash # make flash accessible to the test end |
#util_make_paginator(item_count, items_per_page, page_number) ⇒ Object
Creates a new Paginator that uses the current controller. item_count
, items_per_page
and page_number
are passed straight through.
547 548 549 550 |
# File 'lib/test/rails/view_test_case.rb', line 547 def util_make_paginator(item_count, items_per_page, page_number) ActionController::Pagination::Paginator.new(@controller, item_count, items_per_page, page_number) end |