Created
November 16, 2022 15:19
-
-
Save matsales28/f823baaa9f32f24a269ee486a0f63336 to your computer and use it in GitHub Desktop.
Create matcher for asserting components of ViewComponents have been rendered with arguments or not
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This gist was used to create have_rendered_page_component matcher, because our intention was to | |
# assure that a specific page_component was being rendered. | |
# This is overriding the instrumentation of ViewComponent | |
# to include the parameters that a component might receive when rendering. | |
# frozen_string_literal: true | |
require "active_support/notifications" | |
require "active_support/concern" | |
module ViewComponent | |
module Instrumentation | |
def render_in(view_context, &) | |
arguments = public_methods(false) & instance_variables.map { |method| method.to_s.delete("@").to_sym } | |
parameters = arguments.index_with { |arg| send(arg) } | |
ActiveSupport::Notifications.instrument( | |
"!render.view_component", | |
{ | |
name: self.class.name, | |
identifier: self.class.identifier, | |
parameters: parameters | |
} | |
) do | |
super(view_context, &) | |
end | |
end | |
end | |
end | |
# Overriding RenderTemplateMatcher to be able to receive arguments and also in matchers? method to call assert_page_component | |
module RSpec | |
module Rails | |
module Matchers | |
module RenderTemplate | |
class RenderTemplateMatcher | |
def with(**arguments) | |
@arguments = arguments | |
self | |
end | |
def matches?(*) | |
match_check = match_unless_raises ActiveSupport::TestCase::Assertion do | |
@scope.assert_page_component expected, @arguments, @message | |
end | |
check_redirect unless match_check | |
match_check | |
end | |
end | |
end | |
end | |
end | |
end | |
# Creating the PageComponentMatcher module | |
module PageComponentMatcher | |
extend ActiveSupport::Concern | |
included do | |
setup :setup_subscriptions | |
teardown :teardown_subscriptions | |
end | |
def setup_subscriptions | |
@_pages = Hash.new(0) | |
@_subscribers = [] | |
@_subscribers << ActiveSupport::Notifications.subscribe("!render.view_component") do |event| | |
payload = event.payload | |
@_pages[payload[:name]] = payload[:parameters] if payload[:identifier].match?(%r{/pages/(.*)/}) # If you want to test for just components, change this to %r{/components/(.*)/} | |
end | |
end | |
def teardown_subscriptions | |
return unless defined?(@_subscribers) | |
@_subscribers.each { |subscriber| ActiveSupport::Notifications.unsubscribe(subscriber) } | |
end | |
def reset_template_assertion | |
@_pages.clear | |
end | |
def assert_page_component(component, arguments, message = nil) | |
response.body | |
component_message = message || format( | |
"expecting %<expected>s but rendered %<actual>s", expected: component.inspect, actual: @_pages.keys.first | |
) | |
params_message = format("expecting %<args>s but received %<params>s", args: arguments, params: @_pages.values.first) | |
matches_component = @_pages.any? { |component_name, _| component_name == component } | |
matches_arguments = arguments.present? ? @_pages.each_value.all?(arguments) : true | |
assert matches_component, component_message | |
assert matches_arguments, params_message | |
end | |
def have_rendered_page_component(component, message = nil) | |
RSpec::Rails::Matchers::RenderTemplate::RenderTemplateMatcher.new(self, component, message) | |
end | |
end | |
RSpec.configure do |config| | |
config.include PageComponentMatcher, type: :request | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment