Rails valid markup testing

Coda Hale has given the intersection of the Rails and web standards communities a very nice plugin for keeping your markup clean. It is aptly, if slightly pretentiously, named Responsible Markup.

But let’s be honest, do you really want to spend much time on writing tests for your markup? After all, it’s taking long enough to get the markup right. Ruby to the rescue! Why write tests when we can get Ruby to write them?

Here’s what I’m using.

class ValidMarkupTest < Test::Unit::TestCase
  ResponsibleMarkup::validator_uri = 'http://localhost/w3c-markup-validator/check'

  def self.validate_markup_for_resources(*resources)
    default_actions = {
      :index => { :method => :get, :template => 'list' }, 
      :new   => { :method => :get, :template => 'new' },
      :edit  => { :method => :get, :id => 1, :template => 'edit' }
    }
    if resources.last.kind_of?(Hash)
      actions = resources.pop
      actions.each do |action, options|
        options.reverse_merge!(default_actions[action] || {})
      end
    else
      actions = default_actions
    end

    resources.each do |resource|
      fixtures resource

      controller_class = "#{resource.to_s.camelize}Controller".constantize

      actions.each do |action, options|
        options = options.dup

        define_method("test_action_#{action}_for_#{resource}_returns_valid_markup") do
          @controller = controller_class.new

          request_method    = options.delete(:method)
          expected_template = options.delete(:template)

          send(request_method, action, options)

          assert_response :success
          assert_template expected_template
          assert_valid_markup
        end
      end
    end
  end

  validate_markup_for_resources :thingamuhjigs, :humdingers, :gizmos

  def setup
    @request  = ActionController::TestRequest.new
    @response = ActionController::TestResponse.new
    login_test_user
  end

  def assert_valid_markup
    assert_doctype(:xhtml_10_strict)
    assert_content_type
#    assert_compatible_empty_elements
    assert_no_empty_attributes
    assert_no_long_style_attributes
    assert_unobtrusive_javascript :allowed => [ :inline_events, :blank_hrefs ]
    assert_valid_html
  end

end

The idea is to have separate the testing task into three parts.

  • A generic, lightly configurable, method for defining tests: validate_markup_for_resources
  • A setup method that is specific to your application. In the example above, I need to login a user.
  • A assert_valid_markup method that contains assertions for your validation goals.

Configuration

By default, validate_markup_for_resources generates tests for index, new, and edit actions. For the edit test, it assumes that an object with the id 1 exists. If you need to change the request options used by default, you can override them like this

validate_markup_for_resources :gizmos, :id => 2, :template => 'gizmo', :\other_param => 'xyz'

Running

Normally, by Rails convention, the above example test would belong in test/functional. However, even when using a validator installed on the local machine, it takes quite some time to run. So, in order not to slow down my functional tests too much, I’ve created a new directory, test/markup and run the tests in there with

$ rake test:markup

This rake task is provided by the following snippet in lib/tasks/markup.rake.

namespace :test do
  desc "Run the checks for valid markup defined in test/markup"
  Rake::TestTask.new(:markup => "environment") do |t|
    t.libs << "test"
    t.pattern = 'test/markup/**/*_test.rb'
    t.verbose = true
  end
end

Incidentally, yes, I know that the markup of this blog is broken. Blame WordPress.