RailsでRSpecを使用して、特定のレイアウトの使用をテストすることは可能ですか。たとえば、次のことを行うマッチャーが必要です。
response.should use_layout('my_layout_name')
グーグルでuse_layoutマッチャーを見つけましたが、応答もコントローラーもマッチャーが探していたレイアウトプロパティを持っていないようであるため、機能しません。
RailsでRSpecを使用して、特定のレイアウトの使用をテストすることは可能ですか。たとえば、次のことを行うマッチャーが必要です。
response.should use_layout('my_layout_name')
グーグルでuse_layoutマッチャーを見つけましたが、応答もコントローラーもマッチャーが探していたレイアウトプロパティを持っていないようであるため、機能しません。
David Chelimsky がRuby Forumに良い回答を投稿しました:
response.should render_template("layouts/some_layout")
これは、Rails 上の edge Rails と edge RSpec で機能します。
response.layout.should == 'layouts/application'
これをあなたに適したマッチャーに変えるのは難しくありません。
これには、すでに完全に機能するマッチャーがあります。
response.should render_template(:layout => 'fooo')
(Rspec 2.6.4)
まさにそれを行うマッチャーの書き方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")
この作業を行うには、次のように記述する必要がありました。
response.should render_template("layouts/some_folder/some_layout", "template-name")
これが私が最終的に行った解決策です。rpsec2とrails3用です。
このファイルを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
これがマッチャーの更新バージョンです。最新バージョンの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") }
Shoulda Matchersは、このシナリオのマッチャーを提供します。(ドキュメント)これはうまくいくようです:
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
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