capybara-httpx 1.0.0.preview1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 46bee3c9c3076e589388e150cfd02f6f45d8ff11065b2072590e39f702bff1ba
4
+ data.tar.gz: 8d7855cd4fa44d789f58738a3b25acf934879538f1efacdda84b830fc6b11782
5
+ SHA512:
6
+ metadata.gz: a6f652a7fa29d6e6f5e181e0adc628ebd4702ad3954cd406bd28b380fd1ea982ca56bbf1fcb6061c5ac8895f375d9078ffc2f1e325514402d1ca2f01b3b92aee
7
+ data.tar.gz: 7ffa6525764f05bb4a9e570e9d3104840c213b2d2c5b2125c130a8c5c71302b3e89701c3f365f05003a58e81ce7f7752961d4219a1cf1d0d907be090ceedf3a1
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Tron Jonathan and HALTER Joseph
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ Capybara-HTTPX
2
+ ==============
3
+
4
+ [![Build Status](https://github.com/TalentBox/capybara-httpx/actions/workflows/ci.yml/badge.svg)](https://github.com/TalentBox/capybara-httpx/actions)
5
+
6
+ A [Capybara](https://github.com/teamcapybara/capybara) driver that uses
7
+ [HTTPX](https://github.com/HoneyryderChuck/httpx) to make HTTP requests to a
8
+ Rack application, including applications running on a remote host. This project
9
+ is based on [TalentBox/capybara-typhoeus](https://github.com/TalentBox/capybara-typhoeus),
10
+ with HTTPX replacing Typhoeus as its HTTP client.
11
+
12
+ This driver is intended for testing APIs. It does not implement browser features
13
+ such as JavaScript, clicking controls, or submitting forms through the DOM.
14
+
15
+ ## Installation
16
+
17
+ ```sh
18
+ gem install capybara-httpx
19
+ ```
20
+
21
+ Or add `capybara-httpx` to your Gemfile. HTTPX is installed as a runtime
22
+ dependency.
23
+
24
+ ## Usage
25
+
26
+ ```ruby
27
+ require "capybara/httpx"
28
+
29
+ session = Capybara::Session.new(:httpx, app)
30
+ session.get "/users"
31
+ ```
32
+
33
+ For remote testing, configure the host as usual:
34
+
35
+ ```ruby
36
+ Capybara.app_host = "https://api.example.com"
37
+ ```
38
+
39
+ The driver can also be selected in Cucumber using the `@httpx` tag. Require
40
+ `capybara/httpx/cucumber` from `env.rb`:
41
+
42
+ ```ruby
43
+ require "capybara/httpx/cucumber"
44
+ ```
45
+
46
+ ```gherkin
47
+ @httpx
48
+ Scenario: request API data
49
+ When I send a GET request to /users
50
+ ```
51
+
52
+ The driver provides `authenticate_with`, `request_body`, and `as=` helpers on
53
+ its session. Request options set through `driver.with_options` are passed to
54
+ HTTPX. The default request timeout is three seconds and can be customized when
55
+ registering a driver:
56
+
57
+ ```ruby
58
+ Capybara.register_driver :httpx_with_custom_timeout do |app|
59
+ Capybara::HTTPX::Driver.new(app, timeout: 1)
60
+ end
61
+ ```
62
+
63
+ Array query parameters use HTTPX-style bracket notation by default. The
64
+ `params_encoding` driver setting can also be set to `:rack`, `:multi`, or
65
+ `:none`.
66
+
67
+ ## Running tests
68
+
69
+ ```sh
70
+ bundle install
71
+ bundle exec rake
72
+ ```
73
+
74
+ CI runs the test suite on currently supported Ruby release series: 3.4, 4.0,
75
+ and 4.1.
76
+
77
+ ## License
78
+
79
+ Copyright (c) 2010 Tron Jonathan and HALTER Joseph. See [LICENSE](LICENSE) for
80
+ details.
@@ -0,0 +1,250 @@
1
+ require "base64"
2
+ require "json"
3
+ require "uri"
4
+
5
+ class Capybara::HTTPX::Browser < Capybara::RackTest::Browser
6
+ LastRequest = Struct.new(:method, :url, :params, :headers) do
7
+ def path
8
+ URI.parse(url).path
9
+ end
10
+
11
+ def fullpath
12
+ URI.parse(url).request_uri
13
+ end
14
+
15
+ def request_method
16
+ method.to_s.upcase
17
+ end
18
+
19
+ def env
20
+ headers
21
+ end
22
+ end
23
+
24
+ class ResponseAdapter
25
+ attr_reader :response
26
+
27
+ def initialize(response)
28
+ @response = response
29
+ end
30
+
31
+ def status
32
+ response.status
33
+ end
34
+
35
+ def headers
36
+ response.headers
37
+ end
38
+
39
+ def body
40
+ response.body
41
+ end
42
+
43
+ def uri
44
+ response.uri
45
+ end
46
+
47
+ def [](key)
48
+ headers[key]
49
+ end
50
+
51
+ def redirect?
52
+ [301, 302, 303, 307, 308].include?(status)
53
+ end
54
+ end
55
+
56
+ class TimeoutResponse
57
+ attr_reader :uri, :status, :headers, :body
58
+
59
+ def initialize(uri)
60
+ @uri = URI.parse(uri)
61
+ @status = 0
62
+ @headers = {}
63
+ @body = ""
64
+ end
65
+
66
+ def [](key)
67
+ headers[key]
68
+ end
69
+
70
+ def redirect?
71
+ false
72
+ end
73
+ end
74
+
75
+ attr_accessor :request_body
76
+ attr_reader :last_request, :last_response
77
+
78
+ def reset_cache!
79
+ @xml = nil
80
+ @json = nil
81
+ super
82
+ end
83
+
84
+ def refresh
85
+ reset_cache!
86
+ send(last_request.method, last_request.url, last_request.params, last_request.headers)
87
+ end
88
+
89
+ def current_url
90
+ return "" unless last_response
91
+
92
+ uri = build_uri(last_response.uri.to_s)
93
+ uri.fragment = @current_fragment if @current_fragment
94
+ uri.to_s
95
+ end
96
+
97
+ def dom
98
+ @dom ||= begin
99
+ content_type = if last_response
100
+ last_response.headers["Content-Type"].to_s[/\A[^;]+/] || ""
101
+ else
102
+ ""
103
+ end
104
+ content_type.include?("/xml") ? xml : Capybara::HTML(html)
105
+ end
106
+ end
107
+
108
+ def html
109
+ last_response ? last_response.body.to_s : ""
110
+ end
111
+
112
+ def xml
113
+ @xml ||= Nokogiri::XML(html)
114
+ end
115
+
116
+ def json
117
+ @json ||= JSON.parse(html)
118
+ end
119
+
120
+ def timed_out?
121
+ @timed_out || false
122
+ end
123
+
124
+ %i[get post put delete head patch request].each do |method|
125
+ define_method(method) do |url, params = {}, headers = {}, &block|
126
+ @last_request = LastRequest.new(method, url, params.dup, headers.dup)
127
+ uri = URI.parse(url)
128
+ request_headers = driver.with_headers.merge(
129
+ { "Content-Type" => driver.as, "Accept" => driver.as }.merge(headers)
130
+ )
131
+ referer = request_headers.delete("HTTP_REFERER")
132
+ request_headers["Referer"] = referer if referer
133
+ request_headers["Cookie"] ||= cookie_jar.for(uri)
134
+
135
+ if driver.auth?
136
+ credentials = Base64.strict_encode64("#{driver.login}:#{driver.password}")
137
+ request_headers["Authorization"] ||= "Basic #{credentials}"
138
+ end
139
+
140
+ request_params = driver.with_params.merge(params)
141
+ request_params.delete(:params_encoding)
142
+ encoded_params = encode_params(request_params, params[:params_encoding] || driver.params_encoding)
143
+ unless encoded_params.empty?
144
+ uri.query = [uri.query, encoded_params].compact.reject(&:empty?).join("&")
145
+ end
146
+
147
+ options = {
148
+ timeout: { request_timeout: driver.options[:timeout] },
149
+ max_redirects: driver.follow_redirects? ? driver.redirect_limit : 0
150
+ }.merge(driver.with_options)
151
+ if options[:timeout].is_a?(Numeric)
152
+ options[:timeout] = { request_timeout: options[:timeout] }
153
+ end
154
+
155
+ http = ::HTTPX.plugin(:follow_redirects).with(options)
156
+ @timed_out = false
157
+ response = http.request(method.to_s.upcase, uri.to_s, headers: request_headers, body: request_body)
158
+ @request_body = nil
159
+ if response.is_a?(::HTTPX::ErrorResponse)
160
+ raise response.error unless response.error.is_a?(::HTTPX::TimeoutError)
161
+
162
+ @timed_out = true
163
+ @last_response = TimeoutResponse.new(uri.to_s)
164
+ else
165
+ cookie_jar.merge(response.headers["set-cookie"], uri)
166
+ @last_response = ResponseAdapter.new(response)
167
+ end
168
+ rescue ::HTTPX::TimeoutError
169
+ @timed_out = true
170
+ @request_body = nil
171
+ @last_response = TimeoutResponse.new(uri.to_s)
172
+ end
173
+ end
174
+
175
+ private
176
+
177
+ def encode_params(params, encoding)
178
+ pairs = case encoding
179
+ when :httpx
180
+ flatten_httpx_params(params)
181
+ when :rack
182
+ flatten_rack_params(params)
183
+ when :multi
184
+ flatten_multi_params(params)
185
+ when :none
186
+ params.map { |key, value| [key.to_s, value.to_s] }
187
+ end
188
+ URI.encode_www_form(pairs)
189
+ end
190
+
191
+ def flatten_httpx_params(params, prefix = nil, pairs = [])
192
+ params.each do |key, value|
193
+ name = prefix ? "#{prefix}[#{key}]" : key.to_s
194
+ case value
195
+ when Hash
196
+ flatten_httpx_params(value, name, pairs)
197
+ when Array
198
+ value.each { |entry| flatten_httpx_array(name, entry, pairs) }
199
+ else
200
+ pairs << [name, value]
201
+ end
202
+ end
203
+ pairs
204
+ end
205
+
206
+ def flatten_httpx_array(name, value, pairs)
207
+ case value
208
+ when Hash
209
+ value.each { |key, entry| flatten_httpx_array("#{name}[#{key}]", entry, pairs) }
210
+ when Array
211
+ value.each { |entry| flatten_httpx_array("#{name}[]", entry, pairs) }
212
+ else
213
+ pairs << ["#{name}[]", value]
214
+ end
215
+ end
216
+
217
+ def flatten_rack_params(params, prefix = nil, pairs = [])
218
+ params.each do |key, value|
219
+ name = prefix ? "#{prefix}[#{key}]" : key.to_s
220
+ case value
221
+ when Hash
222
+ flatten_rack_params(value, name, pairs)
223
+ when Array
224
+ value.each { |entry| pairs << ["#{name}[]", entry] }
225
+ else
226
+ pairs << [name, value]
227
+ end
228
+ end
229
+ pairs
230
+ end
231
+
232
+ def flatten_multi_params(params, prefix = nil, pairs = [])
233
+ params.each do |key, value|
234
+ name = prefix ? "#{prefix}[#{key}]" : key.to_s
235
+ case value
236
+ when Hash
237
+ flatten_multi_params(value, name, pairs)
238
+ when Array
239
+ value.each { |entry| pairs << [name, entry] }
240
+ else
241
+ pairs << [name, value]
242
+ end
243
+ end
244
+ pairs
245
+ end
246
+
247
+ def cookie_jar
248
+ @cookie_jar ||= Rack::Test::CookieJar.new [], current_host
249
+ end
250
+ end
@@ -0,0 +1,6 @@
1
+ require "capybara/httpx"
2
+
3
+ Before "@httpx" do
4
+ Capybara.current_driver = :httpx
5
+ page.driver.reset_with!
6
+ end
@@ -0,0 +1,102 @@
1
+ class Capybara::HTTPX::Driver < Capybara::RackTest::Driver
2
+ attr_writer :as, :with_headers, :with_params, :with_options
3
+ attr_reader :login, :password, :params_encoding
4
+
5
+ def initialize(app, **options)
6
+ raise ArgumentError, "httpx requires a rack application, but none was given" unless app
7
+
8
+ super app, **{ timeout: 3 }.merge(options)
9
+ @params_encoding = :httpx
10
+ end
11
+
12
+ def browser
13
+ @browser ||= Capybara::HTTPX::Browser.new self
14
+ end
15
+
16
+ def needs_server?
17
+ true
18
+ end
19
+
20
+ PARAMS_ENCODING_ALLOWED_VALUES = %i[httpx rack multi none].freeze
21
+
22
+ def params_encoding=(value)
23
+ if PARAMS_ENCODING_ALLOWED_VALUES.include?(value)
24
+ @params_encoding = value
25
+ else
26
+ allowed = PARAMS_ENCODING_ALLOWED_VALUES.map(&:inspect).join(", ")
27
+ raise ArgumentError, "Allowed values are: #{allowed}"
28
+ end
29
+ end
30
+
31
+ %i[get post put delete head patch request].each do |method|
32
+ define_method(method) do |url, params = {}, headers = {}, &block|
33
+ browser.reset_host!
34
+ browser.process method, url, params, headers, &block
35
+ end
36
+ end
37
+
38
+ def reset!
39
+ @login = nil
40
+ @password = nil
41
+ super
42
+ end
43
+
44
+ def timed_out?
45
+ browser.timed_out?
46
+ end
47
+
48
+ def reset_with!
49
+ @with_headers = {}
50
+ @with_params = {}
51
+ @with_options = {}
52
+ @as = nil
53
+ end
54
+
55
+ def as
56
+ @as ||= "application/json"
57
+ end
58
+
59
+ def with_headers
60
+ @with_headers ||= {}
61
+ end
62
+
63
+ def with_params
64
+ @with_params ||= {}
65
+ end
66
+
67
+ def with_options
68
+ @with_options ||= {}
69
+ end
70
+
71
+ def authenticate_with(login, password)
72
+ @login, @password = login, password
73
+ end
74
+
75
+ def auth?
76
+ login && password
77
+ end
78
+
79
+ def status_code
80
+ response.status
81
+ end
82
+
83
+ def body
84
+ browser.html
85
+ end
86
+
87
+ def xml
88
+ browser.xml
89
+ end
90
+
91
+ def json
92
+ browser.json
93
+ end
94
+
95
+ def request_body
96
+ browser.request_body
97
+ end
98
+
99
+ def request_body=(value)
100
+ browser.request_body = value
101
+ end
102
+ end
@@ -0,0 +1,50 @@
1
+ class Capybara::HTTPX::Session < Capybara::Session
2
+ %i[get post put delete head patch request].each do |method|
3
+ define_method(method) do |url, params = {}, headers = {}, &block|
4
+ @touched = true
5
+ driver.public_send(method, host_url(url), params, headers, &block)
6
+ end
7
+ end
8
+
9
+ def authenticate_with(login, password)
10
+ driver.authenticate_with login, password
11
+ end
12
+
13
+ def timed_out?
14
+ driver.timed_out?
15
+ end
16
+
17
+ def host_url(url)
18
+ if url !~ /^http/ && Capybara.app_host
19
+ url = Capybara.app_host + url.to_s
20
+ end
21
+
22
+ if @server
23
+ url = "http://#{@server.host}:#{@server.port}" + url.to_s unless url =~ /^http/
24
+
25
+ if Capybara.always_include_port
26
+ uri = URI.parse(url)
27
+ uri.port = @server.port if uri.port == uri.default_port
28
+ url = uri.to_s
29
+ end
30
+ end
31
+
32
+ url
33
+ end
34
+
35
+ def timeout
36
+ driver.options[:timeout]
37
+ end
38
+
39
+ def request_body
40
+ driver.request_body
41
+ end
42
+
43
+ def request_body=(value)
44
+ driver.request_body = value
45
+ end
46
+
47
+ def as=(value)
48
+ driver.as = value
49
+ end
50
+ end
@@ -0,0 +1,24 @@
1
+ require "capybara"
2
+ require "httpx"
3
+
4
+ module Capybara
5
+ module HTTPX
6
+ autoload :Driver, "capybara/httpx/driver"
7
+ autoload :Browser, "capybara/httpx/browser"
8
+ autoload :Session, "capybara/httpx/session"
9
+ end
10
+
11
+ def self.session_pool
12
+ @session_pool ||= Hash.new do |hash, name|
13
+ hash[name] = if current_driver==:httpx
14
+ ::Capybara::HTTPX::Session.new(current_driver, app)
15
+ else
16
+ ::Capybara::Session.new(current_driver, app)
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ Capybara.register_driver :httpx do |app|
23
+ Capybara::HTTPX::Driver.new app
24
+ end
@@ -0,0 +1,237 @@
1
+ require "spec_helper"
2
+
3
+ Capybara.register_driver :httpx_with_custom_timeout do |app|
4
+ Capybara::HTTPX::Driver.new app, timeout: 1
5
+ end
6
+
7
+ module TestSessions
8
+ HTTPXTest = Capybara::Session.new(:httpx, TestApp)
9
+ HTTPXTestCustomTimeout = Capybara::Session.new(:httpx_with_custom_timeout, TestApp)
10
+ end
11
+
12
+ skipped_tests = %i[
13
+ js
14
+ modals
15
+ screenshot
16
+ frames
17
+ windows
18
+ send_keys
19
+ server
20
+ hover
21
+ about_scheme
22
+ download
23
+ css
24
+ scroll
25
+ active_element
26
+ html_validation
27
+ shadow_dom
28
+ ]
29
+ Capybara::SpecHelper.run_specs TestSessions::HTTPXTest, 'HTTPX', capybara_skip: skipped_tests do |example|
30
+ case example.metadata[:full_description]
31
+ when /#attach_file/
32
+ skip "HTTPX driver doesn't support #attach_file"
33
+ when /#check/
34
+ skip "HTTPX driver doesn't support #check"
35
+ when /#uncheck/
36
+ skip "HTTPX driver doesn't support #uncheck"
37
+ when /#click/
38
+ skip "HTTPX driver doesn't support #click"
39
+ when /#select/
40
+ skip "HTTPX driver doesn't support #select"
41
+ when /#unselect/
42
+ skip "HTTPX driver doesn't support #unselect"
43
+ when /#has_css\? with spatial requirements/
44
+ skip "HTTPX driver doesn't support #has_css? with spatial requirements"
45
+ when /#find with spatial filters/
46
+ skip "HTTPX driver doesn't support #find with spatial filters"
47
+ when /can set cookie if a blank path is specified/
48
+ skip "HTTPX driver doesn't support cookie"
49
+ when /has_css\? should support case insensitive :class and :id options/
50
+ skip "Nokogiri doesn't support case insensitive CSS attribute matchers"
51
+ end
52
+ end
53
+
54
+ RSpec.describe Capybara::HTTPX::Session do
55
+
56
+ context "with httpx driver" do
57
+ before { Capybara.current_driver = :httpx }
58
+ let(:session) { TestSessions::HTTPXTest }
59
+
60
+ describe 'Capybara#current_session' do
61
+ it 'should be a httpx session' do
62
+ expect(Capybara.current_session).to be_an_instance_of(Capybara::HTTPX::Session)
63
+ end
64
+ end
65
+
66
+ describe '#driver' do
67
+ it 'should be a httpx driver' do
68
+ expect(session.driver).to be_an_instance_of(Capybara::HTTPX::Driver)
69
+ end
70
+ end
71
+
72
+ describe '#mode' do
73
+ it 'should remember the mode' do
74
+ expect( session.mode ).to eq(:httpx)
75
+ end
76
+ end
77
+
78
+ context "basic authentication" do
79
+ subject do
80
+ app = Sinatra.new do
81
+ use Rack::Auth::Basic do |username, password|
82
+ username=="admin" && password=="secret"
83
+ end
84
+ get("/"){ "Success!" }
85
+ end
86
+ described_class.new :httpx, app
87
+ end
88
+
89
+ it "allow access with right credentials" do
90
+ subject.authenticate_with "admin", "secret"
91
+ subject.get "/"
92
+ expect( subject.status_code ).to be 200
93
+ expect( subject.source ).to eq "Success!"
94
+ end
95
+
96
+ it "deny access with wrong credentials" do
97
+ subject.authenticate_with "admin", "admin"
98
+ subject.get "/"
99
+ expect( subject.status_code ).to be 401
100
+ end
101
+ end
102
+
103
+ context "params encoding" do
104
+ context "setting on driver" do
105
+ let(:driver) { session.driver }
106
+ it "defaults to :httpx" do
107
+ expect( driver.params_encoding ).to eq :httpx
108
+ end
109
+ it "can be set to :rack, :multi or :none" do
110
+ driver.params_encoding = :rack
111
+ expect( driver.params_encoding ).to eq :rack
112
+ driver.params_encoding = :multi
113
+ expect( driver.params_encoding ).to eq :multi
114
+ driver.params_encoding = :none
115
+ expect( driver.params_encoding ).to eq :none
116
+
117
+ expect do
118
+ driver.params_encoding = :unknown
119
+ end.to raise_error ArgumentError, "Allowed values are: :httpx, :rack, :multi, :none"
120
+ end
121
+ end
122
+ context "usage in requests" do
123
+ subject do
124
+ app = Sinatra.new do
125
+ get("/"){ params.inspect }
126
+ end
127
+ described_class.new :httpx, app
128
+ end
129
+ it "defaults to driver setting" do
130
+ subject.get "/", ids: [1, 2, 3]
131
+ expect( subject.body ).to eq({"ids" => ["1", "2", "3"]}.inspect)
132
+
133
+ subject.driver.params_encoding = :rack
134
+ subject.get "/", ids: [1, 2, 3]
135
+ expect( subject.body ).to eq({"ids" => ["1", "2", "3"]}.inspect)
136
+
137
+ subject.driver.params_encoding = :multi
138
+ subject.get "/", ids: [1, 2, 3]
139
+ expect( subject.body ).to eq({"ids" => "3"}.inspect)
140
+
141
+ subject.driver.params_encoding = :none
142
+ subject.get "/", ids: [1, 2, 3]
143
+ expect( subject.body ).to eq({"ids" => "[1, 2, 3]"}.inspect)
144
+ end
145
+ it "can be overriden per request" do
146
+ subject.driver.params_encoding = :none
147
+
148
+ subject.get "/", ids: [1, 2, 3], params_encoding: :httpx
149
+ expect( subject.body ).to eq({"ids" => ["1", "2", "3"]}.inspect)
150
+
151
+ subject.get "/", ids: [1, 2, 3], params_encoding: :rack
152
+ expect( subject.body ).to eq({"ids" => ["1", "2", "3"]}.inspect)
153
+
154
+ subject.get "/", ids: [1, 2, 3], params_encoding: :multi
155
+ expect( subject.body ).to eq({"ids" => "3"}.inspect)
156
+
157
+ subject.driver.params_encoding = :httpx
158
+
159
+ subject.get "/", ids: [1, 2, 3], params_encoding: :none
160
+ expect( subject.body ).to eq({"ids" => "[1, 2, 3]"}.inspect)
161
+ end
162
+ end
163
+ end
164
+
165
+ context "timeout" do
166
+ subject{ described_class.new :httpx, TestApp }
167
+
168
+ context "default" do
169
+ it "is 3 seconds" do
170
+ expect( subject.timeout ).to eq 3
171
+ end
172
+
173
+ it "is used during request" do
174
+ subject.get "/slow_response"
175
+ expect( subject ).not_to be_timed_out
176
+ end
177
+ end
178
+
179
+ context "accepts custom timeout" do
180
+ subject{ described_class.new :httpx_with_custom_timeout, TestApp }
181
+
182
+ it "is stored in options" do
183
+ expect( subject.timeout ).to eq 1
184
+ end
185
+
186
+ it "is used during request" do
187
+ subject.get "/slow_response"
188
+ expect( subject ).to be_timed_out
189
+ end
190
+ end
191
+ end
192
+
193
+ context "#host_url returns url with scheme, host, port and path" do
194
+ subject{ described_class.new :httpx, TestApp }
195
+
196
+ it "with empty url" do
197
+ expect( subject.host_url("") ).to match /\A#{Regexp.escape("http://127.0.0.1")}:\d+\z/
198
+ end
199
+
200
+ it "with relative url" do
201
+ expect( subject.host_url("/demo/test") ).to match /\A#{Regexp.escape("http://127.0.0.1")}:\d+\/demo\/test\z/
202
+ end
203
+
204
+ it "with absolute url" do
205
+ expect(
206
+ subject.host_url("http://www.example.com:443/demo/test")
207
+ ).to eq "http://www.example.com:443/demo/test"
208
+ end
209
+ end
210
+
211
+ context "can upload file by setting the body per request" do
212
+ subject do
213
+ app = Sinatra.new do
214
+ post("/"){ request.body }
215
+ end
216
+ described_class.new :httpx, app
217
+ end
218
+
219
+ it "body is nil be default" do
220
+ expect( subject.request_body ).to be_nil
221
+ subject.post "/"
222
+ expect( subject.status_code ).to be 200
223
+ expect( subject.source ).to eq ""
224
+ end
225
+
226
+ it "I can send data by setting the body" do
227
+ body = "**raw file content**"
228
+ subject.request_body = body
229
+ expect( subject.request_body ).to eq body
230
+ subject.post "/"
231
+ expect( subject.status_code ).to be 200
232
+ expect( subject.source ).to eq body
233
+ expect( subject.request_body ).to be_nil
234
+ end
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+ require "capybara/httpx"
3
+ require "capybara/spec/spec_helper"
4
+ require 'pry'
5
+
6
+ RSpec.configure do |config|
7
+ Capybara::SpecHelper.configure config
8
+ end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capybara-httpx
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.preview1
5
+ platform: ruby
6
+ authors:
7
+ - Joseph HALTER
8
+ - Jonathan TRON
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 1980-01-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: capybara
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: httpx
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rack
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sinatra
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: puma
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: HTTPX driver for Capybara, allowing testing of REST APIs
112
+ email:
113
+ - jonathan.tron@metrilio.com
114
+ - joseph.halter@metrilio.com
115
+ executables: []
116
+ extensions: []
117
+ extra_rdoc_files:
118
+ - README.md
119
+ files:
120
+ - LICENSE
121
+ - README.md
122
+ - lib/capybara/httpx.rb
123
+ - lib/capybara/httpx/browser.rb
124
+ - lib/capybara/httpx/cucumber.rb
125
+ - lib/capybara/httpx/driver.rb
126
+ - lib/capybara/httpx/session.rb
127
+ - spec/session/httpx_spec.rb
128
+ - spec/spec_helper.rb
129
+ homepage: https://forgejo.home.tron.name/metrilio/capybara-httpx
130
+ licenses:
131
+ - MIT
132
+ metadata: {}
133
+ rdoc_options:
134
+ - "--main"
135
+ - README.md
136
+ - "--inline-source"
137
+ - "--line-numbers"
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '3.4'
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ requirements: []
151
+ rubygems_version: 3.7.2
152
+ specification_version: 4
153
+ summary: HTTPX driver for Capybara
154
+ test_files:
155
+ - spec/session/httpx_spec.rb
156
+ - spec/spec_helper.rb