glib-web 4.39.0 → 4.39.1

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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/glib/auth/policy.rb +13 -0
  3. data/app/views/json_ui/garage/actions/_dialogs.json.jbuilder +2 -2
  4. data/app/views/json_ui/garage/forms/dynamic_group.json.jbuilder +2 -2
  5. data/app/views/json_ui/garage/forms/file_upload_new.json.jbuilder +1 -1
  6. data/app/views/json_ui/garage/forms/partial_update.json.jbuilder +12 -12
  7. data/app/views/json_ui/garage/forms/selects.json.jbuilder +1 -1
  8. data/app/views/json_ui/garage/forms/show_hide.json.jbuilder +62 -7
  9. data/app/views/json_ui/garage/lists/edit_mode.json.jbuilder +4 -4
  10. data/app/views/json_ui/garage/pages/custom_style_class.json.jbuilder +1 -1
  11. data/app/views/json_ui/garage/pages/nav_buttons.json.jbuilder +31 -13
  12. data/app/views/json_ui/garage/panels/_styled.json.jbuilder +8 -8
  13. data/app/views/json_ui/garage/panels/hover.json.jbuilder +2 -2
  14. data/app/views/json_ui/garage/panels/timeline.json.jbuilder +5 -5
  15. data/app/views/json_ui/garage/panels/ul.json.jbuilder +1 -1
  16. data/app/views/json_ui/garage/tables/bulk_edit.json.jbuilder +1 -1
  17. data/app/views/json_ui/garage/test_page/file_upload_new.json.jbuilder +1 -1
  18. data/app/views/json_ui/garage/test_page/form.json.jbuilder +6 -6
  19. data/app/views/json_ui/garage/test_page/form_dynamic.json.jbuilder +2 -2
  20. data/app/views/json_ui/garage/test_page/logics_set.json.jbuilder +94 -0
  21. data/app/views/json_ui/garage/views/components_replace.json.jbuilder +13 -13
  22. data/app/views/json_ui/garage/views/components_set.json.jbuilder +6 -6
  23. data/app/views/json_ui/garage/views/fields_focus.json.jbuilder +22 -22
  24. data/lib/glib/json_crawler/router.rb +45 -24
  25. data/lib/glib/rubocop/cops/json_ui/base_nested_parameter.rb +145 -0
  26. data/lib/glib/rubocop/cops/json_ui/nested_action_parameter.rb +55 -0
  27. data/lib/glib/rubocop/cops/json_ui/nested_block_parameter.rb +51 -0
  28. data/lib/glib/rubocop/cops/multiline_method_call_style.rb +74 -5
  29. data/lib/glib/rubocop.rb +3 -0
  30. data/lib/glib/test/parallel_coverage.rb +38 -0
  31. data/lib/glib/test_helpers.rb +12 -0
  32. data/lib/glib-web.rb +1 -0
  33. metadata +6 -1
@@ -11,44 +11,44 @@ page.body padding: glib_json_padding_body, childViews: ->(body) do
11
11
  method: 'post',
12
12
  width: 300,
13
13
  childViews: ->(form) do
