Skip to content

Commit cdeea8b

Browse files
committed
Rework the HttpTestClient to use a Capybara server and the same StubApp as RackTestClient
1 parent 4e25428 commit cdeea8b

File tree

6 files changed

+86
-109
lines changed

6 files changed

+86
-109
lines changed

Gemfile.lock

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ GEM
4141
gherkin (~> 2.12)
4242
multi_json (>= 1.7.5, < 2.0)
4343
multi_test (>= 0.1.1)
44+
daemons (1.1.9)
4445
diff-lcs (1.2.5)
46+
eventmachine (1.0.3)
4547
fakefs (0.6.0)
4648
faraday (0.9.0)
4749
multipart-post (>= 1.2, < 3)
@@ -106,6 +108,10 @@ GEM
106108
sparkr (0.4.1)
107109
term-ansicolor (1.3.0)
108110
tins (~> 1.0)
111+
thin (1.6.2)
112+
daemons (>= 1.0.9)
113+
eventmachine (>= 1.0.0)
114+
rack (>= 1.0.0)
109115
thread_safe (0.3.4)
110116
tilt (1.4.1)
111117
tins (1.3.3)
@@ -132,4 +138,5 @@ DEPENDENCIES
132138
rspec-its (~> 1.0)
133139
rspec_api_documentation!
134140
sinatra (~> 1.4.4)
141+
thin
135142
webmock (~> 1.7)

lib/rspec_api_documentation/http_test_client.rb

Lines changed: 31 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,29 @@
11
require 'faraday'
22

3-
class RequestSaver < Faraday::Middleware
4-
def self.last_request
5-
@@last_request
6-
end
7-
8-
def self.last_request=(request_env)
9-
@@last_request = request_env
10-
end
3+
Faraday::Request.register_middleware :request_saver => lambda { RspecApiDocumentation::RequestSaver }
114

12-
def self.last_response
13-
@@last_response
14-
end
5+
module RspecApiDocumentation
6+
class RequestSaver < Faraday::Middleware
7+
attr_reader :client
158

16-
def self.last_response=(response_env)
17-
@@last_response = response_env
18-
end
9+
def initialize(app, client)
10+
super(app)
11+
@client = client
12+
end
1913

20-
def call(env)
21-
RequestSaver.last_request = env
14+
def call(env)
15+
client.last_request = env
2216

23-
@app.call(env).on_complete do |env|
24-
RequestSaver.last_response = env
17+
@app.call(env).on_complete do |env|
18+
client.last_response = env
19+
end
2520
end
2621
end
27-
end
28-
29-
Faraday::Request.register_middleware :request_saver => lambda { RequestSaver }
3022

31-
module RspecApiDocumentation
3223
class HttpTestClient < ClientBase
24+
attr_reader :last_response, :last_request
25+
26+
LastRequest = Struct.new(:url, :method, :request_headers, :body)
3327

3428
def request_headers
3529
env_to_headers(last_request.request_headers)
@@ -63,6 +57,14 @@ def do_request(method, path, params, request_headers)
6357
http_test_session.send(method, path, params, headers(method, path, params, request_headers))
6458
end
6559

60+
def last_request=(env)
61+
@last_request = LastRequest.new(env.url, env.method, env.request_headers, env.body)
62+
end
63+
64+
def last_response=(env)
65+
@last_response = env
66+
end
67+
6668
protected
6769

6870
def query_hash(query_string)
@@ -79,21 +81,21 @@ def handle_multipart_body(request_headers, request_body)
7981
"rack.input" => StringIO.new(request_body)
8082
}).params
8183

82-
clean_out_uploaded_data(parsed_parameters,request_body)
84+
clean_out_uploaded_data(parsed_parameters, request_body)
8385
end
8486

8587
def document_example(method, path)
8688
return unless metadata[:document]
8789

8890
req_method = last_request.method
8991
if req_method == :post || req_method == :put
90-
request_body =last_request.body
92+
request_body = last_request.body
9193
else
9294
request_body = ""
9395
end
96+
request_body = "" unless request_body # could be nil if nothing is sent
9497

9598
request_metadata = {}
96-
request_body = "" if request_body == "null" || request_body == "\"\""
9799

98100
if request_content_type =~ /multipart\/form-data/ && respond_to?(:handle_multipart_body, true)
99101
request_body = handle_multipart_body(request_headers, request_body)
@@ -118,7 +120,7 @@ def document_example(method, path)
118120

119121
private
120122

121-
def clean_out_uploaded_data(params,request_body)
123+
def clean_out_uploaded_data(params, request_body)
122124
params.each do |_, value|
123125
if value.is_a?(Hash)
124126
if value.has_key?(:tempfile)
@@ -135,19 +137,10 @@ def clean_out_uploaded_data(params,request_body)
135137

