Search code examples
ruby-on-railsminitestactioncablerails-activejob

Testing broadcasts_refreshes in Rails


Can I test broadcasts_refreshes in my ActiveJob tests? Or maybe in my model tests? Is there another place where I should be testing this?

According to the Broadcastable docs (my emphasis added):

broadcasts_refreshes configures the model to broadcast a “page refresh” to a stream name derived at runtime by the stream symbol invocation

The ActionCable TestHelpers all require you to specify a stream but don't mention how to figure out the derived stream name so I checked the Broadcastable code and it looks like broadcasts_refreshes currently uses model_name.plural to derive the stream name.

I then tried assert_broadcasts(stream, number, &block) with both the string result of model_name.plural (in my case "salesforce_contacts") and passing that code as the stream name but in both cases I get a test failure with the message:

1 broadcasts to salesforce_contacts expected, but 0 were sent.

# Testing the background job
require "test_helper"

class UpdateSFContactJobTest < ActiveJob::TestCase
  include ActionCable::TestHelper
  
  test "broadcasts refresh message on change" do
    contact = salesforce_contacts(:one)
  
    assert_broadcasts(contact.model_name.plural, 1) do
      UpdateSFContactJob.perform_now(contact)
    end
    #Assertion fails: 1 broadcasts to salesforce_contacts expected, but 0 were sent.
  end
end
# Testing the model
require "test_helper"

class Salesforce::ContactTest < ActiveSupport::TestCase
  include ActionCable::TestHelper

  test "broadcasts refresh after change" do
    contact = salesforce_contacts(:one)

    assert_broadcasts(contact.model_name.plural, 1) do
      contact.save
    end
    #Assertion fails: 1 broadcasts to salesforce_contacts expected, but 0 were sent.
  end
end

A summarised version of my model code is:

class Salesforce::Contact < ApplicationRecord
  include Mappable

  belongs_to :user

  broadcasts_refreshes

  permit_unexpected_attributes

  has_attribute_mappings Id: :salesforce_id,
    AccountId: :account_id,
    npsp__Deceased__c: :deceased,
    Name: :combined_name
    #snip
end

Solution

  • turbo-rails provides an assert_turbo_stream_broadcasts helper:

    class ModelTest < ActiveSupport::TestCase
      test "the broadcast" do
        model = Model.create!
        model.broadcast_refresh
    
        assert_turbo_stream_broadcasts model, count: 1
      end
    end
    

    https://github.com/hotwired/turbo-rails#testing


    The reason it doesn't work with assert_broadcasts is that you're giving it an incorrect stream name:

    >> model = Model.first
    >> model.broadcast_refresh
    [ActionCable] Broadcasting to Z2lkOi8vc3RhY2tvdmVyZmxvdy9BcnRpY2xlLzEzNA: "<turbo-stream action=\"refresh\"></turbo-stream>"
    #                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    # this is the expected stream name -'
    # which is a global id in param form
    >> model.to_gid_param
    => "Z2lkOi8vc3RhY2tvdmVyZmxvdy9BcnRpY2xlLzEzNA"
    
    class ModelTest < ActiveSupport::TestCase
      test "the broadcast" do
        model = Model.create!
        model.broadcast_refresh
    
        assert_broadcasts model.to_gid_param, 1
      end
    end