rspec-cramp 0.1.1 → 0.1.2
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.
- data/README.md +40 -7
- data/lib/rspec/cramp/matchers/respond_with.rb +2 -0
- data/lib/rspec/cramp/mock_response.rb +13 -4
- data/spec/examples/basic_spec.rb +32 -3
- data/spec/rspec_cramp_spec.rb +32 -10
- data/spec/spec_helper.rb +2 -2
- data/spec/tests.log +3621 -0
- metadata +40 -15
data/README.md
CHANGED
@@ -3,19 +3,22 @@ A set of rspec matchers and helpers that make it easier to write specs for [cram
|
|
3
3
|
Quick start
|
4
4
|
-----------
|
5
5
|
|
6
|
-
gem install rspec-cramp
|
6
|
+
> gem install rspec-cramp
|
7
7
|
|
8
8
|
|
9
9
|
|
10
10
|
require 'rspec/cramp'
|
11
11
|
|
12
|
+
# Decorate your spec with :cramp => true
|
12
13
|
describe HelloWorld, :cramp => true do
|
14
|
+
|
15
|
+
# You need to define this method
|
13
16
|
def app
|
14
|
-
HelloWorld
|
17
|
+
HelloWorld # Here goes your cramp application, action or http routes.
|
15
18
|
end
|
16
19
|
|
20
|
+
# Matching on status code.
|
17
21
|
it "should respond to a GET request" do
|
18
|
-
# Various ways to match a response code.
|
19
22
|
get("/").should respond_with :status => :ok # Matches responses from 200 to 299.
|
20
23
|
get("/").should respond_with :status => 200 # Matches only 200.
|
21
24
|
get("/").should respond_with :status => "200" # Same as above.
|
@@ -23,19 +26,45 @@ Quick start
|
|
23
26
|
get("/").should_not respond_with :status => :error # Matches any HTTP error.
|
24
27
|
end
|
25
28
|
|
29
|
+
# Matching on response body.
|
26
30
|
it "should respond with text starting with 'Hello'" do
|
27
31
|
get("/").should respond_with :body => /^Hello.*/
|
28
32
|
end
|
29
|
-
|
30
33
|
it "should respond with 'Hello, world!'" do
|
31
34
|
get("/").should respond_with :body => "Hello, world!"
|
32
35
|
end
|
33
|
-
|
36
|
+
|
37
|
+
# Matching on response headers.
|
34
38
|
it "should respond with html" do
|
35
39
|
get("/").should respond_with :headers => {"Content-Type" => "text/html"}
|
36
40
|
get("/").should_not respond_with :headers => {"Content-Type" => "text/plain"}
|
37
41
|
get("/").should_not respond_with :headers => {"Unexpected-Header" => /.*/}
|
38
42
|
end
|
43
|
+
|
44
|
+
# Matching using lambdas.
|
45
|
+
it "should match my sophisticated custom matchers" do
|
46
|
+
# Entire headers.
|
47
|
+
status_check = lambda {|status| status.between?(200, 299)}
|
48
|
+
body_check = lambda {|body| body =~ /.*el.*/}
|
49
|
+
headers_check = lambda {|headers| true} # Any headers will do.
|
50
|
+
get("/").should respond_with :status => status_check, :body => body_check, :headers => headers_check
|
51
|
+
# Header value.
|
52
|
+
get("/").should respond_with :headers => {"Content-Type" => lambda {|value| value == "text/html"}}
|
53
|
+
get("/").should_not respond_with :headers => {"Content-Type" => lambda {|value| value == "text/plain"}}
|
54
|
+
end
|
55
|
+
|
56
|
+
# Supports POST/GET/PUT/DELETE and you don't have to use the matcher.
|
57
|
+
it "should work without a matcher" do
|
58
|
+
get "/"
|
59
|
+
post "/"
|
60
|
+
put "/"
|
61
|
+
delete "/"
|
62
|
+
end
|
63
|
+
|
64
|
+
# Request params & custom headers.
|
65
|
+
it "should accept my params" do
|
66
|
+
post("/", :params => {:text => "whatever"}, :headers => {"Custom-Header" => "blah"})
|
67
|
+
end
|
39
68
|
end
|
40
69
|
|
41
70
|
The matcher is fairly flexible, supports regular expressions and also works with multipart responses (more than one `Cramp::Action.render`), SSE and so on. I'll create more examples and docs but for the time being, pls. take a look at the code and [examples](https://github.com/bilus/rspec-cramp/tree/master/spec/examples).
|
@@ -47,11 +76,15 @@ Project status
|
|
47
76
|
|
48
77
|
**IMPORTANT:** This is work in progress.
|
49
78
|
|
50
|
-
|
51
|
-
2. I extracted the code from one of my projects and rewrote the matchers from scratch test-first. Still, after the weekend I plan to actually use it to replace the 'legacy' matchers in my project; this will probably uncover some bugs and may make me add more functionality. *UPDATE: I'm working on it right now.*
|
79
|
+
There are still some things I'll take care of soon (esp. better failure messages).
|
52
80
|
|
53
81
|
If you have any comments regarding the code as it is now (I know it's a bit messy), please feel free to tweet [@MartinBilski](http://twitter.com/#!/MartinBilski)
|
54
82
|
|
83
|
+
Contributors
|
84
|
+
------------
|
85
|
+
|
86
|
+
[Ivan Fomichev](https://github.com/codeholic)
|
87
|
+
|
55
88
|
Notes
|
56
89
|
----
|
57
90
|
|
@@ -7,6 +7,8 @@ RSpec::Matchers.define :respond_with do |options = {}|
|
|
7
7
|
response.matching?(options)
|
8
8
|
end
|
9
9
|
|
10
|
+
# TODO Better message for cases such as: specify { get("/").should respond_with :status => :ok }.
|
11
|
+
|
10
12
|
failure_message_for_should do
|
11
13
|
@actual_response.last_failure_message_for_should
|
12
14
|
end
|
@@ -14,8 +14,7 @@ module RSpec
|
|
14
14
|
stopping = false
|
15
15
|
deferred_body = @body
|
16
16
|
chunks = []
|
17
|
-
|
18
|
-
chunks << chunk unless stopping
|
17
|
+
check = lambda do
|
19
18
|
if chunks.count >= max_chunks
|
20
19
|
@body = chunks
|
21
20
|
stopping = true
|
@@ -23,6 +22,11 @@ module RSpec
|
|
23
22
|
EM.next_tick { EM.stop }
|
24
23
|
end
|
25
24
|
end
|
25
|
+
check.call
|
26
|
+
deferred_body.each do |chunk|
|
27
|
+
chunks << chunk unless stopping
|
28
|
+
check.call
|
29
|
+
end
|
26
30
|
end
|
27
31
|
end
|
28
32
|
|
@@ -117,8 +121,13 @@ module RSpec
|
|
117
121
|
end
|
118
122
|
|
119
123
|
def matching_headers?(expected_header)
|
120
|
-
expected_header.nil?
|
121
|
-
|
124
|
+
if expected_header.nil?
|
125
|
+
true
|
126
|
+
elsif expected_header.is_a? Proc
|
127
|
+
matching_response_element?(:headers, @headers, expected_header)
|
128
|
+
else
|
129
|
+
matching_header_keys?(expected_header) && matching_header_values?(expected_header)
|
130
|
+
end
|
122
131
|
end
|
123
132
|
|
124
133
|
def matching_body?(expected_body)
|
data/spec/examples/basic_spec.rb
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), "../spec_helper")
|
2
2
|
require File.join(File.dirname(__FILE__), "sample_actions")
|
3
3
|
|
4
|
+
# Decorate your spec with :cramp => true
|
4
5
|
describe HelloWorld, :cramp => true do
|
6
|
+
|
7
|
+
# You need to define this method
|
5
8
|
def app
|
6
|
-
HelloWorld
|
9
|
+
HelloWorld # Here goes your cramp application, action or http routes.
|
7
10
|
end
|
8
11
|
|
12
|
+
# Matching on status code.
|
9
13
|
it "should respond to a GET request" do
|
10
|
-
# Variaus ways to match a response code.
|
11
14
|
get("/").should respond_with :status => :ok # Matches responses from 200 to 299.
|
12
15
|
get("/").should respond_with :status => 200 # Matches only 200.
|
13
16
|
get("/").should respond_with :status => "200" # Same as above.
|
@@ -15,17 +18,43 @@ describe HelloWorld, :cramp => true do
|
|
15
18
|
get("/").should_not respond_with :status => :error # Matches any HTTP error.
|
16
19
|
end
|
17
20
|
|
21
|
+
# Matching on response body.
|
18
22
|
it "should respond with text starting with 'Hello'" do
|
19
23
|
get("/").should respond_with :body => /^Hello.*/
|
20
24
|
end
|
21
|
-
|
22
25
|
it "should respond with 'Hello, world!'" do
|
23
26
|
get("/").should respond_with :body => "Hello, world!"
|
24
27
|
end
|
25
28
|
|
29
|
+
# Matching on response headers.
|
26
30
|
it "should respond with html" do
|
27
31
|
get("/").should respond_with :headers => {"Content-Type" => "text/html"}
|
28
32
|
get("/").should_not respond_with :headers => {"Content-Type" => "text/plain"}
|
29
33
|
get("/").should_not respond_with :headers => {"Unexpected-Header" => /.*/}
|
30
34
|
end
|
35
|
+
|
36
|
+
# Matching using lambdas.
|
37
|
+
it "should match my sophisticated custom matchers" do
|
38
|
+
# Entire headers.
|
39
|
+
status_check = lambda {|status| status.between?(200, 299)}
|
40
|
+
body_check = lambda {|body| body =~ /.*el.*/}
|
41
|
+
headers_check = lambda {|headers| true} # Any headers will do.
|
42
|
+
get("/").should respond_with :status => status_check, :body => body_check, :headers => headers_check
|
43
|
+
# Header value.
|
44
|
+
get("/").should respond_with :headers => {"Content-Type" => lambda {|value| value == "text/html"}}
|
45
|
+
get("/").should_not respond_with :headers => {"Content-Type" => lambda {|value| value == "text/plain"}}
|
46
|
+
end
|
47
|
+
|
48
|
+
# Supports POST/GET/PUT/DELETE and you don't have to use the matcher.
|
49
|
+
it "should work without a matcher" do
|
50
|
+
get "/"
|
51
|
+
post "/"
|
52
|
+
put "/"
|
53
|
+
delete "/"
|
54
|
+
end
|
55
|
+
|
56
|
+
# Request params & custom headers.
|
57
|
+
it "should accept my params" do
|
58
|
+
post("/", :params => {:text => "whatever"}, :headers => {"Custom-Header" => "blah"})
|
59
|
+
end
|
31
60
|
end
|
data/spec/rspec_cramp_spec.rb
CHANGED
@@ -91,6 +91,10 @@ module Cramp
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
+
class SseNoRenderAction < Cramp::Action
|
95
|
+
self.transport = :sse
|
96
|
+
end
|
97
|
+
|
94
98
|
class RequestHeaders < Cramp::Action
|
95
99
|
on_start :render_request_headers
|
96
100
|
def render_request_headers
|
@@ -127,10 +131,11 @@ module Cramp
|
|
127
131
|
add('/raise_on_start').to RaiseOnStart
|
128
132
|
add('/raise_on_finish').to RaiseOnFinish
|
129
133
|
add('/sse').to SseAction
|
130
|
-
add('/
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
+
add('/sse_no_render').to SseNoRenderAction
|
135
|
+
get('/get_only').to SuccessfulResponse
|
136
|
+
post('/post_only').to SuccessfulResponse
|
137
|
+
put('/put_only').to SuccessfulResponse
|
138
|
+
delete('/delete_only').to SuccessfulResponse
|
134
139
|
add('/request_headers').to RequestHeaders
|
135
140
|
add('/request_params').to RequestParams
|
136
141
|
end
|
@@ -160,7 +165,6 @@ module Cramp
|
|
160
165
|
end
|
161
166
|
end
|
162
167
|
|
163
|
-
# TODO Rewrite the repetitive code below using data-based spec generation.
|
164
168
|
describe "exact match on response status" do
|
165
169
|
it "should match successful response" do
|
166
170
|
send(method, "/200").should respond_with :status => 200
|
@@ -255,6 +259,21 @@ module Cramp
|
|
255
259
|
it "should not match iff the header isn't there" do
|
256
260
|
send(method, "/custom_header").should_not respond_with :headers => {/Non\-Existent\-One/i => /^QWERTY$/}
|
257
261
|
end
|
262
|
+
end
|
263
|
+
|
264
|
+
describe "lambda match on entire header " do
|
265
|
+
it "should match when true" do
|
266
|
+
match_headers = lambda do |headers|
|
267
|
+
headers.find {|(k, v)| k == "Extra-Header" && v == "ABCD"}
|
268
|
+
end
|
269
|
+
send(method, "/custom_header").should respond_with :headers => match_headers
|
270
|
+
end
|
271
|
+
it "should not match when false" do
|
272
|
+
match_headers = lambda do |headers|
|
273
|
+
headers.find {|(k, v)| k == "Non-Existent-One" && v == "QWERTY"}
|
274
|
+
end
|
275
|
+
send(method, "/custom_header").should_not respond_with :headers => match_headers
|
276
|
+
end
|
258
277
|
end
|
259
278
|
|
260
279
|
# FIXME How to handle a situation where nothing is rendered? get reads the body...
|
@@ -345,6 +364,11 @@ module Cramp
|
|
345
364
|
send(method, "/sse", :max_chunks => 2).should respond_with :chunks => [/^data: Hello 1.*/, /^data: Hello 2.*/]
|
346
365
|
send(method, "/sse", :max_chunks => 2).should_not respond_with :chunks => [/.*Incorrect 1.*/, /.*Incorrect 2.*/]
|
347
366
|
end
|
367
|
+
|
368
|
+
it "should not wait for body if it is skipped explicitly" do
|
369
|
+
lambda { send(method, "/sse_no_render", :max_chunks => 0) }.should_not raise_error Timeout::Error
|
370
|
+
send(method, "/sse_no_render", :max_chunks => 0).should respond_with :status => 200, :body => ""
|
371
|
+
end
|
348
372
|
end
|
349
373
|
|
350
374
|
it "should correctly handle exception in the callbacks" do
|
@@ -385,7 +409,6 @@ module Cramp
|
|
385
409
|
end
|
386
410
|
end
|
387
411
|
|
388
|
-
# TODO Add method-specific paths to http routes and write specs.
|
389
412
|
describe "GET request" do
|
390
413
|
it_should_behave_like "async_request", :get
|
391
414
|
|
@@ -437,9 +460,8 @@ module Cramp
|
|
437
460
|
routes
|
438
461
|
end
|
439
462
|
|
440
|
-
#
|
441
|
-
|
442
|
-
# Anyway, we need more tests here.
|
463
|
+
# Note: Only basic specs here because respond_with matcher uses the same code and is extensively tested.
|
464
|
+
|
443
465
|
it "should support expectations on response status" do
|
444
466
|
get("/200") do |response|
|
445
467
|
response.should be_matching :status => 200
|
@@ -488,4 +510,4 @@ module Cramp
|
|
488
510
|
end
|
489
511
|
end
|
490
512
|
end
|
491
|
-
end
|
513
|
+
end
|
data/spec/spec_helper.rb
CHANGED