代码之家  ›  专栏  ›  技术社区  ›  DEfusion

使用rspec和rails测试给定布局的呈现

  •  27
  • DEfusion  · 技术社区  · 16 年前

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

    response.should use_layout('my_layout_name')
    

    我在google中找到了一个use-layout matcher,但它不起作用,因为响应或控制器似乎都没有matcher要查找的layout属性。

    11 回复  |  直到 7 年前
        1
  •  7
  •   Otto    16 年前

    我找到了一个例子 how to write a use_layout matcher 就这样。以下是链接消失时的代码:

    # 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")
    
        2
  •  56
  •   Kevin Ansfield    14 年前

    大卫·切利姆斯基在 Ruby Forum :

    response.should render_template("layouts/some_layout")
    
        3
  •  16
  •   mislav Telemachus    16 年前

    这对我来说适用于边缘轨道和边缘RSPEC在轨道上:

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

    不难把这个变成适合你的火柴。

        4
  •  15
  •   Will Tomlins    12 年前

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

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

    (RSPEC 2.64)

        5
  •  4
  •   nathanvda    13 年前

    我必须写下以下内容来完成这项工作:

    response.should render_template("layouts/some_folder/some_layout", "template-name")
    
        6
  •  2
  •   dmcnally    15 年前

    这是Matcher的更新版本。我已经更新了它以符合最新版本的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
    

    此外,Matcher现在还可以使用控制器类级别指定的布局,并可以如下使用:

    class PostsController < ApplicationController
      layout "posts"
    end
    

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

    it { should use_layout("posts") }
    
        7
  •  2
  •   jacklin    13 年前

    这就是我最终采用的解决方案。它适用于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

        8
  •  1
  •   lidaobing    12 年前

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

        9
  •  1
  •   Peter DeWeese    12 年前

    controller.active_layout.name 为我工作。

        10
  •  0
  •   Martin Pain Jason Hall    14 年前

    下面是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
    
        11
  •  0
  •   tgf    7 年前

    Shoulda Matchers公司 为此方案提供匹配器。( Documentation ) 这似乎有效:

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

    它会生成适当的故障消息,如:

    预期以“日历布局”布局呈现,但以“应用程序”、“应用程序”呈现

    用试验 rails 4.2 , rspec 3.3 shoulda-matchers 2.8.0

    编辑:Shoulda Matchers提供此方法。shoulda::matchers::actionController::renderWithLayoutMatcher