Pregunta

¿Es posible probar el uso de un diseño determinado usando RSpec con Rails? Por ejemplo, me gustaría un comparador que haga lo siguiente:

response.should use_layout('my_layout_name')

Encontré un comparador use_layout cuando busqué en Google, pero no funciona porque ni la respuesta ni el controlador parecen tener una propiedad de diseño que el comparador estaba buscando.

¿Fue útil?

Solución

Encontré un ejemplo de cómo escribir un use_layout igualador eso hará precisamente eso.Aquí está el código en caso de que el 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")

Otros consejos

David Chelimsky publicó una buena respuesta en el Foro Rubí:

response.should render_template("layouts/some_layout")

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 comparador adecuado para usted.

Ya existe un comparador perfectamente funcional para esto:

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

(Rspec 2.6.4)

Tuve que escribir lo siguiente para que esto funcione:

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

Aquí hay una versión actualizada del comparador.Lo actualicé para que se ajuste a la última versión de RSpec.Agregué los atributos relevantes de solo lectura 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 comparador ahora también funciona con diseños especificados en el nivel de clase del controlador y se puede utilizar de la siguiente manera:

class PostsController < ApplicationController
  layout "posts"
end

Y en las especificaciones del controlador simplemente puedes usar:

it { should use_layout("posts") }

Aquí está la solución con la que terminé.Es para rpsec 2 y rieles 3.
Acabo de agregar este archivo en el directorio spec/support.El enlace es: https://gist.github.com/971342

# spec/support/matchers/render_layout.rb

ActionView :: Base.class_eval do a menos que instance_methods.include? ('_ Render_layout_with_tracking') def _render_layout_with_tracking (lugar _chain: _render_layout,: End de seguimiento

# Puede usar este Matcher en cualquier lugar donde tenga acceso a la instancia del controlador, # como en el controlador o las especificaciones de integración.# == Ejemplo Uso # # espera que no se represente el diseño:# controlador.should_not render_layout # espera que se represente cualquier diseño:# controlador. Debería render_layout # espera que la aplicación/vistas/diseños/application.html.erb se represente:# controlador.sho debería render_layout ('aplicación') # espera que la aplicación/vistas/diseños/application.html.erb no se represente:# controlador.should_not render_layout ('aplicación') # espera que la aplicación/vistas/diseños/móvil/application.html.erb se represente:# controlador.should_not render_layout ('mobile/aplicación') rspec :: matchers.define: render_layout do |*args | esperado = args. primero coincidora do | c | real = get_layout (c) si se espera.nil?!actual.nulo?# real debe ser nulo para que se pase la prueba.Uso:debería_not render_layout elsif real real == esperado.to_s más falso final final

fails_message_for_shho debería hacer | c | real = get_layout (c) si real.nil?&& esperado.nil?"Se espera que se represente un diseño pero ninguno era" Elsif real. ¿Nil?"Diseño esperado #{esperado.inspect} Pero no se presentó un diseño" más "el diseño esperado #{esperado.inspect} pero #{real.inspect} se renderizó" Fin final

fails_message_for_should_not do | c | real = get_layout (c) si se espera.nil?"No esperado sin diseño, pero #{real.inspect} se convirtió en" else "esperado #{esperado.inspect} para no ser presentado, pero fue" final

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 funciona para mi.

Aquí hay una versión del código de dmcnally que no permite pasar argumentos, lo que hace que funcionen "debería usar_diseño" y "no debería usar_diseño" (para afirmar que el controlador está usando cualquier diseño, o ningún diseño, respectivamente, de lo cual esperaría solo el segundo para que sea útil, ya que debería ser más específico si utiliza 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

Coincidencias de deberías proporciona un comparador para este escenario.(Documentación) Esto parece funcionar:

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

Produce mensajes de error apropiados como:

Se espera que se represente 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:debería-matchers proporciona este método.Debería::Matchers::ActionController::RenderWithLayoutMatcher

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top