ruact 0.0.10 → 0.0.12

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 (116) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +123 -48
  3. data/CONTRIBUTING.md +233 -0
  4. data/README.md +16 -6
  5. data/RELEASING.md +125 -139
  6. data/lib/ruact/packaging.rb +68 -0
  7. data/lib/ruact/version.rb +1 -1
  8. data/vendor/javascript/vite-plugin-ruact/flight-client.test.mjs +321 -0
  9. data/vendor/javascript/vite-plugin-ruact/package-lock.json +11 -0
  10. data/vendor/javascript/vite-plugin-ruact/package.json +1 -0
  11. data/vendor/javascript/vite-plugin-ruact/runtime/flight-client.js +14 -3
  12. metadata +6 -107
  13. data/.codecov.yml +0 -31
  14. data/.github/workflows/ci.yml +0 -284
  15. data/.github/workflows/server-functions-bench.yml +0 -54
  16. data/.rubocop.yml +0 -107
  17. data/.rubocop_todo.yml +0 -63
  18. data/Rakefile +0 -10
  19. data/bench/server_functions_dispatch_bench.rb +0 -276
  20. data/bench/server_functions_dispatch_bench.results.md +0 -150
  21. data/docs/internal/README.md +0 -9
  22. data/docs/internal/decisions/server-functions-api.md +0 -2236
  23. data/spec/benchmarks/baseline.json +0 -1
  24. data/spec/benchmarks/render_pipeline_benchmark_spec.rb +0 -92
  25. data/spec/fixtures/flight/README.md +0 -136
  26. data/spec/fixtures/flight/array.txt +0 -1
  27. data/spec/fixtures/flight/as_json_object.txt +0 -2
  28. data/spec/fixtures/flight/bigint.txt +0 -1
  29. data/spec/fixtures/flight/boolean_false.txt +0 -1
  30. data/spec/fixtures/flight/boolean_true.txt +0 -1
  31. data/spec/fixtures/flight/client_component_with_props.txt +0 -2
  32. data/spec/fixtures/flight/client_reference.txt +0 -2
  33. data/spec/fixtures/flight/hash.txt +0 -1
  34. data/spec/fixtures/flight/infinity.txt +0 -1
  35. data/spec/fixtures/flight/nan.txt +0 -1
  36. data/spec/fixtures/flight/negative_infinity.txt +0 -1
  37. data/spec/fixtures/flight/nil.txt +0 -1
  38. data/spec/fixtures/flight/number_float.txt +0 -1
  39. data/spec/fixtures/flight/number_integer.txt +0 -1
  40. data/spec/fixtures/flight/react_element_no_props.txt +0 -1
  41. data/spec/fixtures/flight/redirect_row.txt +0 -1
  42. data/spec/fixtures/flight/serializable_object.txt +0 -2
  43. data/spec/fixtures/flight/string_basic.txt +0 -1
  44. data/spec/fixtures/flight/string_dollar_escape.txt +0 -1
  45. data/spec/fixtures/flight/undefined.txt +0 -1
  46. data/spec/fixtures/readme/children-error.html.erb +0 -3
  47. data/spec/fixtures/readme/children-error.txt +0 -1
  48. data/spec/fixtures/story_7_9_views/controller_request_spec_support/demo/show.html.erb +0 -3
  49. data/spec/fixtures/story_7_9_views/controller_request_spec_support/errors_demo/new.html.erb +0 -3
  50. data/spec/fixtures/story_7_9_views/controller_request_spec_support/exploding_layout_demo/show.html.erb +0 -3
  51. data/spec/fixtures/story_7_9_views/controller_request_spec_support/ghost_layout_demo/show.html.erb +0 -3
  52. data/spec/fixtures/story_7_9_views/controller_request_spec_support/layout_demo/show.html.erb +0 -3
  53. data/spec/fixtures/story_7_9_views/controller_request_spec_support/rootless_layout_demo/show.html.erb +0 -3
  54. data/spec/fixtures/story_7_9_views/controller_request_spec_support/unwired_layout_demo/show.html.erb +0 -3
  55. data/spec/fixtures/story_7_9_views/layouts/bare_host.html.erb +0 -16
  56. data/spec/fixtures/story_7_9_views/layouts/exploding_host.html.erb +0 -24
  57. data/spec/fixtures/story_7_9_views/layouts/rootless_host.html.erb +0 -15
  58. data/spec/fixtures/story_7_9_views/layouts/ruact_host.html.erb +0 -17
  59. data/spec/readme_demo_message_spec.rb +0 -67
  60. data/spec/readme_spec.rb +0 -282
  61. data/spec/ruact/client_manifest_spec.rb +0 -270
  62. data/spec/ruact/component_contract_spec.rb +0 -119
  63. data/spec/ruact/configuration_spec.rb +0 -518
  64. data/spec/ruact/controller_request_spec.rb +0 -671
  65. data/spec/ruact/controller_spec.rb +0 -343
  66. data/spec/ruact/doctor_spec.rb +0 -769
  67. data/spec/ruact/erb_preprocessor_hook_spec.rb +0 -55
  68. data/spec/ruact/erb_preprocessor_spec.rb +0 -361
  69. data/spec/ruact/errors_spec.rb +0 -93
  70. data/spec/ruact/flight/renderer_spec.rb +0 -133
  71. data/spec/ruact/flight/serializer_spec.rb +0 -494
  72. data/spec/ruact/html_converter_spec.rb +0 -375
  73. data/spec/ruact/install_generator_spec.rb +0 -1549
  74. data/spec/ruact/layout_source_spec.rb +0 -108
  75. data/spec/ruact/manifest_resolver_spec.rb +0 -174
  76. data/spec/ruact/query_request_spec.rb +0 -706
  77. data/spec/ruact/query_spec.rb +0 -105
  78. data/spec/ruact/railtie_spec.rb +0 -155
  79. data/spec/ruact/render_context_spec.rb +0 -58
  80. data/spec/ruact/render_pipeline_concurrency_spec.rb +0 -78
  81. data/spec/ruact/render_pipeline_spec.rb +0 -928
  82. data/spec/ruact/scaffold_generator_spec.rb +0 -1849
  83. data/spec/ruact/serializable_spec.rb +0 -179
  84. data/spec/ruact/server_bucket_request_spec.rb +0 -785
  85. data/spec/ruact/server_function_name_spec.rb +0 -53
  86. data/spec/ruact/server_functions/backtrace_cleaner_spec.rb +0 -63
  87. data/spec/ruact/server_functions/bucket_two_payload_spec.rb +0 -200
  88. data/spec/ruact/server_functions/codegen_spec.rb +0 -397
  89. data/spec/ruact/server_functions/error_payload_spec.rb +0 -222
  90. data/spec/ruact/server_functions/error_suggestion_spec.rb +0 -79
  91. data/spec/ruact/server_functions/introspection_spec.rb +0 -135
  92. data/spec/ruact/server_functions/name_bridge_spec.rb +0 -212
  93. data/spec/ruact/server_functions/query_context_spec.rb +0 -72
  94. data/spec/ruact/server_functions/query_source_spec.rb +0 -193
  95. data/spec/ruact/server_functions/railtie_integration_spec.rb +0 -215
  96. data/spec/ruact/server_functions/rake_spec.rb +0 -86
  97. data/spec/ruact/server_functions/route_source_spec.rb +0 -202
  98. data/spec/ruact/server_functions/snapshot_spec.rb +0 -96
  99. data/spec/ruact/server_functions/snapshot_writer_spec.rb +0 -71
  100. data/spec/ruact/server_rescue_request_spec.rb +0 -416
  101. data/spec/ruact/server_spec.rb +0 -179
  102. data/spec/ruact/server_upload_request_spec.rb +0 -311
  103. data/spec/ruact/signed_references_spec.rb +0 -164
  104. data/spec/ruact/string_distance_spec.rb +0 -38
  105. data/spec/ruact/tasks_json_introspection_spec.rb +0 -141
  106. data/spec/ruact/testing/have_ruact_component_spec.rb +0 -170
  107. data/spec/ruact/testing/no_production_load_spec.rb +0 -41
  108. data/spec/ruact/validation_errors_spec.rb +0 -116
  109. data/spec/ruact/view_helper_spec.rb +0 -131
  110. data/spec/spec_helper.rb +0 -77
  111. data/spec/support/fixtures/pixel.png +0 -0
  112. data/spec/support/flight_wire_parser.rb +0 -21
  113. data/spec/support/flight_wire_parser_spec.rb +0 -93
  114. data/spec/support/matchers/flight_fixture_matcher.rb +0 -130
  115. data/spec/support/matchers/flight_fixture_matcher_spec.rb +0 -250
  116. data/spec/support/rails_stub.rb +0 -115
