rspec-enriched_json 0.4.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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 02a818ba249d1c7880a696e4488a45d827261458a569624263c3983d86eb4f7d
|
4
|
+
data.tar.gz: bca3f6099bc1779a07bafd486a4da1734d102fa4d1a3ea97ac18dfe2e059d2ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5b929b27773dbe3423097855d06ce700d377f5fad568218d22a329fbae70714ddf38cb15300e458d3e55e61350b062f0bb32c165017205e334a674020f1ceba
|
7
|
+
data.tar.gz: afa583debdd99a3e93ce77f5764a6b57d22dfb32752565fb9c6f1ebc92b41b9f6801ac191ae7846b685f0c7ac52d8994530d4471ad34008c13b9e6279570da5d
|
data/README.md
CHANGED
@@ -10,7 +10,7 @@ To see the difference between RSpec's built-in JSON formatter and this enriched
|
|
10
10
|
ruby demo.rb
|
11
11
|
```
|
12
12
|
|
13
|
-
This interactive demo script runs the same failing tests with both formatters and shows you the difference side-by-side.
|
13
|
+
This interactive demo script runs the same failing tests with both formatters and shows you the difference side-by-side.
|
14
14
|
|
15
15
|
**What you'll see:**
|
16
16
|
- **Built-in formatter**: Failure information embedded in string messages
|
@@ -88,9 +88,7 @@ With this gem, you get structured data alongside the original message:
|
|
88
88
|
"actual": "Hello, World!",
|
89
89
|
"matcher_name": "RSpec::Matchers::BuiltIn::Eq",
|
90
90
|
"original_message": null,
|
91
|
-
"
|
92
|
-
"diffable": true
|
93
|
-
}
|
91
|
+
"diffable": true
|
94
92
|
}
|
95
93
|
}
|
96
94
|
```
|
@@ -104,7 +102,7 @@ With this gem, you get structured data alongside the original message:
|
|
104
102
|
- **Graceful degradation**: Regular exceptions (non-expectation failures) work normally
|
105
103
|
- **Enhanced metadata capture**: Test location, tags, hierarchy, and custom metadata
|
106
104
|
- **Robust error recovery**: Handles objects that fail to serialize without crashing
|
107
|
-
- **Diff information**: Includes `
|
105
|
+
- **Diff information**: Includes `diffable` to help tools determine if values can be meaningfully diffed
|
108
106
|
|
109
107
|
## Examples
|
110
108
|
|
@@ -111,11 +111,13 @@ module RSpec
|
|
111
111
|
actual: Serializer.serialize_value(actual_raw),
|
112
112
|
original_message: original_message, # Only populated when custom message overrides it
|
113
113
|
matcher_name: matcher.class.name,
|
114
|
-
|
115
|
-
diffable: values_diffable?(expected_raw, actual_raw, matcher)
|
116
|
-
}
|
114
|
+
diffable: values_diffable?(expected_raw, actual_raw, matcher)
|
117
115
|
}
|
118
116
|
|
117
|
+
# Capture matcher-specific instance variables
|
118
|
+
matcher_data = extract_matcher_specific_data(matcher)
|
119
|
+
details.merge!(matcher_data) unless matcher_data.empty?
|
120
|
+
|
119
121
|
# Raise new exception with data attached
|
120
122
|
raise EnrichedExpectationNotMetError.new(e.message, details)
|
121
123
|
end
|
@@ -133,6 +135,71 @@ module RSpec
|
|
133
135
|
nil
|
134
136
|
end
|
135
137
|
|
138
|
+
def extract_matcher_specific_data(matcher)
|
139
|
+
# Skip common instance variables that are already captured
|
140
|
+
skip_vars = [
|
141
|
+
:@expected, :@actual, :@args, :@name,
|
142
|
+
# Skip internal implementation details
|
143
|
+
:@matcher, :@matchers, :@target,
|
144
|
+
:@delegator, :@base_matcher,
|
145
|
+
:@block, :@event_proc,
|
146
|
+
# Skip verbose internal state
|
147
|
+
:@pairings_maximizer, :@best_solution,
|
148
|
+
:@expected_captures, :@match_captures,
|
149
|
+
:@failures, :@errors,
|
150
|
+
# Skip RSpec internals
|
151
|
+
:@matcher_execution_context,
|
152
|
+
:@chained_method_with_args_combos
|
153
|
+
]
|
154
|
+
|
155
|
+
# Define meaningful variables we want to keep
|
156
|
+
useful_vars = [
|
157
|
+
:@missing_items, :@extra_items, # ContainExactly
|
158
|
+
:@expecteds, :@actuals, # Include
|
159
|
+
:@operator, :@delta, :@tolerance, # Comparison matchers
|
160
|
+
:@expected_before, :@expected_after, :@actual_before, :@actual_after, # Change matcher
|
161
|
+
:@from, :@to, :@minimum, :@maximum, :@count, # Various matchers
|
162
|
+
:@failure_message, :@failure_message_when_negated,
|
163
|
+
:@description
|
164
|
+
]
|
165
|
+
|
166
|
+
# Get all instance variables
|
167
|
+
ivars = matcher.instance_variables - skip_vars
|
168
|
+
return {} if ivars.empty?
|
169
|
+
|
170
|
+
# Build a hash of matcher-specific data
|
171
|
+
matcher_data = {}
|
172
|
+
|
173
|
+
ivars.each do |ivar|
|
174
|
+
# Only include if it's in our useful list or looks like user data
|
175
|
+
unless useful_vars.include?(ivar) || ivar.to_s.match?(/^@(missing|extra|failed|unmatched|matched)_/)
|
176
|
+
next
|
177
|
+
end
|
178
|
+
|
179
|
+
value = matcher.instance_variable_get(ivar)
|
180
|
+
|
181
|
+
# Skip if value is nil or the matcher itself
|
182
|
+
next if value.nil? || value == matcher
|
183
|
+
|
184
|
+
# Skip procs and complex objects unless they're simple collections
|
185
|
+
if value.is_a?(Proc) || (value.is_a?(Object) && !value.is_a?(Enumerable) && !value.is_a?(Numeric) && !value.is_a?(String) && !value.is_a?(Symbol))
|
186
|
+
next
|
187
|
+
end
|
188
|
+
|
189
|
+
# Convert instance variable name to a more readable format
|
190
|
+
# @missing_items -> missing_items
|
191
|
+
key = ivar.to_s.delete_prefix("@").to_sym
|
192
|
+
|
193
|
+
# Serialize the value
|
194
|
+
matcher_data[key] = Serializer.serialize_value(value)
|
195
|
+
rescue
|
196
|
+
# Skip this instance variable if we can't serialize it
|
197
|
+
next
|
198
|
+
end
|
199
|
+
|
200
|
+
matcher_data
|
201
|
+
end
|
202
|
+
|
136
203
|
def values_diffable?(expected, actual, matcher)
|
137
204
|
# First check if the matcher itself declares diffability
|
138
205
|
if matcher.respond_to?(:diffable?)
|
@@ -85,13 +85,22 @@ module RSpec
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def safe_structured_data(details)
|
88
|
-
|
88
|
+
# Start with core fields
|
89
|
+
result = {
|
89
90
|
expected: safe_serialize(details[:expected]),
|
90
91
|
actual: safe_serialize(details[:actual]),
|
91
92
|
matcher_name: details[:matcher_name],
|
92
93
|
original_message: details[:original_message],
|
93
|
-
|
94
|
-
}
|
94
|
+
diffable: details[:diffable]
|
95
|
+
}
|
96
|
+
|
97
|
+
# Add any additional matcher-specific fields
|
98
|
+
details.each do |key, value|
|
99
|
+
next if [:expected, :actual, :matcher_name, :original_message, :diffable].include?(key)
|
100
|
+
result[key] = safe_serialize(value)
|
101
|
+
end
|
102
|
+
|
103
|
+
result.compact
|
95
104
|
end
|
96
105
|
|
97
106
|
def safe_serialize(value)
|