stimulus_spec 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b3c093ad148d096d99e96b88f18c7f90814878425dc7c531c4aba4af4149cd81
4
- data.tar.gz: 3e938ad72982b139830f45815c1cc6d4c457f9e8f60af4d1bf362a7cbb641fb6
3
+ metadata.gz: ffe129c9b92bcc3dfe29e7dd6e9be508fd7c14b99603ca7524f964679fe42b6c
4
+ data.tar.gz: a254bb73a1d5e275637e477a333e3bea6ab4248b7555e1d1d3f4bf74de9f213c
5
5
  SHA512:
6
- metadata.gz: 50ff8b23e522757c5bc8387a27b00299db7c7f23b1134cbe6fbe204bebf005b825ba1e621546c681c47eaa6f7ec28e7418b17672e87fea7c01dcf5bea6425910
7
- data.tar.gz: cd08d477efb9bab97f956c943f30e88ebbfc5362d73fe9ede1af2d448e0125c00fe67a6b601361abf37396a996ccdb9fe2c550d0f346dc884f8caa647e9caa00
6
+ metadata.gz: '038f5d80f4a0b38bc9e0664bb3d476db0af508580bc6476095d2791fe65cb7f515e06d1116fecdc8570f559aaf77331fac6c06e5fa2e0b41b7616b6eb652e069'
7
+ data.tar.gz: cc7ed0ded4e4db2426532aeef9a2dcf2ab92aee3b27bf5af792921a70e3ccdfefc84cb679a7004e0231b385a1c6c3254178a5142eccc499dadc31b947711f73a
data/CHANGELOG.md CHANGED
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.0] - 2026-06-22
11
+
12
+ ### Added
13
+
14
+ - `have_stimulus_value(controller, name)` matcher — asserts `data-{controller}-{name}-value` exists
15
+ - `have_stimulus_value(controller, name, expected)` matcher — asserts attribute equals expected value
16
+ - `have_stimulus_class(controller, name)` matcher — asserts `data-{controller}-{name}-class` exists
17
+ - `have_stimulus_class(controller, name, expected)` matcher — asserts attribute equals expected class
18
+
10
19
  ## [0.1.0] - 2026-06-22
11
20
 
12
21
  ### Added
@@ -19,5 +28,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
19
28
  - `have_stimulus_action(descriptor)` matcher — full descriptor (`~=`) and shorthand without event (`*=`)
20
29
  - `have_stimulus_target(controller, target)` matcher — asserts `[data-{controller}-target~="target"]`
21
30
 
22
- [Unreleased]: https://github.com/eclectic-coding/stimulus_spec/compare/v0.1.0...HEAD
31
+ [Unreleased]: https://github.com/eclectic-coding/stimulus_spec/compare/v0.3.0...HEAD
32
+ [0.3.0]: https://github.com/eclectic-coding/stimulus_spec/releases/tag/v0.3.0
23
33
  [0.1.0]: https://github.com/eclectic-coding/stimulus_spec/releases/tag/v0.1.0