14
- res.fields_text id: 'first', name: 'user[full_name]', label: 'Full name', placeholder: 'Full name', width: 'matchParent'
15
- res.spacer height: 4
16
- res.fields_number id: 'second', name: 'user[age]', label: 'Age', placeholder: 'Age', width: 'matchParent'
17
- res.spacer height: 4
18
- res.fields_textarea id: 'third', name: 'user[boi]', label: 'Bio', placeholder: 'Bio', width: 'matchParent'
19
- res.spacer height: 4
20
- res.fields_date id: 'fourth', name: 'user[birth_date]', label: 'Birth date', placeholder: 'Birth date', width: 'matchParent'
21
- res.spacer height: 4
22
- res.panels_horizontal childViews: ->(hori) do
23
- res.button text: 'focus1', onClick: ->(action) do
14
+ form.fields_text id: 'first', name: 'user[full_name]', label: 'Full name', placeholder: 'Full name', width: 'matchParent'
15
+ form.spacer height: 4
16
+ form.fields_number id: 'second', name: 'user[age]', label: 'Age', placeholder: 'Age', width: 'matchParent'
17
+ form.spacer height: 4
18
+ form.fields_textarea id: 'third', name: 'user[boi]', label: 'Bio', placeholder: 'Bio', width: 'matchParent'
19
+ form.spacer height: 4
20
+ form.fields_date id: 'fourth', name: 'user[birth_date]', label: 'Birth date', placeholder: 'Birth date', width: 'matchParent'
21
+ form.spacer height: 4
22
+ form.panels_horizontal childViews: ->(hori) do
23
+ hori.button text: 'focus1', onClick: ->(action) do
24
24
  action.fields_focus targetId: 'first'
25
25
  end
26
- res.spacer width: 4
27
- res.button text: 'focus2', onClick: ->(action) do
26
+ hori.spacer width: 4
27
+ hori.button text: 'focus2', onClick: ->(action) do
28
28
  action.fields_focus targetId: 'second'
29
29
  end
30
- res.spacer width: 4
31
- res.button text: 'focus3', onClick: ->(action) do
30
+ hori.spacer width: 4
31
+ hori.button text: 'focus3', onClick: ->(action) do
32
32
  action.fields_focus targetId: 'third'
33
33
  end
34
- res.spacer width: 4
35
- res.button text: 'focus4', onClick: ->(action) do
34
+ hori.spacer width: 4
35
+ hori.button text: 'focus4', onClick: ->(action) do
36
36
  action.fields_focus targetId: 'fourth'
37
37
  end
38
- res.spacer width: 4
39
- res.button text: 'blur', onClick: ->(action) do
38
+ hori.spacer width: 4
39
+ hori.button text: 'blur', onClick: ->(action) do
40
40
  action.fields_focus targetId: 'first', onFocus: ->(saction) do
41
41
  saction.timeouts_set interval: 1000, onTimeout: ->(ssaction) { ssaction.fields_blur }
42
42
  end
43
43
  end
44
- res.spacer width: 4
45
- res.button text: 'reset', onClick: ->(action) do
44
+ hori.spacer width: 4
45
+ hori.button text: 'reset', onClick: ->(action) do
46
46
  action.fields_reset targetIds: ['first', 'second', 'third', 'fourth'], onReset: ->(saction) do
47
47
  saction.snackbars_alert styleClasses: ['success'], message: 'Reset full name!'
48
48
  end
49
49
  end
50
- res.spacer width: 4
51
- res.fields_submit text: 'submit'
50
+ hori.spacer width: 4
51
+ hori.fields_submit text: 'submit'
52
52
  end
53
53
  end
54
54
 
@@ -8,20 +8,20 @@ module Glib
8
8
  attr_reader :http_actions
9
9
  attr_accessor :host, :skip_similar_page
10
10
 
11
- def log(action, url, response = nil)
12
- if url.present?
13
- url = remove_params(url, [:__glib_permission_test])
11
+ def log(action, key_data, response = nil)
12
+ # Sometimes `key_data` may not be an actual URL, e.g. in the context of dialogs_alert,
13
+ # it is the alert message.
14
+ if key_data&.start_with?('http://', 'https://')
15
+ key_data = remove_params(key_data, [:__glib_permission_test])
14
16
  end
15
17
 
16
18
  @last_log = [
17
19
  action,
18
20
  response.present? ? response.code : nil,
19
- url
21
+ key_data
20
22
  ].compact.join(
21
23
  ' :: '
22
- )
23
-
24
- # puts @last_log
24
+ )
25
25
 
26
26
  @logger += ' ' * @depth + @last_log + "\n"
27
27
  end
@@ -172,24 +172,27 @@ module Glib
172
172
  crawler_actions.each do |crawler_action|
