Class: LiveCable::Testing::TestComponent

Inherits:
SimpleDelegator
  • Object
show all
Defined in:
lib/live_cable/testing/test_component.rb

Overview

Wraps a mounted component for testing. Delegates unknown methods to the component itself, so reactive variables and component methods can be read directly (e.g. counter.count).

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(component, connection, channel) ⇒ TestComponent

Returns a new instance of TestComponent.



17
18
19
20
21
# File 'lib/live_cable/testing/test_component.rb', line 17

def initialize(component, connection, channel)
  super(component)
  @connection = connection
  @channel = channel
end

Instance Attribute Details

#channelLiveCable::Testing::TestChannel (readonly)



15
16
17
# File 'lib/live_cable/testing/test_component.rb', line 15

def channel
  @channel
end

#connectionLiveCable::Connection (readonly)



12
13
14
# File 'lib/live_cable/testing/test_component.rb', line 12

def connection
  @connection
end

Instance Method Details

#broadcasts(key = nil) ⇒ Array<Hash>

Everything the component has broadcast since mounting (renders, acks, status updates, errors), oldest first.

Parameters:

  • key (Symbol, nil) (defaults to: nil)

    Filter to broadcasts containing this key (e.g. :_refresh, :_ack, :_error, :_status)

Returns:

  • (Array<Hash>)


73
74
75
76
77
# File 'lib/live_cable/testing/test_component.rb', line 73

def broadcasts(key = nil)
  return channel.transmissions.dup unless key

  channel.transmissions.select { |broadcast| broadcast.key?(key) }
end

#clear_broadcastsObject

Forget previously captured broadcasts. Useful after mounting, to assert on the effects of a single action.



81
82
83
# File 'lib/live_cable/testing/test_component.rb', line 81

def clear_broadcasts
  channel.transmissions.clear
end

#componentLiveCable::Component

Returns The underlying component instance.

Returns:



24
25
26
# File 'lib/live_cable/testing/test_component.rb', line 24

def component
  __getobj__
end

#dispatched_eventsArray<Hash>

All events the component has dispatched via dispatch_event, in order, whether they rode along with a render or were broadcast on their own.

Returns:

  • (Array<Hash>)

    Event hashes ({ name:, detail:, window: })



90
91
92
# File 'lib/live_cable/testing/test_component.rb', line 90

def dispatched_events
  broadcasts(:_events).flat_map { |broadcast| broadcast[:_events] }
end

#perform(action, params = {}) ⇒ Object

Dispatch an action through the real message pipeline, as if it was triggered by live-action or live-form in the browser.

Params go through a query-string round trip, so values arrive as ActionController::Parameters with string values - exactly like production.

Parameters:

  • action (Symbol, String)

    The action name

  • params (Hash) (defaults to: {})

    Parameters for the action



37
38
39
40
41
42
# File 'lib/live_cable/testing/test_component.rb', line 37

def perform(action, params = {})
  receive_message(
    '_action' => action.to_s,
    'params' => ::Rack::Utils.build_nested_query(params)
  )
end

#receive_stream(stream_name, payload) ⇒ Object

Simulate an external ActionCable broadcast arriving on a stream the component subscribed to via stream_from.

Parameters:

  • stream_name (String)

    The stream name

  • payload (Object)

    The broadcast payload



63
64
65
# File 'lib/live_cable/testing/test_component.rb', line 63

def receive_stream(stream_name, payload)
  channel.broadcast_to(stream_name, payload)
end

#renderedCapybara::Node::Simple

The rendered HTML wrapped in a Capybara node, for use with matchers like have_css / have_content. Requires the capybara gem.

Returns:

  • (Capybara::Node::Simple)


112
113
114
115
116
117
118
119
120
121
# File 'lib/live_cable/testing/test_component.rb', line 112

def rendered
  # ::-prefixed because Delegator subclasses can't resolve top-level
  # constants through their BasicObject ancestry
  unless defined?(::Capybara)
    raise ::LiveCable::Error,
      'Capybara is required for rendered - add it to your Gemfile or use rendered_html'
  end

  ::Capybara.string(rendered_html)
end

#rendered_htmlString

The component's current HTML, reconstructed from its _refresh broadcasts the same way the JavaScript client builds the DOM.

Returns:

  • (String)


98
99
100
101
102
103
104
105
106
# File 'lib/live_cable/testing/test_component.rb', line 98

def rendered_html
  state = RenderState.new

  broadcasts(:_refresh).each do |broadcast|
    state.apply(broadcast[:_refresh])
  end

  state.html
end

#set_reactive(name, value) ⇒ Object

Update a writable reactive variable, as if the client sent a live-reactive input update. Raises (or broadcasts an _error when mounted with raise_errors: false) for non-writable variables.

Parameters:

  • name (Symbol, String)

    The reactive variable name

  • value (Object)

    The new value



50
51
52
53
54
55
56
# File 'lib/live_cable/testing/test_component.rb', line 50

def set_reactive(name, value)
  receive_message(
    '_action' => '_reactive',
    'name' => name.to_s,
    'value' => value
  )
end

#unmountObject

Disconnect the component, running disconnect lifecycle callbacks and cleaning up its state - like a client unsubscribing.



125
126
127
# File 'lib/live_cable/testing/test_component.rb', line 125

def unmount
  component.disconnect
end