UNPKG

configurable-http-client

Version:

HTTP client that allows being configured for different status codes.

332 lines (260 loc) 10.3 kB
const originalHttpClient = require(`./httpClient`) const fetchMock = require(`fetch-mock`) describe(`httpClient`, function() { beforeEach(function() { this.fetch = fetchMock.sandbox() this.fetch.get(`/test`, "Hello") this.fetch.get(`/not_found`, {status: 404, body: "Not Found"}) this.httpClient = originalHttpClient.fetch(this.fetch) }.bind(this)) describe(`fetch`, function() { it(`uses global.fetch by default`, function() { this.httpClient.runRequest(`/test`) expect(this.fetch.lastCall()).not.toBe(undefined) }.bind(this)) it(`allows setting a new fetch()`, function() { const newFetch = fetchMock.sandbox().get(`/test2`, "Hello") this.httpClient = this.httpClient.fetch(newFetch) this.httpClient.runRequest(`/test2`) expect(newFetch.lastCall()).not.toBe(undefined) }.bind(this)) it(`doesn't override the original one`, function() { const newFetch = fetchMock.sandbox().get(`/test2`, "Hello") this.httpClient = this.httpClient.fetch(newFetch) this.httpClient.runRequest(`/test2`) expect(this.fetch.lastCall()).toBe(undefined) }.bind(this)) }.bind(this)) describe(`runRequest`, function() { it(`returns the response from fetch`, (done) => { this.httpClient.runRequest(`/test`) .then((resp) => { expect(resp.body.toString()).toEqual("Hello") done() }) .catch(done) }) }.bind(this)) it(`onResponse doesn't overwrite the original one`, (done) => { const oldSpy = jest.fn() const oldClient = this.httpClient.onResponse(oldSpy) const newSpy = jest.fn() const newClient = oldClient.onResponse(newSpy) newClient.runRequest(`/test`).then(function() { expect(oldSpy).not.toHaveBeenCalled() expect(newSpy).toHaveBeenCalled() done() }.bind(this)) }) it(`onSuccess doesn't overwrite the original one`, (done) => { const oldSpy = jest.fn() const oldClient = this.httpClient.onSuccess(oldSpy) const newSpy = jest.fn() const newClient = oldClient.onSuccess(newSpy) newClient.runRequest(`/test`).then(function() { expect(oldSpy).not.toHaveBeenCalled() expect(newSpy).toHaveBeenCalled() done() }.bind(this)) }) it(`onStatus doesn't overwrite the original one`, (done) => { const oldSpy = jest.fn() const oldClient = this.httpClient.onResponse(oldSpy) const newSpy = jest.fn() const newClient = oldClient.onStatus(404, newSpy) oldClient.runRequest(`/not_found`).then(function() { expect(newSpy).not.toHaveBeenCalled() expect(oldSpy).toHaveBeenCalled() done() }.bind(this)) }) describe(`on 200`, function() { it(`onResponse is called`, (done) => { const onResponse = jest.fn((resp) => { expect(resp.body.toString()).toEqual(`Hello`) }) const newClient = this.httpClient.onResponse(onResponse) newClient.runRequest(`/test`).then(function() { expect(onResponse).toHaveBeenCalled() done() }.bind(this)) }) it(`gives precedence to onSuccess over onResponse`, (done) => { const onResponse = jest.fn() const onErrorResponse = jest.fn() const onSuccess = jest.fn((resp) => { expect(resp.body.toString()).toEqual(`Hello`) }) const newClient = this.httpClient .onResponse(onResponse) .onErrorResponse(onErrorResponse) .onSuccess(onSuccess) newClient.runRequest(`/test`).then(function() { expect(onResponse).not.toHaveBeenCalled() expect(onErrorResponse).not.toHaveBeenCalled() expect(onSuccess).toHaveBeenCalled() done() }.bind(this)) }) }.bind(this)) describe(`on 400`, function() { it(`onResponse is called`, (done) => { const onResponse = jest.fn((resp) => { expect(resp.body.toString()).toEqual(`Not Found`) }) const newClient = this.httpClient.onResponse(onResponse) newClient.runRequest(`/not_found`).then(function() { expect(onResponse).toHaveBeenCalled() done() }.bind(this)) }) it(`gives precedence to onErrorResponse over onResponse`, (done) => { const onResponse = jest.fn() const onSuccess = jest.fn() const onErrorResponse = jest.fn((resp) => { expect(resp.body.toString()).toEqual(`Not Found`) }) const newClient = this.httpClient .onResponse(onResponse) .onErrorResponse(onErrorResponse) .onSuccess(onSuccess) newClient.runRequest(`/not_found`).then(function() { expect(onResponse).not.toHaveBeenCalled() expect(onSuccess).not.toHaveBeenCalled() expect(onErrorResponse).toHaveBeenCalled() done() }.bind(this)) }) it(`gives precedence to onStatus(404) over onErrorResponse`, (done) => { const onResponse = jest.fn() const onSuccess = jest.fn() const onErrorResponse = jest.fn() const on403 = jest.fn() const on404 = jest.fn((resp) => { expect(resp.body.toString()).toEqual(`Not Found`) }) const newClient = this.httpClient .onResponse(onResponse) .onErrorResponse(onErrorResponse) .onStatus(403, on403) .onStatus(404, on404) .onSuccess(onSuccess) newClient.runRequest(`/not_found`).then(function() { expect(onResponse).not.toHaveBeenCalled() expect(onSuccess).not.toHaveBeenCalled() expect(onErrorResponse).not.toHaveBeenCalled() expect(on403).not.toHaveBeenCalled() expect(on404).toHaveBeenCalled() done() }.bind(this)) }) }.bind(this)) it(`executes the onBeforeRun function before running the request`, (done) => { const someDynamicContent = (n) => ++n const beforeRunCallback = (httpClient) => { return httpClient.requestOptions({ headers: { 'some-header': someDynamicContent(0) } }) } this.fetch.get(`/assert_options`, (path, opts) => { return new Promise((resolve) => { expect(opts).toEqual({headers: {'some-header': 1}}) resolve(`Some body`) done() }) }) this.httpClient.onBeforeRun(beforeRunCallback).runRequest(`/assert_options`) }) it(`allows POST`, (done) => { this.fetch.post(`/post`, "Hello") this.httpClient.runRequest(`/post`, { method: `POST` }).then(function() { expect(this.fetch.called(`/post`)).toBe(true) done() }.bind(this)) }) it(`allows passing an object as json_body`, (done) => { this.fetch.post(`/post`, (path, opts) => { expect(opts.body).toEqual(`{"a":1}`) expect(opts.headers[`Content-Type`]).toEqual(`application/json; charset=utf-8`) return 200 }) const opts = { method: `POST`, json_body: {a: 1} } this.httpClient.runRequest(`/post`, opts).then(function() { expect(this.fetch.called(`/post`)).toBe(true) done() }.bind(this)) }) it(`allows passing a header`, (done) => { this.fetch.post(`/post`, (path, opts) => { expect(opts.headers['testHeader']).toEqual('TEST-HEADER') expect(opts.headers['newHeader']).toEqual('NEW-HEADER') return 200 }) const opts = { method: `POST`, headers: {testHeader: 'TEST-HEADER'} } this.httpClient.headers({newHeader: 'NEW-HEADER'}).runRequest(`/post`, opts).then(function() { expect(this.fetch.called(`/post`)).toBe(true) done() }.bind(this)) }) it(`allows passing a context`, (done) => { this.fetch.post(`/post`, () => { return 200 }) this.httpClient.onSuccess((response, context) => { expect(context).toEqual({firstContext: 'FIRST-CONTEXT', secondContext: 'SECOND-CONTEXT' }) done() }).context({firstContext: 'FIRST-CONTEXT'}).context({secondContext: 'SECOND-CONTEXT'}).runRequest(`/post`, {method: `POST`}) }) it(`allows setting the request before the callbacks with request()`, (done) => { this.httpClient.request(`/test`).onStatus(200, function() { done() }).run() }) it(`allows setting the request options before the callbacks`, (done) => { const options = {credentials: `same-origin`, headers: {}} this.fetch.get(`/assert_options`, (path, opts) => { return new Promise((resolve) => { expect(opts).toEqual(options) resolve(`Some body`) done() }) }) this.httpClient .requestOptions(options) .runRequest(`/assert_options`) }) it(`allows clearing callbacks passing null`, (done) => { const onSuccess = jest.fn() const on200 = jest.fn() const newClient = this.httpClient .onSuccess(onSuccess) .onStatus(200, on200) .onStatus(200, null) newClient.runRequest(`/test`).then(function() { expect(on200).not.toHaveBeenCalled() expect(onSuccess).toHaveBeenCalled() done() }.bind(this)) }) describe(`onConnectionError`, function() { it(`allows defining behavior on connection error`, function() { expect.assertions(1) this.fetch.get(`/connection_error`, function() { throw `Connection Error`}) const newClient = this.httpClient .onConnectionError((err) => { expect(err).toEqual(`Connection Error`) }) .request(`/connection_error`) newClient.run() }.bind(this)) it(`doesn't catch errors in other callbacks`, (done) => { expect.assertions(1) this.fetch.get(`/connection_error`, function() { throw `Connection Error`}) const newClient = this.httpClient .onSuccess((resp) => { throw `Expected error` }) .onConnectionError((err) => { throw `Unexpected error` }) .request(`/test`) newClient.run().catch((err) => { expect(err).toEqual(`Expected error`) done() }) }) it(`lets the error go through as default behavior`, (done) => { expect.assertions(1) this.fetch.get(`/connection_error`, function() { throw `Connection Error`}) this.httpClient.runRequest(`/connection_error`).catch((err) => { expect(err).toEqual(`Connection Error`) done() }) }) it.skip(`is respecful with the hyerarchy`, function() {}) }.bind(this)) it.skip(`allows reading the parsed_body`, function() {}) it.skip(`allows passing query params as a parameter`, function() {}) })