Question

Est-il possible de tester l'utilisation d'une présentation donnée à l'aide de RSpec avec Rails, par exemple, j'aimerais un matcher qui effectue les opérations suivantes:

response.should use_layout('my_layout_name')

J'ai trouvé un matcher use_layout lors de la recherche sur Google, mais cela ne fonctionne pas, car ni la réponse ni le contrôleur ne semblent avoir une propriété de disposition recherchée par matcher.

Était-ce utile?

La solution

J'ai trouvé un exemple de comment écrire un use_layout matcher qui fera exactement cela. Voici le code au cas où ce lien disparaîtrait:

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

Autres conseils

David Chelimsky a publié une bonne réponse sur le Ruby Forum :

response.should render_template("layouts/some_layout")

Cela fonctionne pour moi avec Edge Rails et Edge RSpec on Rails:

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

Ne devrait pas être difficile de transformer cela en un ajusteur qui vous convient.

Il existe déjà un matcher parfaitement fonctionnel pour cela:

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

(Rspec 2.6.4)

J'ai dû écrire ce qui suit pour que cela fonctionne:

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

Voici une version mise à jour du matcher. Je l'ai mis à jour pour qu'il soit conforme à la dernière version de RSpec. J'ai ajouté les attributs pertinents en lecture seule et supprimé l'ancien format de retour.

# 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

De plus, le matcher fonctionne également avec les présentations spécifiées au niveau de la classe du contrôleur et peut être utilisé comme suit:

class PostsController < ApplicationController
  layout "posts"
end

Et dans la spécification du contrôleur, vous pouvez simplement utiliser:

it { should use_layout("posts") }

Voici la solution avec laquelle j'ai fini par aller. C'est pour rpsec 2 et rails 3.
Je viens d'ajouter ce fichier dans le répertoire spec / support. Le lien est le suivant: 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

response.should render_template (" layouts / some_folder / some_layout ") response.should render_template (" nom-modèle ")

controller.active_layout.name fonctionne pour moi.

Voici une version du code de dmcnally qui ne permet de passer aucun argument, ce qui permet à "devrait utiliser use_layout". et " ne devrait pas utiliser_layout " work (pour affirmer que le contrôleur utilise une mise en page, ou aucune mise en page, respectivement - dont je m'attendrais seulement à ce que la seconde soit utile car vous devriez être plus précis s'il utilise une mise en page):

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

Les correspondants d’Ina fournissent un indicateur pour ce scénario. ( Documentation ) Cela semble fonctionner:

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

il génère les messages d'échec appropriés, tels que:

Est attendu pour le rendu avec le "quot_ calendar_layout" mise en page, mais rendue avec "application", "application"

Testé avec rails 4.2 , rspec 3.3 et shoulda-matchers 2.8.0

Edit: shoulda-matchers fournit cette méthode. Shoulda :: Matchers :: ActionController :: RenderWithLayoutMatcher

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top