173
173
  action, url, params = crawler_action
174
174
 
175
- if url.present?
176
- url = add_params(url, __glib_permission_test: true)
177
- end
178
-
179
- params = JSON.parse(params) if params.is_a?(String)
180
- params ||= {}
181
-
182
- case action.to_s.downcase
183
- when 'http/post-v1', 'forms/post'
184
- http.post(url, action, params)
185
- when 'http/patch-v1', 'forms/patch'
186
- http.patch(url, action, params)
187
- when 'http/put-v1', 'forms/put'
188
- http.put(url, action, params)
189
- when 'http/delete-v1'
190
- http.delete(url, action, params)
175
+ # In full mode, wrap each action in a transaction that gets rolled back
176
+ # to ensure database state is reset between each URL check (prevent database contamination)
177
+ if ENV['GLIB_DISABLE_PERMISSION_TEST_SKIP'] == 'true'
178
+ # This solution is important for permissions tests (not as much in the crawler tests),
179
+ # because in permission tests, the user hits every single available URLs with a single purpose
180
+ # of checking the permission of every URL, meaning that one incorrect result (e.g. 403 instead of 200 due to
181
+ # side effect from previous URL requests) cannot be tolerated.
182
+ #
183
+ # On the other hand, crawler tests are expected to cover only one scenario anyway, so
184
+ # having the scenario changed (due to side effects) is fine. We decided it's better not
185
+ # to apply this solution for crawler tests out of performance considerations.
186
+ ActiveRecord::Base.transaction do
187
+ execute_crawler_action(http, action, url, params)
188
+ raise ActiveRecord::Rollback
189
+ end
191
190
  else
192
- http.get(url, action, params)
191
+ # In skip mode, add the permission test parameter
192
+ if url.present?
193
+ url = add_params(url, __glib_permission_test: true)
194
+ end
195
+ execute_crawler_action(http, action, url, params)
193
196
  end
194
197
  end
195
198
  end
@@ -224,6 +227,24 @@ module Glib
224
227
  end
225
228
 
226
229
  private
230
+ def execute_crawler_action(http, action, url, params)
231
+ params = JSON.parse(params) if params.is_a?(String)
232
+ params ||= {}
233
+
234
+ case action.to_s.downcase
235
+ when 'http/post-v1', 'forms/post'
236
+ http.post(url, action, params)
237
+ when 'http/patch-v1', 'forms/patch'
238
+ http.patch(url, action, params)
239
+ when 'http/put-v1', 'forms/put'
240
+ http.put(url, action, params)
241
+ when 'http/delete-v1'
242
+ http.delete(url, action, params)
243
+ else
244
+ http.get(url, action, params)
245
+ end
246
+ end
247
+
227
248
  def add_params(url, new_params)
228
249
  uri = URI(url)
