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
22
23
24
# File 'lib/live_cable/testing/test_component.rb', line 17

def initialize(component, connection, channel)
  super(component)
  @connection = connection
  @channel = channel
  @broadcasts = []

  capture_broadcasts(component)
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>)


76
77
78
79
80
# File 'lib/live_cable/testing/test_component.rb', line 76

def broadcasts(key = nil)
  return @broadcasts.dup unless key

  @broadcasts.select { |broadcast| broadcast.key?(key) }
end

#clear_broadcastsObject

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



84
85
86
# File 'lib/live_cable/testing/test_component.rb', line 84

def clear_broadcasts
  @broadcasts.clear
end

#componentLiveCable::Component

Returns The underlying component instance.

Returns:



27
28
29
# File 'lib/live_cable/testing/test_component.rb', line 27

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: })



93
94
95
# File 'lib/live_cable/testing/test_component.rb', line 93

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



40
41
42
43
44
45
# File 'lib/live_cable/testing/test_component.rb', line 40

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



66
67
68
# File 'lib/live_cable/testing/test_component.rb', line 66

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)


115
116
117
118
119
120
121
122
123
124
# File 'lib/live_cable/testing/test_component.rb', line 115

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)


101
102
103
104
105
106
107
108
109
# File 'lib/live_cable/testing/test_component.rb', line 101

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



53
54
55
56
57
58
59
# File 'lib/live_cable/testing/test_component.rb', line 53

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.



128
129
130
# File 'lib/live_cable/testing/test_component.rb', line 128

def unmount
  component.disconnect
end