stimulus_spec 0.5.0 → 0.6.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 +9 -1
- data/README.md +17 -2
- data/ROADMAP.md +0 -7
- data/lib/stimulus_spec/capybara/matchers/have_stimulus_action.rb +14 -8
- data/lib/stimulus_spec/capybara/matchers/have_stimulus_class.rb +13 -1
- data/lib/stimulus_spec/capybara/matchers/have_stimulus_controller.rb +25 -9
- data/lib/stimulus_spec/capybara/matchers/have_stimulus_outlet.rb +13 -1
- data/lib/stimulus_spec/capybara/matchers/have_stimulus_target.rb +14 -2
- data/lib/stimulus_spec/capybara/matchers/have_stimulus_value.rb +13 -1
- data/lib/stimulus_spec/matchers/have_stimulus_action.rb +18 -3
- data/lib/stimulus_spec/matchers/have_stimulus_class.rb +18 -8
- data/lib/stimulus_spec/matchers/have_stimulus_controller.rb +30 -11
- data/lib/stimulus_spec/matchers/have_stimulus_outlet.rb +18 -8
- data/lib/stimulus_spec/matchers/have_stimulus_target.rb +17 -2
- data/lib/stimulus_spec/matchers/have_stimulus_value.rb +18 -8
- data/lib/stimulus_spec/version.rb +1 -1
- data/sig/stimulus_spec.rbs +17 -5
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 016bc15660c32251a12c1c9129fa88c86a3e2ac1059949535a67cdd5d64448ce
|
|
4
|
+
data.tar.gz: 76277d4b548369259e6ae9f28b8ad2b4d22637659f7c13a938e5cf2fd95127e5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8502635e782f3c870ee6aa638e09cba1bbc054c731d1c4599e5b23a31551bd0fb5dce9fc71eaa3d2ca8d3713b2ab8ba26591749a59b9bcd51bb09d871d11a2cc
|
|
7
|
+
data.tar.gz: 300a7bc9351bb8d0dbcc3f70122094d03705fd876322f36187c587daa0bf44446477a57df6e2130252d3501577b1e410bd1510836e70c97729b430b7dd5a6f33
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.6.0] - 2026-06-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Multi-controller assertion: `have_stimulus_controller("hello", "clipboard")` asserts multiple controllers on a single element
|
|
15
|
+
- Scoped matching via `.within(selector)` on all matchers (request-spec and Capybara)
|
|
16
|
+
|
|
10
17
|
## [0.5.0] - 2026-06-23
|
|
11
18
|
|
|
12
19
|
### Added
|
|
@@ -46,7 +53,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
46
53
|
- `have_stimulus_action(descriptor)` matcher — full descriptor (`~=`) and shorthand without event (`*=`)
|
|
47
54
|
- `have_stimulus_target(controller, target)` matcher — asserts `[data-{controller}-target~="target"]`
|
|
48
55
|
|
|
49
|
-
[Unreleased]: https://github.com/eclectic-coding/stimulus_spec/compare/v0.
|
|
56
|
+
[Unreleased]: https://github.com/eclectic-coding/stimulus_spec/compare/v0.6.0...HEAD
|
|
57
|
+
[0.6.0]: https://github.com/eclectic-coding/stimulus_spec/releases/tag/v0.6.0
|
|
50
58
|
[0.5.0]: https://github.com/eclectic-coding/stimulus_spec/releases/tag/v0.5.0
|
|
51
59
|
[0.4.0]: https://github.com/eclectic-coding/stimulus_spec/releases/tag/v0.4.0
|
|
52
60
|
[0.3.0]: https://github.com/eclectic-coding/stimulus_spec/releases/tag/v0.3.0
|
data/README.md
CHANGED
|
@@ -26,6 +26,7 @@ Companion gem to [turbo_rspec](https://github.com/eclectic-coding/turbo_rspec)
|
|
|
26
26
|
- [have\_stimulus\_value](#have_stimulus_value)
|
|
27
27
|
- [have\_stimulus\_class](#have_stimulus_class)
|
|
28
28
|
- [have\_stimulus\_outlet](#have_stimulus_outlet)
|
|
29
|
+
- [Scoped matching with `.within`](#scoped-matching-with-within)
|
|
29
30
|
- [Example](#example)
|
|
30
31
|
- [Relationship to turbo\_rspec](#relationship-to-turbo_rspec)
|
|
31
32
|
- [Contributing](#contributing)
|
|
@@ -84,8 +85,8 @@ Assert that rendered HTML contains a `data-controller` attribute with the given
|
|
|
84
85
|
```ruby
|
|
85
86
|
expect(response).to have_stimulus_controller("hello")
|
|
86
87
|
|
|
87
|
-
#
|
|
88
|
-
expect(response).to have_stimulus_controller("clipboard")
|
|
88
|
+
# Assert multiple controllers on a single element
|
|
89
|
+
expect(response).to have_stimulus_controller("hello", "clipboard")
|
|
89
90
|
|
|
90
91
|
# Negation
|
|
91
92
|
expect(response).not_to have_stimulus_controller("missing")
|
|
@@ -165,6 +166,20 @@ expect(response).to have_stimulus_outlet("search", "results", "#results-list")
|
|
|
165
166
|
expect(response).not_to have_stimulus_outlet("search", "results")
|
|
166
167
|
```
|
|
167
168
|
|
|
169
|
+
### Scoped matching with `.within`
|
|
170
|
+
|
|
171
|
+
All matchers support `.within(selector)` to restrict matching to a specific part of the page:
|
|
172
|
+
|
|
173
|
+
```ruby
|
|
174
|
+
# Request/controller specs — search within a CSS selector
|
|
175
|
+
expect(response).to have_stimulus_controller("search").within(".search-form")
|
|
176
|
+
expect(response).to have_stimulus_action("click->search#query").within(".search-form")
|
|
177
|
+
expect(response).to have_stimulus_target("search", "input").within(".search-form")
|
|
178
|
+
|
|
179
|
+
# System/feature specs — same API
|
|
180
|
+
expect(page).to have_stimulus_controller("search").within(".search-form")
|
|
181
|
+
```
|
|
182
|
+
|
|
168
183
|
[Back to top](#stimulusspec)
|
|
169
184
|
|
|
170
185
|
## Example
|
data/ROADMAP.md
CHANGED
|
@@ -11,13 +11,6 @@ RSpec matchers for [Stimulus](https://github.com/hotwired/stimulus-rails): contr
|
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
-
## 0.6.0 — Multi-Controller and Scoped Matching
|
|
15
|
-
|
|
16
|
-
- `have_stimulus_controller("hello", "clipboard")` — assert multiple controllers on a single element
|
|
17
|
-
- Scoped matching — assert Stimulus attributes within a specific CSS selector (e.g., within a form or component root)
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
14
|
## 0.7.0 — Documentation and Polish
|
|
22
15
|
|
|
23
16
|
- Full YARD documentation on all public methods and classes
|
|
@@ -8,13 +8,18 @@ module StimulusSpec
|
|
|
8
8
|
@descriptor = descriptor.to_s
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
def within(selector)
|
|
12
|
+
@scope = selector
|
|
13
|
+
self
|
|
14
|
+
end
|
|
15
|
+
|
|
11
16
|
def matches?(page)
|
|
12
17
|
@page = page
|
|
13
|
-
page.has_css?(
|
|
18
|
+
page.has_css?(scoped_selector, wait: 0)
|
|
14
19
|
end
|
|
15
20
|
|
|
16
21
|
def does_not_match?(page)
|
|
17
|
-
page.has_no_css?(
|
|
22
|
+
page.has_no_css?(scoped_selector, wait: 0)
|
|
18
23
|
end
|
|
19
24
|
|
|
20
25
|
def failure_message
|
|
@@ -31,12 +36,13 @@ module StimulusSpec
|
|
|
31
36
|
|
|
32
37
|
private
|
|
33
38
|
|
|
34
|
-
def
|
|
35
|
-
if @descriptor.include?("->")
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
def scoped_selector
|
|
40
|
+
base = if @descriptor.include?("->")
|
|
41
|
+
"[data-action~='#{@descriptor}']"
|
|
42
|
+
else
|
|
43
|
+
"[data-action*='#{@descriptor}']"
|
|
44
|
+
end
|
|
45
|
+
@scope ? "#{@scope} #{base}" : base
|
|
40
46
|
end
|
|
41
47
|
end
|
|
42
48
|
|
|
@@ -11,9 +11,14 @@ module StimulusSpec
|
|
|
11
11
|
@attr = "data-#{@controller}-#{@name}-class"
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
def within(selector)
|
|
15
|
+
@scope = selector
|
|
16
|
+
self
|
|
17
|
+
end
|
|
18
|
+
|
|
14
19
|
def matches?(page)
|
|
15
20
|
@page = page
|
|
16
|
-
element = page.first(
|
|
21
|
+
element = page.first(scoped_selector, minimum: 0, wait: 0)
|
|
17
22
|
return false unless element
|
|
18
23
|
|
|
19
24
|
if @expected
|
|
@@ -47,6 +52,13 @@ module StimulusSpec
|
|
|
47
52
|
"have Stimulus class \"#{@name}\" for controller \"#{@controller}\""
|
|
48
53
|
end
|
|
49
54
|
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def scoped_selector
|
|
59
|
+
base = "[#{@attr}]"
|
|
60
|
+
@scope ? "#{@scope} #{base}" : base
|
|
61
|
+
end
|
|
50
62
|
end
|
|
51
63
|
|
|
52
64
|
def have_stimulus_class(controller, name, expected = nil)
|
|
@@ -4,34 +4,50 @@ module StimulusSpec
|
|
|
4
4
|
module Capybara
|
|
5
5
|
module Matchers
|
|
6
6
|
class HaveStimulusController
|
|
7
|
-
def initialize(
|
|
8
|
-
@
|
|
7
|
+
def initialize(*names)
|
|
8
|
+
@names = names.map(&:to_s)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def within(selector)
|
|
12
|
+
@scope = selector
|
|
13
|
+
self
|
|
9
14
|
end
|
|
10
15
|
|
|
11
16
|
def matches?(page)
|
|
12
17
|
@page = page
|
|
13
|
-
page.has_css?(
|
|
18
|
+
page.has_css?(scoped_selector, wait: 0)
|
|
14
19
|
end
|
|
15
20
|
|
|
16
21
|
def does_not_match?(page)
|
|
17
|
-
page.has_no_css?(
|
|
22
|
+
page.has_no_css?(scoped_selector, wait: 0)
|
|
18
23
|
end
|
|
19
24
|
|
|
20
25
|
def failure_message
|
|
21
|
-
"expected to find an element with data-controller
|
|
26
|
+
"expected to find an element with data-controller=#{label} on the page"
|
|
22
27
|
end
|
|
23
28
|
|
|
24
29
|
def failure_message_when_negated
|
|
25
|
-
"expected not to find an element with data-controller
|
|
30
|
+
"expected not to find an element with data-controller=#{label} on the page"
|
|
26
31
|
end
|
|
27
32
|
|
|
28
33
|
def description
|
|
29
|
-
"have Stimulus controller
|
|
34
|
+
"have Stimulus controller #{label}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def label
|
|
40
|
+
@names.map { |n| "\"#{n}\"" }.join(", ")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def scoped_selector
|
|
44
|
+
selector = @names.map { |n| "[data-controller~='#{n}']" }.join
|
|
45
|
+
@scope ? "#{@scope} #{selector}" : selector
|
|
30
46
|
end
|
|
31
47
|
end
|
|
32
48
|
|
|
33
|
-
def have_stimulus_controller(
|
|
34
|
-
HaveStimulusController.new(
|
|
49
|
+
def have_stimulus_controller(*names)
|
|
50
|
+
HaveStimulusController.new(*names)
|
|
35
51
|
end
|
|
36
52
|
end
|
|
37
53
|
end
|
|
@@ -11,9 +11,14 @@ module StimulusSpec
|
|
|
11
11
|
@attr = "data-#{@controller}-#{@outlet}-outlet"
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
def within(selector)
|
|
15
|
+
@scope = selector
|
|
16
|
+
self
|
|
17
|
+
end
|
|
18
|
+
|
|
14
19
|
def matches?(page)
|
|
15
20
|
@page = page
|
|
16
|
-
element = page.first(
|
|
21
|
+
element = page.first(scoped_selector, minimum: 0, wait: 0)
|
|
17
22
|
return false unless element
|
|
18
23
|
|
|
19
24
|
if @selector
|
|
@@ -47,6 +52,13 @@ module StimulusSpec
|
|
|
47
52
|
"have Stimulus outlet \"#{@outlet}\" for controller \"#{@controller}\""
|
|
48
53
|
end
|
|
49
54
|
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def scoped_selector
|
|
59
|
+
base = "[#{@attr}]"
|
|
60
|
+
@scope ? "#{@scope} #{base}" : base
|
|
61
|
+
end
|
|
50
62
|
end
|
|
51
63
|
|
|
52
64
|
def have_stimulus_outlet(controller, outlet, selector = nil)
|
|
@@ -9,13 +9,18 @@ module StimulusSpec
|
|
|
9
9
|
@target = target.to_s
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
+
def within(selector)
|
|
13
|
+
@scope = selector
|
|
14
|
+
self
|
|
15
|
+
end
|
|
16
|
+
|
|
12
17
|
def matches?(page)
|
|
13
18
|
@page = page
|
|
14
|
-
page.has_css?(
|
|
19
|
+
page.has_css?(scoped_selector, wait: 0)
|
|
15
20
|
end
|
|
16
21
|
|
|
17
22
|
def does_not_match?(page)
|
|
18
|
-
page.has_no_css?(
|
|
23
|
+
page.has_no_css?(scoped_selector, wait: 0)
|
|
19
24
|
end
|
|
20
25
|
|
|
21
26
|
def failure_message
|
|
@@ -29,6 +34,13 @@ module StimulusSpec
|
|
|
29
34
|
def description
|
|
30
35
|
"have Stimulus target \"#{@target}\" for controller \"#{@controller}\""
|
|
31
36
|
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def scoped_selector
|
|
41
|
+
base = "[data-#{@controller}-target~='#{@target}']"
|
|
42
|
+
@scope ? "#{@scope} #{base}" : base
|
|
43
|
+
end
|
|
32
44
|
end
|
|
33
45
|
|
|
34
46
|
def have_stimulus_target(controller, target)
|
|
@@ -11,9 +11,14 @@ module StimulusSpec
|
|
|
11
11
|
@attr = "data-#{@controller}-#{@name}-value"
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
def within(selector)
|
|
15
|
+
@scope = selector
|
|
16
|
+
self
|
|
17
|
+
end
|
|
18
|
+
|
|
14
19
|
def matches?(page)
|
|
15
20
|
@page = page
|
|
16
|
-
element = page.first(
|
|
21
|
+
element = page.first(scoped_selector, minimum: 0, wait: 0)
|
|
17
22
|
return false unless element
|
|
18
23
|
|
|
19
24
|
if @expected
|
|
@@ -47,6 +52,13 @@ module StimulusSpec
|
|
|
47
52
|
"have Stimulus value \"#{@name}\" for controller \"#{@controller}\""
|
|
48
53
|
end
|
|
49
54
|
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def scoped_selector
|
|
59
|
+
base = "[#{@attr}]"
|
|
60
|
+
@scope ? "#{@scope} #{base}" : base
|
|
61
|
+
end
|
|
50
62
|
end
|
|
51
63
|
|
|
52
64
|
def have_stimulus_value(controller, name, expected = nil)
|
|
@@ -7,13 +7,21 @@ module StimulusSpec
|
|
|
7
7
|
@descriptor = descriptor.to_s
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
+
def within(selector)
|
|
11
|
+
@scope = selector
|
|
12
|
+
self
|
|
13
|
+
end
|
|
14
|
+
|
|
10
15
|
def matches?(subject)
|
|
11
16
|
@body = extract_body(subject)
|
|
12
17
|
@doc = Nokogiri::HTML5.fragment(@body)
|
|
18
|
+
root = search_root
|
|
19
|
+
return false unless root
|
|
20
|
+
|
|
13
21
|
if @descriptor.include?("->")
|
|
14
|
-
|
|
22
|
+
!root.at_css("[data-action~='#{@descriptor}']").nil?
|
|
15
23
|
else
|
|
16
|
-
|
|
24
|
+
!root.at_css("[data-action*='#{@descriptor}']").nil?
|
|
17
25
|
end
|
|
18
26
|
end
|
|
19
27
|
|
|
@@ -43,8 +51,15 @@ module StimulusSpec
|
|
|
43
51
|
subject.respond_to?(:body) ? subject.body : subject.to_s
|
|
44
52
|
end
|
|
45
53
|
|
|
54
|
+
def search_root
|
|
55
|
+
return @doc unless @scope
|
|
56
|
+
|
|
57
|
+
@doc.at_css(@scope)
|
|
58
|
+
end
|
|
59
|
+
|
|
46
60
|
def snippet
|
|
47
|
-
|
|
61
|
+
root = search_root || @doc
|
|
62
|
+
elements = root.css("[data-action]")
|
|
48
63
|
return @body if elements.empty?
|
|
49
64
|
|
|
50
65
|
elements.map(&:to_html).join("\n")
|
|
@@ -10,18 +10,21 @@ module StimulusSpec
|
|
|
10
10
|
@attr = "data-#{@controller}-#{@name}-class"
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
def within(selector)
|
|
14
|
+
@scope = selector
|
|
15
|
+
self
|
|
16
|
+
end
|
|
17
|
+
|
|
13
18
|
def matches?(subject)
|
|
14
19
|
@body = extract_body(subject)
|
|
15
20
|
@doc = Nokogiri::HTML5.fragment(@body)
|
|
16
|
-
@element =
|
|
21
|
+
@element = search_root&.at_css("[#{@attr}]")
|
|
17
22
|
return false unless @element
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
true
|
|
24
|
-
end
|
|
24
|
+
return true unless @expected
|
|
25
|
+
|
|
26
|
+
@actual = @element[@attr]
|
|
27
|
+
@actual == @expected.to_s
|
|
25
28
|
end
|
|
26
29
|
|
|
27
30
|
def does_not_match?(subject)
|
|
@@ -54,8 +57,15 @@ module StimulusSpec
|
|
|
54
57
|
subject.respond_to?(:body) ? subject.body : subject.to_s
|
|
55
58
|
end
|
|
56
59
|
|
|
60
|
+
def search_root
|
|
61
|
+
return @doc unless @scope
|
|
62
|
+
|
|
63
|
+
@doc.at_css(@scope)
|
|
64
|
+
end
|
|
65
|
+
|
|
57
66
|
def snippet
|
|
58
|
-
|
|
67
|
+
root = search_root || @doc
|
|
68
|
+
elements = root.css("[data-controller]")
|
|
59
69
|
return @body if elements.empty?
|
|
60
70
|
|
|
61
71
|
elements.map(&:to_html).join("\n")
|
|
@@ -3,15 +3,24 @@
|
|
|
3
3
|
module StimulusSpec
|
|
4
4
|
module Matchers
|
|
5
5
|
class HaveStimulusController
|
|
6
|
-
def initialize(
|
|
7
|
-
@
|
|
6
|
+
def initialize(*names)
|
|
7
|
+
@names = names.map(&:to_s)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def within(selector)
|
|
11
|
+
@scope = selector
|
|
12
|
+
self
|
|
8
13
|
end
|
|
9
14
|
|
|
10
15
|
def matches?(subject)
|
|
11
16
|
@body = extract_body(subject)
|
|
12
17
|
@doc = Nokogiri::HTML5.fragment(@body)
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
root = search_root
|
|
19
|
+
return false unless root
|
|
20
|
+
|
|
21
|
+
@found_controllers = root.css("[data-controller]").flat_map { |el| el["data-controller"].split }
|
|
22
|
+
selector = @names.map { |n| "[data-controller~='#{n}']" }.join
|
|
23
|
+
!root.at_css(selector).nil?
|
|
15
24
|
end
|
|
16
25
|
|
|
17
26
|
def does_not_match?(subject)
|
|
@@ -19,8 +28,9 @@ module StimulusSpec
|
|
|
19
28
|
end
|
|
20
29
|
|
|
21
30
|
def failure_message
|
|
22
|
-
|
|
23
|
-
|
|
31
|
+
label = @names.map { |n| "\"#{n}\"" }.join(", ")
|
|
32
|
+
msg = "expected to find an element with data-controller=#{label}"
|
|
33
|
+
if @found_controllers&.any?
|
|
24
34
|
msg += "\n found controllers: #{@found_controllers.uniq.map { |c| "\"#{c}\"" }.join(", ")}"
|
|
25
35
|
end
|
|
26
36
|
msg += "\n in:\n#{snippet}"
|
|
@@ -28,11 +38,13 @@ module StimulusSpec
|
|
|
28
38
|
end
|
|
29
39
|
|
|
30
40
|
def failure_message_when_negated
|
|
31
|
-
|
|
41
|
+
label = @names.map { |n| "\"#{n}\"" }.join(", ")
|
|
42
|
+
"expected not to find an element with data-controller=#{label} but found one"
|
|
32
43
|
end
|
|
33
44
|
|
|
34
45
|
def description
|
|
35
|
-
|
|
46
|
+
label = @names.map { |n| "\"#{n}\"" }.join(", ")
|
|
47
|
+
"have Stimulus controller #{label}"
|
|
36
48
|
end
|
|
37
49
|
|
|
38
50
|
private
|
|
@@ -41,16 +53,23 @@ module StimulusSpec
|
|
|
41
53
|
subject.respond_to?(:body) ? subject.body : subject.to_s
|
|
42
54
|
end
|
|
43
55
|
|
|
56
|
+
def search_root
|
|
57
|
+
return @doc unless @scope
|
|
58
|
+
|
|
59
|
+
@doc.at_css(@scope)
|
|
60
|
+
end
|
|
61
|
+
|
|
44
62
|
def snippet
|
|
45
|
-
|
|
63
|
+
root = search_root || @doc
|
|
64
|
+
elements = root.css("[data-controller]")
|
|
46
65
|
return @body if elements.empty?
|
|
47
66
|
|
|
48
67
|
elements.map(&:to_html).join("\n")
|
|
49
68
|
end
|
|
50
69
|
end
|
|
51
70
|
|
|
52
|
-
def have_stimulus_controller(
|
|
53
|
-
HaveStimulusController.new(
|
|
71
|
+
def have_stimulus_controller(*names)
|
|
72
|
+
HaveStimulusController.new(*names)
|
|
54
73
|
end
|
|
55
74
|
end
|
|
56
75
|
end
|
|
@@ -10,18 +10,21 @@ module StimulusSpec
|
|
|
10
10
|
@attr = "data-#{@controller}-#{@outlet}-outlet"
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
def within(selector)
|
|
14
|
+
@scope = selector
|
|
15
|
+
self
|
|
16
|
+
end
|
|
17
|
+
|
|
13
18
|
def matches?(subject)
|
|
14
19
|
@body = extract_body(subject)
|
|
15
20
|
@doc = Nokogiri::HTML5.fragment(@body)
|
|
16
|
-
@element =
|
|
21
|
+
@element = search_root&.at_css("[#{@attr}]")
|
|
17
22
|
return false unless @element
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
true
|
|
24
|
-
end
|
|
24
|
+
return true unless @selector
|
|
25
|
+
|
|
26
|
+
@actual = @element[@attr]
|
|
27
|
+
@actual == @selector.to_s
|
|
25
28
|
end
|
|
26
29
|
|
|
27
30
|
def does_not_match?(subject)
|
|
@@ -54,8 +57,15 @@ module StimulusSpec
|
|
|
54
57
|
subject.respond_to?(:body) ? subject.body : subject.to_s
|
|
55
58
|
end
|
|
56
59
|
|
|
60
|
+
def search_root
|
|
61
|
+
return @doc unless @scope
|
|
62
|
+
|
|
63
|
+
@doc.at_css(@scope)
|
|
64
|
+
end
|
|
65
|
+
|
|
57
66
|
def snippet
|
|
58
|
-
|
|
67
|
+
root = search_root || @doc
|
|
68
|
+
elements = root.css("[data-controller]")
|
|
59
69
|
return @body if elements.empty?
|
|
60
70
|
|
|
61
71
|
elements.map(&:to_html).join("\n")
|
|
@@ -9,10 +9,18 @@ module StimulusSpec
|
|
|
9
9
|
@attr = "data-#{@controller}-target"
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
+
def within(selector)
|
|
13
|
+
@scope = selector
|
|
14
|
+
self
|
|
15
|
+
end
|
|
16
|
+
|
|
12
17
|
def matches?(subject)
|
|
13
18
|
@body = extract_body(subject)
|
|
14
19
|
@doc = Nokogiri::HTML5.fragment(@body)
|
|
15
|
-
|
|
20
|
+
root = search_root
|
|
21
|
+
return false unless root
|
|
22
|
+
|
|
23
|
+
!root.at_css("[#{@attr}~='#{@target}']").nil?
|
|
16
24
|
end
|
|
17
25
|
|
|
18
26
|
def does_not_match?(subject)
|
|
@@ -41,8 +49,15 @@ module StimulusSpec
|
|
|
41
49
|
subject.respond_to?(:body) ? subject.body : subject.to_s
|
|
42
50
|
end
|
|
43
51
|
|
|
52
|
+
def search_root
|
|
53
|
+
return @doc unless @scope
|
|
54
|
+
|
|
55
|
+
@doc.at_css(@scope)
|
|
56
|
+
end
|
|
57
|
+
|
|
44
58
|
def snippet
|
|
45
|
-
|
|
59
|
+
root = search_root || @doc
|
|
60
|
+
elements = root.css("[#{@attr}]")
|
|
46
61
|
return @body if elements.empty?
|
|
47
62
|
|
|
48
63
|
elements.map(&:to_html).join("\n")
|
|
@@ -10,18 +10,21 @@ module StimulusSpec
|
|
|
10
10
|
@attr = "data-#{@controller}-#{@name}-value"
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
def within(selector)
|
|
14
|
+
@scope = selector
|
|
15
|
+
self
|
|
16
|
+
end
|
|
17
|
+
|
|
13
18
|
def matches?(subject)
|
|
14
19
|
@body = extract_body(subject)
|
|
15
20
|
@doc = Nokogiri::HTML5.fragment(@body)
|
|
16
|
-
@element =
|
|
21
|
+
@element = search_root&.at_css("[#{@attr}]")
|
|
17
22
|
return false unless @element
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
true
|
|
24
|
-
end
|
|
24
|
+
return true unless @expected
|
|
25
|
+
|
|
26
|
+
@actual = @element[@attr]
|
|
27
|
+
@actual == @expected.to_s
|
|
25
28
|
end
|
|
26
29
|
|
|
27
30
|
def does_not_match?(subject)
|
|
@@ -54,8 +57,15 @@ module StimulusSpec
|
|
|
54
57
|
subject.respond_to?(:body) ? subject.body : subject.to_s
|
|
55
58
|
end
|
|
56
59
|
|
|
60
|
+
def search_root
|
|
61
|
+
return @doc unless @scope
|
|
62
|
+
|
|
63
|
+
@doc.at_css(@scope)
|
|
64
|
+
end
|
|
65
|
+
|
|
57
66
|
def snippet
|
|
58
|
-
|
|
67
|
+
root = search_root || @doc
|
|
68
|
+
elements = root.css("[data-controller]")
|
|
59
69
|
return @body if elements.empty?
|
|
60
70
|
|
|
61
71
|
elements.map(&:to_html).join("\n")
|
data/sig/stimulus_spec.rbs
CHANGED
|
@@ -13,7 +13,7 @@ module StimulusSpec
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
module Matchers
|
|
16
|
-
def have_stimulus_controller: (String
|
|
16
|
+
def have_stimulus_controller: (*String names) -> HaveStimulusController
|
|
17
17
|
def have_stimulus_action: (String descriptor) -> HaveStimulusAction
|
|
18
18
|
def have_stimulus_target: (String controller, String target) -> HaveStimulusTarget
|
|
19
19
|
def have_stimulus_value: (String controller, String name, ?String? expected) -> HaveStimulusValue
|
|
@@ -21,7 +21,8 @@ module StimulusSpec
|
|
|
21
21
|
def have_stimulus_outlet: (String controller, String outlet, ?String? selector) -> HaveStimulusOutlet
|
|
22
22
|
|
|
23
23
|
class HaveStimulusController
|
|
24
|
-
def initialize: (String
|
|
24
|
+
def initialize: (*String names) -> void
|
|
25
|
+
def within: (String selector) -> self
|
|
25
26
|
def matches?: (untyped subject) -> bool
|
|
26
27
|
def does_not_match?: (untyped subject) -> bool
|
|
27
28
|
def failure_message: () -> String
|
|
@@ -31,6 +32,7 @@ module StimulusSpec
|
|
|
31
32
|
|
|
32
33
|
class HaveStimulusAction
|
|
33
34
|
def initialize: (String descriptor) -> void
|
|
35
|
+
def within: (String selector) -> self
|
|
34
36
|
def matches?: (untyped subject) -> bool
|
|
35
37
|
def does_not_match?: (untyped subject) -> bool
|
|
36
38
|
def failure_message: () -> String
|
|
@@ -40,6 +42,7 @@ module StimulusSpec
|
|
|
40
42
|
|
|
41
43
|
class HaveStimulusTarget
|
|
42
44
|
def initialize: (String controller, String target) -> void
|
|
45
|
+
def within: (String selector) -> self
|
|
43
46
|
def matches?: (untyped subject) -> bool
|
|
44
47
|
def does_not_match?: (untyped subject) -> bool
|
|
45
48
|
def failure_message: () -> String
|
|
@@ -49,6 +52,7 @@ module StimulusSpec
|
|
|
49
52
|
|
|
50
53
|
class HaveStimulusValue
|
|
51
54
|
def initialize: (String controller, String name, ?String? expected) -> void
|
|
55
|
+
def within: (String selector) -> self
|
|
52
56
|
def matches?: (untyped subject) -> bool
|
|
53
57
|
def does_not_match?: (untyped subject) -> bool
|
|
54
58
|
def failure_message: () -> String
|
|
@@ -58,6 +62,7 @@ module StimulusSpec
|
|
|
58
62
|
|
|
59
63
|
class HaveStimulusClass
|
|
60
64
|
def initialize: (String controller, String name, ?String? expected) -> void
|
|
65
|
+
def within: (String selector) -> self
|
|
61
66
|
def matches?: (untyped subject) -> bool
|
|
62
67
|
def does_not_match?: (untyped subject) -> bool
|
|
63
68
|
def failure_message: () -> String
|
|
@@ -67,6 +72,7 @@ module StimulusSpec
|
|
|
67
72
|
|
|
68
73
|
class HaveStimulusOutlet
|
|
69
74
|
def initialize: (String controller, String outlet, ?String? selector) -> void
|
|
75
|
+
def within: (String selector) -> self
|
|
70
76
|
def matches?: (untyped subject) -> bool
|
|
71
77
|
def does_not_match?: (untyped subject) -> bool
|
|
72
78
|
def failure_message: () -> String
|
|
@@ -77,7 +83,7 @@ module StimulusSpec
|
|
|
77
83
|
|
|
78
84
|
module Capybara
|
|
79
85
|
module Matchers
|
|
80
|
-
def have_stimulus_controller: (String
|
|
86
|
+
def have_stimulus_controller: (*String names) -> HaveStimulusController
|
|
81
87
|
def have_stimulus_action: (String descriptor) -> HaveStimulusAction
|
|
82
88
|
def have_stimulus_target: (String controller, String target) -> HaveStimulusTarget
|
|
83
89
|
def have_stimulus_value: (String controller, String name, ?String? expected) -> HaveStimulusValue
|
|
@@ -85,7 +91,8 @@ module StimulusSpec
|
|
|
85
91
|
def have_stimulus_outlet: (String controller, String outlet, ?String? selector) -> HaveStimulusOutlet
|
|
86
92
|
|
|
87
93
|
class HaveStimulusController
|
|
88
|
-
def initialize: (String
|
|
94
|
+
def initialize: (*String names) -> void
|
|
95
|
+
def within: (String selector) -> self
|
|
89
96
|
def matches?: (untyped page) -> bool
|
|
90
97
|
def does_not_match?: (untyped page) -> bool
|
|
91
98
|
def failure_message: () -> String
|
|
@@ -95,6 +102,7 @@ module StimulusSpec
|
|
|
95
102
|
|
|
96
103
|
class HaveStimulusAction
|
|
97
104
|
def initialize: (String descriptor) -> void
|
|
105
|
+
def within: (String selector) -> self
|
|
98
106
|
def matches?: (untyped page) -> bool
|
|
99
107
|
def does_not_match?: (untyped page) -> bool
|
|
100
108
|
def failure_message: () -> String
|
|
@@ -104,6 +112,7 @@ module StimulusSpec
|
|
|
104
112
|
|
|
105
113
|
class HaveStimulusTarget
|
|
106
114
|
def initialize: (String controller, String target) -> void
|
|
115
|
+
def within: (String selector) -> self
|
|
107
116
|
def matches?: (untyped page) -> bool
|
|
108
117
|
def does_not_match?: (untyped page) -> bool
|
|
109
118
|
def failure_message: () -> String
|
|
@@ -113,6 +122,7 @@ module StimulusSpec
|
|
|
113
122
|
|
|
114
123
|
class HaveStimulusValue
|
|
115
124
|
def initialize: (String controller, String name, ?String? expected) -> void
|
|
125
|
+
def within: (String selector) -> self
|
|
116
126
|
def matches?: (untyped page) -> bool
|
|
117
127
|
def does_not_match?: (untyped page) -> bool
|
|
118
128
|
def failure_message: () -> String
|
|
@@ -122,6 +132,7 @@ module StimulusSpec
|
|
|
122
132
|
|
|
123
133
|
class HaveStimulusClass
|
|
124
134
|
def initialize: (String controller, String name, ?String? expected) -> void
|
|
135
|
+
def within: (String selector) -> self
|
|
125
136
|
def matches?: (untyped page) -> bool
|
|
126
137
|
def does_not_match?: (untyped page) -> bool
|
|
127
138
|
def failure_message: () -> String
|
|
@@ -131,6 +142,7 @@ module StimulusSpec
|
|
|
131
142
|
|
|
132
143
|
class HaveStimulusOutlet
|
|
133
144
|
def initialize: (String controller, String outlet, ?String? selector) -> void
|
|
145
|
+
def within: (String selector) -> self
|
|
134
146
|
def matches?: (untyped page) -> bool
|
|
135
147
|
def does_not_match?: (untyped page) -> bool
|
|
136
148
|
def failure_message: () -> String
|
|
@@ -139,4 +151,4 @@ module StimulusSpec
|
|
|
139
151
|
end
|
|
140
152
|
end
|
|
141
153
|
end
|
|
142
|
-
end
|
|
154
|
+
end
|