229
250
  existing = URI.decode_www_form(uri.query || '')
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Glib
6
+ module JsonUi
7
+ # Base class for checking nested block parameter violations in JsonUi templates.
8
+ # Handles both parameter shadowing and incorrect usage of outer variables.
9
+ class BaseNestedParameter < Base
10
+ extend AutoCorrector
11
+
12
+ MSG_OUTER_VAR = 'Use the immediate block parameter `%<immediate>s` instead of outer variable `%<outer>s`.'
13
+
14
+ def on_block(node)
15
+ check_nested_block(node)
16
+ end
17
+
18
+ alias on_numblock on_block
19
+
20
+ private
21
+
22
+ def check_nested_block(node)
23
+ block_param = extract_block_param(node)
24
+ return unless block_param
25
+ return unless relevant_block?(node)
26
+
27
+ parent_blocks = find_parent_relevant_blocks(node)
28
+ return if parent_blocks.empty?
29
+
30
+ parent_params = parent_blocks.filter_map { |b| extract_block_param(b) }
31
+
32
+ # Check for parameter shadowing
33
+ check_shadowing(node, block_param, parent_params)
34
+
35
+ # Check for incorrect usage of outer variables
36
+ check_send_nodes_in_body(node.body, block_param, parent_params)
37
+ end
38
+
39
+ def check_shadowing(node, block_param, parent_params)
40
+ parent_params.each do |parent_param|
41
+ next unless block_param == parent_param
42
+
43
+ param_node = node.arguments.children.first
44
+ suggested_name = suggest_param_name(parent_param)
45
+
46
+ add_offense(
47
+ param_node,
48
+ message: shadowing_message(parent_param, suggested_name)
49
+ ) do |corrector|
50
+ corrector.replace(param_node, suggested_name)
51
+ replace_param_usages(corrector, node.body, parent_param, suggested_name)
52
+ end
53
+ end
54
+ end
55
+
56
+ def check_send_nodes_in_body(body_node, current_param, parent_params)
57
+ return unless body_node
58
+
59
+ body_node.each_child_node do |child|
60
+ if child.send_type? || child.csend_type?
61
+ check_send_node(child, current_param, parent_params)
62
+ elsif !child.block_type? && !child.numblock_type?
63
+ # Recurse into non-block nodes
64
+ check_send_nodes_in_body(child, current_param, parent_params)
65
+ end
66
+ end
67
+ end
68
+
69
+ def check_send_node(send_node, current_param, parent_params)
70
+ receiver = send_node.receiver
71
+ return unless receiver&.lvar_type?
72
+
73
+ receiver_name = receiver.children.first
74
+
75
+ parent_params.each do |parent_param|
76
+ next unless receiver_name == parent_param.to_sym
77
+
78
+ add_offense(
79
+ receiver,
80
+ message: format(MSG_OUTER_VAR, immediate: current_param, outer: parent_param)
81
+ ) do |corrector|
82
+ corrector.replace(receiver, current_param.to_s)
83
+ end
84
+ break
85
+ end
86
+ end
87
+
88
+ def extract_block_param(node)
89
+ return nil unless node.block_type? || node.numblock_type?
90
+ return nil if node.numblock_type? # Numbered blocks not supported
91
+
92
+ args = node.arguments
93
+ return nil if args.children.empty?
94
+
95
+ args.children.first.children.first
96
+ end
97
+
98
+ def find_parent_relevant_blocks(node)
99
+ blocks = []
100
+ current = node.parent
101
+
102
+ while current
103
+ if (current.block_type? || current.numblock_type?) && current != node
104
+ blocks << current if relevant_block?(current)
105
+ end
106
+ current = current.parent
107
+ end
108
+
109
+ blocks
110
+ end
111
+
112
+ def lambda_block?(block_node)
113
+ block_node.block_type? && block_node.send_node.method_name == :lambda
114
+ end
115
+
116
+ def hash_pair_parent(block_node)
117
+ current = block_node.parent
118
+ current if current&.pair_type?
119
+ end
120
+
121
+ def replace_param_usages(corrector, body_node, old_name, new_name)
122
+ return unless body_node
123
+
124
+ body_node.each_descendant(:lvar) do |lvar_node|
125
+ corrector.replace(lvar_node, new_name) if lvar_node.children.first == old_name.to_sym
126
+ end
127
+ end
128
+
129
+ def suggest_param_name(parent_param)
130
+ parent_param.to_s.start_with?('sub') ? "#{parent_param}2" : "sub#{parent_param}"
131
+ end
132
+
133
+ def shadowing_message(parent_param, suggested_name)
134
+ "Avoid shadowing the outer parameter `#{parent_param}`. Use a different name like `#{suggested_name}`."
135
+ end
136
+
137
+ # To be implemented by subclasses
138
+ def relevant_block?(_block_node)
139
+ raise NotImplementedError, "#{self.class} must implement #relevant_block?"
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_nested_parameter'
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module Glib
8
+ module JsonUi
9
+ # Enforces using the immediate block parameter instead of outer block variables
10
+ # in nested action blocks (onClick, onClose, onChange, etc.) in JsonUi templates.
11
+ #
12
+ # @example
13
+ # # bad - parameter shadowing
14
+ # button onClick: ->(action) do
15
+ # action.dialogs_alert onClose: ->(action) do # shadows outer 'action'
16
+ # action.snackbars_alert message: 'Closed'
17
+ # end
18
+ # end
19
+ #
20
+ # # good
21
+ # button onClick: ->(action) do
22
+ # action.dialogs_alert onClose: ->(subaction) do
23
+ # subaction.snackbars_alert message: 'Closed'
24
+ # end
25
+ # end
26
+ #
27
+ # # bad - using outer variable
28
+ # button onClick: ->(action) do
29
+ # action.dialogs_alert onClose: ->(subaction) do
30
+ # action.forms_submit # using 'action' instead of 'subaction'
31
+ # end
32
+ # end
33
+ #
34
+ # # good
35
+ # button onClick: ->(action) do
36
+ # action.dialogs_alert onClose: ->(subaction) do
37
+ # subaction.forms_submit
38
+ # end
39
+ # end
40
+ class NestedActionParameter < BaseNestedParameter
41
+ private
42
+
43
+ def relevant_block?(block_node)
44
+ return false unless lambda_block?(block_node)
45
+
46
+ pair = hash_pair_parent(block_node)
47
+ return false unless pair
48
+
49
+ pair.key.sym_type? && pair.key.value.to_s.start_with?('on')
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_nested_parameter'
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module Glib
8
+ module JsonUi
9
+ # Enforces using the immediate block parameter instead of outer block variables
10
+ # in nested view blocks (childViews, content) in JsonUi templates.
11
+ #
12
+ # @example
13
+ # # bad - using outer variable
14
+ # scroll.panels_form childViews: ->(form) do
15
+ # scroll.label text: 'TEST' # using 'scroll' instead of 'form'
16
+ # end
17
+ #
18
+ # # good
19
+ # scroll.panels_form childViews: ->(form) do
20
+ # form.label text: 'TEST'
21
+ # end
22
+ #
23
+ # # bad - parameter shadowing
24
+ # scroll.panels_form childViews: ->(form) do
25
+ # form.panels_responsive childViews: ->(form) do # shadows outer 'form'
26
+ # form.fields_text name: 'user[field]'
27
+ # end
28
+ # end
29
+ #
30
+ # # good
31
+ # scroll.panels_form childViews: ->(form) do
32
+ # form.panels_responsive childViews: ->(res) do
33
+ # res.fields_text name: 'user[field]'
34
+ # end
35
+ # end
36
+ class NestedBlockParameter < BaseNestedParameter
37
+ private
38
+
39
+ def relevant_block?(block_node)
40
+ return false unless lambda_block?(block_node)
41
+
42
+ pair = hash_pair_parent(block_node)
43
+ return false unless pair
44
+
45
+ pair.key.sym_type? && [:childViews, :content].include?(pair.key.value)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -37,6 +37,7 @@ module RuboCop
37
37
  return unless multi_line_call_with_args?(node)