data/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  Drop-in RSpec matchers for [hotwired/stimulus-rails](https://github.com/hotwired/stimulus-rails) — stop hand-rolling `data-controller` assertions and test your Stimulus wiring with expressive, purpose-built matchers.
10
10
 
11
- - **Request/controller specs** — `have_stimulus_controller`, `have_stimulus_action`, `have_stimulus_target`
11
+ - **Request/controller specs** — `have_stimulus_controller`, `have_stimulus_action`, `have_stimulus_target`, `have_stimulus_value`, `have_stimulus_class`
12
12
  - **Auto-included** — zero setup required when `stimulus-rails` is in your bundle
13
13
  - **Configurable** — disable auto-include when you need manual control
14
14
 
@@ -22,6 +22,8 @@ Companion gem to [turbo_rspec](https://github.com/eclectic-coding/turbo_rspec)
22
22
  - [have\_stimulus\_controller](#have_stimulus_controller)
23
23
  - [have\_stimulus\_action](#have_stimulus_action)
24
24
  - [have\_stimulus\_target](#have_stimulus_target)
25
+ - [have\_stimulus\_value](#have_stimulus_value)
26
+ - [have\_stimulus\_class](#have_stimulus_class)
25
27
  - [Example](#example)
26
28
  - [Relationship to turbo\_rspec](#relationship-to-turbo_rspec)
27
29
  - [Contributing](#contributing)
@@ -112,6 +114,36 @@ expect(response).to have_stimulus_target("hello", "output")
112
114
  expect(response).not_to have_stimulus_target("hello", "missing")
113
115
  ```
114
116
 
117
+ ### `have_stimulus_value`
118
+
119
+ Assert that rendered HTML contains a `data-{controller}-{name}-value` attribute, optionally with a specific value.
120
+
121
+ ```ruby
122
+ # Assert the value attribute exists
123
+ expect(response).to have_stimulus_value("search", "url")
124
+
125
+ # Assert a specific value
126
+ expect(response).to have_stimulus_value("search", "url", "/results")
127
+
128
+ # Negation
129
+ expect(response).not_to have_stimulus_value("search", "url")
130
+ ```
131
+
132
+ ### `have_stimulus_class`
133
+
134
+ Assert that rendered HTML contains a `data-{controller}-{name}-class` attribute, optionally with a specific class.
135
+
136
+ ```ruby
137
+ # Assert the class attribute exists
138
+ expect(response).to have_stimulus_class("search", "loading")
139
+
140
+ # Assert a specific class value
141
+ expect(response).to have_stimulus_class("search", "loading", "opacity-50")
142
+
143
+ # Negation
144
+ expect(response).not_to have_stimulus_class("search", "loading")
145
+ ```
146
+
115
147
  [Back to top](#stimulusspec)
116
148
 
117
149
  ## Example
data/ROADMAP.md CHANGED
@@ -11,23 +11,6 @@ RSpec matchers for [Stimulus](https://github.com/hotwired/stimulus-rails): contr
11
11
 
12
12
  ---
13
13
 
14
- ## 0.2.0 — Values and Classes
15
-
16
- - `have_stimulus_value("search", "url")` — assert `data-search-url-value` attribute exists
17
- - `have_stimulus_value("search", "url", "/results")` — assert attribute equals expected value
18
- - `have_stimulus_class("search", "loading")` — assert `data-search-loading-class` exists
19
- - `have_stimulus_class("search", "loading", "opacity-50")` — assert attribute equals expected class
20
-
21
- ---
22
-
23
- ## 0.3.0 — Outlets and Capybara Foundation
24
-
25
- - `have_stimulus_outlet("search", "results")` — assert `data-search-results-outlet` exists
26
- - `have_stimulus_outlet("search", "results", "#results-list")` — assert selector value
27
- - Capybara matchers: `have_stimulus_controller`, `have_stimulus_action`, `have_stimulus_target` using `has_css?` / `has_no_css?` with `wait: 0`
28
- - Auto-include `StimulusSpec::Capybara::Matchers` into `type: :system` and `type: :feature` (gated on `capybara`)
29
-
30
- ---
31
14
 
32
15
  ## 0.4.0 — Capybara Values and Rich Failures
33
16
 
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusSpec
4
+ module Matchers
5
+ class HaveStimulusClass
6
+ def initialize(controller, name, expected = nil)
7
+ @controller = controller.to_s
8
+ @name = name.to_s
9
+ @expected = expected
10
+ @attr = "data-#{@controller}-#{@name}-class"
11
+ end
12
+
13
+ def matches?(subject)
14
+ @body = extract_body(subject)
15
+ element = document.at_css("[#{@attr}]")
16
+ return false unless element
17
+
18
+ if @expected
19
+ @actual = element[@attr]
20
+ @actual == @expected.to_s
21
+ else
22
+ true
23
+ end
24
+ end
25
+
26
+ def does_not_match?(subject)
27
+ !matches?(subject)
28
+ end
29
+
30
+ def failure_message
31
+ if @expected && @actual
32
+ "expected #{@attr} to be \"#{@expected}\" but was \"#{@actual}\""
33
+ else
34
+ "expected to find an element with #{@attr} but found none in:\n#{@body}"
35
+ end
36
+ end
37
+
38
+ def failure_message_when_negated
39
+ "expected not to find an element with #{@attr} but found one"
40
+ end
41
+
42
+ def description
43
+ if @expected
44
+ "have Stimulus class \"#{@name}\" with \"#{@expected}\" for controller \"#{@controller}\""
45
+ else
46
+ "have Stimulus class \"#{@name}\" for controller \"#{@controller}\""
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def extract_body(subject)
53
+ subject.respond_to?(:body) ? subject.body : subject.to_s
54
+ end
55
+
56
+ def document
57
+ Nokogiri::HTML5.fragment(@body)
58
+ end
59
+ end
60
+
61
+ def have_stimulus_class(controller, name, expected = nil)
62
+ HaveStimulusClass.new(controller, name, expected)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusSpec
4
+ module Matchers
5
+ class HaveStimulusValue
6
+ def initialize(controller, name, expected = nil)
7
+ @controller = controller.to_s
8
+ @name = name.to_s
9
+ @expected = expected
10
+ @attr = "data-#{@controller}-#{@name}-value"
11
+ end
12
+
13
+ def matches?(subject)
14
+ @body = extract_body(subject)
15
+ element = document.at_css("[#{@attr}]")
16
+ return false unless element
17
+
18
+ if @expected
19
+ @actual = element[@attr]
20
+ @actual == @expected.to_s
21
+ else
22
+ true
23
+ end
24
+ end
25
+
26
+ def does_not_match?(subject)
27
+ !matches?(subject)
28
+ end
29
+
30
+ def failure_message
31
+ if @expected && @actual
32
+ "expected #{@attr} to be \"#{@expected}\" but was \"#{@actual}\""
33
+ else
34
+ "expected to find an element with #{@attr} but found none in:\n#{@body}"
35
+ end
36
+ end
37
+
38
+ def failure_message_when_negated
39
+ "expected not to find an element with #{@attr} but found one"
40
+ end
41
+
42
+ def description
43
+ if @expected
44
+ "have Stimulus value \"#{@name}\" with \"#{@expected}\" for controller \"#{@controller}\""
45
+ else
46
+ "have Stimulus value \"#{@name}\" for controller \"#{@controller}\""
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def extract_body(subject)
53
+ subject.respond_to?(:body) ? subject.body : subject.to_s
54
+ end
55
+
56
+ def document
57
+ Nokogiri::HTML5.fragment(@body)
58
+ end
59
+ end
60
+
61
+ def have_stimulus_value(controller, name, expected = nil)
62
+ HaveStimulusValue.new(controller, name, expected)
63
+ end
64
+ end
65
+ end
@@ -5,6 +5,8 @@ require "nokogiri"
5
5
  require_relative "matchers/have_stimulus_controller"
6
6
  require_relative "matchers/have_stimulus_action"
7
7
  require_relative "matchers/have_stimulus_target"
8
+ require_relative "matchers/have_stimulus_value"
9
+ require_relative "matchers/have_stimulus_class"
8
10
 
9
11
  module StimulusSpec
10
12
  module Matchers
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StimulusSpec
4
- VERSION = "0.1.0"
4
+ VERSION = "0.3.0"
5
5
  end
@@ -16,6 +16,8 @@ module StimulusSpec
16
16
  def have_stimulus_controller: (String name) -> HaveStimulusController
17
17
  def have_stimulus_action: (String descriptor) -> HaveStimulusAction
18
18
  def have_stimulus_target: (String controller, String target) -> HaveStimulusTarget
19
+ def have_stimulus_value: (String controller, String name, ?String? expected) -> HaveStimulusValue
20
+ def have_stimulus_class: (String controller, String name, ?String? expected) -> HaveStimulusClass
19
21
 
20
22
  class HaveStimulusController
21
23
  def initialize: (String name) -> void
@@ -43,5 +45,23 @@ module StimulusSpec
43
45
  def failure_message_when_negated: () -> String
44
46
  def description: () -> String
45
47
  end
48
+
49
+ class HaveStimulusValue
50
+ def initialize: (String controller, String name, ?String? expected) -> void
51
+ def matches?: (untyped subject) -> bool
52
+ def does_not_match?: (untyped subject) -> bool
53
+ def failure_message: () -> String
54
+ def failure_message_when_negated: () -> String
55
+ def description: () -> String
56
+ end
57
+
58
+ class HaveStimulusClass
59
+ def initialize: (String controller, String name, ?String? expected) -> void
60
+ def matches?: (untyped subject) -> bool
61
+ def does_not_match?: (untyped subject) -> bool
62
+ def failure_message: () -> String
63
+ def failure_message_when_negated: () -> String
64
+ def description: () -> String
65
+ end
46
66
  end
47
67
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stimulus_spec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chuck Smith
@@ -47,8 +47,10 @@ files:
47
47
  - lib/stimulus_spec/configuration.rb
48
48
  - lib/stimulus_spec/matchers.rb
49
49
  - lib/stimulus_spec/matchers/have_stimulus_action.rb
50
+ - lib/stimulus_spec/matchers/have_stimulus_class.rb
50
51
  - lib/stimulus_spec/matchers/have_stimulus_controller.rb
51
52
  - lib/stimulus_spec/matchers/have_stimulus_target.rb
53
+ - lib/stimulus_spec/matchers/have_stimulus_value.rb
52
54
  - lib/stimulus_spec/version.rb
53
55
  - sig/stimulus_spec.rbs
54
56
  homepage: https://github.com/eclectic-coding/stimulus_spec