136138
def http_test_session
137139
::Faraday.new(:url => options[:host]) do |faraday|
138-
faraday.request :request_saver # save the request and response
139-
faraday.request :url_encoded # form-encode POST params
140-
faraday.response :logger # log requests to STDOUT
141-
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
140+
faraday.request :url_encoded # form-encode POST params
141+
faraday.request :request_saver, self # save the request and response
142+
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
142143
end
143144
end
144-
145-
def last_request
146-
RequestSaver.last_request
147-
end
148-
149-
def last_response
150-
RequestSaver.last_response
151-
end
152145
end
153146
end

rspec_api_documentation.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Gem::Specification.new do |s|
2929
s.add_development_dependency "rack-oauth2", "~> 1.0.7"
3030
s.add_development_dependency "webmock", "~> 1.7"
3131
s.add_development_dependency "rspec-its", "~> 1.0"
32+
s.add_development_dependency "thin"
3233

3334
s.files = Dir.glob("lib/**/*") + Dir.glob("templates/**/*")
3435
s.require_path = "lib"

spec/http_test_client_spec.rb

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,52 @@
11
require 'spec_helper'
22
require 'rack/test'
3+
require 'capybara'
4+
require 'capybara/server'
5+
require 'sinatra/base'
6+
require 'webmock'
7+
require 'support/stub_app'
38

49
describe RspecApiDocumentation::HttpTestClient do
510
before(:all) do
6-
WebMock.allow_net_connect!
11+
WebMock.allow_net_connect!
712

8-
$external_test_app_pid = spawn("ruby ./spec/support/external_test_app.rb")
9-
Process.detach $external_test_app_pid
10-
sleep 3 #Wait until the test app is up
13+
Capybara.server do |app, port|
14+
require 'rack/handler/thin'
15+
Thin::Logging.silent = true
16+
Rack::Handler::Thin.run(app, :Port => port)
17+
end
18+
19+
server = Capybara::Server.new(StubApp.new, 8888)
20+
server.boot
1121
end
1222

1323
after(:all) do
1424
WebMock.disable_net_connect!
15-
16-
Process.kill('TERM', $external_test_app_pid)
1725
end
1826

19-
let(:client_context) { double(example: example, app_root: 'nowhere') }
20-
let(:target_host) { 'http://localhost:4567' }
27+
let(:client_context) { |example| double(example: example, app_root: 'nowhere') }
28+
let(:target_host) { 'http://localhost:8888' }
2129
let(:test_client) { RspecApiDocumentation::HttpTestClient.new(client_context, {host: target_host}) }
2230

2331
subject { test_client }
2432

2533
it { should be_a(RspecApiDocumentation::HttpTestClient) }
2634

2735
its(:context) { should equal(client_context) }
28-
its(:example) { should equal(example) }
29-
its(:metadata) { should equal(example.metadata) }
36+
its(:example) { |example| should equal(example) }
37+
its(:metadata) { |example| should equal(example.metadata) }
3038

3139
describe "xml data", :document => true do
3240
before do
3341
test_client.get "/xml"
3442
end
3543

3644
it "should handle xml data" do
37-
test_client.response_headers["Content-Type"].should =~ /application\/xml/
45+
expect(test_client.response_headers["Content-Type"]).to match(/application\/xml/)
3846
end
3947

40-
it "should log the request" do
41-
example.metadata[:requests].first[:response_body].should be_present
48+
it "should log the request" do |example|
49+
expect(example.metadata[:requests].first[:response_body]).to be_present
4250
end
4351
end
4452

@@ -48,7 +56,7 @@
4856
end
4957

5058
it 'should contain the query_string' do
51-
test_client.query_string.should == "query_string=true"
59+
expect(test_client.query_string).to eq("query_string=true")
5260
end
5361
end
5462

@@ -58,7 +66,7 @@
5866
end
5967

