render_turbo_stream 3.0.5 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,29 +9,57 @@ module RenderTurboStream
9
9
 
10
10
  channel = "authenticated-user-#{user.id}"
11
11
 
12
- libs = RenderTurboStream::Test::Request::Libs
12
+ libs = RenderTurboStream::Test::Request::Libs.new(response)
13
13
 
14
- r = libs.select_responses(response, channel, target_id, action, type: :channel, &block)
14
+ r = libs.select_responses(channel, RenderTurboStream::Libs.target_id_to_target(target_id), action, &block)
15
15
 
16
16
  assert(
17
17
  r[:responses].length == count,
18
- libs.assert_error_message(count, r[:responses].length, r[:log])
18
+ libs.class.assert_error_message(count, r[:responses].length, r[:log])
19
+ )
20
+ end
21
+
22
+ def assert_action_to_me(user, action, count: 1, &block)
23
+
24
+ channel = "authenticated-user-#{user.id}"
25
+
26
+ libs = RenderTurboStream::Test::Request::Libs.new(response)
27
+
28
+ r = libs.select_actions(channel, action, &block)
29
+
30
+ assert(
31
+ r[:responses].length == count,
32
+ libs.class.assert_error_message(count, r[:responses].length, r[:log])
19
33
  )
20
34
  end
21
35
 
22
36
  # Assert a action by turbo streams channel to a group of authenticated users
23
37
 
24
- def assert_channel_to_authenticated_group(group, target_id, action: nil, count: 1, &block)
38
+ def assert_channel_to_authenticated_group(group, target_id, count: 1, &block)
39
+
40
+ channel = "authenticated-group-#{group}"
41
+
42
+ libs = RenderTurboStream::Test::Request::Libs.new(response)
43
+
44
+ r = libs.select_responses(channel, target_id, action, &block)
45
+
46
+ assert(
47
+ r[:responses].length == count,
48
+ libs.class.assert_error_message(count, r[:responses].length, r[:log])
49
+ )
50
+ end
51
+
52
+ def assert_action_to_authenticated_group(group, action, count: 1, &block)
25
53
 
26
54
  channel = "authenticated-group-#{group}"
27
55
 
28
- libs = RenderTurboStream::Test::Request::Libs
56
+ libs = RenderTurboStream::Test::Request::Libs.new(response)
29
57
 
30
- r = libs.select_responses(response, channel, target_id, action, type: :channel, &block)
58
+ r = libs.select_actions(channel, action, &block)
31
59
 
32
60
  assert(
33
61
  r[:responses].length == count,
34
- libs.assert_error_message(count, r[:responses].length, r[:log])
62
+ libs.class.assert_error_message(count, r[:responses].length, r[:log])
35
63
  )
36
64
  end
37
65
 
@@ -39,13 +67,25 @@ module RenderTurboStream
39
67
 
40
68
  def assert_channel_to_all(target_id, action: nil, count: 1, &block)
41
69
 
42
- libs = RenderTurboStream::Test::Request::Libs
70
+ libs = RenderTurboStream::Test::Request::Libs.new(response)
71
+
72
+ r = libs.select_responses('all', RenderTurboStream::Libs.target_id_to_target(target_id), action, &block)
73
+
74
+ assert(
75
+ r[:responses].length == count,
76
+ libs.class.assert_error_message(count, r[:responses].length, r[:log])
77
+ )
78
+ end
79
+
80
+ def assert_action_to_all(action, count: 1, &block)
81
+
82
+ libs = RenderTurboStream::Test::Request::Libs.new(response)
43
83
 
44
- r = libs.select_responses(response, 'all', target_id, action, type: :channel, &block)
84
+ r = libs.select_actions('all', action, &block)
45
85
 
46
86
  assert(
47
87
  r[:responses].length == count,
48
- libs.assert_error_message(count, r[:responses].length, r[:log])
88
+ libs.class.assert_error_message(count, r[:responses].length, r[:log])
49
89
  )
50
90
  end
51
91
 
@@ -6,7 +6,7 @@ module RenderTurboStream
6
6
  # Assert that each of given target_ids is targeted exactly once
7
7
 
8
8
  def assert_once_targeted(*target_ids)
9
- responses = RenderTurboStream::Test::Request::Libs.all_turbo_responses(response)
9
+ responses = RenderTurboStream::Test::Request::Libs.new(response).all_turbo_responses
10
10
  id_counts = {}
11
11
  responses.each do |r|
12
12
  if r['target'].is_a?(Array)
@@ -33,17 +33,17 @@ module RenderTurboStream
33
33
  # Helper for the developer for writing tests: Array with all attributes of all turbo-stream and turbo-channel actions that runned on the last request
34
34
 
35
35
  def all_turbo_responses
