HHH v4

stub controllers in ViewComponent tests

Edit
equivalent Web Development
Public
Rails
ViewComponent
RSpec


every ViewComponent test will pass ViewComponent::TestHelpers#vc_test_controller to component, which includes routes, helpers, etc. that component uses.
 
therefore ViewComponent tests are easy to stub. All you need to do is:

require "rails_helper"

RSpec.describe MyComponent, type: :component do
  include ViewComponent::TestHelpers

  it do
    allow(vc_test_controller).to receive(:current_user).and_return(user)
    vc_test_controller.params[:company_id]=11

    render_inline(MyComponent.new)
  new
end

so if you need to stub current_user in ViewComponent it just works👍

Issue with previews


The problem are ViewComponent previews. Previews use actual instance of  controllers. Therefore if yo need to pass different current_user to preview you are out of luck. What you can do instead is pass the current controller as an argument (a dependacy injection priinciple)

class MyComponent< ApplicationComponent
  attr_reader :context
  delegate :current_user, to: :context
  
  def initialize(context:)
    @context = context
  end
  
  def show_tab?
    current_user.present? 
  end

  def show_something_else?
    params[:company_id].present?
  end
end

therefore in your preview:

class App::MyComponentPreview < ViewComponent::Preview
  def owner
    current_user = User.find_by!(email: "[email protected]")

    controller_instance = OpenStruct.new(current_user: current_user)
    render(MyComponent.new(context: controller_instance))
  end
end


in actual prod code just pass current controller (self)

# app/views/layouts/application.html.erb
<%= render(MyComponent.new(context: self)) 

In our Component tests we need to explicitly tell them that context is vc_test_controller

require "rails_helper"

RSpec.describe MyComponent, type: :component do
  include ViewComponent::TestHelpers

  it do
    controller_instance = vc_test_controller
    allow(controller_instance).to receive(:current_user).and_return(user)
    controller_instance.params[:company_id]=11

    render_inline(MyComponent.new(context: controller_instance)
  new
end

this way we can still change `params` use helpers, stub helpers in our test and we can demonstrate different users in our preview







sources