38
38
  return if proper_parentheses_style?(node)
39
39
  return if proper_backslash_style?(node) && allow_backslash?
40
+ return if inside_correctable_parent?(node)
40
41
 
41
42
  add_offense(node) do |corrector|
42
43
  autocorrect(corrector, node)
@@ -122,12 +123,28 @@ module RuboCop
122
123
  args
123
124
  end
124
125
 
126
+ def inside_correctable_parent?(node)
127
+ # Check if this node is inside a block that belongs to a multi-line call
128
+ # that will also be corrected. If so, skip this node to avoid conflicts.
129
+ current = node.parent
130
+
131
+ while current
132
+ if current.send_type? || current.csend_type?
133
+ if multi_line_call_with_args?(current) && !proper_parentheses_style?(current)
134
+ return true
135
+ end
136
+ end
137
+ current = current.parent
138
+ end
139
+
140
+ false
141
+ end
142
+
125
143
  def autocorrect(corrector, node)
126
144
  method_end_pos = node.loc.selector.end_pos
127
145
 
128
- # Find the indentation of the method call
129
- line_begin_pos = processed_source.buffer.line_range(node.loc.line).begin_pos
130
- base_indent = node.source_range.begin_pos - line_begin_pos
146
+ # Calculate indentation based on the node's actual column position
147
+ base_indent = node.loc.column
131
148
  arg_indent = ' ' * (base_indent + 2)