36
- RenderTurboStream::Test::Request::Libs.all_turbo_responses(response)
36
+ RenderTurboStream::Test::Request::Libs.new(response).all_turbo_responses
37
37
  end
38
38
 
39
39
  # Returns Array of all target_ids that arre affected at least once on the last response
40
40
  def turbo_targets
41
- RenderTurboStream::Test::Request::Libs.turbo_targets(response)
41
+ RenderTurboStream::Test::Request::Libs.new(response).turbo_targets
42
42
  end
43
43
 
44
44
  # Returns the path sent to turbo_stream.redirect_to.
45
- def turbo_redirect_to
46
- resps = RenderTurboStream::Test::Request::Libs.all_turbo_responses(response)
45
+ def assert_turbo_redirect_to(path)
46
+ resps = RenderTurboStream::Test::Request::Libs.new(response).all_turbo_responses
47
47
  url = nil
48
48
  resps.each do |r|
49
49
  if r['type'] == 'stream-command'
@@ -56,19 +56,31 @@ module RenderTurboStream
56
56
  end
57
57
  end
58
58
  end
59
- url
59
+ assert url == path, "Expected turbo_redirect_to «#{path}» but got: «#{url}»"
60
60
  end
61
61
 
62
62
  # assert one or more specific actions to a target_id
63
- def assert_stream_response(target_id, action: nil, count: 1, type: :stream, &block)
63
+ def assert_stream_response(target_id, action: nil, count: 1, &block)
64
64
 
65
- libs = RenderTurboStream::Test::Request::Libs
65
+ libs = RenderTurboStream::Test::Request::Libs.new(response)
66
66
 
67
- r = libs.select_responses(response, false, target_id, action, type: type, &block)
67
+ r = libs.select_responses( false, RenderTurboStream::Libs.target_id_to_target(target_id), action, &block)
68
68
 
69
69
  assert(
70
70
  r[:responses].length == count,
71
- libs.assert_error_message(count, r[:responses].length, r[:log])
71
+ libs.class.assert_error_message(count, r[:responses].length, r[:log])
72
+ )
73
+ end
74
+
75
+ def assert_stream_action(action, target_id: nil, count: 1, &block)
76
+
77
+ libs = RenderTurboStream::Test::Request::Libs.new(response)
78
+
79
+ r = libs.select_actions( false, action, &block)
80
+
81
+ assert(
82
+ r[:responses].length == count,
83
+ libs.class.assert_error_message(count, r[:responses].length, r[:log])
72
84
  )
73
85
  end
74
86
 
@@ -2,10 +2,15 @@ module RenderTurboStream
2
2
  module Test
3
3
  module Request
4
4
  class Libs
5
- def self.all_turbo_responses(response)
6
- e = Nokogiri::HTML(response.body).search('#rendered-partials').first
5
+
6
+ def initialize(response)
7
+ @response = response
8
+ end
9
+
10
+ def all_turbo_responses
11
+ e = Nokogiri::HTML(@response.body).search('#rendered-partials').first
7
12
  res = (e.present? ? JSON.parse(e.inner_html) : [])
8
- response.headers.each do |k, v|
13
+ @response.headers.each do |k, v|
9
14
  next unless k.match(/^test-turbo-channel-[\d]+$/)
10
15
  h = JSON.parse(v)
11
16
  res.push(h)
@@ -13,90 +18,119 @@ module RenderTurboStream
13
18
  res
14
19
  end
15
20
 
16
- def self.select_responses(response, channel, target_id, action, type: nil, prohibit_multiple_to_same_target: [:replace], &block)
17
- all = all_turbo_responses(response)
21
+ # checks only for rendered partials, not for actions
22
+
23
+ def select_responses(channel, target, action, prohibit_multiple_to_same_target: [:replace], &block)
24
+ all = all_turbo_responses
18
25
  res = { log: [], responses: [] }
26
+ raise 'Missing argument: target' unless target.present?
19
27
 
20
- if !target_id.present?
21
- res[:log].push("No target «##{target_id}» provided!")
28
+ if !target.present?
29
+ res[:log].push("missing argument: target")
22
30
  elsif prohibit_multiple_to_same_target.present?
23
31
  has_prohibited_action = false
24
32
  c = all.select do |e|
25
33
  if prohibit_multiple_to_same_target.include?(e['action']&.to_sym)
26
34
  has_prohibited_action = true
27
35
  end
28
- e['target'] == "##{target_id}"
36
+ e['target'] == target
29
37
  end.length
30
38
  if c >= 2 && has_prohibited_action
