Skip to content

Commit

Permalink
Add Cookie inspector
Browse files Browse the repository at this point in the history
  • Loading branch information
gavv committed Jun 27, 2016
1 parent 7d145c8 commit 97ac019
Show file tree
Hide file tree
Showing 5 changed files with 278 additions and 8 deletions.
105 changes: 105 additions & 0 deletions cookie.go
@@ -0,0 +1,105 @@
package httpexpect

import (
"net/http"
"time"
)

// Cookie provides methods to inspect attached http.Cookie value.
type Cookie struct {
chain chain
value *http.Cookie
}

// NewCookie returns a new Cookie object given a reporter used to report
// failures and cookie value to be inspected.
//
// reporter and value should not be nil.
//
// Example:
// cookie := NewCookie(reporter, &http.Cookie{...})
// cookie.Domain().Equal("example.com")
// cookie.Path().Equal("/")
// cookie.Expires().InRange(time.Now(), time.Now().Add(time.Hour * 24))
func NewCookie(reporter Reporter, value *http.Cookie) *Cookie {
chain := makeChain(reporter)
if value == nil {
chain.fail("expected non-nil cookie")
}
return &Cookie{chain, value}
}

// Raw returns underlying http.Cookie value attached to Cookie.
// This is the value originally passed to NewCookie.
//
// Example:
// cookie := NewCookie(t, c)
// assert.Equal(t, c, cookie.Raw())
func (c *Cookie) Raw() *http.Cookie {
return c.value
}

// Name returns a new String object that may be used to inspect
// cookie name.
//
// Example:
// cookie := NewCookie(t, &http.Cookie{...})
// cookie.Name().Equal("session")
func (c *Cookie) Name() *String {
if c.chain.failed() {
return &String{c.chain, ""}
}
return &String{c.chain, c.value.Name}
}

// Value returns a new String object that may be used to inspect
// cookie value.
//
// Example:
// cookie := NewCookie(t, &http.Cookie{...})
// cookie.Value().Equal("gH6z7Y")
func (c *Cookie) Value() *String {
if c.chain.failed() {
return &String{c.chain, ""}
}
return &String{c.chain, c.value.Value}
}

// Domain returns a new String object that may be used to inspect
// cookie domain.
//
// Example:
// cookie := NewCookie(t, &http.Cookie{...})
// cookie.Domain().Equal("example.com")
func (c *Cookie) Domain() *String {
if c.chain.failed() {
return &String{c.chain, ""}
}
return &String{c.chain, c.value.Domain}
}

// Path returns a new String object that may be used to inspect
// cookie path.
//
// Example:
// cookie := NewCookie(t, &http.Cookie{...})
// cookie.Path().Equal("/foo")
func (c *Cookie) Path() *String {
if c.chain.failed() {
return &String{c.chain, ""}
}
return &String{c.chain, c.value.Path}
}

// Expires returns a new DateTime object that may be used to inspect
// cookie expiration date.
//
// Example:
// cookie := NewCookie(t, &http.Cookie{...})
// cookie.Expires().InRange(time.Now(), time.Now().Add(time.Hour * 24))
func (c *Cookie) Expires() *DateTime {
if c.chain.failed() {
return &DateTime{c.chain, time.Unix(0, 0)}
}
return &DateTime{c.chain, c.value.Expires}
}
53 changes: 53 additions & 0 deletions cookie_test.go
@@ -0,0 +1,53 @@
package httpexpect

import (
"github.com/stretchr/testify/assert"
"net/http"
"testing"
"time"
)

func TestCookieFailed(t *testing.T) {
chain := makeChain(newMockReporter(t))

chain.fail("fail")

value := &Cookie{chain, nil}

assert.True(t, value.Raw() == nil)
assert.True(t, value.Name() != nil)
assert.True(t, value.Value() != nil)
assert.True(t, value.Domain() != nil)
assert.True(t, value.Path() != nil)
assert.True(t, value.Expires() != nil)
}

func TestCookieGetters(t *testing.T) {
reporter := newMockReporter(t)

NewCookie(reporter, nil).chain.assertFailed(t)

value := NewCookie(reporter, &http.Cookie{
Name: "name",
Value: "value",
Domain: "example.com",
Path: "/path",
Expires: time.Unix(1234, 0),
})

value.chain.assertOK(t)

value.Name().chain.assertOK(t)
value.Value().chain.assertOK(t)
value.Domain().chain.assertOK(t)
value.Path().chain.assertOK(t)
value.Expires().chain.assertOK(t)

assert.Equal(t, "name", value.Name().Raw())
assert.Equal(t, "value", value.Value().Raw())
assert.Equal(t, "example.com", value.Domain().Raw())
assert.Equal(t, "/path", value.Path().Raw())
assert.True(t, time.Unix(1234, 0).Equal(value.Expires().Raw()))

value.chain.assertOK(t)
}
2 changes: 1 addition & 1 deletion datetime.go
Expand Up @@ -11,7 +11,7 @@ type DateTime struct {
}

// NewDateTime returns a new DateTime object given a reporter used to report
// failures time.Time value to be inspected.
// failures and time.Time value to be inspected.
//
// reporter should not be nil.
//
Expand Down
52 changes: 46 additions & 6 deletions response.go
Expand Up @@ -38,6 +38,7 @@ type Response struct {
chain chain
resp *http.Response
content []byte
cookies []*http.Cookie
time time.Duration
}

