2008-09-20 21 views
26

Có thể kiểm tra việc sử dụng một cách bố trí cho sử dụng RSpec với Rails, ví dụ tôi muốn một khớp nào sau đây:Testing vẽ của một bố cục được với RSpec & Rails

response.should use_layout('my_layout_name') 

tôi tìm thấy một matcher use_layout khi Googling nhưng nó không hoạt động vì cả response hoặc controller đều có một thuộc tính layout mà matcher đang tìm kiếm.

Trả lời

7

Tôi đã tìm thấy ví dụ về how to write a use_layout matcher sẽ thực hiện điều đó. Dưới đây là đoạn code trong trường hợp liên kết biến mất:

# 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") 
+0

Đó là cùng một mà tôi tìm thấy, và từ các thử nghiệm của tôi nó dường như không hoạt động vì không có thuộc tính bố trí trên phản hồi (hoặc bộ điều khiển) từ những gì tôi có thể thấy. – DEfusion

+0

Ah có vẻ như có một phương pháp bố trí, nhưng phải mất một số đối số. Tôi sẽ suy nghĩ về giải pháp có thể là gì. – Otto

+0

Trên Rails 2.2.2 hiện tại và hoạt động tốt – DEfusion

16

này làm việc cho tôi với Rails cạnh và cạnh RSpec on Rails:

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

Không nên khó có thể tắt chức năng này vào một khớp phù hợp cho bạn.

+0

Cũng hoạt động đối với tôi. – Otto

+6

Điều này không hoạt động trong các phiên bản mới hơn của rspec. Thay vì sử dụng 'response.should render_template ('layout/the_layout") ' – jpemberthy

2

Đây là phiên bản cập nhật của trình phù hợp. Tôi đã cập nhật nó để phù hợp với phiên bản mới nhất của RSpec. Tôi đã thêm các thuộc tính chỉ đọc có liên quan và xóa định dạng trả về cũ.

# 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 

Bên cạnh đó các khớp bây giờ cũng làm việc với bố trí quy định ở cấp lớp điều khiển và có thể được sử dụng như sau:

class PostsController < ApplicationController 
    layout "posts" 
end 

Và trong spec điều khiển bạn chỉ có thể sử dụng:

it { should use_layout("posts") } 
1

controller.active_layout.name phù hợp với tôi.

0

Dưới đây là phiên bản mã của dmcnally cho phép không có đối số nào được chuyển, thực hiện công việc "nên use_layout" và "should_not use_layout" (để khẳng định rằng bộ điều khiển đang sử dụng bố cục bất kỳ hoặc bố cục tương ứng) mong đợi chỉ thứ hai là hữu ích khi bạn cần cụ thể hơn nếu nó là sử dụng một 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 
56

David Chelimsky đăng tải một câu trả lời tốt hơn trên Ruby Forum:

response.should render_template("layouts/some_layout") 
+0

Đây là câu trả lời đúng cho Rspec 2. – Raphomet

+0

không hoạt động với rpsec 1 như giải thích bởi Raphomet – shingara

+0

@Kevin Ansfield: nhưng câu hỏi là về cách bố trí không –

2

đây là giải pháp tôi đã kết thúc với. Nó cho rpsec 2 và đường ray 3.
Tôi vừa thêm tập tin này vào thư mục spec/support. Liên kết là: 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

+0

Trong Rails 3, giải pháp này làm việc cho tôi (xem phương thức get_layout) – KIR

4

tôi đã phải viết sau đây để làm công việc này:

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

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

14

Có đã một khớp một cách hoàn hảo chức năng cho việc này:

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

(Rspec 2.6. 4)

+0

Điều đó đã cho tôi một kết quả sai, nghĩa là " response.should render_template (layout: false) "nó thông qua mặc dù tôi đã có một bố trí. –

+4

làm việc cho tôi một cách chính xác, cần thiết để sử dụng' response.should render_template (: layout => 'layouts/fooo') 'tuy nhiên. – fifigyuri

0

Đối sánh ifa cung cấp đối sánh cho trường hợp này.(Documentation) Điều này dường như làm việc:

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

nó tạo ra thông điệp thất bại thích hợp như:

Dự kiến ​​sẽ làm với "calendar_layout" bố trí, nhưng trả lại với "ứng dụng", "ứng dụng"

Thử nghiệm với rails 4.2, rspec 3.3shoulda-matchers 2.8.0

Edit: shoulda-matchers cung cấp phương thức này. Shoulda :: Matchers :: ActionController :: RenderWithLayoutMatcher

+0

Tôi đang sử dụng RSpec 3.3 và nó không hoạt động chút nào, không có phương pháp như vậy trong RSpec. – Erowlin

+0

Bạn đúng. Tôi đã nhìn vào nơi mà phương pháp đó đã đến từ và nó thực sự từ Shoulda :: Matchers :: ActionController :: RenderWithLayoutMatcher (v.2.8.0) http://www.rubydoc.info/github/thoughtbot/shoulda-matchers/ Shoulda% 2FMatchers% 2FActionController% 3Arender_with_layout Tôi sẽ cập nhật điều này. – tgf

Các vấn đề liên quan