Тестирование рендеринга заданного макета с помощью RSpec и Rails
-
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