turbo_rspec 1.1.0 → 1.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8356be265d63e581709f7252b6981d9f721172d68e417e23bc02581214773629
4
- data.tar.gz: 3394a171db1031c16533bde8eb141eb1cd1f40bfed737b47c4f6e80b05ca23b5
3
+ metadata.gz: 7341e9dfd6be8235a2269e94ef9923e470aa5da675ccd52f8d507f42c3950398
4
+ data.tar.gz: 65f4f2bb0aa32c4032d4ba2daad8c9442e20d056b3a455b0937eaeaf380f924a
5
5
  SHA512:
6
- metadata.gz: c2094508851098b590cd9539c01b60768a44f959b4af7bb20083e736a6e9b7631776f8bdde870fd543a7302d0fb1983a839932d8839b74de450274d00470c335
7
- data.tar.gz: 06c44da054b038c40cb83b681da7d9897f3d76f436afe2adf484c1cd2cab243caf2f824d763ce958172d9d66f02c11e2646130fbe31c47a59df68ac800e0ab33
6
+ metadata.gz: b433e046578d5f3914a95cd443ed32020bff526bddf3bf79eea34ef7bc52a7ce06823ac25714f309842c357d97e0e70edd208b75a85c8e0a118e7d8b86b36c9f
7
+ data.tar.gz: 44d25746b61d50d932f74f92b2f6a07c50c70a6d320c452f302693b507617da38facf8fca1d0ac61f66cf01a49187e8288a20c6182b27cbe4ab91db42fe28ec5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.2.0] - 2026-06-01
4
+
5
+ ### Added
6
+
7
+ - `have_turbo_stream.with_attributes(hash)` — assert arbitrary HTML attributes on a stream element; accepts string or symbol keys
8
+ - `have_turbo_frame.with_attributes(hash)` — same for frame elements in request specs
9
+ - `have_turbo_stream.children_only` — assert the `children-only` attribute on Turbo 8 morph streams
10
+ - `TurboRspec.register_action(:name)` — declare custom Turbo stream actions; `with_action` now raises `ArgumentError` for unrecognised actions with a hint to register them
11
+ - `TurboRspec::BUILTIN_ACTIONS` — public constant listing all built-in action names
12
+ - `TurboRspec.known_actions` — returns built-in + registered custom actions
13
+
3
14
  ## [1.1.0] - 2026-06-01
4
15
 
5
16
  ### Added
data/README.md CHANGED
@@ -99,13 +99,33 @@ expect(response).to have_turbo_stream
99
99
  .targeting("messages")
100
100
  .with_content("Hello")
101
101
 
102
+ # With arbitrary attributes
103
+ expect(response).to have_turbo_stream.with_attributes("data-controller" => "messages")
104
+
105
+ # Turbo 8 morph with children-only
106
+ expect(response).to have_turbo_stream.with_action(:morph).children_only
107
+
108
+ # Count qualifiers — assert how many matching streams appear
109
+ expect(response).to have_turbo_stream.with_action(:append).once
110
+ expect(response).to have_turbo_stream.with_action(:append).twice
111
+ expect(response).to have_turbo_stream.with_action(:append).exactly(3).times
112
+ expect(response).to have_turbo_stream.with_action(:append).at_least(2).times
113
+ expect(response).to have_turbo_stream.with_action(:append).at_most(1).times
114
+
102
115
  # Negation
103
116
  expect(response).not_to have_turbo_stream.with_action(:replace)
