Skip to content

Commit

Permalink
Merge pull request #1 from httprb/st-rename-matcher-to-be-http-gem-re…
Browse files Browse the repository at this point in the history
…sponse

Rename matcher to be http gem response
  • Loading branch information
stoivo committed Aug 2, 2023
2 parents 9b748da + 1cb6d05 commit aeb8509
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 55 deletions.
3 changes: 3 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ Metrics/BlockLength:
Exclude:
- spec/**/*.rb

Metrics/MethodLength:
Max: 20

RSpec/MultipleExpectations:
Max: 10
RSpec/ExampleLength:
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ RSpec.describe Service do
include HTTP::Support::RspecMatchers

it "makes request" do
expect(response).to have_httprb_status(200)
expect(response).to be_an_http_gem_response.with(status: 200)
end
end
```
Expand All @@ -62,14 +62,14 @@ Here's some simple examples to get you started:
```ruby
it "has successful response" do
response = HTTP.get("www.nrk.no")
expect(response).to have_httprb_status(:success) # will match 2xx status code
expect(response).to have_httprb_status(:redirect) # will match 3xx status code
expect(response).to have_httprb_status(:error) # will match 3xx status code
expect(response).to be_an_http_gem_response.with(status: :success) # will match 2xx status code
expect(response).to be_an_http_gem_response.with(status: :redirect) # will match 3xx status code
expect(response).to be_an_http_gem_response.with(status: :error) # will match 3xx status code

expect(response).to have_httprb_status(:ok) # require 200 status code
expect(response).to have_httprb_status(200) # require 200 status code
expect(response).to have_httprb_status(:not_found) # require 404 status code
expect(response).to have_httprb_status(404) # require 404 status code
expect(response).to be_an_http_gem_response.with(status: :ok) # require 200 status code
expect(response).to be_an_http_gem_response.with(status: 200) # require 200 status code
expect(response).to be_an_http_gem_response.with(status: :not_found) # require 404 status code
expect(response).to be_an_http_gem_response.with(status: 404) # require 404 status code

# you can access HTTP::Support::RspecMatchers::STATUS_CODE_TO_SYMBOL to see the full
# mapping between code and symbol
Expand Down
2 changes: 1 addition & 1 deletion lib/http/rspec.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# frozen_string_literal: true

require_relative "support/support/matchers"
require_relative "support/matchers"
68 changes: 45 additions & 23 deletions lib/http/support/rspec_matchers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,42 +15,52 @@ module RspecMatchers
end
STATUS_SYMBOL_TO_CODE = STATUS_CODE_TO_SYMBOL.invert

matcher :have_httprb_status do |_expected| # rubocop:disable Metrics/BlockLength
matcher :be_an_http_gem_response do |_expected| # rubocop:disable Metrics/BlockLength
chain :with do |options|
if options[:status]
raise ArgumentError, "status is all ready passed in" if @expected_status

@expected_status = options[:status]
end
end

def expected_code
case expected
when Integer then expected
case @expected_status
when Integer then @expected_status
when :success, :successful then 200..299
when :redirect then 300..399
when :error then 500..599
when Symbol
STATUS_SYMBOL_TO_CODE.fetch(expected) { raise ArgumentError, "unknown symbol #{expected.inspect}" }
STATUS_SYMBOL_TO_CODE.fetch(@expected_status) do
raise ArgumentError, "unknown symbol #{@expected_status.inspect}"
end
else
raise ArgumentError, "unknown expected value. Should be either a Integer or a symbol"
raise ArgumentError, "unknown status value. Should be either a Integer or a symbol"
end
end

match do |actual|
@actual = actual

return false if invalid_response_type_message
match_response_type && match_status_code
end

def match_response_type = @actual.is_a?(HTTP::Response)

def match_status_code
# without @expected_status we dont have anything to compare against
return true unless @expected_status

case expected_code
when Integer
expected_code == actual.status.code
expected_code == @actual.status.code
when Range
expected_code.cover?(actual.status.code)
expected_code.cover?(@actual.status.code)
else
raise "Unknown expected code #{expected_code}. Please report this as an issue"
end
end

def invalid_response_type_message
return if @actual.is_a? HTTP::Response

