RSpec & Rails를 사용하여 특정 레이아웃의 렌더링 테스트
-
01-07-2019 - |
문제
Rails와 함께 RSpec을 사용하여 주어진 레이아웃의 사용을 테스트하는 것이 가능합니까? 예를 들어 다음을 수행하는 매처를 원합니다:
response.should use_layout('my_layout_name')
인터넷 검색에서 use_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")
다른 팁
David Chelimsky가 좋은 답변을 게시했습니다. 루비 포럼:
response.should render_template("layouts/some_layout")
이것은 Edge Rails 및 Edge RSpec on Rails에서 작동합니다.
response.layout.should == 'layouts/application'
이것을 당신에게 적합한 matcher로 바꾸는 것은 어렵지 않을 것입니다.
이에 대해 완벽하게 기능하는 일치자가 이미 있습니다.
response.should render_template(:layout => 'fooo')
(R스펙 2.6.4)
이 작업을 수행하려면 다음을 작성해야 했습니다.
response.should render_template("layouts/some_folder/some_layout", "template-name")
다음은 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
또한 매처는 이제 컨트롤러 클래스 수준에서 지정된 레이아웃에서도 작동하며 다음과 같이 사용할 수 있습니다.
class PostsController < ApplicationController
layout "posts"
end
컨트롤러 사양에서는 다음을 간단히 사용할 수 있습니다.
it { should use_layout("posts") }
내가 결국 해결 한 해결책은 다음과 같습니다.rpsec 2 및 레일 3용입니다.
방금 spec/support 디렉토리에 이 파일을 추가했습니다.링크는 다음과 같습니다: https://gist.github.com/971342
# spec/support/matchers/render_layout.rb
actionView :: base.class_eval instance_methods.include? ethod_chain : _render_layout, : 추적 끝 끝
# 컨트롤러 또는 통합 사양과 같은 컨트롤러 인스턴스에 액세스 할 수있는이 매치기를 사용할 수 있습니다.# # == 예제 사용 # # 레이아웃이 렌더링되지 않을 것으로 예상합니다.# controller.should_not render_layout # 모든 레이아웃이 렌더링 될 것으로 예상합니다.# controller.sh render_layout # app/views/layouts/application.html.erb가 렌더링 될 것으로 기대합니다.# controller.sh render_layout ( 'Application') # 앱/뷰/레이아웃/application.html.erb를 기대합니다.# controller.should_not render_layout ( '응용 프로그램') # 앱/보기/레이아웃/mobile/application.html.erb가 렌더링 될 것으로 기대합니다.# controller.should_not render_layout ( 'mobile/application') rspec :: matchers.define : render_layout do |*args | 예상 = args.first match do | c | 실제 = get_layout (c) 예상되는 경우?!실제.nil?# 테스트를 통과하려면 실제값이 nil이어야 합니다.용법:DUTE_ render_layout elsif 실제 실제 == excling.to_s else false end end
실패 _message_for_should do | c | 실제 = get_layout (c) 실제 .nil 인 경우?&& 예상됨.nil?"레이아웃이 렌더링 될 것으로 예상되었지만"Elsif actual.nil?"예상 레이아웃 #{exposs.inspect}이지만"else "예상 레이아웃 #{expect.Inspect}이 렌더링되지 않았지만 #{acture.inspect}가 렌더링되었습니다.
실패 _message_for_should_not do | c | 실제 = get_layout (c) 예상되는 경우?"예상 레이아웃은 없지만 #{actual.inspect}가"else "exposs #{exposs.inspect} 렌더링되지 않았지만"종료 끝이었습니다.
def get_layout(controller) if template = controller.instance_variable_get(:@_rendered_layout) template.virtual_path.sub(/layouts\//, '') end end end
response.should render_template("layouts/some_folder/some_layout")
response.should render_template("template-name")
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
마땅히 매처스 이 시나리오에 대한 일치자를 제공합니다.(선적 서류 비치) 이것은 작동하는 것 같습니다.
expect(response).to render_with_layout('my_layout')
다음과 같은 적절한 실패 메시지가 생성됩니다.
"calendar_layout" 레이아웃으로 렌더링할 것으로 예상되었지만 "application", "application"으로 렌더링되었습니다.
테스트됨 rails 4.2
, rspec 3.3
그리고 shoulda-matchers 2.8.0
편집하다:shoulda-matchers는 이 방법을 제공합니다.Shoulda::Matchers::ActionController::RenderWithLayoutMatcher