Expand All @@ -58,23 +59,24 @@ func NewResponse(
}

func makeResponse(chain chain, response *http.Response, duration time.Duration) *Response {
if response == nil {
var content []byte
var cookies []*http.Cookie
if response != nil {
content = getContent(&chain, response)
cookies = response.Cookies()
} else {
chain.fail("expected non-nil response")
}
content := getContent(&chain, response)
return &Response{
chain: chain,
resp: response,
content: content,
cookies: cookies,
time: duration,
}
}

func getContent(chain *chain, resp *http.Response) []byte {
if chain.failed() {
return nil
}

if resp.Body == nil {
return []byte{}
}
Expand Down Expand Up @@ -210,6 +212,44 @@ func (r *Response) Header(header string) *String {
return &String{r.chain, value}
}

// Cookies returns a new Array object with all available cookie names.
// Returned Array contains a String value for every cookie name.
//
// Example:
// resp := NewResponse(t, response)
// resp.Cookies().Contains("session")
func (r *Response) Cookies() *Array {
if r.chain.failed() {
return &Array{r.chain, nil}
}
names := []interface{}{}
for _, c := range r.cookies {
names = append(names, c.Name)
}
return &Array{r.chain, names}
}

// Cookie returns a new Cookie object that may be used to inspect given cookie.
//
// Example:
// resp := NewResponse(t, response)
// resp.Cookie("session").Domain().Equal("example.com")
func (r *Response) Cookie(name string) *Cookie {
if r.chain.failed() {
return &Cookie{r.chain, nil}
}
names := []string{}
for _, c := range r.cookies {
if c.Name == name {
return &Cookie{r.chain, c}
}
names = append(names, c.Name)
}
r.chain.fail("\nexpected response with cookie:\n %q\n\nbut got only cookies:\n%s",
name, dumpValue(names))
return &Cookie{r.chain, nil}
}

// Body returns a new String object that may be used to inspect response body.
//
// Example:
Expand Down
74 changes: 73 additions & 1 deletion response_test.go
Expand Up @@ -15,18 +15,22 @@ func TestResponseFailed(t *testing.T) {

chain.fail("fail")

resp := &Response{chain, nil, nil, 0}
resp := &Response{chain, nil, nil, nil, 0}

resp.chain.assertFailed(t)

assert.False(t, resp.Duration() == nil)
assert.False(t, resp.Headers() == nil)
assert.False(t, resp.Header("foo") == nil)
assert.False(t, resp.Cookies() == nil)
assert.False(t, resp.Cookie("foo") == nil)
assert.False(t, resp.Body() == nil)
assert.False(t, resp.JSON() == nil)

resp.Headers().chain.assertFailed(t)
resp.Header("foo").chain.assertFailed(t)
resp.Cookies().chain.assertFailed(t)
resp.Cookie("foo").chain.assertFailed(t)
resp.Body().chain.assertFailed(t)
resp.Text().chain.assertFailed(t)
resp.JSON().chain.assertFailed(t)
Expand Down Expand Up @@ -139,6 +143,74 @@ func TestResponseHeaders(t *testing.T) {
resp.Header("Bad-Header").Empty().chain.assertOK(t)
}

func TestResponseCookies(t *testing.T) {
reporter := newMockReporter(t)

headers := map[string][]string{
"Set-Cookie": {
"foo=aaa",
"bar=bbb; expires=Fri, 31 Dec 2010 23:59:59 GMT; " +
"path=/xxx; domain=example.com",
},
}

httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: http.Header(headers),
Body: nil,
}

resp := NewResponse(reporter, httpResp)
resp.chain.assertOK(t)
resp.chain.reset()

assert.Equal(t, []interface{}{"foo", "bar"}, resp.Cookies().Raw())
resp.chain.assertOK(t)

c1 := resp.Cookie("foo")
resp.chain.assertOK(t)
assert.Equal(t, "foo", c1.Raw().Name)
assert.Equal(t, "aaa", c1.Raw().Value)
assert.Equal(t, "", c1.Raw().Domain)
assert.Equal(t, "", c1.Raw().Path)

c2 := resp.Cookie("bar")
resp.chain.assertOK(t)
assert.Equal(t, "bar", c2.Raw().Name)
assert.Equal(t, "bbb", c2.Raw().Value)
assert.Equal(t, "example.com", c2.Raw().Domain)
assert.Equal(t, "/xxx", c2.Raw().Path)
assert.True(t, time.Date(2010, 12, 31, 23, 59, 59, 0, time.UTC).
Equal(c2.Raw().Expires))

c3 := resp.Cookie("baz")
resp.chain.assertFailed(t)
c3.chain.assertFailed(t)
assert.True(t, c3.Raw() == nil)
}

func TestResponseNoCookies(t *testing.T) {
reporter := newMockReporter(t)

httpResp := &http.Response{
StatusCode: http.StatusOK,
Header: nil,
Body: nil,
}

resp := NewResponse(reporter, httpResp)
resp.chain.assertOK(t)
resp.chain.reset()

assert.Equal(t, []interface{}{}, resp.Cookies().Raw())
resp.chain.assertOK(t)

c := resp.Cookie("foo")
resp.chain.assertFailed(t)
c.chain.assertFailed(t)
assert.True(t, c.Raw() == nil)
}

func TestResponseBody(t *testing.T) {
reporter := newMockReporter(t)

Expand Down

0 comments on commit 97ac019

Please sign in to comment.