render_turbo_stream 3.0.4 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.4"
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.4
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: []