ruby-on-rails - través - poder debidamente otorgado cuando se actúa por medio de apoderado
Prueba de la representación de un diseño determinado con RSpec y rieles (11)
Aquí está la solución con la que terminé. Es para rpsec 2 y rieles 3.
Acabo de agregar este archivo en el directorio de especificaciones / soporte. El enlace es: https://gist.github.com/971342
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
# spec/support/matchers/render_layout.rb
¿Es posible probar el uso de un diseño dado usando RSpec con Rails, por ejemplo, me gustaría un matcher que haga lo siguiente:
response.should use_layout(''my_layout_name'')
Encontré un elemento de sincronización de use_layout cuando busqué en Google, pero no funciona, ya que ni la respuesta ni el controlador parecen tener una propiedad de diseño que el emparejador estaba buscando.
Aquí hay una versión actualizada del emparejador. Lo he actualizado para que se ajuste a la última versión de RSpec. Agregué los atributos de solo lectura relevantes y eliminé el formato de devolución anterior.
# 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
Además, el matcher ahora también funciona con los diseños especificados en el nivel de clase del controlador y se puede usar de la siguiente manera:
class PostsController < ApplicationController
layout "posts"
end
Y en la especificación del controlador puede simplemente usar:
it { should use_layout("posts") }
Aquí hay una versión del código de dmcnally que no permite que se pasen los argumentos, haciendo que "should use_layout" y "should_not use_layout" funcionen (para afirmar que el controlador está usando cualquier diseño, o no, respectivamente, de los cuales esperaría solo el segundo ser útil como debería ser más específico si está usando un diseño):
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
David Chelimsky publicó una buena respuesta en el Ruby Forum :
response.should render_template("layouts/some_layout")
Encontré un ejemplo de cómo escribir un use_layout
use_layout que hará exactamente eso. Aquí está el código en caso de que ese enlace desaparezca:
# 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")
Esto funciona para mí con edge Rails y edge RSpec on Rails:
response.layout.should == ''layouts/application''
No debería ser difícil convertir esto en un matcher adecuado para usted.
Tuve que escribir lo siguiente para que esto funcione:
response.should render_template("layouts/some_folder/some_layout", "template-name")
Ya hay un matcher perfectamente funcional para esto:
response.should render_template(:layout => ''fooo'')
(Rspec 2.6.4)
controller.active_layout.name
funciona para mí.
response.should render_template("layouts/some_folder/some_layout") response.should render_template("template-name")
Shoulda Matchers proporciona un marcador para este escenario. ( Documentation ) Esto parece funcionar:
expect(response).to render_with_layout(''my_layout'')
produce mensajes de falla apropiados como:
Se espera que se renderice con el diseño "calendar_layout", pero se representa con "aplicación", "aplicación"
Probado con rails 4.2
, rspec 3.3
y shoulda-matchers 2.8.0
Editar: shoulda-matchers proporciona este método. Shoulda :: Matchers :: ActionController :: RenderWithLayoutMatcher