6068
it "should contain all the headers" do
61-
test_client.request_headers.should eq({
69+
expect(test_client.request_headers).to eq({
6270
"Accept" => "application/json",
6371
"Content-Type" => "application/json"
6472
})
@@ -71,9 +79,9 @@
7179
end
7280

7381
context "when examples should be documented", :document => true do
74-
it "should still argument the metadata" do
82+
it "should still argument the metadata" do |example|
7583
metadata = example.metadata[:requests].first
76-
metadata[:request_query_parameters].should == {'query' => "", 'other' => 'exists'}
84+
expect(metadata[:request_query_parameters]).to eq({'query' => "", 'other' => 'exists'})
7785
end
7886
end
7987
end
@@ -87,38 +95,39 @@
8795
let(:headers) { { "Content-Type" => "application/json;charset=utf-8", "X-Custom-Header" => "custom header value" } }
8896

8997
context "when examples should be documented", :document => true do
90-
it "should augment the metadata with information about the request" do
98+
it "should augment the metadata with information about the request" do |example|
9199
metadata = example.metadata[:requests].first
92-
metadata[:request_method].should eq("POST")
93-
metadata[:request_path].should eq("/greet?query=test+query")
94-
metadata[:request_body].should be_present
95-
metadata[:request_headers].should include({'CONTENT_TYPE' => 'application/json;charset=utf-8'})
96-
metadata[:request_headers].should include({'HTTP_X_CUSTOM_HEADER' => 'custom header value'})
97-
metadata[:request_query_parameters].should == {"query" => "test query"}
98-
metadata[:request_content_type].should match(/application\/json/)
99-
metadata[:response_status].should eq(200)
100-
metadata[:response_body].should be_present
101-
metadata[:response_headers]['Content-Type'].should match(/application\/json/)
102-
metadata[:response_headers]['Content-Length'].should == '18'
103-
metadata[:response_content_type].should match(/application\/json/)
104-
metadata[:curl].should eq(RspecApiDocumentation::Curl.new("POST", "/greet?query=test+query", post_data, {"Content-Type" => "application/json;charset=utf-8", "X-Custom-Header" => "custom header value"}))
100+
expect(metadata[:request_method]).to eq("POST")
101+
expect(metadata[:request_path]).to eq("/greet?query=test+query")
102+
expect(metadata[:request_body]).to be_present
103+
expect(metadata[:request_headers]).to include({'CONTENT_TYPE' => 'application/json;charset=utf-8'})
104+
expect(metadata[:request_headers]).to include({'HTTP_X_CUSTOM_HEADER' => 'custom header value'})
105+
expect(metadata[:request_query_parameters]).to eq({"query" => "test query"})
106+
expect(metadata[:request_content_type]).to match(/application\/json/)
107+
expect(metadata[:response_status]).to eq(200)
108+
expect(metadata[:response_body]).to be_present
109+
expect(metadata[:response_headers]['Content-Type']).to match(/application\/json/)
110+
expect(metadata[:response_headers]['Content-Length']).to eq('17')
111+
expect(metadata[:response_content_type]).to match(/application\/json/)
112+
expect(metadata[:curl]).to eq(RspecApiDocumentation::Curl.new("POST", "/greet?query=test+query", post_data, {"Content-Type" => "application/json;charset=utf-8", "X-Custom-Header" => "custom header value"}))
105113
end
106114

107115
context "when post data is not json" do
108116
let(:post_data) { { :target => "nurse", :email => "[email protected]" } }
117+
let(:headers) { { "X-Custom-Header" => "custom header value" } }
109118

110-
it "should not nil out request_body" do
119+
it "should not nil out request_body" do |example|
111120
body = example.metadata[:requests].first[:request_body]
112-
body.should =~ /target=nurse/
113-
body.should =~ /email=email%40example\.com/
121+
expect(body).to match(/target=nurse/)
122+
expect(body).to match(/email=email%40example\.com/)
114123
end
115124
end
116125

117126
context "when post data is nil" do
118127
let(:post_data) { }
119128

120-
it "should nil out request_body" do
121-
example.metadata[:requests].first[:request_body].should be_nil
129+
it "should nil out request_body" do |example|
130+
expect(example.metadata[:requests].first[:request_body]).to be_nil
122131
end
123132
end
124133
end

spec/rack_test_client_spec.rb

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,7 @@
11
require 'spec_helper'
22
require 'rack/test'
33
require 'sinatra/base'
4-
5-
class StubApp < Sinatra::Base
6-
get "/" do
7-
content_type :json
8-
9-
{ :hello => "world" }.to_json
10-
end
11-
12-
post "/greet" do
13-
content_type :json
14-
15-
request.body.rewind
16-
begin
17-
data = JSON.parse request.body.read
18-
rescue JSON::ParserError
19-
request.body.rewind
20-
data = request.body.read
21-
end
22-
{ :hello => data["target"] }.to_json
23-
end
24-
25-
get "/xml" do
26-
content_type :xml
27-
28-
"<hello>World</hello>"
29-
end
30-
end
4+
require 'support/stub_app'
315

326
describe RspecApiDocumentation::RackTestClient do
337
let(:context) { |example| double(:app => StubApp, :example => example) }

spec/support/external_test_app.rb renamed to spec/support/stub_app.rb

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
require 'sinatra/base'
2-
require 'json'
3-
41
class StubApp < Sinatra::Base
5-
set :logging, false
6-
72
get "/" do
83
content_type :json
94

@@ -20,7 +15,7 @@ class StubApp < Sinatra::Base
2015
request.body.rewind
2116
data = request.body.read
2217
end
23-
data.to_json
18+
{ :hello => data["target"] }.to_json
2419
end
2520

2621
get "/xml" do
@@ -29,5 +24,3 @@ class StubApp < Sinatra::Base
2924
"<hello>World</hello>"
3025
end
3126
end
32-
33-
StubApp.run!

0 commit comments

Comments
 (0)