"expected a HTTP::Response object, but an instance of " \
"#{@actual.class} was received"
end

def status_code_to_name(code)
STATUS_CODE_TO_SYMBOL.fetch(code, "unkown name")
end
Expand All @@ -63,22 +73,34 @@ def expected_type
end
end

def actual_type
"#{actual.status.code} #{status_code_to_name(actual.status.code).inspect}"
description do
"http gem respond"
.then { @expected_status ? "#{_1} with #{expected_type}" : _1 }
end

description do
"respond with #{expected_type}"
def invalid_response_type_message
"expected a HTTP::Response object, but an instance of " \
"#{@actual.class} was received"
end

def actual_type
"#{actual.status.code} #{status_code_to_name(actual.status.code).inspect}"
end

def failure_message
invalid_response_type_message ||
"expected the response to have #{expected_type} but it was #{actual_type}"
return invalid_response_type_message unless match_response_type

return "expected the response to have #{expected_type} but it was #{actual_type}" unless match_status_code

"unknown reason why it fails, please report it"
end

def failure_message_when_negated
invalid_response_type_message ||
"expected the response not to have #{expected_type} but it was #{actual_type}"
return invalid_response_type_message unless match_response_type

return "expected the response not to have #{expected_type} but it was #{actual_type}" if match_status_code

"unknown reason why it fails, please report it"
end
end
end
Expand Down
63 changes: 40 additions & 23 deletions spec/http/support/rspec_matchers_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,35 @@
RSpec.describe HTTP::Support::RspecMatchers do
include described_class

describe "have_httprb_status" do
describe "be_an_http_gem_response" do
it "raises error if it gets unexpected argument" do
matcher = have_httprb_status(200)
matcher = be_an_http_gem_response

expect(matcher.matches?("response")).to be(false)
expect(matcher.failure_message)
.to eq("expected a HTTP::Response object, but an instance of String was received")
end

it "works with description for 200 ok" do
matcher = have_httprb_status(200)
it "description with no other constrains" do
matcher = be_an_http_gem_response
stub_request(:get, "https://nrk.no/").to_return(:status => 200)

response = HTTP.get("https://nrk.no")
expect(matcher.matches?(response)).to be(true)
expect(matcher.description).to eq("respond with 200 :ok")
expect(matcher.description).to eq("http gem respond")
end

it "description include status" do
matcher = be_an_http_gem_response.with(:status => 200)
stub_request(:get, "https://nrk.no/").to_return(:status => 200)

response = HTTP.get("https://nrk.no")
expect(matcher.matches?(response)).to be(true)
expect(matcher.description).to eq("http gem respond with 200 :ok")
end

it "has reasonable failure message for 200 ok failure" do
matcher = have_httprb_status(200)
matcher = be_an_http_gem_response.with(:status => 200)
stub_request(:get, "https://nrk.no/").to_return(:status => 400)

response = HTTP.get("https://nrk.no")
Expand All @@ -36,7 +45,7 @@
end

it "has reasonable description for negated 200 ok failure" do
matcher = have_httprb_status(200)
matcher = be_an_http_gem_response.with(:status => 200)
stub_request(:get, "https://nrk.no/").to_return(:status => 200)

response = HTTP.get("https://nrk.no")
Expand All @@ -54,86 +63,86 @@

it "raises for unknown symbol" do
expect do
matcher = have_httprb_status(:ruby)
matcher = be_an_http_gem_response.with(:status => :ruby)
matcher.matches?(response)
end
.to raise_error(ArgumentError, "unknown symbol :ruby")
end