31
- res[:log].push("Target «##{target_id}» is targeted #{c} #{'time'.pluralize(c)} which is prohibited for the actions #{prohibit_multiple_to_same_target.join(', ')}")
39
+ res[:log].push("Target «#{target}» is targeted #{c} #{'time'.pluralize(c)} which is prohibited for the actions #{prohibit_multiple_to_same_target.join(', ')}")
32
40
  return res
33
41
  end
34
42
  end
35
43
 
36
- id_matched = false
44
+ target_matched = false
45
+ permitted_types = if channel == false
46
+ ['stream-partial', 'stream-template']
47
+ else
48
+ ['stream-partial', 'stream-template', 'channel-partial', 'channel-template']
49
+ end
37
50
 
38
51
  responses = all.select do |a|
39
- types = [a['type']]
40
- if ['channel-partial', 'channel-template'].include?(a['type'])
41
- types.push('channel')
42
- elsif ['stream-partial'].include?(a['type'])
43
- types.push('stream')
44
- elsif ['stream-command'].include?(a['type'])
45
- types.push('command')
46
- types.push('stream')
47
- elsif ['channel-command'].include?(a['type'])
48
- types.push('command')
49
- types.push('channel')
50
- end
51
52
 
52
- if target_id.present? && a['target'] == "##{target_id}"
53
- id_matched = true
53
+ if a['target'] == target
54
+ target_matched = true
54
55
  end
55
56
 
56
- if target_id.present? && a['target'] != "##{target_id}"
57
+ if a['target'] != target
57
58
  false
58
- elsif type.present? && !types.include?(type.to_s)
59
- res[:log].push("Target «##{target_id}»: Types #{types.join(', ')} not matching with given type «#{type}»")
59
+ elsif !permitted_types.include?(a['type'])
60
+ res[:log].push("Type «#{a['type']}» does not match the types you are looking for: #{permitted_types}")
60
61
  false
61
62
  elsif channel.present? && a['channel'] != channel.to_s
62
- res[:log].push("Target «##{target_id}»: Channel #{a['channel']} not matching with given channel «#{channel}»")
63
+ res[:log].push("Target «#{target}»: Channel #{a['channel']} not matching with given channel «#{channel}»")
63
64
  false
64
65
  elsif action.present? && a['action'] != action.to_s
65
- res[:log].push("Target «##{target_id}»: Action #{a['action']} not matching with given action «#{action}»")
66
+ res[:log].push("Target «#{target}»: Action «#{a['action']}» not matching with given action «#{action}»")
66
67
  false
67
68
  elsif block_given?
68
- if types.include?('command')
69
- args = a['array'][1..-1]
70
- if yield(args)
69
+ nok = Nokogiri::HTML(a['html_response'])
70
+ if yield(nok).present?
71
71
  true
72
72
  else
73
- res[:log].push("Given block not matching Arguments => «#{args}»")
73
+ res[:log].push("Target «#{target}»: Given block not matching in => «#{nok.inner_html}»")
74
74
  false
75
75
  end
76
- else
77
- nok = Nokogiri::HTML(a['html_response'])
78
- if yield(nok).present?
76
+ else
77
+ true
78
+ end
79
+ end
80
+
81
+ unless target_matched
82
+ res[:log].push("Target «#{target}» not found in targets: #{turbo_targets}")
83
+ end
84
+
85
+ res[:responses] = responses
86
+ res
87
+ end
88
+
89
+ # checks only for commands, not for rendered partials
90
+ def select_actions(channel, action, &block)
91
+ all = all_turbo_responses
92
+ res = { log: [], responses: [] }
93
+ possible_types = ['stream-command', 'channel-command']
94
+ raise 'Missing argument: action' unless action.present?
95
+
96
+ action_found = false
97
+
98
+ responses = all.select do |a|
99
+ if a['action'] == action.to_s
100
+ action_found = true
101
+ end
102
+
103
+ if a['action'] != action.to_s
104
+ false
105
+ elsif !possible_types.include?(a['type'])
106
+ res[:log].push("Action «#{action}» is type «#{a['type']}» (accepted types are: #{possible_types.join(', ')})")
107
+ false
108
+ elsif channel.present? && a['channel'] != channel.to_s
109
+ res[:log].push("Channel «#{channel}» not found within action «#{action}»")
110
+ false
111
+ elsif block_given?
112
+ args = a['array'][1..-1]
113
+ if yield(args)
79
114
  true
80
115
  else
81
- res[:log].push("Target «##{target_id}»: Given block not matching (checked by .present?)")
116
+ res[:log].push("Given block not matching Arguments => «#{args}»")
82
117
  false
83
118
  end
84
- end
85
119
  else
86
120
  true
87
121
  end
88
122
  end
89
123
 
90
- unless id_matched
91
- res[:log].push("Target «##{target_id}» not found")
124
+ unless action_found
125
+ res[:log].push("Action «#{action}» not found under responded actions: #{turbo_actions}")
92
126
  end
