rspec-given 3.3.0 → 3.4.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
  SHA1:
3
- metadata.gz: 8f6b65b46cef2fc751535568e6bd4b49bab117ad
4
- data.tar.gz: 87338960a579e6e2b881c4438954733703801322
3
+ metadata.gz: 28324282e7dae4f8e019d59cc094b90e43e2c2bb
4
+ data.tar.gz: 12422b6076ce08f5c257d5da088a4753c6e6bc2f
5
5
  SHA512:
6
- metadata.gz: 2188ecabba52de943bfaff4ff22ead2808a41402b9d2d807c1afdc19c5955e53794891eff19c2f904dca4a7d220d6730b104021133f39c3fc95604262755a0b2
7
- data.tar.gz: c2b4b93337146df65592f25002cb96ce3537dc2e804b6a2cd76f81076c3b2ec126809cb6d93b9653f6b9891e745de9ff8fd9ca7ab04b915ca333a4d0c3bd8b40
6
+ metadata.gz: 931a00a40a178c7a35b6231aee226139225b6f82d4198a81ded2f0e52086d355fa5cf78f1acb18f427bcc7eced5d5a57dfa03dac5107177cf438366658c022ea
7
+ data.tar.gz: d0021d7b45dab9bf98381f992acfb6bafe6237e71d3dc8237c1e0071a08d0b438d0874321cefb2e3a73d365a864129f08fde414efc8a86649d562fa146a4e876
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  | :----: |
5
5
  | [![Master Build Status](https://secure.travis-ci.org/jimweirich/rspec-given.png?branch=master)](https://travis-ci.org/jimweirich/rspec-given) |
6
6
 
7
- Covering rspec-given, minitest-given, and given-core, version 3.3.0.beta21.
7
+ Covering rspec-given, minitest-given, and given-core, version 3.4.0.
8
8
 
9
9
  rspec-given and minitest-given are extensions to your favorite testing
10
10
  framework to allow Given/When/Then notation when writing specs.
@@ -866,6 +866,11 @@ License. See the MIT-LICENSE file in the source distribution.
866
866
 
867
867
  # History
868
868
 
869
+ * Version 3.4.0
870
+
871
+ * Bare failure objects in Then clauses will now propagate their
872
+ captured failure (added <code>to_bool</code> to failure object).
873
+
869
874
  * Version 3.3.0
870
875
 
871
876
  * Add support for <code>to_bool</code>.
data/Rakefile CHANGED
@@ -42,7 +42,7 @@ task :tag do
42
42
  end
43
43
 
44
44
  desc "Publish the gems"
45
- task :publish => [:clobber, :gem] do
45
+ task :publish_gems => [:clobber, :gem] do
46
46
  FileList['pkg/*.gem'].each do |gemname|
47
47
  sh "gem push #{gemname}"
48
48
  end
@@ -0,0 +1,282 @@
1
+ ## Beautiful Failure Messages
2
+
3
+ The RSpec/Given library is an extension to the RSpec testing framework
4
+ that explicitly supports a Given/When/Then style for testing. It has
5
+ two goals:
6
+
7
+ * Encourage specification language when writing tests
8
+ * Allow beautiful failure messages without writing custom matchers
9
+
10
+ RSpec/Given has a been very successful in both these goals. Consider
11
+ the following spec snippet for a Page object in a Wiki Rails
12
+ application:
13
+
14
+ ```ruby
15
+ describe "content conversion to HTML" do
16
+ Given(:page) {
17
+ Page.new(
18
+ name: "HomePage",
19
+ content: "Have a _nice_ day.")
20
+ }
21
+ Then { page.html_content == "Have a <em>nice</em> day." }
22
+ end
23
+ ```
24
+
25
+ Assuming that the <code>html_content</code> method is incomplete and
26
+ not yet marking emphasized text, the failure message from the
27
+ specification will be:
28
+
29
+ 1) Page content conversion to HTML
30
+ Failure/Error: Then { page.html_content == "Have a <em>nice</em> day." }
31
+ Then expression failed at .../spec/models/page_spec.rb:38
32
+ expected: "Have a _nice_ day."
33
+ to equal: "Have a <em>nice</em> day."
34
+ false <- page.html_content == "Have a <em>nice</em> day."
35
+ "Have a _nice_ day."
36
+ <- page.html_content
37
+ #<Page name: "HomePage", content: "Have a _nice_ day." ...>
38
+ <- page
39
+ # ./spec/models/page_spec.rb:38:in `block in Then'
40
+
41
+ Let's break that down:
42
+
43
+ **It says what failed:**
44
+
45
+ Failure/Error: Then { page.html_content == "Have a <em>nice</em> day." }
46
+
47
+ **It says where it failed:**
48
+
49
+ Then expression failed at .../spec/models/page_spec.rb:38
50
+
51
+ **It says what was expected:**
52
+
53
+ expected: "Have a _nice_ day."
54
+ to equal: "Have a <em>nice</em> day."
55
+
56
+ **It then breaks down each subexpression and displays its value:**
57
+
58
+ false <- page.html_content == "Have a <em>nice</em> day."
59
+ "Have a _nice_ day."
60
+ <- page.html_content
61
+ #<Page name: "HomePage", content: "Have a _nice_ day." ...>
62
+ <- page
63
+
64
+ All of this happens without the developer needing to write any special
65
+ error matchers or custom output. Everything you need to debug a spec
66
+ failure is there in the output.
67
+
68
+ ## A More Complex Example
69
+
70
+ Let's look at a more complex example. Suppose we want to test
71
+ validations in the Page object. For example, we might want to make
72
+ sure that:
73
+
74
+ * The page has a name
75
+ * The name conforms to the standard wiki naming convention (i.e. WikiName).
76
+
77
+ Here's the beginning of that specification:
78
+
79
+ ```ruby
80
+ describe Page do
81
+ VALID_ATTRS = { name: "SomePage", content: "CONTENT" }
82
+ Given(:attrs) { VALID_ATTRS }
83
+ Given(:page) { Page.new(attrs) }
84
+
85
+ ...
86
+ end
87
+ ```
88
+
89
+ <code>VALID\_ATTRS</code> is a list of attributes that will construct a
90
+ valid page object. Normally I would put <code>VALID\_ATTRS</code> in something like
91
+ Factory Girl, but a simple constant is good enough this example.
92
+
93
+ I then declare a given that <code>attrs</code> is the valid
94
+ attributes, and that <code>Page</code> is constructed from these valid
95
+ attributes.
96
+
97
+ I can now describe a valid page object.
98
+
99
+ ```ruby
100
+ context "with valid attributes" do
101
+ Then { page.valid? }
102
+ end
103
+ ```
104
+
105
+ To describe a validation failure where the name is missing, I create a
106
+ context where I override the default <code>attrs</code> with a version
107
+ that omits the name.
108
+
109
+ ```ruby
110
+ context "with missing name" do
111
+ Given(:attrs) { VALID_ATTRS.merge(name: nil) }
112
+ Then { page.invalid? }
113
+ And { ! page.errors[:name].empty? }
114
+ And { page.errors[:name].any? { |msg| msg =~ /blank/ } }
115
+ end
116
+ ```
117
+
118
+ Why Then/And/And? Because there are three things that should be true
119
+ if a validation fails.
120
+
121
+ 1. The object must not be valid
122
+ 2. The field that has the error must have error messages
123
+ 3. At least one of the error messages should mention the word 'blank'
124
+
125
+ Suppose the Page object has a validation on name, but doesn't check
126
+ for presence. The failure message clearly tells you that the spec
127
+ failed because no error messages on the <code>name</code> field
128
+ mentioned 'blank'.
129
+
130
+ 1) Page validations with missing name
131
+ Failure/Error: Then { page.invalid? }
132
+ And expression failed at ./spec/models/page_spec.rb:27
133
+ Failing expression: And { page.errors[:name].any? { |msg| msg =~ /blank/ } }
134
+ false <- page.errors[:name].any? { |msg| msg =~ /blank/ }
135
+ ["is not a wiki name"]
136
+ <- page.errors[:name]
137
+ #<ActiveModel::Errors:... @messages={:name=>["is not a wiki name"]}>
138
+ <- page.errors
139
+ #<Page name: nil, content: "CONTENT", ...>
140
+ <- page
141
+ # ./spec/models/page_spec.rb:25:in `block in Then'
142
+
143
+ We get informative error messages, which is exactly what we want.
144
+
145
+ However, the spec itself is a little wordy, with repeating
146
+ Then/And/And. What if we wrote a simple query function that checked
147
+ for the three conditions and reported true/false accordingly.
148
+
149
+ ```ruby
150
+ def invalid?(page, field, pattern)
151
+ page.invalid? &&
152
+ ! page.errors[field].empty? &&
153
+ page.errors[field].any? { |msg| msg =~ pattern }
154
+ end
155
+ ```
156
+
157
+ Now we can use <code>invalid?</code> in all our validations
158
+ specifications:
159
+
160
+ ```ruby
161
+ context "with missing name" do
162
+ Given(:attrs) { VALID_ATTRS.merge(name: nil) }
163
+ Then { invalid?(page, :name, /blank/) }
164
+ end
165
+ ```
166
+
167
+ But there is a downside. Because <code>invalid?</code> only returns
168
+ true/false, and there are no mention of the <code>errors</code> object
169
+ in the Then clause, the failure message is really uninformative:
170
+
171
+ 1) Page validations with missing name
172
+ Failure/Error: Then { invalid_on(page, :name, /blank/) }
173
+ Then expression failed at ./spec/models/page_spec.rb:31
174
+ false <- invalid_on(page, :name, /blank/)
175
+ #<Page name: nil, content: "CONTENT", ...>
176
+ <- page
177
+ # ./spec/models/page_spec.rb:31:in `block in Then'
178
+
179
+ All we know is that the page is invalid. We get no indication of what
180
+ fields were actually in error and what the error messages actually
181
+ were.
182
+
183
+ ## Custom Failure Message
184
+
185
+ By abstracting away the details how to check for invalid models (which
186
+ is generally a good thing), RSpec/Given lost the ability to give us
187
+ the details of why it failed.
188
+
189
+ Fortunately, there is a simple fix. Instead of returning a simple
190
+ true/false value, the <code>invalid?</code> method should return an
191
+ object, that when inspected, tells why it failed.
192
+
193
+ If a _Then_ clause returns a value that supports a
194
+ <code>to_bool</code> method, then RSpec/Given will call that method
195
+ before checking for true/false (in rspec-given 3.3.0 or later). All we
196
+ need to do is arrange for that object to be returned.
197
+
198
+ ```ruby
199
+ def must_be_invalid(model, field, pattern=//)
200
+ MustBeInvalid.new(model, field, pattern)
201
+ end
202
+ ```
203
+
204
+ Since the method no longer returns a true/false value, I've changed
205
+ the name from <code>invalid?</code> to <code>must\_be\_invalid</code>.
206
+
207
+ The code for the <code>MustBeInvalid</code> class is a bit long, but
208
+ there is nothing complex in it. The <code>to_bool</code> method
209
+ carefully checks for each of our three conditions and records the
210
+ exact reason for failure in the @why instance variable. The
211
+ <code>inspect</code> method (called by RSpec/Given to display its
212
+ value) just returns the @why value with additional details about the
213
+ errors on the object.
214
+
215
+ ```ruby
216
+ class MustBeInvalid
217
+ def initialize(model, field, pattern)
218
+ @model = model
219
+ @field = field
220
+ @pattern = pattern
221
+ @why = nil
222
+ end
223
+
224
+ def to_bool
225
+ if @model.valid?
226
+ @why = "#{@model.class} was valid (expected invalid)"
227
+ false
228
+ elsif @model.errors[@field].empty?
229
+ @why = "#{@model.class} had no errors on field #{@field}" +
230
+ error_descriptions
231
+ false
232
+ elsif @model.errors[@field].none? { |msg| msg =~ @pattern }
233
+ @why = "#{@model.class} had no errors " +
234
+ "matching #{@pattern} on field #{@field}" +
235
+ error_descriptions
236
+ false
237
+ else
238
+ @why = "OK (expected invalid)"
239
+ true
240
+ end
241
+ end
242
+
243
+ def inspect
244
+ to_bool if @why.nil?
245
+ @why
246
+ end
247
+
248
+ private
249
+
250
+ def error_descriptions
251
+ if @model.errors.empty?
252
+ ""
253
+ else
254
+ "\n Errors were:\n * " +
255
+ @model.errors.full_messages.
256
+ map { |msg| msg }.join("\n * ")
257
+ end
258
+ end
259
+ end
260
+ ```
261
+
262
+ The failure message returned by <code>MustBeInvalid</code> is once
263
+ again clear and to the point. It contains all the information needed
264
+ for debugging.
265
+
266
+ 1) Page validations with missing name
267
+ Failure/Error: Then { must_be_invalid(page, :name, /blank/) }
268
+ Then expression failed at ./spec/models/page_spec.rb:31
269
+ Page had no errors matching (?-mix:blank) on field name
270
+ Errors were:
271
+ * Name is not a wiki name
272
+ <- must_be_invalid(page, :name, /blank/)
273
+ #<Page name: nil, content: "CONTENT", ...>
274
+ <- page
275
+ # ./spec/models/page_spec.rb:31:in `block in Then'
276
+
277
+ ## Summary
278
+
279
+ I've always felt that you can tell the maturity level of a piece of
280
+ software by the beauty of the error messages it produces. By
281
+ providing the ability to do custom messages where needed, RSpec/Given
282
+ takes a step in that direction.
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Failing Then clauses" do
4
+
5
+ # NOTE: FAIL and ERROR are special versions of the Then clause that
6
+ # expect failures and errors. These are used only in the framework
7
+ # testing and are not generally available.
8
+
9
+ context "with false" do
10
+ FAIL { false }
11
+ end
12
+
13
+ context "with exception comparison in when result" do
14
+ When(:result) { fail "explicitly" }
15
+ ERROR { result == 1 }
16
+ end
17
+
18
+ context "with bare exception in when result" do
19
+ When(:result) { fail "explicitly" }
20
+ ERROR { result }
21
+ end
22
+
23
+ end
@@ -0,0 +1,31 @@
1
+ require 'rspec/given'
2
+
3
+ # These extensions are used for framework testing, where failing a
4
+ # Then block is a passing condition.
5
+ module Given
6
+ module InstanceExtensions
7
+ NotMetError = RSpec::Expectations::ExpectationNotMetError
8
+
9
+ def _gvn_fail(&block)
10
+ expect { _gvn_then(&block) }.to raise_error(NotMetError)
11
+ end
12
+
13
+ def _gvn_error(&block)
14
+ expect { _gvn_then(&block) }.to raise_error(StandardError)
15
+ end
16
+ end
17
+
18
+ module ClassExtensions
19
+
20
+ # Fails spec if block passes.
21
+ def FAIL(&block)
22
+ Then(on_eval: "_gvn_fail", &block)
23
+ end
24
+
25
+ # Fails spec if block does not raise some kind of error.
26
+ def ERROR(&block)
27
+ Then(on_eval: "_gvn_error", &block)
28
+ end
29
+
30
+ end
31
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-given
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.0
4
+ version: 3.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jim Weirich
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-20 00:00:00.000000000 Z
11
+ date: 2013-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: given_core
@@ -16,26 +16,26 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 3.3.0
19
+ version: 3.4.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 3.3.0
26
+ version: 3.4.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '2.12'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.12'
41
41
  description: |
