expect.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. // Package httpexpect helps with end-to-end HTTP and REST API testing.
  2. //
  3. // Usage examples
  4. //
  5. // See example directory:
  6. // - https://godoc.org/github.com/ion-contrib/httpexpect/_examples
  7. // - https://github.com/ion-contrib/httpexpect/tree/master/_examples
  8. //
  9. // Communication mode
  10. //
  11. // There are two common ways to test API with httpexpect:
  12. // - start HTTP server and instruct httpexpect to use HTTP client for communication
  13. // - don't start server and instruct httpexpect to invoke http handler directly
  14. //
  15. // The second approach works only if the server is a Go module and its handler can
  16. // be imported in tests.
  17. //
  18. // Concrete behaviour is determined by Client implementation passed to Config struct.
  19. // If you're using http.Client, set its Transport field (http.RoundTriper) to one of
  20. // the following:
  21. // 1. default (nil) - use HTTP transport from net/http (you should start server)
  22. // 2. httpexpect.Binder - invoke given http.Handler directly
  23. //
  24. // Note that http handler can be usually obtained from http framework you're using.
  25. // E.g., echo framework provides either http.Handler.
  26. //
  27. // You can also provide your own implementation of RequestFactory (creates http.Request),
  28. // or Client (gets http.Request and returns http.Response).
  29. //
  30. // If you're starting server from tests, it's very handy to use net/http/httptest.
  31. //
  32. // Value equality
  33. //
  34. // Whenever values are checked for equality in httpexpect, they are converted
  35. // to "canonical form":
  36. // - structs are converted to map[string]interface{}
  37. // - type aliases are removed
  38. // - numeric types are converted to float64
  39. // - non-nil interfaces pointing to nil slices and maps are replaced with
  40. // nil interfaces
  41. //
  42. // This is equivalent to subsequently json.Marshal() and json.Unmarshal() the value
  43. // and currently is implemented so.
  44. //
  45. // Failure handling
  46. //
  47. // When some check fails, failure is reported. If non-fatal failures are used
  48. // (see Reporter interface), execution is continued and instance that was checked
  49. // is marked as failed.
  50. //
  51. // If specific instance is marked as failed, all subsequent checks are ignored
  52. // for this instance and for any child instances retrieved after failure.
  53. //
  54. // Example:
  55. // array := NewArray(NewAssertReporter(t), []interface{}{"foo", 123})
  56. //
  57. // e0 := array.Element(0) // success
  58. // e1 := array.Element(1) // success
  59. //
  60. // s0 := e0.String() // success
  61. // s1 := e1.String() // failure; e1 and s1 are marked as failed, e0 and s0 are not
  62. //
  63. // s0.Equal("foo") // success
  64. // s1.Equal("bar") // this check is ignored because s1 is marked as failed
  65. package httpexpect
  66. import (
  67. "io"
  68. "net/http"
  69. "net/http/cookiejar"
  70. "time"
  71. "golang.org/x/net/publicsuffix"
  72. )
  73. // Expect is a toplevel object that contains user Config and allows
  74. // to construct Request objects.
  75. type Expect struct {
  76. config Config
  77. builders []func(*Request)
  78. }
  79. // Config contains various settings.
  80. type Config struct {
  81. // BaseURL is a URL to prepended to all request. My be empty. If
  82. // non-empty, trailing slash is allowed but not required and is
  83. // appended automatically.
  84. BaseURL string
  85. // RequestFactory is used to pass in a custom *http.Request generation func.
  86. // May be nil.
  87. //
  88. // You can use DefaultRequestFactory, or provide custom implementation.
  89. // Useful for Google App Engine testing for example.
  90. RequestFactory RequestFactory
  91. // Client is used to send http.Request and receive http.Response.
  92. // Should not be nil.
  93. //
  94. // You can use http.DefaultClient or http.Client, or provide
  95. // custom implementation.
  96. Client Client
  97. // Reporter is used to report failures.
  98. // Should not be nil.
  99. //
  100. // You can use AssertReporter, RequireReporter (they use testify),
  101. // or testing.TB, or provide custom implementation.
  102. Reporter Reporter
  103. // Printers are used to print requests and responses.
  104. // May be nil.
  105. //
  106. // You can use CompactPrinter, DebugPrinter, CurlPrinter, or provide
  107. // custom implementation.
  108. //
  109. // You can also use builtin printers with alternative Logger if
  110. // you're happy with their format, but want to send logs somewhere
  111. // else instead of testing.TB.
  112. Printers []Printer
  113. }
  114. // RequestFactory is used to create all http.Request objects.
  115. // aetest.Instance from the Google App Engine implements this interface.
  116. type RequestFactory interface {
  117. NewRequest(method, urlStr string, body io.Reader) (*http.Request, error)
  118. }
  119. // Client is used to send http.Request and receive http.Response.
  120. // http.Client, Binder, and FastBinder implement this interface.
  121. type Client interface {
  122. // Do sends request and returns response.
  123. Do(*http.Request) (*http.Response, error)
  124. }
  125. // Printer is used to print requests and responses.
  126. // CompactPrinter, DebugPrinter, and CurlPrinter implement this interface.
  127. type Printer interface {
  128. // Request is called before request is sent.
  129. Request(*http.Request)
  130. // Response is called after response is received.
  131. Response(*http.Response, time.Duration)
  132. }
  133. // Logger is used as output backend for Printer.
  134. // testing.TB implements this interface.
  135. type Logger interface {
  136. // Logf writes message to log.
  137. Logf(fmt string, args ...interface{})
  138. }
  139. // Reporter is used to report failures.
  140. // testing.TB, AssertReporter, and RequireReporter implement this interface.
  141. type Reporter interface {
  142. // Errorf reports failure.
  143. // Allowed to return normally or terminate test using t.FailNow().
  144. Errorf(message string, args ...interface{})
  145. }
  146. // LoggerReporter combines Logger and Reporter interfaces.
  147. type LoggerReporter interface {
  148. Logger
  149. Reporter
  150. }
  151. // DefaultRequestFactory is the default RequestFactory implementation which just
  152. // calls http.NewRequest.
  153. type DefaultRequestFactory struct{}
  154. // NewRequest implements RequestFactory.NewRequest.
  155. func (DefaultRequestFactory) NewRequest(
  156. method, urlStr string, body io.Reader) (*http.Request, error) {
  157. return http.NewRequest(method, urlStr, body)
  158. }
  159. // New returns a new Expect object.
  160. //
  161. // baseURL specifies URL to prepended to all request. My be empty. If non-empty,
  162. // trailing slash is allowed but not required and is appended automatically.
  163. //
  164. // New is a shorthand for WithConfig. It uses:
  165. // - CompactPrinter as Printer, with testing.TB as Logger
  166. // - AssertReporter as Reporter
  167. // - DefaultRequestFactory as RequestFactory
  168. //
  169. // Client is set to a default client with a non-nil Jar:
  170. // &http.Client{
  171. // Jar: httpexpect.NewJar(),
  172. // }
  173. //
  174. // Example:
  175. // func TestSomething(t *testing.T) {
  176. // e := httpexpect.New(t, "http://example.com/")
  177. //
  178. // e.GET("/path").
  179. // Expect().
  180. // Status(http.StatusOK)
  181. // }
  182. func New(t LoggerReporter, baseURL string) *Expect {
  183. return WithConfig(Config{
  184. BaseURL: baseURL,
  185. Reporter: NewAssertReporter(t),
  186. Printers: []Printer{
  187. NewCompactPrinter(t),
  188. },
  189. })
  190. }
  191. // WithConfig returns a new Expect object with given config.
  192. //
  193. // Reporter should not be nil.
  194. //
  195. // If RequestFactory is nil, it's set to a DefaultRequestFactory instance.
  196. //
  197. // If Client is nil, it's set to a default client with a non-nil Jar:
  198. // &http.Client{
  199. // Jar: httpexpect.NewJar(),
  200. // }
  201. //
  202. // Example:
  203. // func TestSomething(t *testing.T) {
  204. // e := httpexpect.WithConfig(httpexpect.Config{
  205. // BaseURL: "http://example.com/",
  206. // Client: &http.Client{
  207. // Transport: httpexpect.NewBinder(myHandler()),
  208. // Jar: httpexpect.NewJar(),
  209. // },
  210. // Reporter: httpexpect.NewAssertReporter(t),
  211. // Printers: []httpexpect.Printer{
  212. // httpexpect.NewCurlPrinter(t),
  213. // httpexpect.NewDebugPrinter(t, true)
  214. // },
  215. // })
  216. //
  217. // e.GET("/path").
  218. // Expect().
  219. // Status(http.StatusOK)
  220. // }
  221. func WithConfig(config Config) *Expect {
  222. if config.Reporter == nil {
  223. panic("config.Reporter is nil")
  224. }
  225. if config.RequestFactory == nil {
  226. config.RequestFactory = DefaultRequestFactory{}
  227. }
  228. if config.Client == nil {
  229. config.Client = &http.Client{
  230. Jar: NewJar(),
  231. }
  232. }
  233. return &Expect{
  234. config: config,
  235. builders: nil,
  236. }
  237. }
  238. // NewJar returns a new http.CookieJar.
  239. //
  240. // Returned jar is implemented in net/http/cookiejar. PublicSuffixList is
  241. // implemented in golang.org/x/net/publicsuffix.
  242. //
  243. // Note that this jar ignores cookies when request url is empty.
  244. func NewJar() http.CookieJar {
  245. jar, err := cookiejar.New(&cookiejar.Options{
  246. PublicSuffixList: publicsuffix.List,
  247. })
  248. if err != nil {
  249. panic(err)
  250. }
  251. return jar
  252. }
  253. // Builder returns a copy of Expect instance with given builder attached to it.
  254. // Returned copy contains all previously attached builders plus a new one.
  255. // Builders are invoked from Request method, after constructing every new request.
  256. //
  257. // Example:
  258. // e := httpexpect.New(t, "http://example.com")
  259. //
  260. // token := e.POST("/login").WithForm(Login{"ford", "betelgeuse7"}).
  261. // Expect().
  262. // Status(http.StatusOK).JSON().Object().Value("token").String().Raw()
  263. //
  264. // auth := e.Builder(func (req *httpexpect.Request) {
  265. // req.WithHeader("Authorization", "Bearer "+token)
  266. // })
  267. //
  268. // auth.GET("/restricted").
  269. // Expect().
  270. // Status(http.StatusOK)
  271. func (e *Expect) Builder(builder func(*Request)) *Expect {
  272. ret := *e
  273. ret.builders = append(e.builders, builder)
  274. return &ret
  275. }
  276. // Request returns a new Request object.
  277. // Arguments a similar to NewRequest.
  278. // After creating request, all builders attached to Expect object are invoked.
  279. // See Builder.
  280. func (e *Expect) Request(method, path string, pathargs ...interface{}) *Request {
  281. req := NewRequest(e.config, method, path, pathargs...)
  282. for _, builder := range e.builders {
  283. builder(req)
  284. }
  285. return req
  286. }
  287. // OPTIONS is a shorthand for e.Request("OPTIONS", path, pathargs...).
  288. func (e *Expect) OPTIONS(path string, pathargs ...interface{}) *Request {
  289. return e.Request("OPTIONS", path, pathargs...)
  290. }
  291. // HEAD is a shorthand for e.Request("HEAD", path, pathargs...).
  292. func (e *Expect) HEAD(path string, pathargs ...interface{}) *Request {
  293. return e.Request("HEAD", path, pathargs...)
  294. }
  295. // GET is a shorthand for e.Request("GET", path, pathargs...).
  296. func (e *Expect) GET(path string, pathargs ...interface{}) *Request {
  297. return e.Request("GET", path, pathargs...)
  298. }
  299. // POST is a shorthand for e.Request("POST", path, pathargs...).
  300. func (e *Expect) POST(path string, pathargs ...interface{}) *Request {
  301. return e.Request("POST", path, pathargs...)
  302. }
  303. // PUT is a shorthand for e.Request("PUT", path, pathargs...).
  304. func (e *Expect) PUT(path string, pathargs ...interface{}) *Request {
  305. return e.Request("PUT", path, pathargs...)
  306. }
  307. // PATCH is a shorthand for e.Request("PATCH", path, pathargs...).
  308. func (e *Expect) PATCH(path string, pathargs ...interface{}) *Request {
  309. return e.Request("PATCH", path, pathargs...)
  310. }
  311. // DELETE is a shorthand for e.Request("DELETE", path, pathargs...).
  312. func (e *Expect) DELETE(path string, pathargs ...interface{}) *Request {
  313. return e.Request("DELETE", path, pathargs...)
  314. }
  315. // Value is a shorthand for NewValue(e.config.Reporter, value).
  316. func (e *Expect) Value(value interface{}) *Value {
  317. return NewValue(e.config.Reporter, value)
  318. }
  319. // Object is a shorthand for NewObject(e.config.Reporter, value).
  320. func (e *Expect) Object(value map[string]interface{}) *Object {
  321. return NewObject(e.config.Reporter, value)
  322. }
  323. // Array is a shorthand for NewArray(e.config.Reporter, value).
  324. func (e *Expect) Array(value []interface{}) *Array {
  325. return NewArray(e.config.Reporter, value)
  326. }
  327. // String is a shorthand for NewString(e.config.Reporter, value).
  328. func (e *Expect) String(value string) *String {
  329. return NewString(e.config.Reporter, value)
  330. }
  331. // Number is a shorthand for NewNumber(e.config.Reporter, value).
  332. func (e *Expect) Number(value float64) *Number {
  333. return NewNumber(e.config.Reporter, value)
  334. }
  335. // Boolean is a shorthand for NewBoolean(e.config.Reporter, value).
  336. func (e *Expect) Boolean(value bool) *Boolean {
  337. return NewBoolean(e.config.Reporter, value)
  338. }