Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HaveHTTPStatus matcher #378

Merged
merged 1 commit into from Mar 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions matchers.go
Expand Up @@ -408,6 +408,15 @@ func BeADirectory() types.GomegaMatcher {
return &matchers.BeADirectoryMatcher{}
}

//HaveHTTPStatus succeeds if the Status or StatusCode field of an HTTP response matches.
//Actual must be either a *http.Response or *httptest.ResponseRecorder.
//Expected must be either an int or a string.
// Expect(resp).Should(HaveHTTPStatus(http.StatusOK)) // asserts that resp.StatusCode == 200
// Expect(resp).Should(HaveHTTPStatus("404 Not Found")) // asserts that resp.Status == "404 Not Found"
func HaveHTTPStatus(expected interface{}) types.GomegaMatcher {
return &matchers.HaveHTTPStatusMatcher{Expected: expected}
}

//And succeeds only if all of the given matchers succeed.
//The matchers are tried in order, and will fail-fast if one doesn't succeed.
// Expect("hi").To(And(HaveLen(2), Equal("hi"))
Expand Down
42 changes: 42 additions & 0 deletions matchers/have_http_status_matcher.go
@@ -0,0 +1,42 @@
package matchers

import (
"fmt"
"net/http"
"net/http/httptest"

"github.com/onsi/gomega/format"
)

type HaveHTTPStatusMatcher struct {
Expected interface{}
}

func (matcher *HaveHTTPStatusMatcher) Match(actual interface{}) (success bool, err error) {
var resp *http.Response
switch a := actual.(type) {
case *http.Response:
resp = a
case *httptest.ResponseRecorder:
resp = a.Result()
default:
return false, fmt.Errorf("HaveHTTPStatus matcher expects *http.Response or *httptest.ResponseRecorder. Got:\n%s", format.Object(actual, 1))
}

switch e := matcher.Expected.(type) {
case int:
return resp.StatusCode == e, nil
case string:
return resp.Status == e, nil
}

return false, fmt.Errorf("HaveHTTPStatus matcher must be passed an int or a string. Got:\n%s", format.Object(matcher.Expected, 1))
}

func (matcher *HaveHTTPStatusMatcher) FailureMessage(actual interface{}) (message string) {
return format.Message(actual, "to have HTTP status", matcher.Expected)
}

func (matcher *HaveHTTPStatusMatcher) NegatedFailureMessage(actual interface{}) (message string) {
return format.Message(actual, "not to have HTTP status", matcher.Expected)
}
91 changes: 91 additions & 0 deletions matchers/have_http_status_matcher_test.go
@@ -0,0 +1,91 @@
package matchers_test

import (
"net/http"
"net/http/httptest"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("HaveHTTPStatus", func() {
When("ACTUAL is *http.Response", func() {
When("EXPECTED is integer", func() {
It("matches the StatusCode", func() {
resp := &http.Response{StatusCode: http.StatusOK}
Expect(resp).To(HaveHTTPStatus(http.StatusOK))
Expect(resp).NotTo(HaveHTTPStatus(http.StatusNotFound))
})
})
When("EXPECTED is string", func() {
It("matches the Status", func() {
resp := &http.Response{Status: "200 OK"}
Expect(resp).To(HaveHTTPStatus("200 OK"))
Expect(resp).NotTo(HaveHTTPStatus("404 Not Found"))
})
})
When("EXPECTED is anything else", func() {
It("does not match", func() {
failures := InterceptGomegaFailures(func() {
resp := &http.Response{StatusCode: http.StatusOK}
Expect(resp).NotTo(HaveHTTPStatus(true))
})
Expect(failures).To(ConsistOf("HaveHTTPStatus matcher must be passed an int or a string. Got:\n <bool>: true"))
})
})
})

When("ACTUAL is *httptest.ResponseRecorder", func() {
When("EXPECTED is integer", func() {
It("matches the StatusCode", func() {
resp := &httptest.ResponseRecorder{Code: http.StatusOK}
Expect(resp).To(HaveHTTPStatus(http.StatusOK))
Expect(resp).NotTo(HaveHTTPStatus(http.StatusNotFound))
})
})
When("EXPECTED is string", func() {
It("matches the Status", func() {
resp := &httptest.ResponseRecorder{Code: http.StatusOK}
Expect(resp).To(HaveHTTPStatus("200 OK"))
Expect(resp).NotTo(HaveHTTPStatus("404 Not Found"))
})
})
When("EXPECTED is anything else", func() {
It("does not match", func() {
failures := InterceptGomegaFailures(func() {
resp := &httptest.ResponseRecorder{Code: http.StatusOK}
Expect(resp).NotTo(HaveHTTPStatus(nil))
})
Expect(failures).To(ConsistOf("HaveHTTPStatus matcher must be passed an int or a string. Got:\n <nil>: nil"))
})
})
})

When("ACTUAL is neither *http.Response nor *httptest.ResponseRecorder", func() {
It("errors", func() {
failures := InterceptGomegaFailures(func() {
Expect("foo").To(HaveHTTPStatus(http.StatusOK))
})
Expect(failures).To(ConsistOf("HaveHTTPStatus matcher expects *http.Response or *httptest.ResponseRecorder. Got:\n <string>: foo"))
})
})

Describe("FailureMessage", func() {
It("returns message", func() {
failures := InterceptGomegaFailures(func() {
resp := &http.Response{StatusCode: http.StatusBadGateway}
Expect(resp).To(HaveHTTPStatus(http.StatusOK))
})
Expect(failures).To(ConsistOf(MatchRegexp("Expected(.|\n)*StatusCode: 502(.|\n)*to have HTTP status\n <int>: 200")))
})
})
Describe("NegatedFailureMessage", func() {
It("returns message", func() {
failures := InterceptGomegaFailures(func() {
resp := &http.Response{StatusCode: http.StatusOK}
Expect(resp).NotTo(HaveHTTPStatus(http.StatusOK))
})
Expect(failures).To(ConsistOf(MatchRegexp("Expected(.|\n)*StatusCode: 200(.|\n)*not to have HTTP status\n <int>: 200")))
})
})
})