28

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

response.should use_layout('my_layout_name')

我在谷歌搜索时发现了一个 use_layout 匹配器,但它不起作用,因为响应或控制器似乎都没有匹配器正在寻找的布局属性。

4

11 回答 11

57

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

response.should render_template("layouts/some_layout")
于 2010-09-28T13:45:28.040 回答
16

这适用于 Edge Rails 和 Edge RSpec on Rails:

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

将其变成适合您的匹配器应该不难。

于 2008-09-27T16:39:39.163 回答
15

已经有一个功能完善的匹配器:

response.should render_template(:layout => 'fooo')

(Rspec 2.6.4)

于 2012-05-28T14:48:08.503 回答
7

我找到了一个如何编写一个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")
于 2008-09-21T05:15:28.167 回答
5

我必须编写以下内容才能完成这项工作:

response.should render_template("layouts/some_folder/some_layout", "template-name")
于 2012-01-09T15:31:40.077 回答
2

这是匹配器的更新版本。我已经更新它以符合最新版本的 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") }
于 2009-08-22T17:08:20.790 回答
2

这是我最终采用的解决方案。它适用于 rpsec 2 和 rails 3。
我刚刚在 spec/support 目录中添加了这个文件。链接是:https ://gist.github.com/971342

# spec/support/matchers/render_layout.rb

ActionView::Base.class_eval do unless instance_methods.include?('_render_layout_with_tracking') def _render_layout_with_tracking(layout, locals, &block) controller.instance_variable_set(:@_rendered_layout, layout) _render_layout_without_tracking(layout, locals, &block) end alias_method_chain :_render_layout, :tracking end end

# You can use this matcher anywhere that you have access to the controller instance, # like in controller or integration specs. # # == Example Usage # # Expects no layout to be rendered: # controller.should_not render_layout # Expects any layout to be rendered: # controller.should render_layout # Expects app/views/layouts/application.html.erb to be rendered: # controller.should render_layout('application') # Expects app/views/layouts/application.html.erb not to be rendered: # controller.should_not render_layout('application') # Expects app/views/layouts/mobile/application.html.erb to be rendered: # controller.should_not render_layout('mobile/application') RSpec::Matchers.define :render_layout do |*args| expected = args.first match do |c| actual = get_layout(c) if expected.nil? !actual.nil? # actual must be nil for the test to pass. Usage: should_not render_layout elsif actual actual == expected.to_s else false end end

failure_message_for_should do |c| actual = get_layout(c) if actual.nil? && expected.nil? "expected a layout to be rendered but none was" elsif actual.nil? "expected layout #{expected.inspect} but no layout was rendered" else "expected layout #{expected.inspect} but #{actual.inspect} was rendered" end end

failure_message_for_should_not do |c| actual = get_layout(c) if expected.nil? "expected no layout but #{actual.inspect} was rendered" else "expected #{expected.inspect} not to be rendered but it was" end end

def get_layout(controller) if template = controller.instance_variable_get(:@_rendered_layout) template.virtual_path.sub(/layouts\//, '') end end end

于 2011-05-16T02:09:54.937 回答
1

controller.active_layout.name为我工作。

于 2009-08-23T20:45:18.463 回答
1

response.should render_template("layouts/some_folder/some_layout") response.should render_template("template-name")

于 2012-05-18T03:53:11.757 回答
1

Shoulda Matchers为这种情况提供了一个匹配器。(文档)这似乎工作:

       expect(response).to render_with_layout('my_layout')

它会产生适当的失败消息,例如:

预计使用“calendar_layout”布局呈现,但使用“应用程序”、“应用程序”呈现

rails 4.2,rspec 3.3shoulda-matchers 2.8.0

编辑:shouda-matchers 提供了这种方法。应该::Matchers::ActionController::RenderWithLayoutMatcher

于 2015-07-31T20:05:54.150 回答
0

这是 dmcnally 代码的一个版本,它不允许传递任何参数,使“应该使用布局”和“应该不使用布局”工作(分别断言控制器正在使用任何布局或没有布局 - 我希望只有第二个有用,因为如果它使用布局,您应该更具体):

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
于 2010-03-20T18:41:43.687 回答