turbo_rspec 0.2.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +96 -3
- data/ROADMAP.md +0 -10
- data/lib/turbo_rspec/capybara/matchers/have_turbo_frame.rb +70 -0
- data/lib/turbo_rspec/capybara/matchers/have_turbo_stream_tag.rb +49 -0
- data/lib/turbo_rspec/capybara/matchers.rb +24 -0
- data/lib/turbo_rspec/version.rb +1 -1
- data/lib/turbo_rspec.rb +5 -0
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a7ce28ec048a3f308d82036741fa064f49ecdba1d9d66c7c84af42a3ef2b69e3
|
|
4
|
+
data.tar.gz: ef5cb3cfba998e9b7c64070eb8dbd319532c3e5584c09c7f6d5cc651ec53b71e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6d85a8b12609e066c575f0d728ebffd0827c35fbb5b9d7572e6c7ec62493556aee058fb4dc005b1cfe9f2abe1359f5df7ef1c280bfc74b3427903aab9a8c92e5
|
|
7
|
+
data.tar.gz: 513effacfe8f0a663ae31456e9d82e7acb763ebc6eb04931fb536caab9d9c88752ad405ade01d79a296d8ef67e932ab6ce9e4edf0c6487b46873d9e3dfc4cab5
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.3.0] - 2026-05-28
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `have_turbo_frame(id)` Capybara matcher for system/feature specs — asserts a `<turbo-frame>` element is on the page
|
|
8
|
+
- `.with_content(text)` — asserts text content within the frame
|
|
9
|
+
- `.loaded` — asserts the frame has the `[complete]` attribute (finished loading)
|
|
10
|
+
- `have_turbo_stream_tag` Capybara matcher — asserts a `<turbo-stream-source>` subscription element is present; accepts an optional signed stream name
|
|
11
|
+
- `within_turbo_frame(id) { }` — scopes Capybara assertions to the frame's DOM
|
|
12
|
+
- Auto-include `TurboRspec::Capybara::Matchers` into `type: :system` and `type: :feature` example groups when both `turbo-rails` and `capybara` are present
|
|
13
|
+
|
|
3
14
|
## [0.2.0] - 2026-05-28
|
|
4
15
|
|
|
5
16
|
### Added
|
data/README.md
CHANGED
|
@@ -22,7 +22,10 @@ end
|
|
|
22
22
|
|
|
23
23
|
### Rails + turbo-rails (automatic)
|
|
24
24
|
|
|
25
|
-
No setup needed. When `turbo-rails` is in your bundle
|
|
25
|
+
No setup needed. When `turbo-rails` is in your bundle:
|
|
26
|
+
|
|
27
|
+
- `TurboRspec::Matchers` is automatically included in all `type: :request` example groups
|
|
28
|
+
- `TurboRspec::Capybara::Matchers` is automatically included in all `type: :system` and `type: :feature` example groups when `capybara` is also present
|
|
26
29
|
|
|
27
30
|
### Manual include
|
|
28
31
|
|
|
@@ -31,7 +34,8 @@ For non-Rails projects or custom contexts, include the matchers explicitly:
|
|
|
31
34
|
```ruby
|
|
32
35
|
# spec/spec_helper.rb
|
|
33
36
|
RSpec.configure do |config|
|
|
34
|
-
config.include TurboRspec::Matchers
|
|
37
|
+
config.include TurboRspec::Matchers # request specs
|
|
38
|
+
config.include TurboRspec::Capybara::Matchers # system/feature specs
|
|
35
39
|
end
|
|
36
40
|
```
|
|
37
41
|
|
|
@@ -40,7 +44,7 @@ end
|
|
|
40
44
|
```ruby
|
|
41
45
|
# spec/support/turbo_rspec.rb
|
|
42
46
|
TurboRspec.configure do |config|
|
|
43
|
-
config.auto_include = false # disable automatic inclusion
|
|
47
|
+
config.auto_include = false # disable automatic inclusion
|
|
44
48
|
end
|
|
45
49
|
```
|
|
46
50
|
|
|
@@ -106,6 +110,76 @@ expect(response).to have_turbo_frame.with_id("post").rendering("posts/_post")
|
|
|
106
110
|
expect(response).not_to have_turbo_frame.with_id("notifications")
|
|
107
111
|
```
|
|
108
112
|
|
|
113
|
+
### `have_broadcasted_turbo_stream_to`
|
|
114
|
+
|
|
115
|
+
Assert that a block broadcasts a `<turbo-stream>` over ActionCable. Requires ActionCable's test adapter.
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
# Basic — any broadcast to the stream
|
|
119
|
+
expect { MyJob.perform_now }.to have_broadcasted_turbo_stream_to("notifications")
|
|
120
|
+
|
|
121
|
+
# With constraints (same chain as have_turbo_stream)
|
|
122
|
+
expect { MyJob.perform_now }.to have_broadcasted_turbo_stream_to("notifications")
|
|
123
|
+
.with_action(:append)
|
|
124
|
+
.targeting("messages")
|
|
125
|
+
.with_content("Hello")
|
|
126
|
+
|
|
127
|
+
# Count qualifiers
|
|
128
|
+
expect { MyJob.perform_now }.to have_broadcasted_turbo_stream_to("notifications").once
|
|
129
|
+
expect { MyJob.perform_now }.to have_broadcasted_turbo_stream_to("notifications").exactly(3).times
|
|
130
|
+
expect { MyJob.perform_now }.to have_broadcasted_turbo_stream_to("notifications").at_least(2).times
|
|
131
|
+
|
|
132
|
+
# Alias
|
|
133
|
+
expect { MyJob.perform_now }.to broadcast_turbo_stream_to("notifications")
|
|
134
|
+
|
|
135
|
+
# Negation
|
|
136
|
+
expect { MyJob.perform_now }.not_to have_broadcasted_turbo_stream_to("notifications")
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### `have_turbo_frame` (system/feature specs)
|
|
140
|
+
|
|
141
|
+
Assert that a `<turbo-frame>` element is present on the page (Capybara).
|
|
142
|
+
|
|
143
|
+
```ruby
|
|
144
|
+
# Basic
|
|
145
|
+
expect(page).to have_turbo_frame("messages")
|
|
146
|
+
|
|
147
|
+
# With content
|
|
148
|
+
expect(page).to have_turbo_frame("messages").with_content("Hello")
|
|
149
|
+
|
|
150
|
+
# Loaded (frame finished loading)
|
|
151
|
+
expect(page).to have_turbo_frame("messages").loaded
|
|
152
|
+
|
|
153
|
+
# Negation
|
|
154
|
+
expect(page).not_to have_turbo_frame("notifications")
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### `within_turbo_frame`
|
|
158
|
+
|
|
159
|
+
Scope Capybara assertions to a specific frame's DOM.
|
|
160
|
+
|
|
161
|
+
```ruby
|
|
162
|
+
within_turbo_frame("messages") do
|
|
163
|
+
expect(page).to have_content("Hello")
|
|
164
|
+
click_button "Reply"
|
|
165
|
+
end
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### `have_turbo_stream_tag`
|
|
169
|
+
|
|
170
|
+
Assert that a `<turbo-stream-source>` subscription element is on the page.
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
# Any stream source
|
|
174
|
+
expect(page).to have_turbo_stream_tag
|
|
175
|
+
|
|
176
|
+
# With signed stream name
|
|
177
|
+
expect(page).to have_turbo_stream_tag("signed_stream_name")
|
|
178
|
+
|
|
179
|
+
# Negation
|
|
180
|
+
expect(page).not_to have_turbo_stream_tag
|
|
181
|
+
```
|
|
182
|
+
|
|
109
183
|
## Example: request spec
|
|
110
184
|
|
|
111
185
|
```ruby
|
|
@@ -136,6 +210,25 @@ RSpec.describe "Messages", type: :request do
|
|
|
136
210
|
end
|
|
137
211
|
```
|
|
138
212
|
|
|
213
|
+
## Example: system spec
|
|
214
|
+
|
|
215
|
+
```ruby
|
|
216
|
+
RSpec.describe "Messages", type: :system do
|
|
217
|
+
it "appends a new message via Turbo Frame" do
|
|
218
|
+
visit messages_path
|
|
219
|
+
fill_in "Body", with: "Hello"
|
|
220
|
+
click_button "Send"
|
|
221
|
+
|
|
222
|
+
expect(page).to have_turbo_frame("messages").with_content("Hello")
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
it "shows the subscription stream tag" do
|
|
226
|
+
visit messages_path
|
|
227
|
+
expect(page).to have_turbo_stream_tag
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
```
|
|
231
|
+
|
|
139
232
|
## Contributing
|
|
140
233
|
|
|
141
234
|
Bug reports and pull requests are welcome on [GitHub](https://github.com/eclectic-coding/turbo_rspec).
|
data/ROADMAP.md
CHANGED
|
@@ -5,16 +5,6 @@ RSpec matchers for [Turbo](https://github.com/hotwired/turbo-rails): Turbo Strea
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
## v0.3.0 — Capybara / system spec integration
|
|
9
|
-
|
|
10
|
-
**Goal:** assertions that work against a live browser in feature/system specs.
|
|
11
|
-
|
|
12
|
-
- `have_turbo_frame(id)` Capybara matcher — waits for the frame to appear on the page
|
|
13
|
-
- `.with_content(...)` — delegates to Capybara's `have_content` with correct scope
|
|
14
|
-
- `.loaded` — asserts `[complete]` attribute is present (frame finished loading)
|
|
15
|
-
- `within_turbo_frame(id) { ... }` — scopes Capybara assertions to the frame's DOM
|
|
16
|
-
- `have_turbo_stream_tag` — asserts a `<turbo-stream-source>` subscription element exists on the page
|
|
17
|
-
- Docs: system spec patterns, async update testing
|
|
18
8
|
|
|
19
9
|
---
|
|
20
10
|
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TurboRspec
|
|
4
|
+
module Capybara
|
|
5
|
+
module Matchers
|
|
6
|
+
class HaveTurboFrame
|
|
7
|
+
def initialize(id)
|
|
8
|
+
@id = id.to_s
|
|
9
|
+
@content = nil
|
|
10
|
+
@loaded = false
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def with_content(text)
|
|
14
|
+
@content = text.to_s
|
|
15
|
+
self
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def loaded
|
|
19
|
+
@loaded = true
|
|
20
|
+
self
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def matches?(page_or_node)
|
|
24
|
+
@node = find_frame(page_or_node)
|
|
25
|
+
return false unless @node
|
|
26
|
+
return false if @loaded && !@node[:complete]
|
|
27
|
+
return false if @content && !@node.has_content?(@content, wait: 0)
|
|
28
|
+
true
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def does_not_match?(page_or_node)
|
|
32
|
+
!matches?(page_or_node)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def failure_message
|
|
36
|
+
if @node.nil?
|
|
37
|
+
"expected page to have turbo-frame##{@id}#{constraint_description} but it was not found"
|
|
38
|
+
elsif @loaded && !@node[:complete]
|
|
39
|
+
"expected turbo-frame##{@id} to be loaded (missing [complete] attribute)"
|
|
40
|
+
else
|
|
41
|
+
"expected turbo-frame##{@id} to have content #{@content.inspect}"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def failure_message_when_negated
|
|
46
|
+
"expected page not to have turbo-frame##{@id}#{constraint_description}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def description
|
|
50
|
+
"have turbo-frame##{@id}#{constraint_description}"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def find_frame(page_or_node)
|
|
56
|
+
page_or_node.find("turbo-frame##{@id}", wait: 0)
|
|
57
|
+
rescue ::Capybara::ElementNotFound
|
|
58
|
+
nil
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def constraint_description
|
|
62
|
+
parts = []
|
|
63
|
+
parts << " loaded" if @loaded
|
|
64
|
+
parts << " with content #{@content.inspect}" if @content
|
|
65
|
+
parts.join
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TurboRspec
|
|
4
|
+
module Capybara
|
|
5
|
+
module Matchers
|
|
6
|
+
class HaveTurboStreamTag
|
|
7
|
+
def initialize(signed_stream_name: nil)
|
|
8
|
+
@signed_stream_name = signed_stream_name
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def matches?(page_or_node)
|
|
12
|
+
selector = build_selector
|
|
13
|
+
page_or_node.has_css?(selector, wait: 0)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def does_not_match?(page_or_node)
|
|
17
|
+
selector = build_selector
|
|
18
|
+
page_or_node.has_no_css?(selector, wait: 0)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def failure_message
|
|
22
|
+
"expected page to have a turbo-stream-source element#{stream_description}"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def failure_message_when_negated
|
|
26
|
+
"expected page not to have a turbo-stream-source element#{stream_description}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def description
|
|
30
|
+
"have turbo-stream-source#{stream_description}"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def build_selector
|
|
36
|
+
if @signed_stream_name
|
|
37
|
+
"turbo-stream-source[src*=\"#{@signed_stream_name}\"]"
|
|
38
|
+
else
|
|
39
|
+
"turbo-stream-source"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def stream_description
|
|
44
|
+
@signed_stream_name ? " for #{@signed_stream_name.inspect}" : ""
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "matchers/have_turbo_frame"
|
|
4
|
+
require_relative "matchers/have_turbo_stream_tag"
|
|
5
|
+
|
|
6
|
+
module TurboRspec
|
|
7
|
+
module Capybara
|
|
8
|
+
module Matchers
|
|
9
|
+
def have_turbo_frame(id)
|
|
10
|
+
HaveTurboFrame.new(id)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def have_turbo_stream_tag(signed_stream_name = nil)
|
|
14
|
+
HaveTurboStreamTag.new(signed_stream_name: signed_stream_name)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# :nocov:
|
|
18
|
+
def within_turbo_frame(id, &block)
|
|
19
|
+
page.within("turbo-frame##{id}", &block)
|
|
20
|
+
end
|
|
21
|
+
# :nocov:
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
data/lib/turbo_rspec/version.rb
CHANGED
data/lib/turbo_rspec.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "turbo_rspec/version"
|
|
4
4
|
require_relative "turbo_rspec/configuration"
|
|
5
5
|
require_relative "turbo_rspec/matchers"
|
|
6
|
+
require_relative "turbo_rspec/capybara/matchers"
|
|
6
7
|
|
|
7
8
|
module TurboRspec
|
|
8
9
|
class Error < StandardError; end
|
|
@@ -23,6 +24,10 @@ module TurboRspec
|
|
|
23
24
|
def install_rspec_integration(config)
|
|
24
25
|
return unless configuration.auto_include && Gem.loaded_specs.key?("turbo-rails")
|
|
25
26
|
config.include Matchers, type: :request
|
|
27
|
+
if Gem.loaded_specs.key?("capybara")
|
|
28
|
+
config.include Capybara::Matchers, type: :system
|
|
29
|
+
config.include Capybara::Matchers, type: :feature
|
|
30
|
+
end
|
|
26
31
|
end
|
|
27
32
|
end
|
|
28
33
|
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: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chuck Smith
|
|
@@ -43,6 +43,9 @@ files:
|
|
|
43
43
|
- Rakefile
|
|
44
44
|
- codecov.yml
|
|
45
45
|
- lib/turbo_rspec.rb
|
|
46
|
+
- lib/turbo_rspec/capybara/matchers.rb
|
|
47
|
+
- lib/turbo_rspec/capybara/matchers/have_turbo_frame.rb
|
|
48
|
+
- lib/turbo_rspec/capybara/matchers/have_turbo_stream_tag.rb
|
|
46
49
|
- lib/turbo_rspec/configuration.rb
|
|
47
50
|
- lib/turbo_rspec/matchers.rb
|
|
48
51
|
- lib/turbo_rspec/matchers/have_broadcasted_turbo_stream_to.rb
|