it "raises for wrong type" do
expect do
matcher = have_httprb_status("Coty")
matcher = be_an_http_gem_response.with(:status => "Coty")
matcher.matches?(response)
end
.to raise_error(ArgumentError, "unknown expected value. Should be " \
.to raise_error(ArgumentError, "unknown status value. Should be " \
"either a Integer or a symbol")
end

it "can take :continue and convert in into 100" do
matcher = have_httprb_status(:continue)
matcher = be_an_http_gem_response.with(:status => :continue)
expect(matcher.matches?(response)).to be(false)
expect(matcher.failure_message)
.to match(/expected the response to have 100 :continue but/)
end

it "can take :switching_protocols and convert in into 101" do
matcher = have_httprb_status(:switching_protocols)
matcher = be_an_http_gem_response.with(:status => :switching_protocols)
expect(matcher.matches?(response)).to be(false)
expect(matcher.failure_message)
.to match(/expected the response to have 101 :switching_protocols but/)
end

it "can take :ok and convert in into 200" do
matcher = have_httprb_status(:ok)
matcher = be_an_http_gem_response.with(:status => :ok)
expect(matcher.matches?(response)).to be(false)
expect(matcher.failure_message)
.to match(/expected the response to have 200 :ok but/)
end

it "can take :created and convert in into 201" do
matcher = have_httprb_status(:created)
matcher = be_an_http_gem_response.with(:status => :created)
expect(matcher.matches?(response)).to be(false)
expect(matcher.failure_message)
.to match(/expected the response to have 201 :created but/)
end

it "can take :non_authoritative_information and convert in into 203" do
matcher = have_httprb_status(:non_authoritative_information)
matcher = be_an_http_gem_response.with(:status => :non_authoritative_information)
expect(matcher.matches?(response)).to be(false)
expect(matcher.failure_message)
.to match(/expected the response to have 203 :non_authoritative_information but/)
end

it "can take :multi_status and convert in into 207" do
matcher = have_httprb_status(:multi_status)
matcher = be_an_http_gem_response.with(:status => :multi_status)
expect(matcher.matches?(response)).to be(false)
expect(matcher.failure_message)
.to match(/expected the response to have 207 :multi_status but/)
end

it "can take :not_found and convert in into 404" do
matcher = have_httprb_status(:not_found)
matcher = be_an_http_gem_response.with(:status => :not_found)
expect(matcher.matches?(response)).to be(false)
expect(matcher.failure_message)
.to match(/expected the response to have 404 :not_found but/)
end

it "can take :uri_too_long and convert in into 414" do
matcher = have_httprb_status(:uri_too_long)
matcher = be_an_http_gem_response.with(:status => :uri_too_long)
expect(matcher.matches?(response)).to be(false)
expect(matcher.failure_message)
.to match(/expected the response to have 414 :uri_too_long but/)
end

it "can take :internal_server_error and convert in into 500" do
matcher = have_httprb_status(:internal_server_error)
matcher = be_an_http_gem_response.with(:status => :internal_server_error)
expect(matcher.matches?(response)).to be(false)
expect(matcher.failure_message)
.to match(/expected the response to have 500 :internal_server_error but/)
end

it "can take :gateway_timeout and convert in into 504" do
matcher = have_httprb_status(:gateway_timeout)
matcher = be_an_http_gem_response.with(:status => :gateway_timeout)
expect(matcher.matches?(response)).to be(false)
expect(matcher.failure_message)
.to match(/expected the response to have 504 :gateway_timeout but/)
Expand All @@ -142,7 +151,7 @@

%i[success successful].each do |success_name|
it "accepts #{success_name} for all 2xx codes" do
matcher = have_httprb_status(success_name)
matcher = be_an_http_gem_response.with(:status => success_name)

stub_request(:get, "https://nrk.no/").to_return(:status => 200)
response = HTTP.get("https://nrk.no")
Expand All @@ -166,7 +175,7 @@
end

it "accepts :redirect for all 3xx codes" do
matcher = have_httprb_status(:redirect)
matcher = be_an_http_gem_response.with(:status => :redirect)

stub_request(:get, "https://nrk.no/").to_return(:status => 300)
response = HTTP.get("https://nrk.no")
Expand All @@ -189,7 +198,7 @@
end

it "accepts :error for all 5xx codes" do
matcher = have_httprb_status(:error)
matcher = be_an_http_gem_response.with(:status => :error)

stub_request(:get, "https://nrk.no/").to_return(:status => 500)
response = HTTP.get("https://nrk.no")
Expand All @@ -211,4 +220,12 @@
.to eq("expected the response to have 500..599 code but it was 400 :bad_request")
end
end

it "raises if you call it with twice with status" do
expect do
matcher = be_an_http_gem_response.with(:status => 200).with(:status => 300)
matcher.matches?(response)
end
.to raise_error(ArgumentError, "status is all ready passed in")
end
end

0 comments on commit aeb8509

Please sign in to comment.