使用RSpec和Rails测试给定布局的渲染

时间:2020-03-06 14:29:33  来源:igfitidea点击:

是否可以使用带有Rails的RSpec来测试给定布局的使用,例如,我想要执行以下操作的匹配器:

response.should use_layout('my_layout_name')

我在Googling时找到了use_layout匹配器,但由于响应或者控制器似乎都没有匹配器正在寻找的layout属性,因此它无法正常工作。

解决方案

我找到了一个示例,说明如何编写一个可以做到这一点的" use_layout"匹配器。这是链接消失的代码:

# in spec_helper.rb

class UseLayout
   def initialize(expected)
     @expected = 'layouts/' + expected
   end
   def matches?(controller)
     @actual = controller.layout
     #@actual.equal?(@expected)
     @actual == @expected
   end
   def failure_message
     return "use_layout expected #{@expected.inspect}, got # 
{@actual.inspect}", @expected, @actual
   end
   def negeative_failure_message
     return "use_layout expected #{@expected.inspect} not to equal # 
{@actual.inspect}", @expected, @actual
   end
end

def use_layout(expected)
   UseLayout.new(expected)
end

# in controller spec
   response.should use_layout("application")

这对我适用于Edge Rails和Rails上的edge RSpec:

response.layout.should == 'layouts/application'

将它变成适合匹配器应该不难。

这是匹配器的更新版本。我已经对其进行更新以符合RSpec的最新版本。我添加了相关的只读属性,并删除了旧的返回格式。

# in spec_helper.rb

class UseLayout
  attr_reader :expected
  attr_reader :actual

  def initialize(expected)
    @expected = 'layouts/' + expected
  end

  def matches?(controller)
    if controller.is_a?(ActionController::Base)
      @actual = 'layouts/' + controller.class.read_inheritable_attribute(:layout)
    else
      @actual = controller.layout
    end
    @actual ||= "layouts/application"
    @actual == @expected
  end

  def description
    "Determines if a controller uses a layout"
  end

  def failure_message
    return "use_layout expected #{@expected.inspect}, got #{@actual.inspect}"
  end

 def negeative_failure_message
   return "use_layout expected #{@expected.inspect} not to equal #{@actual.inspect}"
  end
end

def use_layout(expected)
  UseLayout.new(expected)
end

此外,匹配器现在还可以与在控制器类级别指定的布局一起使用,并且可以按以下方式使用:

class PostsController < ApplicationController
  layout "posts"
end

在控制器规范中,我们可以简单地使用:

it { should use_layout("posts") }

controller.active_layout.name对我有用。

这是dmcnally代码的一个版本,该版本不允许传递任何参数,从而使" should use_layout"和" should_not use_layout"起作用(以断言控制器正在使用任何布局或者不使用布局,我希望它们仅使用第二个布局)很有用,因为如果使用布局,则应该更具体):

class UseLayout
   def initialize(expected = nil)
     if expected.nil?
       @expected = nil
     else
       @expected = 'layouts/' + expected
     end
   end
   def matches?(controller)
     @actual = controller.layout
     #@actual.equal?(@expected)
     if @expected.nil?
       @actual
     else
       @actual == @expected
     end
   end
   def failure_message
     if @expected.nil?
       return 'use_layout expected a layout to be used, but none was', 'any', @actual
     else
       return "use_layout expected #{@expected.inspect}, got #{@actual.inspect}", @expected, @actual
     end
   end
   def negative_failure_message
     if @expected.nil?
       return "use_layout expected no layout to be used, but #{@actual.inspect} found", 'any', @actual
     else
       return "use_layout expected #{@expected.inspect} not to equal #{@actual.inspect}", @expected, @actual
     end
   end
end

def use_layout(expected = nil)
   UseLayout.new(expected)
end

David Chelimsky在Ruby论坛上发布了一个很好的答案:

response.should render_template("layouts/some_layout")