Тестирование рендеринга заданного макета с помощью RSpec и Rails

StackOverflow https://stackoverflow.com/questions/109284

  •  01-07-2019
  •  | 
  •  

Вопрос

Можно ли протестировать использование данного макета с помощью RSpec с Rails, например, мне нужен сопоставитель, который делает следующее:

response.should use_layout('my_layout_name')

Я нашел сопоставитель use_layout при поиске в Google, но он не работает, поскольку ни ответ, ни контроллер, похоже, не имеют свойства макета, которое искал сопоставитель.

Это было полезно?

Решение

Я нашел пример как написать 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_layout")

У меня это работает с Edge Rails и Edge RSpec on Rails:

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

Не должно быть сложно превратить это в подходящее для вас средство сопоставления.

Для этого уже есть вполне функциональное средство сопоставления:

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

(Рспец 2.6.4)

Мне пришлось написать следующее, чтобы эта работа заработала:

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

Вот обновленная версия сопоставителя.Я обновил его, чтобы он соответствовал последней версии 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 do vifs_methods.include? ('_ Render_layout_with_tracking') def _render_layout_with_tracking (layout, locals, & block) controller.instance_varible_set (: @_ rendered_layout, layout) _render_lay_with _method_chain: _render_layout,: Отслеживание конец

# Вы можете использовать этот сочетание везде, где у вас есть доступ к экземпляру контроллера, как в спецификациях контроллера или интеграции.# # == Пример использования # # ожидает, что макет не будет отображаться:# controller.should_not render_layout # ожидает, что любой макет будет отображаться:# controller.slowld render_layout # ожидает приложение/представления/макеты/application.html.erb для визуализации:# controller.slowld render_layout ('application') # ожидает app/views/mayouts/application.html.erb не будет отображаться:# controller.should_not render_layout ('application') # ожидает приложения/представления/макеты/mobile/application.html.erb будет отображаться:# controller.should_not render_layout ('mobile/application') rspec :: matchers.define: render_layout do |*args | ожидается = args. Первое матч do | c | Фактический = get_layout (c), если ожидается.nil?!актуальный.ноль?# фактическое значение должно быть равно нулю, чтобы тест прошел.Использование:wop_not render_layout elsif фактический фактический == weder.to_s else false end end

affly_message_for_fold Do | C | Фактическое = get_layout (c), если Actual.nil?&& ожидается.ноль?«Ожидается, что макет будет представлен, но ни один из них не был» Эльсиф Фактический. NIL?«Ожидаемый макет #{weder.inspect}, но не было установлено никакого макета« else »ожидаемого макета #{weder.inspect}, но #{faction.inspect} был сделан« Конец

affly_message_for_should_not do | c | Фактический = get_layout (c), если ожидается.nil?«Ожидается, что макет, но #{actual.inspept} был сделан« else »ожидается #{wed.inspept} не для того, чтобы быть отображенным, но это был« Конец конца

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, которая не позволяет передавать аргументы, благодаря чему работают «следует использовать_макет» и «должен_не использовать_макет» (чтобы утверждать, что контроллер использует любой макет или не использует макет соответственно - из которых я ожидал бы только второй чтобы быть полезным, поскольку вы должны быть более конкретными, если он использует макет):

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

Редактировать:musta-matchers предоставляет этот метод.Должен::Matchers::ActionController::RenderWithLayoutMatcher

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top