@@ -1,375 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- module Ruact
6
- RSpec.describe HtmlConverter do
7
- subject(:convert) { ->(html, registry = []) { described_class.convert(html, registry) } }
8
-
9
- describe "text nodes" do
10
- it "returns a plain string for plain text" do
11
- expect(convert.call("hello")).to eq("hello")
12
- end
13
- end
14
-
15
- # Bugfix (Sprint Change Proposal 2026-06-16 §4.5): the ERB `delay` attribute
16
- # is carried as `data-ruact-delay` and must reach SuspenseElement#delay; an
17
- # absent, blank, or unparseable value falls back to the element's default.
18
- describe "Suspense element conversion (delay)" do
19
- let(:default_delay) do
20
- Ruact::Flight::SuspenseElement.new(fallback: nil, children: "x").delay
21
- end
22
-
23
- it "parses data-ruact-delay into SuspenseElement#delay as a Float" do
24
- html = %(<ruact-suspense data-ruact-fallback="loading" data-ruact-delay="2.5"><p>content</p></ruact-suspense>)
25
- result = convert.call(html)
26
- expect(result).to be_a(Ruact::Flight::SuspenseElement)
27
- expect(result.delay).to eq(2.5)
28
- end
29
-
30
- it "falls back to the default delay when the attribute is absent" do
31
- html = %(<ruact-suspense data-ruact-fallback="loading"><p>content</p></ruact-suspense>)
32
- result = convert.call(html)
33
- expect(result).to be_a(Ruact::Flight::SuspenseElement)
34
- expect(result.delay).to eq(default_delay)
35
- end
36
-
37
- it "falls back to the default delay when the attribute is unparseable" do
38
- html = %(<ruact-suspense data-ruact-fallback="loading" data-ruact-delay="soon"><p>content</p></ruact-suspense>)
39
- expect(convert.call(html).delay).to eq(default_delay)
40
- end
41
-
42
- it "falls back to the default delay when the attribute is blank" do
43
- html = %(<ruact-suspense data-ruact-fallback="loading" data-ruact-delay=""><p>content</p></ruact-suspense>)
44
- expect(convert.call(html).delay).to eq(default_delay)
45
- end
46
-
47
- it "treats delay=\"0\" as an explicit zero delay, not absent" do
48
- html = %(<ruact-suspense data-ruact-fallback="loading" data-ruact-delay="0"><p>content</p></ruact-suspense>)
49
- expect(convert.call(html).delay).to eq(0.0)
50
- end
51
-
52
- it "parses a delay value with surrounding whitespace" do
53
- html = %(<ruact-suspense data-ruact-fallback="loading" data-ruact-delay=" 2.5 "><p>content</p></ruact-suspense>)
54
- expect(convert.call(html).delay).to eq(2.5)
55
- end
56
-
57
- it "falls back to the default delay when the value overflows to a non-finite Float" do
58
- # Float("1e309") => Infinity (Float() does not raise on overflow); a
59
- # non-finite delay must not reach the renderer's sleep (RangeError).
60
- html = %(<ruact-suspense data-ruact-fallback="loading" data-ruact-delay="1e309"><p>content</p></ruact-suspense>)
61
- expect(convert.call(html).delay).to eq(default_delay)
62
- end
63
- end
64
-
65
- describe "single DOM element" do
66
- it "converts a div with class and text child" do
67
- result = convert.call('<div class="box">hi</div>')
68
- expect(result).to be_a(Flight::ReactElement)
69
- expect(result.type).to eq("div")
70
- expect(result.props["className"]).to eq("box")
71
- expect(result.props["children"]).to eq("hi")
72
- end
73
-
74
- it "converts `for` attribute to `htmlFor`" do
75
- result = convert.call('<label for="email">Email</label>')
76
- expect(result.props.keys).to include("htmlFor")
77
- expect(result.props["htmlFor"]).to eq("email")
78
- end
79
-
80
- it "extracts `data-react-key` into the element key and removes it from props" do
81
- result = convert.call('<article data-react-key="post-1">body</article>')
82
- expect(result.key).to eq("post-1")
83
- expect(result.props).not_to have_key("data-react-key")
84
- end
85
- end
86
-
87
- describe "nested elements" do
88
- it "produces a child ReactElement for a nested element" do
89
- result = convert.call("<div><span>hello</span></div>")
90
- expect(result.type).to eq("div")
91
- child = result.props["children"]
92
- expect(child).to be_a(Flight::ReactElement)
93
- expect(child.type).to eq("span")
94
- end
95
-
96
- it "produces an array of children for multiple child elements" do
97
- result = convert.call("<ul><li>a</li><li>b</li></ul>")
98
- children = result.props["children"]
99
- expect(children).to be_an(Array)
100
- expect(children.length).to eq(2)
101
- expect(children[0].type).to eq("li")
102
- expect(children[1].type).to eq("li")
103
- end
104
- end
105
-
106
- describe "fragment (multiple root elements)" do
107
- it "returns an array for multiple sibling root elements" do
108
- result = convert.call("<p>one</p><p>two</p>")
109
- expect(result).to be_an(Array)
110
- expect(result.length).to eq(2)
111
- end
112
- end
113
-
114
- describe "client component via registry" do
115
- it "replaces Ruact comment placeholder with the registered ReactElement" do
116
- ref = Flight::ClientReference.new(module_id: "./LikeButton", export_name: "LikeButton")
117
- registry = [{ token: "__RUACT_0__", name: "LikeButton", ref: ref, props: { "postId" => 1 } }]
118
- result = convert.call("<!-- __RUACT_0__ -->", registry)
119
-
120
- expect(result).to be_a(Flight::ReactElement)
121
- expect(result.type).to eq(ref)
122
- expect(result.props).to eq({ "postId" => 1 })
123
- end
124
-
125
- it "wraps a client component inside a parent DOM element" do
126
- ref = Flight::ClientReference.new(module_id: "./Button", export_name: "Button")
127
- registry = [{ token: "__RUACT_0__", name: "Button", ref: ref, props: {} }]
128
- result = convert.call('<div class="wrapper"><!-- __RUACT_0__ --></div>', registry)
129
-
130
- expect(result.type).to eq("div")
131
- child = result.props["children"]
132
- expect(child).to be_a(Flight::ReactElement)
133
- expect(child.type).to eq(ref)
134
- end
135
- end
136
-
137
- describe "form element value handling" do
138
- it "converts text input value to defaultValue (uncontrolled)" do
139
- result = convert.call('<input type="text" value="hello" />')
140
- expect(result.props).to have_key("defaultValue")
141
- expect(result.props["defaultValue"]).to eq("hello")
142
- expect(result.props).not_to have_key("value")
143
- end
144
-
145
- it "preserves value on submit inputs (controlled is correct for buttons)" do
146
- result = convert.call('<input type="submit" value="Save" />')
147
- expect(result.props).to have_key("value")
148
- expect(result.props["value"]).to eq("Save")
149
- expect(result.props).not_to have_key("defaultValue")
150
- end
151
-
152
- it "preserves value on reset inputs" do
153
- result = convert.call('<input type="reset" value="Clear" />')
154
- expect(result.props["value"]).to eq("Clear")
155
- expect(result.props).not_to have_key("defaultValue")
156
- end
157
-
158
- it "converts textarea value to defaultValue" do
159
- result = convert.call('<textarea value="content">content</textarea>')
160
- expect(result.props["defaultValue"]).to eq("content")
161
- expect(result.props).not_to have_key("value")
162
- end
163
-
164
- it "converts select value to defaultValue" do
165
- result = convert.call('<select value="b"><option value="a">A</option><option value="b">B</option></select>')
166
- expect(result.props["defaultValue"]).to eq("b")
167
- expect(result.props).not_to have_key("value")
168
- end
169
-
170
- it "converts checked attribute to defaultChecked" do
171
- result = convert.call('<input type="checkbox" checked="checked" />')
172
- expect(result.props).to have_key("defaultChecked")
173
- expect(result.props["defaultChecked"]).to eq("checked")
174
- expect(result.props).not_to have_key("checked")
175
- end
176
- end
177
-
178
- describe "style attribute" do
179
- it "converts a CSS string to a camelCase hash" do
180
- result = convert.call('<h1 style="font-size:28px;font-weight:700;margin-bottom:24px">Title</h1>')
181
- expect(result.props["style"]).to eq({
182
- "fontSize" => "28px",
183
- "fontWeight" => "700",
184
- "marginBottom" => "24px"
185
- })
186
- end
187
-
188
- it "handles multi-word property values without splitting" do
189
- result = convert.call('<div style="max-width:640px;margin:40px auto">x</div>')
190
- expect(result.props["style"]).to eq({
191
- "maxWidth" => "640px",
192
- "margin" => "40px auto"
193
- })
194
- end
195
- end
196
-
197
- describe "input validation (Story 7.4)" do
198
- describe "nil input" do
199
- it "raises Ruact::HtmlConverterError" do
200
- expect { described_class.convert(nil) }.to raise_error(Ruact::HtmlConverterError)
201
- end
202
-
203
- it "message contains 'received nil; expected a String of HTML'" do
204
- expect { described_class.convert(nil) }
205
- .to raise_error(Ruact::HtmlConverterError,
206
- /HtmlConverter\.convert received nil; expected a String of HTML/)
207
- end
208
-
209
- it "message contains the 'Most likely cause' hint" do
210
- expect { described_class.convert(nil) }
211
- .to raise_error(Ruact::HtmlConverterError, /Most likely cause:/)
212
- expect { described_class.convert(nil) }
213
- .to raise_error(Ruact::HtmlConverterError, /missing yield, an empty respond_to branch/)
214
- end
215
-
216
- it "message contains the documentation pointer" do
217
- expect { described_class.convert(nil) }
218
- .to raise_error(Ruact::HtmlConverterError,
219
- /See HtmlConverter\.convert documentation for the canonical contract\./)
220
- end
221
-
222
- it "message points at the spec's file:line, not html_converter.rb (Called from)" do
223
- expected_line = __LINE__ + 1
224
- expect { described_class.convert(nil) }
225
- .to raise_error(Ruact::HtmlConverterError,
226
- /Called from: #{Regexp.escape(__FILE__)}:#{expected_line}/)
227
- end
228
-
229
- it "does not invoke Nokogiri::HTML::DocumentFragment.parse" do
230
- allow(Nokogiri::HTML::DocumentFragment).to receive(:parse).and_call_original
231
- expect { described_class.convert(nil) }.to raise_error(Ruact::HtmlConverterError)
232
- expect(Nokogiri::HTML::DocumentFragment).not_to have_received(:parse)
233
- end
234
- end
235
-
236
- describe "non-String inputs" do
237
- it "raises with 'got Integer' and 'Received: 42' for an Integer" do
238
- expect { described_class.convert(42) }
239
- .to raise_error(Ruact::HtmlConverterError,
240
- /HtmlConverter\.convert expected a String of HTML; got Integer/)
241
- expect { described_class.convert(42) }
242
- .to raise_error(Ruact::HtmlConverterError, /Received: 42/)
243
- end
244
-
245
- it "raises with 'got Symbol' for a Symbol" do
246
- expect { described_class.convert(:symbol) }
247
- .to raise_error(Ruact::HtmlConverterError, /got Symbol/)
248
- expect { described_class.convert(:symbol) }
249
- .to raise_error(Ruact::HtmlConverterError, /Received: :symbol/)
250
- end
251
-
252
- it "raises with 'got Array' for an Array" do
253
- expect { described_class.convert(["array"]) }
254
- .to raise_error(Ruact::HtmlConverterError, /got Array/)
255
- expect { described_class.convert(["array"]) }
256
- .to raise_error(Ruact::HtmlConverterError, /Received: \["array"\]/)
257
- end
258
-
259
- it "raises with 'got Hash' for a Hash" do
260
- expect { described_class.convert({ hash: 1 }) }
261
- .to raise_error(Ruact::HtmlConverterError, /got Hash/)
262
- expect { described_class.convert({ hash: 1 }) }
263
- .to raise_error(Ruact::HtmlConverterError, /Received: \{.*hash.*1.*\}/)
264
- end
265
-
266
- it "raises with 'got Object' for a generic Object" do
267
- expect { described_class.convert(Object.new) }
268
- .to raise_error(Ruact::HtmlConverterError, /got Object/)
269
- end
270
-
271
- it "message points at the spec's file:line for non-nil non-String input" do
272
- expected_line = __LINE__ + 1
273
- expect { described_class.convert(42) }
274
- .to raise_error(Ruact::HtmlConverterError,
275
- /Called from: #{Regexp.escape(__FILE__)}:#{expected_line}/)
276
- end
277
-
278
- it "truncates large input previews to ≤ 84 chars (80 + '...')" do
279
- large_value = (1..10_000).to_a
280
- message = nil
281
- begin
282
- described_class.convert(large_value)
283
- rescue Ruact::HtmlConverterError => e
284
- message = e.message
285
- end
286
-
287
- received_line = message.lines.find { |l| l.include?("Received:") }
288
- expect(received_line).not_to be_nil
289
- preview = received_line.sub(/^\s*Received:\s/, "").strip
290
- expect(preview.length).to be <= 84
291
- expect(preview).to end_with("...")
292
- end
293
- end
294
-
295
- describe "subclasses and edge cases" do
296
- it "accepts String subclasses (e.g. ActionView SafeBuffer-like)" do
297
- safe_buffer_class = Class.new(String)
298
- input = safe_buffer_class.new("<div>hi</div>")
299
- expect { described_class.convert(input) }.not_to raise_error
300
-
301
- result = described_class.convert(input)
302
- expect(result).to be_a(Ruact::Flight::ReactElement)
303
- expect(result.type).to eq("div")
304
- end
305
-
306
- it "accepts an empty string without raising" do
307
- expect { described_class.convert("") }.not_to raise_error
308
- end
309
-
310
- it "raises Ruact::HtmlConverterError (not NoMethodError) for BasicObject inputs" do
311
- basic = BasicObject.new
312
- expect { described_class.convert(basic) }
313
- .to raise_error(Ruact::HtmlConverterError, /HtmlConverter\.convert expected a String of HTML/)
314
- end
315
-
316
- it "produces a readable message even when value#inspect raises" do
317
- hostile = Class.new do
318
- def inspect
319
- raise "I refuse to introspect"
320
- end
321
- end.new
322
-
323
- expect { described_class.convert(hostile) }
324
- .to raise_error(Ruact::HtmlConverterError, /Received: <inspect raised>/)
325
- end
326
-
327
- it "produces a readable message even when value#class raises (BasicObject)" do
328
- basic = BasicObject.new
329
- expect { described_class.convert(basic) }
330
- .to raise_error(Ruact::HtmlConverterError) do |error|
331
- expect(error.message).to include("got ")
332
- expect(error.message).not_to match(/got\s*$/)
333
- end
334
- end
335
- end
336
-
337
- describe "backtrace shape" do
338
- it "frame 0 of the backtrace points outside the gem" do
339
- described_class.convert(nil)
340
- rescue Ruact::HtmlConverterError => e
341
- expect(e.backtrace.first).not_to include("/lib/ruact/html_converter.rb")
342
- expect(e.backtrace.first).to include(__FILE__)
343
- end
344
-
345
- it "frame 0 references the test file when called from a spec" do
346
- described_class.convert(42)
347
- rescue Ruact::HtmlConverterError => e
348
- expect(e.backtrace.first).to start_with(__FILE__)
349
- end
350
- end
351
- end
352
-
353
- # Detailed coverage of HtmlConverter input validation (nil + non-String inputs,
354
- # backtrace shape, BasicObject handling) lives in the "input validation (Story 7.4)"
355
- # block above (lines 147-300). This regression suite is intentionally minimal — two
356
- # smoke specs that name the suite for greppability via `:story_7_7` and the
357
- # "Story 7.7" describe substring; do NOT duplicate the 7.4 detailed coverage here.
358
- describe "edge cases (Story 7.7) — code-review regression suite", :story_7_7 do
359
- it "raises Ruact::HtmlConverterError for nil input (smoke; full coverage at :147-184)" do
360
- expect { described_class.convert(nil) }.to raise_error(Ruact::HtmlConverterError) do |error|
361
- expect(error.message).to include("received nil")
362
- expect(error.message).to include("expected a String of HTML")
363
- end
364
- end
365
-
366
- it "raises Ruact::HtmlConverterError for a non-String input (smoke; full coverage at :186-243)" do
367
- expect { described_class.convert(42) }.to raise_error(Ruact::HtmlConverterError) do |error|
368
- expect(error.message).to include("expected a String of HTML")
369
- expect(error.message).to include("got Integer")
370
- expect(error.message).to include("Received: 42")
371
- end
372
- end
373
- end
374
- end
375
- end