Class Test::Rails::ViewTestCase
In: lib/test/rails/view_test_case.rb
Parent: Test::Rails::FunctionalTestCase

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 &amp; Goodbye'
      assert_h 1, 'Hello &amp; 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.

Methods

Public Instance methods

Returns the action_name based on a backtrace line passed in as test.

Asserts that there is an error on field of type type.

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

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

Asserts a hN tag of level level exists and contains content.

view:

  <h3>Recent Builds</h3>

test:

  assert_h 3, 'Recent Builds'

Asserts that an image exists with a src of src.

view:

  <img src="/images/bucket.jpg" alt="Bucket">

test:

  assert_image '/images/bucket.jpg'

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]"

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'

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'

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'

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'

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

Asserts that a submit element with a value of value exists.

view:

  <input type="submit" value="Create!" %>

test:

  assert_submit 'Create!'

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'

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
assert_textarea(*args)

Alias for assert_text_area

Asserts that a title with title exists.

view:

  <title>some content</title>

test:

  assert_title 'some content'

Allows the view instance variables to be set like flash:

test:

  def test_show
    assigns[:route] = routes(:work)

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'

Opposite of assert_select.

Creates an assertion options hash for href and content.

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
  • app/views/route/show.

And in test_show_no_photos, render will look for:

If a view cannot be found the test will flunk.

Sets up the test case.

Creates a new Paginator that uses the current controller. item_count, items_per_page and page_number are passed straight through.

[Validate]