93
127
 
94
128
  res[:responses] = responses
95
129
  res
96
130
  end
97
131
 
98
- def self.turbo_targets(response)
99
- responses = all_turbo_responses(response)
132
+ def turbo_targets
133
+ responses = all_turbo_responses
100
134
  targets = []
101
135
  responses.each do |r|
102
136
  if r['target'].is_a?(Array)
@@ -111,6 +145,27 @@ module RenderTurboStream
111
145
  targets
112
146
  end
113
147
 
148
+ def turbo_actions
149
+ responses = all_turbo_responses
150
+ actions = []
151
+ responses.each do |r|
152
+ actions.push(r['action']) unless actions.include?(r['action'])
153
+ end
154
+
155
+ actions
156
+ end
157
+
158
+ def targets_counts
159
+ responses = all_turbo_responses
160
+ targets = {}
161
+ responses.each do |r|
162
+ targets[r['target']] ||= 0
163
+ targets[r['target']] += 1
164
+ end
165
+
166
+ targets
167
+ end
168
+
114
169
  def self.assert_error_message(expected, received, log)
115
170
  [
116
171
  "Expected #{expected} #{'response'.pluralize(expected)} but found #{received}.",
@@ -1,3 +1,3 @@
1
1
  module RenderTurboStream
2
- VERSION = "3.0.5"
2
+ VERSION = "4.0.0"
3
3
  end
@@ -12,4 +12,7 @@ require 'render_turbo_stream/controller_channel_helpers'
12
12
  require 'render_turbo_stream/channel_view_helpers'
13
13
 
14
14
  require 'render_turbo_stream/channel_libs'
15
+ require 'render_turbo_stream/controller_libs'
16
+ require 'render_turbo_stream/check_template'
17
+ require 'render_turbo_stream/libs'
15
18
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: render_turbo_stream
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.5
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - christian
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-12 00:00:00.000000000 Z
11
+ date: 2023-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -24,11 +24,12 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 7.0.3
27
- description: Handles translated flash messages, sets status and renders partials via
28
- Turbo Stream or Turbo::StreamsChannel directly from the controller. No need to write
29
- *.turbo_stream.* templates. Together with the turbo_power gem or custom turbo_stream
30
- actions, it can run javascript. Redirects can be handled easily and in multiple
31
- ways. Through request testing helpers, this allows for consistent testing strategy.
27
+ description: Handles translated flash messages, sets status, wrapps partials in the
28
+ necessary frames and renders via Turbo Stream or Turbo::StreamsChannel directly
29
+ from the controller. No need to write *.turbo_stream.* templates. Together with
30
+ the turbo_power gem or custom turbo_stream actions, it can run javascript. Redirects
31
+ can be handled easily and in multiple ways. Through request testing helpers, this
32
+ allows for consistent testing strategy.
32
33
  email:
33
34
  - christian@sedlmair.ch
34
35
  executables: []
@@ -39,6 +40,7 @@ files:
39
40
  - Rakefile
40
41
  - app/controllers/render_turbo_stream/application_controller.rb
41
42
  - app/controllers/render_turbo_stream/render_turbo_stream_render_controller.rb
43
+ - app/views/layouts/_add_turbo_frame_tag.html.erb
42
44
  - app/views/render_turbo_stream.turbo_stream.erb
43
45
  - app/views/render_turbo_stream_command.html.erb
44
46
  - app/views/render_turbo_stream_empty_template.html.erb
@@ -46,9 +48,12 @@ files:
46
48
  - lib/render_turbo_stream.rb
47
49
  - lib/render_turbo_stream/channel_libs.rb
48
50
  - lib/render_turbo_stream/channel_view_helpers.rb
51
+ - lib/render_turbo_stream/check_template.rb
49
52
  - lib/render_turbo_stream/controller_channel_helpers.rb
50
53
  - lib/render_turbo_stream/controller_helpers.rb
54
+ - lib/render_turbo_stream/controller_libs.rb
51
55
  - lib/render_turbo_stream/engine.rb
56
+ - lib/render_turbo_stream/libs.rb
52
57
  - lib/render_turbo_stream/railtie.rb
53
58
  - lib/render_turbo_stream/test/request/channel_helpers.rb
54
59
  - lib/render_turbo_stream/test/request/helpers.rb
@@ -80,6 +85,5 @@ requirements: []
80
85
  rubygems_version: 3.4.12
81
86
  signing_key:
82
87
  specification_version: 4
83
- summary: Complete workflow for turbo streams and channels. With testing strategy.
84
- Rails like.
88
+ summary: Complete workflow for turbo that just works and has a testing strategy.
85
89
  test_files: []