132
149
 
133
150
  # Build the new argument list
@@ -137,7 +154,9 @@ module RuboCop
137
154
 
138
155
  if arg.hash_type?
139
156
  arg.pairs.each do |pair|
140
- arg_parts << pair.source
157
+ # Re-indent pair if it contains a block
158
+ pair_source = reindent_pair_with_block(pair, arg_indent)
159
+ arg_parts << pair_source
141
160
  end
142
161
  else
143
162
  arg_parts << arg.source
@@ -151,7 +170,7 @@ module RuboCop
151
170
 
152
171
  # If there's a block, add it on the last argument line
153
172
  if node.block_literal?
154
- block_source = node.block_literal.source
173
+ block_source = reindent_block(node.block_literal, arg_indent)
155
174
  replacement += " #{block_source}"
156
175
  end
157
176
 
@@ -175,6 +194,56 @@ module RuboCop
175
194
 
176
195
  corrector.replace(range, replacement)
177
196
  end
197
+
198
+ def reindent_pair_with_block(pair, base_indent)
199
+ # Check if the pair's value is a block
200
+ return pair.source unless pair.value.block_type?
201
+
202
+ # Format: "key: ->(param) do ... end"
203
+ key_source = pair.key.source
204
+ block_source = reindent_block(pair.value, base_indent)
205
+
206
+ "#{key_source}: #{block_source}"
207
+ end
208
+
209
+ def reindent_block(block_node, base_indent)
210
+ # Get block source lines
211
+ source = block_node.source
212
+ lines = source.lines
213
+
214
+ return source if lines.length == 1 # Single line block, no reindent needed
215
+
216
+ # Find the current indentation of the block's first line
217
+ # (this is usually where "do" appears)
218
+ first_line = lines[0]
219
+
220
+ # Process the block:
221
+ # Line 0: "->(param) do" - keep as is
222
+ # Lines 1..-2: block body - re-indent to base_indent + 2
223
+ # Last line: "end" - indent to base_indent
224
+
225
+ result_lines = []
226
+ block_body_indent = base_indent + ' ' * 2
227
+
228
+ lines.each_with_index do |line, index|
229
+ if index == 0
230
+ # First line: "->(param) do"
231
+ result_lines << line.rstrip
232
+ elsif index == lines.length - 1
233
+ # Last line: "end"
234
+ result_lines << "#{base_indent}#{line.strip}"
235
+ else
236
+ # Body lines: re-indent
237
+ # Remove existing indentation and add new indentation
238
+ stripped = line.lstrip
239
+ next if stripped.empty? # Skip blank lines
240
+
241
+ result_lines << "#{block_body_indent}#{stripped.rstrip}"
242
+ end
243
+ end
244
+
245
+ result_lines.join("\n")
246
+ end
178
247
  end
179
248
  end
180
249
  end
data/lib/glib/rubocop.rb CHANGED
@@ -1,2 +1,5 @@
1
1
  require_relative 'rubocop/cops/localize'
2
2
  require_relative 'rubocop/cops/multiline_method_call_style'