104
117
  ```
105
118
 
106
119
  #### Actions
107
120
 
108
- Turbo supports the following stream actions: `append`, `prepend`, `replace`, `update`, `remove`, `before`, `after`, `refresh`.
121
+ Turbo's built-in stream actions: `append`, `prepend`, `replace`, `update`, `remove`, `before`, `after`, `refresh`, `morph`.
122
+
123
+ `with_action` raises `ArgumentError` for unrecognised names. Register custom actions in your test setup:
124
+
125
+ ```ruby
126
+ # spec/support/turbo_rspec.rb
127
+ TurboRspec.register_action(:sparkle, :highlight)
128
+ ```
109
129
 
110
130
  ### `have_turbo_streams`
111
131
 
@@ -189,6 +209,18 @@ expect(page).to have_turbo_frame("messages").with_content("Hello")
189
209
  # Loaded (frame finished loading)
190
210
  expect(page).to have_turbo_frame("messages").loaded
191
211
 
212
+ # Lazy frame — assert loading="lazy" attribute
213
+ expect(page).to have_turbo_frame("messages").lazy
214
+
215
+ # With src — assert the src attribute on a lazy-loaded frame
216
+ expect(page).to have_turbo_frame("messages").with_src("/messages/new")
217
+
218
+ # With arbitrary attributes (request specs only — use Capybara selectors in system specs)
219
+ expect(response).to have_turbo_frame.with_attributes("data-controller" => "chat")
220
+
221
+ # Chained
222
+ expect(page).to have_turbo_frame("messages").lazy.with_src("/messages/new")
223
+
192
224
  # Negation
193
225
  expect(page).not_to have_turbo_frame("notifications")
194
226
  ```
