开发者

Getting some unexpected errors while testing a Rails 3 controller

开发者 https://www.devze.com 2023-03-13 03:21 出处:网络
I have a services model defined as such: class Service < ActiveRecord::Base attr_accessible :service_type #, ...

I have a services model defined as such:

class Service < ActiveRecord::Base
  attr_accessible :service_type #, ...

  SERVICE_TYPES = {
    :restaurant => "restaurant",
    :retailer   => "retailer"
  }

  SERVICE_TYPES.values.each do |method|
   define_method method.pluralize.to_sym do
      where(:service_type => method)
   end
  end

  def domestic
    where(:country => 'USA')
  end

  def international
    where("country != 'USA'")
  end
end

I decided to not use a traditional STI pattern for the different services because they will all have the same attributes and otherwise behave identically. There is a parent model, but it is used only for normalization purposes and the web user never needs to know about it. As far as the application goes, there are service types, and specific services under those. So basically I want URLs like this:

http://myapp/services        # <- Lists all service types
http://myapp/restaurants     # <- Lists all restaurant-type services
http://myapp/restaurants/foo # <- Lists a specific restaurant (using friendly_id gem)
http://myapp/retailers       # <- Lists all retailer-type services
http://myapp/retailers/bar   # <- Lists a specific retailer

So I created a routing pattern like so:

controller :services, :via => [:get] do 
  match '/services'          => :index
  match '/:service_type'     => :service_index, :as => 'service_type', :constraints => { :service_type => Regexp.new(Service::SERVICE_TYPES.values.map{|s| Regexp.escape(s.pluralize) }.join('|')) }
  match '/:service_type/:id' => :show,          :as => 'service',      :constraints => { :service_type => Regexp.new(Service::SERVICE_TYPES.values.map{|s| Regexp.escape(s.pluralize) }.join('|')) }
end

Which gets me

    services GET  /services(.:format)                              {:controller=>"services", :action=>"index"}
service_type GET  /:service_type(.:format)                         {:service_type=>/restaurants|retailers/, :controller=>"services", :action=>"service_index"}
     service GET  /:service_type/:id(.:format)                     {:service_type=>/restaurants|retailers/, :controller=>"services", :action=>"show"}

And the controller is defined as

class ServicesController < ApplicationController
  def index
    @service_types = Service::SERVICE_TYPES.values
    @page_title = "Services"
  end

  def service_index
    @service_type  = params[:service_type]
    @domestic      = Service.send(@service_type).domestic
    @international = Service.send(@service_type).international
    @page_title    = @service_type.capitalize
  end

  def show
    @service = Service.find(params[:id])
    @page_title = "Services - #{@service.name}"
  end
end

This all works as expected when I test it in the browser. But when I try to run an integration test in Rspec2 I'm getting some really unexpected behavior.

require 'spec_helper'

describe ServicesController do
  describe "GET 'index'" do
    it "should be successful" do
      get :index
      response.should be_success
    end

    it "should have the right title" do
      get :index
      response.should have_selector(
        "title", 
        :content => "#{@base_title}Services"
      )
    end

    it "should have a link to each service" do
      get :index
      Service::SERVICE_TYPES.values.each do |service_type|
        response.should have_selector("a", :href => service_type_path(service_type.pluralize),
                                           :content => service_type.pluralize)
      end
    end
  end

  describe "GET 'service_index'" do
    Service::SERVICE_TYPES.values.each do |service_type|
      context service_type.pluralize do
        it "should be successful" do
          get :service_index, :service_type => service_type.pluralize
          response.should be_success
        end

        it "should have the right title" do
          get :service_index, :service_type => service_type.pluralize
          response.should have_selector(
            "title", 
            :content => "#{@base_title}#{service_type.pluralize.capitalize}"
          )
        end

        it "should have a link to each service" do
          get :service_index, :service_type => service_type.pluralize
          Service.send(service_type.pluralize).each do |service|
            response.should have_selector("a", :href => service_path(service_type.pluralize, service),
                                               :content => service.name)
          end
        end
      end
    end
  end

  describe "GET 'show'" do
    it "should be successful" do
      get 'show'
      response.should be_success
    end
  end
end

The get action appears to run successfully because the "should be successful" tests all pass, but the others fail because it can't find the proper selector(s) on the page. The odd thing is that the dump of HTML that is returned doesn't appear to come from my app.

  1) ServicesController GET 'index' should have the right title
     Failure/Error: response.should have_selector(
       expected following output to contain a <title>Services</title> tag:
       <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
     # ./spec/controllers/services_controller_spec.rb:12:in `block (3 levels) in <top (required)>'

  2) ServicesController GET 'index' should have a link to each service
     Failure/Error: response.should have_selector("a", :href => service_type_path(service_type.pluralize),
       expected following output to contain a <a href='/restaurants'>Restaurants</a> tag:
       <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
     # ./spec/controllers/services_controller_spec.rb:21:in `block (4 levels) in <top (required)>'
     # ./spec/controllers/services_controller_spec.rb:20:in `each'
     # ./spec/controllers/services_controller_spec.rb:20:in `block (3 levels) in <top (required)>'

  3) ServicesController GET 'service_index' restaurants should have the right title
     Failure/Error: response.should have_selector(
       expected following output to contain a <title>Restaurants</title> tag:
       <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
     # ./spec/controllers/services_controller_spec.rb:37:in `block (5 levels) in <top (required)>'

  4) ServicesController GET 'service_index' restaurants should have a link to each service
     Failure/Error: response.should have_selector("a", :href => service_path(service_type.pluralize, service),
       expected following output to contain a <a href='/restaurants/foo'>Foo</a> tag:
       <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
     # ./spec/controllers/services_controller_spec.rb:46:in `block (6 levels) in <top (required)>'
     # ./spec/controllers/services_controller_spec.rb:45:in `block (5 levels) in <top (required)>'

What I would expect to see if this was indeed a failure would be the complete dump of my HTML application template which is marked up in HTML 5. Instead I'm getting only the doctype of a page marked up as HTML 4.

Any ideas what would cause that?

As a secondary issue, I can't figure out any way to turn on logging in Webrat to see what HTTP activity is actually happening. How开发者_JAVA百科 can I do that?


Yeah, never mind. I'm an idiot and forgot to put render_views inside my test which is why it wasn't rendering the view.

0

精彩评论

暂无评论...
验证码 换一张
取 消