@@ -52,6 +52,29 @@ files:
52
52
  - README.md
53
53
  - Rakefile
54
54
  - TODO
55
+ - doc/article/custom_error_messages.md
56
+ - doc/main.rdoc
57
+ - examples/example_helper.rb
58
+ - examples/failing/natural_failing_spec.rb
59
+ - examples/failing/sample_spec.rb
60
+ - examples/integration/and_spec.rb
61
+ - examples/integration/failing/eval_subexpression_spec.rb
62
+ - examples/integration/failing/module_nesting_spec.rb
63
+ - examples/integration/failing/to_bool_returns_false.rb
64
+ - examples/integration/failing/undefined_method_spec.rb
65
+ - examples/integration/failing_messages_spec.rb
66
+ - examples/integration/focused_line_spec.rb
67
+ - examples/integration/given_spec.rb
68
+ - examples/integration/invariant_spec.rb
69
+ - examples/integration/then_spec.rb
70
+ - examples/loader.rb
71
+ - examples/minitest/assert_raises_spec.rb
72
+ - examples/minitest_helper.rb
73
+ - examples/other/line_example.rb
74
+ - examples/stack/stack.rb
75
+ - examples/stack/stack_spec.rb
76
+ - examples/stack/stack_spec1.rb
77
+ - examples/use_assertions.rb
55
78
  - lib/given.rb