3
+ require_relative 'rubocop/cops/json_ui/base_nested_parameter'
4
+ require_relative 'rubocop/cops/json_ui/nested_block_parameter'
5
+ require_relative 'rubocop/cops/json_ui/nested_action_parameter'
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Glib
4
+ module Test
5
+ # ParallelCoverage configures Rails parallel testing to work properly with SimpleCov.
6
+ #
7
+ # Without this configuration, SimpleCov reports inaccurate coverage (often very low, like 1-2%)
8
+ # when running tests with parallelization enabled, because it only captures data from one worker
9
+ # instead of merging results from all parallel workers.
10
+ #
11
+ # Usage:
12
+ # class ActiveSupport::TestCase
13
+ # include Glib::Test::ParallelCoverage
14
+ # end
15
+ #
16
+ # This will:
17
+ # - Enable parallel test execution using all available processors
18
+ # - Configure SimpleCov to track each worker separately
19
+ # - Automatically merge coverage results from all workers
20
+ module ParallelCoverage
21
+ extend ActiveSupport::Concern
22
+
23
+ included do
24
+ # Set threshold for force parallelization.
25
+ parallelize(workers: :number_of_processors, threshold: 1)
26
+
27
+ # Configure SimpleCov to properly merge coverage from parallel workers
28
+ parallelize_setup do |worker|
29
+ SimpleCov.command_name "#{SimpleCov.command_name}-#{worker}"
30
+ end
31
+
32
+ parallelize_teardown do |_worker|
33
+ SimpleCov.result
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -83,6 +83,18 @@ module Glib
83
83
  "http://#{HOST}/users/sign_out.json"
84
84
  end
85
85
 
86
+ def glib_travel(*args, &block)
87
+ Timecop.travel(*args, &block)
88
+ end
89
+
90
+ def glib_travel_freeze(*args, &block)
91
+ Timecop.freeze(*args, &block)
92
+ end
93
+
94
+ def glib_travel_back
95
+ Timecop.return
96
+ end
97
+
86
98
  private
87
99
  def __execute_crawler(user, inspect_http:, log_file: nil, &block)
88
100
  auth_token = login user
data/lib/glib-web.rb CHANGED
@@ -8,6 +8,7 @@ require 'glib/json_crawler'
8
8
 
9
9
  require 'glib/dynamic_text'
10
10
  require 'glib/test_helpers'
11
+ require 'glib/test/parallel_coverage'
11
12
  require 'glib/integration_test'
12
13
 
13
14
  require 'glib/time_freezable_mailer'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glib-web
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.39.0
4
+ version: 4.39.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''
@@ -376,6 +376,7 @@ files:
376
376
  - app/views/json_ui/garage/test_page/form.json.jbuilder
377
377
  - app/views/json_ui/garage/test_page/form_dynamic.json.jbuilder
378
378
  - app/views/json_ui/garage/test_page/lifecycle.json.jbuilder
379
+ - app/views/json_ui/garage/test_page/logics_set.json.jbuilder
379
380
  - app/views/json_ui/garage/test_page/multiupload.json.jbuilder
380
381
  - app/views/json_ui/garage/test_page/selectable.json.jbuilder
381
382
  - app/views/json_ui/garage/test_page/window.json.jbuilder
@@ -442,9 +443,13 @@ files:
442
443
  - lib/glib/json_crawler/router.rb
443
444
  - lib/glib/mailer_tester.rb
444
445
  - lib/glib/rubocop.rb
446
+ - lib/glib/rubocop/cops/json_ui/base_nested_parameter.rb
447
+ - lib/glib/rubocop/cops/json_ui/nested_action_parameter.rb
448
+ - lib/glib/rubocop/cops/json_ui/nested_block_parameter.rb
445
449
  - lib/glib/rubocop/cops/localize.rb
446
450
  - lib/glib/rubocop/cops/multiline_method_call_style.rb
447
451
  - lib/glib/snapshot.rb
452
+ - lib/glib/test/parallel_coverage.rb
448
453
  - lib/glib/test_helpers.rb
449
454
  - lib/glib/time_freezable_mailer.rb
450
455
  - lib/glib/time_returning_mailer.rb