data/ROADMAP.md CHANGED
@@ -4,17 +4,6 @@ RSpec matchers for [Turbo](https://github.com/hotwired/turbo-rails): Turbo Strea
4
4
 
5
5
  ---
6
6
 
7
- ## 1.1 — Matcher parity
8
-
9
- - **Count qualifiers on `have_turbo_stream`** — `.once`, `.twice`, `.exactly(n).times` for request specs, matching the parity already present on `have_broadcasted_turbo_stream_to`. A single response with two `append` streams is a real case that currently requires two separate expectations.
10
- - **Capybara `have_turbo_frame` additions** — `.with_src(url)` (assert the `src` attribute of a lazy frame) and `.lazy` (assert `loading="lazy"` is set). These cover the lazy-loading pattern that's very common with Turbo Frames.
11
-
12
- ## 1.2 — Turbo 8 / morphing
13
-
14
- - **`with_attributes(hash)` chain** — generic attribute assertion for both `have_turbo_stream` and `have_turbo_frame`. Covers non-standard attributes (e.g., `data-*` passed through custom actions) without needing new named chains per attribute.
15
- - **Morph-aware assertions** — `morph` is a supported action but Turbo 8's `<turbo-stream action="morph">` has distinct semantics (`[children-only]` attribute). A `.children_only` chain on `have_turbo_stream` would make morph specs readable without raw attribute checks.
16
- - **Custom Turbo action support** — Turbo 8 allows registering custom stream actions. A `TurboRspec.register_action(:sparkle)` API would let teams assert their own actions without them being treated as unknown values.
17
-
18
7
  ## 1.3 — Stimulus companion
19
8
 
20
9
  - **Stimulus matchers** — `have_stimulus_controller`, `have_stimulus_action`, `have_stimulus_target` Capybara matchers. turbo-rails ships with Stimulus; teams using both already test Stimulus behavior manually. This is the natural next surface area for a complete Hotwire testing toolkit.
@@ -13,8 +13,14 @@ module TurboRspec
13
13
  # @return [Boolean]
14
14
  attr_accessor :auto_include
15
15
 
16
+ # @!attribute [rw] custom_actions
17
+ # Additional stream action names registered via +TurboRspec.register_action+.
18
+ # @return [Array<String>]
19
+ attr_accessor :custom_actions
20
+
16
21
  def initialize
17
22
  @auto_include = true
23
+ @custom_actions = []
18
24
  end
19
25
  end
20
26
  end
@@ -21,6 +21,7 @@ module TurboRspec
21
21
  @id = nil
22
22
  @content = nil
23
23
  @partial = nil
24
+ @attributes = {}
24
25
  end
25
26
 
26
27
  # Constrains the match to frames with the given id attribute.
@@ -47,6 +48,14 @@ module TurboRspec
47
48
  self
48
49
  end
49
50
 
51
+ # Constrains the match to frames that have all of the given HTML attributes.
52
+ # @param attrs [Hash]
53
+ # @return [self]
54
+ def with_attributes(attrs)
55
+ @attributes = attrs.transform_keys(&:to_s).transform_values(&:to_s)
56
+ self
57
+ end
58
+
50
59
  # @param response_or_body [#body, String]
51
60
  # @return [Boolean]
52
61
  def matches?(response_or_body)
@@ -92,7 +101,8 @@ module TurboRspec
92
101
  def frame_matches?(frame)
93
102
  matches_id?(frame) &&
94
103
  matches_content?(frame) &&
95
- matches_partial?(frame)
104
+ matches_partial?(frame) &&
105
+ matches_attributes?(frame)
96
106
  end
97
107
 
98
108
  def matches_id?(frame)
@@ -109,11 +119,17 @@ module TurboRspec
109
119
  frame.to_html.include?(@partial)
110
120
  end
111
121
 
122
+ def matches_attributes?(frame)
123
+ return true if @attributes.empty?
124
+ @attributes.all? { |k, v| frame[k] == v }
125
+ end
126
+
112
127
  def constraint_description
113
128
  parts = []
114
129
  parts << " with id #{@id.inspect}" if @id
115
130
  parts << " with content #{@content.inspect}" if @content
116
131
  parts << " rendering #{@partial.inspect}" if @partial
132
+ parts << " with attributes #{@attributes.inspect}" if @attributes.any?
117
133
  parts.join
118
134
  end
119
135
 
@@ -144,11 +160,13 @@ module TurboRspec
144
160
  count += 1 if !@id.nil? && matches_id?(frame)
145
161
  count += 1 if !@content.nil? && matches_content?(frame)
146
162
  count += 1 if !@partial.nil? && matches_partial?(frame)
163
+ count += 1 if @attributes.any? && matches_attributes?(frame)
147
164
  count
148
165
  end
149
166
 
150
167
  def constraint_count
151
- [@id, @content, @partial].count { |c| !c.nil? }
168
+ [@id, @content, @partial].count { |c| !c.nil? } +
169
+ (@attributes.any? ? 1 : 0)
152
170
  end
153
171
 
154
172
  def constraint_diff(frame)
@@ -156,6 +174,10 @@ module TurboRspec
156
174
  lines << " #{matches_id?(frame) ? "✓" : "✗"} id: expected #{@id.inspect}, got #{frame["id"].inspect}" if @id
157
175
  lines << " #{matches_content?(frame) ? "✓" : "✗"} content: expected to include #{@content.inspect}, got #{frame.text.strip.slice(0, 50).inspect}" if @content
158
176
  lines << " #{matches_partial?(frame) ? "✓" : "✗"} rendering: expected to include #{@partial.inspect}" if @partial
177
+ @attributes.each do |k, v|
178
+ actual = frame[k]
179
+ lines << " #{(actual == v) ? "✓" : "✗"} attr[#{k}]: expected #{v.inspect}, got #{actual.inspect}"
180
+ end
159
181
  lines
160
182
  end
161
183
  end
@@ -28,6 +28,8 @@ module TurboRspec
28
28
  @target_all = nil
29
29
  @content = nil
30
30
  @partial = nil
31
+ @attributes = {}
32
+ @children_only = false
31
33
  @expected_count = nil
32
34
  @count_type = :at_least
33
35
  @matching_count = 0
@@ -35,9 +37,15 @@ module TurboRspec
35
37
 
36
38
  # Constrains the match to streams with the given action.
37
39
  # @param action [Symbol, String] e.g. +:append+, +:replace+, +:remove+, +:refresh+, +:morph+
40
+ # @raise [ArgumentError] if the action is not a known built-in or registered custom action
38
41
  # @return [self]
39
42
  def with_action(action)
40
- @action = action.to_s
43
+ action_str = action.to_s
44
+ unless TurboRspec.known_actions.include?(action_str)
45
+ raise ArgumentError, "Unknown Turbo stream action #{action_str.inspect}. " \
46
+ "Register custom actions with TurboRspec.register_action(:#{action_str})."
47
+ end
48
+ @action = action_str
41
49
  self
42
50
  end
43
51
 
@@ -73,6 +81,26 @@ module TurboRspec
73
81
  self
74
82
  end
75
83
 
84
+ # Constrains the match to streams that have all of the given HTML attributes.
85
+ # Keys and values are compared as strings.
86
+ # @param attrs [Hash]
87
+ # @return [self]
88
+ # @example
89
+ # expect(response).to have_turbo_stream.with_attributes("data-controller" => "messages")
90
+ def with_attributes(attrs)
91
+ @attributes = attrs.transform_keys(&:to_s).transform_values(&:to_s)
92
+ self
93
+ end
94
+
95
+ # Constrains the match to morph streams with the +children-only+ attribute set.
96
+ # @return [self]
97
+ # @example
98
+ # expect(response).to have_turbo_stream.with_action(:morph).children_only
99
+ def children_only
100
+ @children_only = true
101
+ self
102
+ end
103
+
76
104
  # Asserts exactly one matching stream.
77
105
  # @return [self]
78
106
  def once
@@ -167,7 +195,9 @@ module TurboRspec
167
195
  matches_target?(stream) &&
168
196
  matches_target_all?(stream) &&
169
197
  matches_content?(stream) &&
170
- matches_partial?(stream)
198
+ matches_partial?(stream) &&
199
+ matches_attributes?(stream) &&
200
+ matches_children_only?(stream)
171
201
  end
172
202
 
173
203
  def matches_action?(stream)
@@ -192,6 +222,16 @@ module TurboRspec
192
222
  stream.to_html.include?(@partial)
193
223
  end
194
224
 
225
+ def matches_attributes?(stream)
226
+ return true if @attributes.empty?
227
+ @attributes.all? { |k, v| stream[k] == v }
228
+ end
229
+
230
+ def matches_children_only?(stream)
231
+ return true unless @children_only
232
+ !stream["children-only"].nil?
233
+ end
234
+
195
235
  def count_matches?(n)
196
236
  if @expected_count.nil?
197
237
  n >= 1
@@ -213,6 +253,8 @@ module TurboRspec
213
253
  parts << " targeting all #{@target_all.inspect}" if @target_all
214
254
  parts << " with content #{@content.inspect}" if @content
215
255
  parts << " rendering #{@partial.inspect}" if @partial
256
+ parts << " with attributes #{@attributes.inspect}" if @attributes.any?
257
+ parts << " children only" if @children_only
216
258
  parts.join
217
259
  end
218
260
 
@@ -261,11 +303,15 @@ module TurboRspec
261
303
  count += 1 if !@target_all.nil? && matches_target_all?(stream)
262
304
  count += 1 if !@content.nil? && matches_content?(stream)
263
305
  count += 1 if !@partial.nil? && matches_partial?(stream)
306
+ count += 1 if @attributes.any? && matches_attributes?(stream)
307
+ count += 1 if @children_only && matches_children_only?(stream)
264
308
  count
265
309
  end
266
310
 
267
311
  def constraint_count
268
- [@action, @target, @target_all, @content, @partial].count { |c| !c.nil? }
312
+ [@action, @target, @target_all, @content, @partial].count { |c| !c.nil? } +
313
+ (@attributes.any? ? 1 : 0) +
314
+ (@children_only ? 1 : 0)
269
315
  end
270
316
 
271
317
  def constraint_diff(stream)
@@ -275,6 +321,11 @@ module TurboRspec
275
321
  lines << " #{matches_target_all?(stream) ? "✓" : "✗"} targets: expected #{@target_all.inspect}, got #{stream["targets"].inspect}" if @target_all
276
322
  lines << " #{matches_content?(stream) ? "✓" : "✗"} content: expected to include #{@content.inspect}, got #{stream.text.strip.slice(0, 50).inspect}" if @content
277
323
  lines << " #{matches_partial?(stream) ? "✓" : "✗"} rendering: expected to include #{@partial.inspect}" if @partial
324
+ @attributes.each do |k, v|
325
+ actual = stream[k]
326
+ lines << " #{(actual == v) ? "✓" : "✗"} attr[#{k}]: expected #{v.inspect}, got #{actual.inspect}"
327
+ end
328
+ lines << " #{matches_children_only?(stream) ? "✓" : "✗"} children-only: expected attribute to be present" if @children_only
278
329
  lines
279
330
  end
280
331
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TurboRspec
4
- VERSION = "1.1.0"
4
+ VERSION = "1.2.0"
5
5
  end
data/lib/turbo_rspec.rb CHANGED
@@ -19,6 +19,9 @@ module TurboRspec
19
19
  # Base error class for TurboRspec.
20
20
  class Error < StandardError; end
21
21
 
22
+ # Built-in Turbo stream action names.
23
+ BUILTIN_ACTIONS = %w[append prepend replace update remove before after refresh morph].freeze
24
+
22
25
  class << self
23
26
  # Yields the configuration object for customization.
24
27
  #
@@ -46,6 +49,24 @@ module TurboRspec
46
49
  @configuration = Configuration.new
47
50
  end
48
51
 
52
+ # Registers one or more custom Turbo stream action names so that
53
+ # +have_turbo_stream.with_action(:name)+ does not raise +ArgumentError+.
54
+ #
55
+ # @param actions [Array<Symbol, String>]
56
+ # @return [void]
57
+ # @example
58
+ # TurboRspec.register_action(:sparkle, :highlight)
59
+ def register_action(*actions)
60
+ configuration.custom_actions |= actions.map(&:to_s)
61
+ end
62
+
63
+ # Returns all known stream action names (built-in + registered custom).
64
+ #
65
+ # @return [Array<String>]
66
+ def known_actions
67
+ BUILTIN_ACTIONS + configuration.custom_actions
68
+ end
69
+
49
70
  # Installs RSpec integration — includes matchers and helpers into the
50
71
  # appropriate example groups. Called automatically when RSpec is present.
51
72
  #
data/sig/turbo_rspec.rbs CHANGED
@@ -1,4 +1,159 @@
1
1
  module TurboRspec
2
2
  VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
- end
3
+
4
+ # All built-in Turbo stream action names.
5
+ BUILTIN_ACTIONS: Array[String]
6
+
7
+ def self.configure: () { (Configuration) -> void } -> void
8
+ def self.configuration: () -> Configuration
9
+ def self.reset_configuration!: () -> void
10
+ def self.register_action: (*(Symbol | String) actions) -> void
11
+ def self.known_actions: () -> Array[String]
12
+ def self.install_rspec_integration: (untyped config) -> void
13
+
14
+ class Error < StandardError
15
+ end
16
+
17
+ class Configuration
18
+ attr_accessor auto_include: bool
19
+ attr_accessor custom_actions: Array[String]
20
+
21
+ def initialize: () -> void
22
+ end
23
+
24
+ module Matchers
25
+ def have_turbo_stream: () -> HaveTurboStream
26
+ def assert_no_turbo_stream: () -> HaveTurboStream
27
+ def have_turbo_streams: (*HaveTurboStream matchers) -> HaveTurboStreams
28
+ def have_turbo_frame: () -> HaveTurboFrame
29
+ def have_broadcasted_turbo_stream_to: (String | untyped stream_or_object) -> HaveBroadcastedTurboStreamTo
30
+ def broadcast_turbo_stream_to: (String | untyped stream_or_object) -> HaveBroadcastedTurboStreamTo
31
+
32
+ class HaveTurboStream
33
+ def initialize: () -> void
34
+
35
+ # Constraint chain
36
+ def with_action: (Symbol | String action) -> self
37
+ def targeting: (String dom_id) -> self
38
+ def targeting_all: (String selector) -> self
39
+ def with_content: (String text) -> self
40
+ def rendering: (String partial) -> self
41
+ def with_attributes: (Hash[String | Symbol, untyped] attrs) -> self
42
+ def children_only: () -> self
43
+
44
+ # Count qualifiers
45
+ def once: () -> self
46
+ def twice: () -> self
47
+ def exactly: (Integer n) -> self
48
+ def at_least: (Integer n) -> self
49
+ def at_most: (Integer n) -> self
50
+ def times: () -> self
51
+
52
+ # RSpec matcher interface
53
+ def matches?: (untyped response_or_body) -> bool
54
+ def does_not_match?: (untyped response_or_body) -> bool
55
+ def failure_message: () -> String
56
+ def failure_message_when_negated: () -> String
57
+ def description: () -> String
58
+ end
59
+
60
+ class HaveTurboFrame
61
+ def initialize: () -> void
62
+
63
+ # Constraint chain
64
+ def with_id: (String id) -> self
65
+ def with_content: (String text) -> self
66
+ def rendering: (String partial) -> self
67
+ def with_attributes: (Hash[String | Symbol, untyped] attrs) -> self
68
+
69
+ # RSpec matcher interface
70
+ def matches?: (untyped response_or_body) -> bool
71
+ def does_not_match?: (untyped response_or_body) -> bool
72
+ def failure_message: () -> String
73
+ def failure_message_when_negated: () -> String
74
+ def description: () -> String
75
+ end
76
+
77
+ class HaveBroadcastedTurboStreamTo
78
+ def initialize: (String | untyped stream_or_object) -> void
79
+
80
+ # Constraint chain (mirrors HaveTurboStream)
81
+ def with_action: (Symbol | String action) -> self
82
+ def targeting: (String dom_id) -> self
83
+ def targeting_all: (String selector) -> self
84
+ def with_content: (String text) -> self
85
+ def rendering: (String partial) -> self
86
+
87
+ # Count qualifiers
88
+ def once: () -> self
89
+ def twice: () -> self
90
+ def exactly: (Integer n) -> self
91
+ def at_least: (Integer n) -> self
92
+ def at_most: (Integer n) -> self
93
+ def times: () -> self
94
+
95
+ # RSpec block-expectation matcher interface
96
+ def supports_block_expectations?: () -> bool
97
+ def matches?: (untyped block) -> bool
98
+ def does_not_match?: (untyped block) -> bool
99
+ def failure_message: () -> String
100
+ def failure_message_when_negated: () -> String
101
+ def description: () -> String
102
+ end
103
+
104
+ class HaveTurboStreams
105
+ def initialize: (Array[HaveTurboStream] expected_streams) -> void
106
+ def matches?: (untyped response_or_body) -> bool
107
+ def does_not_match?: (untyped response_or_body) -> bool
108
+ def failure_message: () -> String
109
+ def failure_message_when_negated: () -> String
110
+ def description: () -> String
111
+ end
112
+ end
113
+
114
+ module Helpers
115
+ def turbo_stream_html: (action: Symbol | String, ?target: String?, ?targets: String?, ?content: String?) -> String
116
+ def turbo_frame_html: (id: String, ?content: String?) -> String
117
+ end
118
+
119
+ module Assertions
120
+ def assert_turbo_stream: (untyped response_or_body, ?action: (Symbol | String)?, ?target: String?, ?targets: String?, ?content: String?, ?partial: String?, ?message: String?) -> void
121
+ def refute_turbo_stream: (untyped response_or_body, ?action: (Symbol | String)?, ?target: String?, ?targets: String?, ?content: String?, ?partial: String?, ?message: String?) -> void
122
+ def assert_turbo_frame: (untyped response_or_body, ?id: String?, ?content: String?, ?partial: String?, ?message: String?) -> void
123
+ def refute_turbo_frame: (untyped response_or_body, ?id: String?, ?content: String?, ?partial: String?, ?message: String?) -> void
124
+ end
125
+
126
+ module Capybara
127
+ module Matchers
128
+ def have_turbo_frame: (String id) -> HaveTurboFrame
129
+ def have_turbo_stream_tag: (?String? signed_stream_name) -> HaveTurboStreamTag
130
+ def within_turbo_frame: (String id) { () -> void } -> void
131
+
132
+ class HaveTurboFrame
133
+ def initialize: (String id) -> void
134
+
135
+ # Constraint chain
136
+ def with_content: (String text) -> self
137
+ def loaded: () -> self
138
+ def with_src: (String url) -> self
139
+ def lazy: () -> self
140
+
141
+ # Capybara matcher interface
142
+ def matches?: (untyped page_or_node) -> bool
143
+ def does_not_match?: (untyped page_or_node) -> bool
144
+ def failure_message: () -> String
145
+ def failure_message_when_negated: () -> String
146
+ def description: () -> String
147
+ end
148
+
149
+ class HaveTurboStreamTag
150
+ def initialize: (?signed_stream_name: String?) -> void
151
+ def matches?: (untyped page_or_node) -> bool
152
+ def does_not_match?: (untyped page_or_node) -> bool
153
+ def failure_message: () -> String
154
+ def failure_message_when_negated: () -> String
155
+ def description: () -> String
156
+ end
157
+ end
158
+ end
159
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turbo_rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chuck Smith