56
79
  - lib/rspec-given.rb
57
80
  - lib/rspec/given.rb
@@ -65,6 +88,7 @@ files:
65
88
  - spec/lib/given/ext/numeric_spec.rb
66
89
  - spec/lib/given/ext/numeric_specifications.rb
67
90
  - spec/lib/given/extensions_spec.rb
91
+ - spec/lib/given/failing_thens_spec.rb
68
92
  - spec/lib/given/failure_matcher_spec.rb
69
93
  - spec/lib/given/failure_spec.rb
70
94
  - spec/lib/given/file_cache_spec.rb
@@ -77,57 +101,36 @@ files:
77
101
  - spec/lib/given/options_spec.rb
78
102
  - spec/spec_helper.rb
79
103
  - spec/support/be_booleany.rb
104
+ - spec/support/failure_and_errors.rb
80
105
  - spec/support/faux_then.rb
81
106
  - spec/support/natural_assertion_control.rb
82
- - examples/example_helper.rb
83
- - examples/failing/natural_failing_spec.rb
84
- - examples/failing/sample_spec.rb
85
- - examples/integration/and_spec.rb
86
- - examples/integration/failing/eval_subexpression_spec.rb
87
- - examples/integration/failing/module_nesting_spec.rb
88
- - examples/integration/failing/to_bool_returns_false.rb
89
- - examples/integration/failing/undefined_method_spec.rb
90
- - examples/integration/failing_messages_spec.rb
91
- - examples/integration/focused_line_spec.rb
92
- - examples/integration/given_spec.rb
93
- - examples/integration/invariant_spec.rb
94
- - examples/integration/then_spec.rb
95
- - examples/loader.rb
96
- - examples/minitest/assert_raises_spec.rb
97
- - examples/minitest_helper.rb
98
- - examples/other/line_example.rb
99
- - examples/stack/stack.rb
100
- - examples/stack/stack_spec.rb
101
- - examples/stack/stack_spec1.rb
102
- - examples/use_assertions.rb
103
- - doc/main.rdoc
104
107
  homepage: http://github.com/jimweirich/rspec-given
105
108
  licenses:
106
109
  - MIT
107
110
  metadata: {}
108
111
  post_install_message:
109
112
  rdoc_options:
110
- - --line-numbers
111
- - --inline-source
112
- - --main
113
+ - "--line-numbers"
114
+ - "--inline-source"
115
+ - "--main"
113
116
  - doc/main.rdoc
114
- - --title
117
+ - "--title"
115
118
  - RSpec Given Extensions
116
119
  require_paths:
117
120
  - lib
118
121
  required_ruby_version: !ruby/object:Gem::Requirement
119
122
  requirements:
120
- - - '>='
123
+ - - ">="
121
124
  - !ruby/object:Gem::Version
122
125
  version: 1.9.2
123
126
  required_rubygems_version: !ruby/object:Gem::Requirement
124
127
  requirements:
125
- - - '>='
128
+ - - ">="
126
129
  - !ruby/object:Gem::Version
127
130
  version: '0'
128
131
  requirements: []
129
132
  rubyforge_project: given
130
- rubygems_version: 2.1.11
133
+ rubygems_version: 2.2.0
131
134
  signing_key:
132
135
  specification_version: 4
133
136
  summary: Given/When/Then Specification Extensions for RSpec.