From 629a84355a95f0f4509681b9416f0776805c9f14 Mon Sep 17 00:00:00 2001 From: Dmitry Demyankov Date: Tue, 16 Feb 2016 11:38:43 +0100 Subject: [PATCH 1/6] refactoring unit tests, work in progress --- src/__tests__/expectations/get-accounts.js | 24 ++ src/__tests__/expectations/get-instrument.js | 24 ++ src/__tests__/expectations/index.js | 9 + src/__tests__/expectations/ping.js | 20 ++ src/__tests__/index.test.2.js | 228 +++++++++++++++++ src/__tests__/index.test.back.js | 236 +++++++++++++++++ src/__tests__/index.test.js | 255 ++++--------------- test/test-helper.js | 55 +++- test/tests.webpack.js | 9 +- 9 files changed, 646 insertions(+), 214 deletions(-) create mode 100644 src/__tests__/expectations/get-accounts.js create mode 100644 src/__tests__/expectations/get-instrument.js create mode 100644 src/__tests__/expectations/index.js create mode 100644 src/__tests__/expectations/ping.js create mode 100644 src/__tests__/index.test.2.js create mode 100644 src/__tests__/index.test.back.js diff --git a/src/__tests__/expectations/get-accounts.js b/src/__tests__/expectations/get-accounts.js new file mode 100644 index 0000000..80cb056 --- /dev/null +++ b/src/__tests__/expectations/get-accounts.js @@ -0,0 +1,24 @@ +import api from '../../index'; + +export default { + conditions: { + request: [ + api.get, + ['/api/2/accounts'], + ], + response: [ + 'GET', + '/api/2/accounts', + [401, { 'Content-Type': 'application/json; charset=UTF-8' }, JSON.stringify({ code: 'NEXT_INVALID_SESSION' })], + ], + }, + expected: { + url: '/api/2/accounts', + headers: { 'Accept': 'application/json' }, + method: 'get', + credentials: true, + body: undefined, + status: 401, + data: { code: 'NEXT_INVALID_SESSION' }, + }, +}; diff --git a/src/__tests__/expectations/get-instrument.js b/src/__tests__/expectations/get-instrument.js new file mode 100644 index 0000000..0ac77c3 --- /dev/null +++ b/src/__tests__/expectations/get-instrument.js @@ -0,0 +1,24 @@ +import api from '../../index'; + +export default { + conditions: { + request: [ + api.get, + ['/api/2/instruments/{instrument_id}?positions={positions}', { instrument_id: 123, positions: [456, 789], accno: 987 }, { 'Accept-Language': 'sv' }], + ], + response: [ + 'GET', + '/api/2/instruments/123?positions=456%2C789&accno=987', + [200, { 'Content-Type': 'application/json; charset=UTF-8' }, JSON.stringify({ instrument_id: 123 })], + ], + }, + expected: { + url: `/api/2/instruments/123?positions=${encodeURIComponent('456,789')}&accno=987`, + headers: { 'Accept-Language': 'sv', 'Accept': 'application/json' }, + method: 'get', + credentials: true, + body: undefined, + status: 200, + data: { instrument_id: 123 }, + }, +}; diff --git a/src/__tests__/expectations/index.js b/src/__tests__/expectations/index.js new file mode 100644 index 0000000..646b5af --- /dev/null +++ b/src/__tests__/expectations/index.js @@ -0,0 +1,9 @@ +import getInstrument from './get-instrument'; +import getAccounts from './get-accounts'; +import ping from './ping'; + +export default { + getInstrument, + getAccounts, + ping, +}; diff --git a/src/__tests__/expectations/ping.js b/src/__tests__/expectations/ping.js new file mode 100644 index 0000000..2a2e94d --- /dev/null +++ b/src/__tests__/expectations/ping.js @@ -0,0 +1,20 @@ +import api from '../../index'; + +export default { + conditions: { + request: [ + api.get, + ['/api/2/ping'], + ], + response: [ + 'GET', + '/api/2/ping', + [200, {}, 'pong'], + ], + }, + expected: { + url: '/api/2/ping', + status: 200, + data: 'pong', + }, +}; diff --git a/src/__tests__/index.test.2.js b/src/__tests__/index.test.2.js new file mode 100644 index 0000000..3c0ca10 --- /dev/null +++ b/src/__tests__/index.test.2.js @@ -0,0 +1,228 @@ +import 'test-helper'; +import { expect } from 'chai'; +import { get, post, put, del } from './../index'; + +describe('next-api', () => { + const ntag = 'qwerty-12345-6789'; + + let sandbox; + let promise; + let response; + let fetchSpy; + + beforeEach(() => { + initSandbox(); + initResponses(); + initSpies(); + }); + + afterEach(() => sandbox.restore()); + + function initSandbox() { + sandbox = sinon.sandbox.create(); + sandbox.useFakeTimers(); + sandbox.useFakeServer(); + sandbox.server.respondImmediately = true; + } + + function initResponses() { + sandbox.server.respondWith('/next/2/accounts', JSON.stringify([{ accno: 123 }])); + sandbox.server.respondWith('/next/2/accounts/123', JSON.stringify({ accno: 123 })); + sandbox.server.respondWith('/next/2/accounts/456', [401, {}, '']); + sandbox.server.respondWith('/next/2/instruments/123?positions=456,789&accno=987', JSON.stringify({ instrument_id: 123 })); + sandbox.server.respondWith('/next/2/accounts/123', JSON.stringify({ accno: 123 })); + sandbox.server.respondWith('GET', '/next/2/user/settings/foo', + [204, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, '']); + sandbox.server.respondWith('POST', '/next/2/user/settings/bar', + [200, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, JSON.stringify([{ key: 'bar', value: { bar: 'bar' }}])]); + sandbox.server.respondWith('PUT', '/next/2/user/settings/bar', + [200, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, JSON.stringify([{ key: 'bar', value: { bar: 'bar' }}])]); + sandbox.server.respondWith('DELETE', '/next/2/user/settings/bar', + [200, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, '']); + sandbox.server.respondWith('/next/2/news?days=0', JSON.stringify([{ news_id: 1 }])); + } + + function initSpies() { + fetchSpy = sandbox.spy(window, 'fetch'); + } + + function settle(method, url, params, headers) { + return function settlePromise() { + promise = method(url, params, headers) + .then(res => response = res) + .catch(res => response = res); + sandbox.clock.tick(1000); + }; + } + + function expectUrl(url) { + expect(fetchSpy.args[0][0]).to.equal(url); + } + + function expectHeaders(headers) { + expect(fetchSpy.args[0][1].headers).to.deep.equal(headers); + } + + describe('URL', () => { + describe('when url is invalid', () => + it('should throw an error', () => expect(() => get('')).to.throw(Error))); + + describe('when path parameters are missing', () => + it('should throw an error', () => expect(() => get('/next/2/accounts/{accno}')).to.throw(Error))); + + describe('when path parameters are required', () => { + beforeEach(settle(get, '/next/2/accounts/{accno}', { accno: 123 })); + + it('should fetch with expected url', (done) => { + expectUrl('/next/2/accounts/123'); + done(); + }); + }); + + describe('when path parameters are not required', () => { + beforeEach(settle(get, '/next/2/accounts')); + + it('should fetch with expected url', (done) => { + expectUrl('/next/2/accounts'); + done(); + }); + }); + + describe('when path and query parameters are provided', () => { + beforeEach(settle(get, '/next/2/instruments/{instrument_id}', { instrument_id: 123, positions: [456, 789], accno: 987 })); + + it('should fetch with expected url', (done) => { + expectUrl('/next/2/instruments/123?positions=' + encodeURIComponent('456,789') + '&accno=987'); + done(); + }); + }); + + describe('when path contains query parameters', () => { + beforeEach(settle(get, '/next/2/instruments/{instrument_id}?positions={positions}', { instrument_id: 123, positions: [456, 789], accno: 987 })); + + it('should fetch with expected url', (done) => { + expectUrl('/next/2/instruments/123?positions=' + encodeURIComponent('456,789') + '&accno=987'); + done(); + }); + }); + }); + + describe('promise', () => { + describe('when HTTP request succeeded', () => { + beforeEach(settle(get, '/next/2/accounts')); + + it('should resolve promise', (done) => { + /*eslint-disable */ + expect(promise).should.be.fulfilled; + /*eslint-enable */ + done(); + }); + }); + + describe('when HTTP request fails', () => { + beforeEach(settle(get, '/next/2/accounts/{accno}', { accno: 456 })); + + it('should reject promise', (done) => { + /*eslint-disable */ + expect(promise).should.be.rejected; + /*eslint-enable */ + done(); + }); + + it('should set response status', (done) => { + expect(response.status).to.equal(401); + done(); + }); + }); + }); + + describe('get', () => { + describe('accounts', () => { + beforeEach(settle(get, '/next/2/accounts/{accno}', { accno: 123 }, { 'Accept-Language': 'sv' })); + + it('should set expected headers', () => expectHeaders({ Accept: 'application/json', 'Accept-Language': 'sv' })); + it('should set method \'get\'', () => expect(fetchSpy.args[0][1].method).to.equal('get')); + it('should include credentials', () => expect(fetchSpy.args[0][1].credentials).to.equal('include')); + it('should not set body', () => expect(fetchSpy.args[0][1].body).to.be.undefined); + it('should return expected status', () => expect(response.status).to.equal(200)); + it('should return expected response data', () => expect(response.data).to.deep.equal({ accno: 123 })); + }); + + describe('news', () => { + beforeEach(settle(get, '/next/2/news?days={days}', { days: 0 })); + + it('should return expected status', () => expect(response.status).to.equal(200)); + it('should return expected response data', () => expect(response.data).to.deep.equal([{ news_id: 1 }])); + }); + + describe('settings', () => { + beforeEach(settle(get, '/next/2/user/settings/{foo}', { foo: 'foo' })); + + it('should return expected status', () => expect(response.status).to.equal(204)); + it('should return expected response data', () => expect(response.data).to.be.undefined); + }); + }); + + describe('post', () => { + beforeEach(settle(get, '/next/2/user/settings/{key}', { key: 'foo' }, { 'Accept-Language': 'sv' })); + + describe('when parameters are missing', () => { + beforeEach(settle(post, '/next/2/user/settings/{key}', { key: 'bar' }, { 'Accept-Language': 'sv' })); + it('should set empty POST body', () => expect(fetchSpy.args[1][1].body).to.equal('')); + }); + + describe('when parameters are provided', () => { + beforeEach(settle(post, '/next/2/user/settings/{key}', { key: 'bar', value: { bar: 'bar' }}, { 'Accept-Language': 'sv' })); + it('should set POST body', () => expect(fetchSpy.args[1][1].body).to.deep.equal('value=' + encodeURIComponent(JSON.stringify({ bar: 'bar' })))); + }); + + describe('when making POST request', () => { + beforeEach(settle(post, '/next/2/user/settings/{key}', { key: 'bar', value: { bar: 'bar' }}, { 'Accept-Language': 'sv' })); + + it('should set expected headers', () => + expect(fetchSpy.args[1][1].headers).to.deep.equal( + { 'Content-type': 'application/x-www-form-urlencoded', Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); + it('should set method \'post\'', () => expect(fetchSpy.args[1][1].method).to.equal('post')); + it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); + }); + + describe('when making POST request with custom Content-type header', () => { + beforeEach(settle(post, '/next/2/user/lists/{list_id}/{instrument_id}', + { list_id: 1, instrument_id: 101}, { 'Accept-Language': 'sv', 'Content-type': 'application/json' })); + + it('should set expected headers', () => + expect(fetchSpy.args[1][1].headers).to.deep.equal( + { 'Content-type': 'application/json', Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); + it('should set method \'post\'', () => expect(fetchSpy.args[1][1].method).to.equal('post')); + it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); + }); + }); + + describe('put', () => { + beforeEach(() => { + settle(get, '/next/2/user/settings/{key}', { key: 'foo' }, { 'Accept-Language': 'sv' })(); + settle(put, '/next/2/user/settings/{key}', { key: 'bar', value: { bar: 'bar' }}, { 'Accept-Language': 'sv' })(); + }); + + it('should set ntag header', () => + expect(fetchSpy.args[1][1].headers).to.deep.equal( + { 'Content-type': 'application/x-www-form-urlencoded', Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); + it('should set PUT body', () => expect(fetchSpy.args[1][1].body).to.deep.equal('value=' + encodeURIComponent(JSON.stringify({ bar: 'bar' })))); + it('should set method \'put\'', () => expect(fetchSpy.args[1][1].method).to.equal('put')); + it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); + }); + + describe('delete', () => { + beforeEach(() => { + settle(get, '/next/2/user/settings/{key}', { key: 'foo' }, { 'Accept-Language': 'sv' })(); + settle(del, '/next/2/user/settings/{key}', { key: 'bar' }, { 'Accept-Language': 'sv' })(); + }); + + it('should set ntag header', () => + expect(fetchSpy.args[1][1].headers).to.deep.equal( + { Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); + it('should not set body', () => expect(fetchSpy.args[1][1].body).to.be.undefined); + it('should set method \'delete\'', () => expect(fetchSpy.args[1][1].method).to.equal('delete')); + it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); + }); +}); diff --git a/src/__tests__/index.test.back.js b/src/__tests__/index.test.back.js new file mode 100644 index 0000000..4c5b4af --- /dev/null +++ b/src/__tests__/index.test.back.js @@ -0,0 +1,236 @@ +import 'test-helper'; +import { expect } from 'chai'; +import { get, post, put, del } from './../index'; + +describe.skip('next-api', () => { + const ntag = 'qwerty-12345-6789'; + + let sandbox; + let promise; + let response; + let fetchSpy; + + beforeEach(() => { + initSandbox(); + initResponses(); + initSpies(); + }); + + afterEach(() => sandbox.restore()); + + function initSandbox() { + sandbox = sinon.sandbox.create(); + sandbox.useFakeTimers(); + sandbox.useFakeServer(); + sandbox.server.respondImmediately = true; + } + + function initResponses() { + sandbox.server.respondWith('/next/2/accounts', JSON.stringify([{ accno: 123 }])); + sandbox.server.respondWith('/next/2/accounts/123', JSON.stringify({ accno: 123 })); + sandbox.server.respondWith('/next/2/accounts/456', [401, {}, '']); + sandbox.server.respondWith('/next/2/instruments/123?positions=456,789&accno=987', JSON.stringify({ instrument_id: 123 })); + sandbox.server.respondWith('/next/2/accounts/123', JSON.stringify({ accno: 123 })); + sandbox.server.respondWith('GET', '/next/2/user/settings/foo', + [204, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, '']); + sandbox.server.respondWith('POST', '/next/2/user/settings/bar', + [200, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, JSON.stringify([{ key: 'bar', value: { bar: 'bar' }}])]); + sandbox.server.respondWith('PUT', '/next/2/user/settings/bar', + [200, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, JSON.stringify([{ key: 'bar', value: { bar: 'bar' }}])]); + sandbox.server.respondWith('DELETE', '/next/2/user/settings/bar', + [200, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, '']); + sandbox.server.respondWith('/next/2/news?days=0', JSON.stringify([{ news_id: 1 }])); + sandbox.server.respondWith('/next/2/ping', 'pong'); + } + + function initSpies() { + fetchSpy = sandbox.spy(window, 'fetch'); + } + + function settle(method, url, params, headers) { + return function settlePromise() { + promise = method(url, params, headers) + .then(res => response = res) + .catch(res => response = res); + sandbox.clock.tick(1000); + }; + } + + function expectUrl(url) { + expect(fetchSpy.args[0][0]).to.equal(url); + } + + function expectHeaders(headers) { + expect(fetchSpy.args[0][1].headers).to.deep.equal(headers); + } + + describe('URL', () => { + describe('when url is invalid', () => + it('should throw an error', () => expect(() => get('')).to.throw(Error))); + + describe('when path parameters are missing', () => + it('should throw an error', () => expect(() => get('/next/2/accounts/{accno}')).to.throw(Error))); + + describe('when path parameters are required', () => { + beforeEach(settle(get, '/next/2/accounts/{accno}', { accno: 123 })); + + it('should fetch with expected url', (done) => { + expectUrl('/next/2/accounts/123'); + done(); + }); + }); + + describe('when path parameters are not required', () => { + beforeEach(settle(get, '/next/2/accounts')); + + it('should fetch with expected url', (done) => { + expectUrl('/next/2/accounts'); + done(); + }); + }); + + describe('when path and query parameters are provided', () => { + beforeEach(settle(get, '/next/2/instruments/{instrument_id}', { instrument_id: 123, positions: [456, 789], accno: 987 })); + + it('should fetch with expected url', (done) => { + expectUrl('/next/2/instruments/123?positions=' + encodeURIComponent('456,789') + '&accno=987'); + done(); + }); + }); + + describe('when path contains query parameters', () => { + beforeEach(settle(get, '/next/2/instruments/{instrument_id}?positions={positions}', { instrument_id: 123, positions: [456, 789], accno: 987 })); + + it('should fetch with expected url', (done) => { + expectUrl('/next/2/instruments/123?positions=' + encodeURIComponent('456,789') + '&accno=987'); + done(); + }); + }); + }); + + describe('promise', () => { + describe('when HTTP request succeeded', () => { + beforeEach(settle(get, '/next/2/accounts')); + + it('should resolve promise', (done) => { + /*eslint-disable */ + expect(promise).should.be.fulfilled; + /*eslint-enable */ + done(); + }); + }); + + describe('when HTTP request fails', () => { + beforeEach(settle(get, '/next/2/accounts/{accno}', { accno: 456 })); + + it('should reject promise', (done) => { + /*eslint-disable */ + expect(promise).should.be.rejected; + /*eslint-enable */ + done(); + }); + + it('should set response status', (done) => { + expect(response.status).to.equal(401); + done(); + }); + }); + }); + + describe('get', () => { + describe('accounts', () => { + beforeEach(settle(get, '/next/2/accounts/{accno}', { accno: 123 }, { 'Accept-Language': 'sv' })); + + it('should set expected headers', () => expectHeaders({ Accept: 'application/json', 'Accept-Language': 'sv' })); + it('should set method \'get\'', () => expect(fetchSpy.args[0][1].method).to.equal('get')); + it('should include credentials', () => expect(fetchSpy.args[0][1].credentials).to.equal('include')); + it('should not set body', () => expect(fetchSpy.args[0][1].body).to.be.undefined); + it('should return expected status', () => expect(response.status).to.equal(200)); + it('should return expected response data', () => expect(response.data).to.deep.equal({ accno: 123 })); + }); + + describe('news', () => { + beforeEach(settle(get, '/next/2/news?days={days}', { days: 0 })); + + it('should return expected status', () => expect(response.status).to.equal(200)); + it('should return expected response data', () => expect(response.data).to.deep.equal([{ news_id: 1 }])); + }); + + describe('settings', () => { + beforeEach(settle(get, '/next/2/user/settings/{foo}', { foo: 'foo' })); + + it('should return expected status', () => expect(response.status).to.equal(204)); + it('should return expected response data', () => expect(response.data).to.be.undefined); + }); + }); + + describe('post', () => { + beforeEach(settle(get, '/next/2/user/settings/{key}', { key: 'foo' }, { 'Accept-Language': 'sv' })); + + describe('when parameters are missing', () => { + beforeEach(settle(post, '/next/2/user/settings/{key}', { key: 'bar' }, { 'Accept-Language': 'sv' })); + it('should set empty POST body', () => expect(fetchSpy.args[1][1].body).to.equal('')); + }); + + describe('when parameters are provided', () => { + beforeEach(settle(post, '/next/2/user/settings/{key}', { key: 'bar', value: { bar: 'bar' }}, { 'Accept-Language': 'sv' })); + it('should set POST body', () => expect(fetchSpy.args[1][1].body).to.deep.equal('value=' + encodeURIComponent(JSON.stringify({ bar: 'bar' })))); + }); + + describe('when making POST request', () => { + beforeEach(settle(post, '/next/2/user/settings/{key}', { key: 'bar', value: { bar: 'bar' }}, { 'Accept-Language': 'sv' })); + + it('should set expected headers', () => + expect(fetchSpy.args[1][1].headers).to.deep.equal( + { 'Content-type': 'application/x-www-form-urlencoded', Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); + it('should set method \'post\'', () => expect(fetchSpy.args[1][1].method).to.equal('post')); + it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); + }); + + describe('when making POST request with custom Content-type header', () => { + beforeEach(settle(post, '/next/2/user/lists/{list_id}/{instrument_id}', + { list_id: 1, instrument_id: 101}, { 'Accept-Language': 'sv', 'Content-type': 'application/json' })); + + it('should set expected headers', () => + expect(fetchSpy.args[1][1].headers).to.deep.equal( + { 'Content-type': 'application/json', Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); + it('should set method \'post\'', () => expect(fetchSpy.args[1][1].method).to.equal('post')); + it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); + }); + }); + + describe('put', () => { + beforeEach(() => { + settle(get, '/next/2/user/settings/{key}', { key: 'foo' }, { 'Accept-Language': 'sv' })(); + settle(put, '/next/2/user/settings/{key}', { key: 'bar', value: { bar: 'bar' }}, { 'Accept-Language': 'sv' })(); + }); + + it('should set ntag header', () => + expect(fetchSpy.args[1][1].headers).to.deep.equal( + { 'Content-type': 'application/x-www-form-urlencoded', Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); + it('should set PUT body', () => expect(fetchSpy.args[1][1].body).to.deep.equal('value=' + encodeURIComponent(JSON.stringify({ bar: 'bar' })))); + it('should set method \'put\'', () => expect(fetchSpy.args[1][1].method).to.equal('put')); + it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); + }); + + describe('delete', () => { + beforeEach(() => { + settle(get, '/next/2/user/settings/{key}', { key: 'foo' }, { 'Accept-Language': 'sv' })(); + settle(del, '/next/2/user/settings/{key}', { key: 'bar' }, { 'Accept-Language': 'sv' })(); + }); + + it('should set ntag header', () => + expect(fetchSpy.args[1][1].headers).to.deep.equal( + { Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); + it('should not set body', () => expect(fetchSpy.args[1][1].body).to.be.undefined); + it('should set method \'delete\'', () => expect(fetchSpy.args[1][1].method).to.equal('delete')); + it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); + }); + + describe('when Content-type is not JSON', () => { + beforeEach(settle(get, '/next/2/ping')); + + it('should return expected status', () => expect(response.status).to.equal(200)); + it('should return expected response data', () => expect(response.data).to.equal('pong')); + }); +}); diff --git a/src/__tests__/index.test.js b/src/__tests__/index.test.js index 3c0ca10..7c5f095 100644 --- a/src/__tests__/index.test.js +++ b/src/__tests__/index.test.js @@ -1,228 +1,59 @@ -import 'test-helper'; -import { expect } from 'chai'; -import { get, post, put, del } from './../index'; - -describe('next-api', () => { - const ntag = 'qwerty-12345-6789'; - - let sandbox; - let promise; - let response; - let fetchSpy; - - beforeEach(() => { - initSandbox(); - initResponses(); - initSpies(); - }); - - afterEach(() => sandbox.restore()); - - function initSandbox() { - sandbox = sinon.sandbox.create(); - sandbox.useFakeTimers(); - sandbox.useFakeServer(); - sandbox.server.respondImmediately = true; - } - - function initResponses() { - sandbox.server.respondWith('/next/2/accounts', JSON.stringify([{ accno: 123 }])); - sandbox.server.respondWith('/next/2/accounts/123', JSON.stringify({ accno: 123 })); - sandbox.server.respondWith('/next/2/accounts/456', [401, {}, '']); - sandbox.server.respondWith('/next/2/instruments/123?positions=456,789&accno=987', JSON.stringify({ instrument_id: 123 })); - sandbox.server.respondWith('/next/2/accounts/123', JSON.stringify({ accno: 123 })); - sandbox.server.respondWith('GET', '/next/2/user/settings/foo', - [204, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, '']); - sandbox.server.respondWith('POST', '/next/2/user/settings/bar', - [200, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, JSON.stringify([{ key: 'bar', value: { bar: 'bar' }}])]); - sandbox.server.respondWith('PUT', '/next/2/user/settings/bar', - [200, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, JSON.stringify([{ key: 'bar', value: { bar: 'bar' }}])]); - sandbox.server.respondWith('DELETE', '/next/2/user/settings/bar', - [200, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, '']); - sandbox.server.respondWith('/next/2/news?days=0', JSON.stringify([{ news_id: 1 }])); - } - - function initSpies() { - fetchSpy = sandbox.spy(window, 'fetch'); - } - - function settle(method, url, params, headers) { - return function settlePromise() { - promise = method(url, params, headers) - .then(res => response = res) - .catch(res => response = res); - sandbox.clock.tick(1000); - }; - } - - function expectUrl(url) { - expect(fetchSpy.args[0][0]).to.equal(url); - } - - function expectHeaders(headers) { - expect(fetchSpy.args[0][1].headers).to.deep.equal(headers); - } - - describe('URL', () => { - describe('when url is invalid', () => - it('should throw an error', () => expect(() => get('')).to.throw(Error))); +import { initSandBox, respondWith, execute, expectations } from 'test-helper'; +import tests from './expectations'; - describe('when path parameters are missing', () => - it('should throw an error', () => expect(() => get('/next/2/accounts/{accno}')).to.throw(Error))); - - describe('when path parameters are required', () => { - beforeEach(settle(get, '/next/2/accounts/{accno}', { accno: 123 })); - - it('should fetch with expected url', (done) => { - expectUrl('/next/2/accounts/123'); - done(); - }); - }); - - describe('when path parameters are not required', () => { - beforeEach(settle(get, '/next/2/accounts')); - - it('should fetch with expected url', (done) => { - expectUrl('/next/2/accounts'); - done(); - }); - }); - - describe('when path and query parameters are provided', () => { - beforeEach(settle(get, '/next/2/instruments/{instrument_id}', { instrument_id: 123, positions: [456, 789], accno: 987 })); - - it('should fetch with expected url', (done) => { - expectUrl('/next/2/instruments/123?positions=' + encodeURIComponent('456,789') + '&accno=987'); - done(); - }); - }); - - describe('when path contains query parameters', () => { - beforeEach(settle(get, '/next/2/instruments/{instrument_id}?positions={positions}', { instrument_id: 123, positions: [456, 789], accno: 987 })); - - it('should fetch with expected url', (done) => { - expectUrl('/next/2/instruments/123?positions=' + encodeURIComponent('456,789') + '&accno=987'); - done(); - }); - }); - }); - - describe('promise', () => { - describe('when HTTP request succeeded', () => { - beforeEach(settle(get, '/next/2/accounts')); - - it('should resolve promise', (done) => { - /*eslint-disable */ - expect(promise).should.be.fulfilled; - /*eslint-enable */ - done(); - }); - }); - - describe('when HTTP request fails', () => { - beforeEach(settle(get, '/next/2/accounts/{accno}', { accno: 456 })); - - it('should reject promise', (done) => { - /*eslint-disable */ - expect(promise).should.be.rejected; - /*eslint-enable */ - done(); - }); - - it('should set response status', (done) => { - expect(response.status).to.equal(401); - done(); - }); - }); - }); - - describe('get', () => { - describe('accounts', () => { - beforeEach(settle(get, '/next/2/accounts/{accno}', { accno: 123 }, { 'Accept-Language': 'sv' })); - - it('should set expected headers', () => expectHeaders({ Accept: 'application/json', 'Accept-Language': 'sv' })); - it('should set method \'get\'', () => expect(fetchSpy.args[0][1].method).to.equal('get')); - it('should include credentials', () => expect(fetchSpy.args[0][1].credentials).to.equal('include')); - it('should not set body', () => expect(fetchSpy.args[0][1].body).to.be.undefined); - it('should return expected status', () => expect(response.status).to.equal(200)); - it('should return expected response data', () => expect(response.data).to.deep.equal({ accno: 123 })); - }); - - describe('news', () => { - beforeEach(settle(get, '/next/2/news?days={days}', { days: 0 })); - - it('should return expected status', () => expect(response.status).to.equal(200)); - it('should return expected response data', () => expect(response.data).to.deep.equal([{ news_id: 1 }])); - }); +import api from '../index'; +import { expect } from 'chai'; - describe('settings', () => { - beforeEach(settle(get, '/next/2/user/settings/{foo}', { foo: 'foo' })); +function init(done, { request, response }) { + initSandBox.apply(this); + respondWith.call(this, response); + execute.apply(null, request) + .then(res => this.response = res, res => this.response = res) + .then(() => done()) + .catch(() => done()); +} - it('should return expected status', () => expect(response.status).to.equal(204)); - it('should return expected response data', () => expect(response.data).to.be.undefined); - }); - }); +function verifyExpectations(expected) { + Object.keys(expected) + .forEach(key => it(`should fetch with expected ${key}`, function() { + expectations[key].call(this, expected[key]); + })); +} - describe('post', () => { - beforeEach(settle(get, '/next/2/user/settings/{key}', { key: 'foo' }, { 'Accept-Language': 'sv' })); - - describe('when parameters are missing', () => { - beforeEach(settle(post, '/next/2/user/settings/{key}', { key: 'bar' }, { 'Accept-Language': 'sv' })); - it('should set empty POST body', () => expect(fetchSpy.args[1][1].body).to.equal('')); +function test({ conditions, expected }) { + return function() { + beforeEach(function(done) { + init.call(this, done, conditions); }); - describe('when parameters are provided', () => { - beforeEach(settle(post, '/next/2/user/settings/{key}', { key: 'bar', value: { bar: 'bar' }}, { 'Accept-Language': 'sv' })); - it('should set POST body', () => expect(fetchSpy.args[1][1].body).to.deep.equal('value=' + encodeURIComponent(JSON.stringify({ bar: 'bar' })))); + afterEach(function() { + this.sandbox.restore(); }); - describe('when making POST request', () => { - beforeEach(settle(post, '/next/2/user/settings/{key}', { key: 'bar', value: { bar: 'bar' }}, { 'Accept-Language': 'sv' })); + verifyExpectations.call(this, expected); + }; +} - it('should set expected headers', () => - expect(fetchSpy.args[1][1].headers).to.deep.equal( - { 'Content-type': 'application/x-www-form-urlencoded', Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); - it('should set method \'post\'', () => expect(fetchSpy.args[1][1].method).to.equal('post')); - it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); - }); +function testThrows(conditions) { + return function() { + conditions.forEach(condition => Object.keys(api).forEach(testMethodThrows(condition))); + }; +} - describe('when making POST request with custom Content-type header', () => { - beforeEach(settle(post, '/next/2/user/lists/{list_id}/{instrument_id}', - { list_id: 1, instrument_id: 101}, { 'Accept-Language': 'sv', 'Content-type': 'application/json' })); +function testMethodThrows(condition) { + return method => it(`should throw an error with ${method} and url '${condition}'`, + () => expect(() => api[method](condition)).to.throw(Error)); +} - it('should set expected headers', () => - expect(fetchSpy.args[1][1].headers).to.deep.equal( - { 'Content-type': 'application/json', Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); - it('should set method \'post\'', () => expect(fetchSpy.args[1][1].method).to.equal('post')); - it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); - }); - }); - - describe('put', () => { - beforeEach(() => { - settle(get, '/next/2/user/settings/{key}', { key: 'foo' }, { 'Accept-Language': 'sv' })(); - settle(put, '/next/2/user/settings/{key}', { key: 'bar', value: { bar: 'bar' }}, { 'Accept-Language': 'sv' })(); - }); +describe('api', function() { + const ntag = 'qwerty-12345-6789'; - it('should set ntag header', () => - expect(fetchSpy.args[1][1].headers).to.deep.equal( - { 'Content-type': 'application/x-www-form-urlencoded', Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); - it('should set PUT body', () => expect(fetchSpy.args[1][1].body).to.deep.equal('value=' + encodeURIComponent(JSON.stringify({ bar: 'bar' })))); - it('should set method \'put\'', () => expect(fetchSpy.args[1][1].method).to.equal('put')); - it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); - }); + describe('when url is invalid', testThrows([undefined, '', '/api/2/accounts/{accno}'])); + describe('when request succeeded', test(tests.getInstrument)); + describe('when request failed', test(tests.getAccounts)); + describe('when response is not JSON', test(tests.ping)); - describe('delete', () => { - beforeEach(() => { - settle(get, '/next/2/user/settings/{key}', { key: 'foo' }, { 'Accept-Language': 'sv' })(); - settle(del, '/next/2/user/settings/{key}', { key: 'bar' }, { 'Accept-Language': 'sv' })(); - }); + describe('when making POST request', function() { - it('should set ntag header', () => - expect(fetchSpy.args[1][1].headers).to.deep.equal( - { Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); - it('should not set body', () => expect(fetchSpy.args[1][1].body).to.be.undefined); - it('should set method \'delete\'', () => expect(fetchSpy.args[1][1].method).to.equal('delete')); - it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); }); }); diff --git a/test/test-helper.js b/test/test-helper.js index a812bfc..763f22e 100644 --- a/test/test-helper.js +++ b/test/test-helper.js @@ -1 +1,54 @@ -require('es5-shim'); // make phantomjs happy +import { expect } from 'chai'; + +export function initSandBox() { + this.sandbox = sinon.sandbox.create(); + this.sandbox.useFakeServer(); + this.sandbox.server.autoRespond = true; + this.fetchSpy = this.sandbox.spy(window, 'fetch'); +} + +export function respondWith(response) { + this.sandbox.server.respondWith.apply(this.sandbox.server, response); +} + +export function execute(method, request) { + return method.apply(null, request); +} + +export const expectations = { + url: expectUrl, + headers: expectHeaders, + method: expectMethod, + credentials: expectCredentials, + body: expectBody, + status: expectStatus, + data: expectData, +}; + +function expectUrl(url) { + expect(this.fetchSpy).to.have.been.calledWith(url); +} + +function expectHeaders(headers) { + expect(this.fetchSpy.args[0][1].headers).to.deep.equal(headers); +} + +function expectMethod(method) { + expect(this.fetchSpy.args[0][1].method).to.equal(method); +} + +function expectCredentials() { + expect(this.fetchSpy.args[0][1].credentials).to.equal('include'); +} + +function expectBody(body) { + expect(this.fetchSpy.args[0][1].body).to.deep.equal(body); +} + +function expectStatus(status) { + expect(this.response.status).to.equal(status); +} + +function expectData(data) { + expect(this.response.data).to.deep.equal(data); +} diff --git a/test/tests.webpack.js b/test/tests.webpack.js index 4645bcf..9905b9f 100644 --- a/test/tests.webpack.js +++ b/test/tests.webpack.js @@ -1,3 +1,10 @@ +// make phantomjs happy, polyfill .bind etc... +require('es5-shim'); + +var chai = require('chai'); +var sinonChai = require('sinon-chai'); +chai.use(sinonChai); + // --- Load all common js tests via webpack var context = require.context('./../src', true, /\.test\.js$/); -context.keys().forEach(context); \ No newline at end of file +context.keys().forEach(context); From 6ee4a44e99331c7ddac0619e39dc0bf1d1abca15 Mon Sep 17 00:00:00 2001 From: Dmitry Demyankov Date: Tue, 16 Feb 2016 11:50:02 +0100 Subject: [PATCH 2/6] locking dependencies versions --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index cec08c5..f59e01d 100644 --- a/package.json +++ b/package.json @@ -67,8 +67,8 @@ "webpack-dev-server": "^1.8.2" }, "dependencies": { - "es6-promise": "^2.3.0", - "isomorphic-fetch": "^2.1.1", - "lodash": "^3.10.0" + "es6-promise": "2.3.0", + "isomorphic-fetch": "2.1.1", + "lodash": "3.10.0" } } From 6fba55229ca35280380398a450f3bcb09886f4db Mon Sep 17 00:00:00 2001 From: Dmitry Demyankov Date: Tue, 16 Feb 2016 14:13:59 +0100 Subject: [PATCH 3/6] added expectEqual and expectDeepEqual functions for common assertions --- test/test-helper.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/test/test-helper.js b/test/test-helper.js index 763f22e..e46a5c3 100644 --- a/test/test-helper.js +++ b/test/test-helper.js @@ -30,25 +30,33 @@ function expectUrl(url) { } function expectHeaders(headers) { - expect(this.fetchSpy.args[0][1].headers).to.deep.equal(headers); + expectDeepEqual(headers, this.fetchSpy.args[0][1].headers); } function expectMethod(method) { - expect(this.fetchSpy.args[0][1].method).to.equal(method); + expectEqual(method, this.fetchSpy.args[0][1].method); } function expectCredentials() { - expect(this.fetchSpy.args[0][1].credentials).to.equal('include'); + expectEqual('include', this.fetchSpy.args[0][1].credentials); } function expectBody(body) { - expect(this.fetchSpy.args[0][1].body).to.deep.equal(body); + expectDeepEqual(body, this.fetchSpy.args[0][1].body); } function expectStatus(status) { - expect(this.response.status).to.equal(status); + expectEqual(status, this.response.status); } function expectData(data) { - expect(this.response.data).to.deep.equal(data); + expectDeepEqual(data, this.response.data); +} + +function expectEqual(expected, actual) { + expect(actual).to.equal(expected); +} + +function expectDeepEqual(expected, actual) { + expect(actual).to.deep.equal(expected); } From ccddbf81888a7f2cbd2f060be4e8c87ef3bf9e34 Mon Sep 17 00:00:00 2001 From: Dmitry Demyankov Date: Tue, 16 Feb 2016 15:09:14 +0100 Subject: [PATCH 4/6] Bug fixes: fixed incorrect setting of request body when making POST/PUT request with JSON payload Added unit tests --- src/__tests__/expectations/get-instrument.js | 5 +++- src/__tests__/expectations/index.js | 2 ++ .../expectations/post-user-settings.js | 27 +++++++++++++++++++ src/__tests__/index.test.js | 7 +---- src/index.js | 4 +-- 5 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 src/__tests__/expectations/post-user-settings.js diff --git a/src/__tests__/expectations/get-instrument.js b/src/__tests__/expectations/get-instrument.js index 0ac77c3..4cc103d 100644 --- a/src/__tests__/expectations/get-instrument.js +++ b/src/__tests__/expectations/get-instrument.js @@ -1,10 +1,13 @@ import api from '../../index'; +const params = { instrument_id: 123, positions: [456, 789], accno: 987 }; +const headers = { 'Accept-Language': 'sv' }; + export default { conditions: { request: [ api.get, - ['/api/2/instruments/{instrument_id}?positions={positions}', { instrument_id: 123, positions: [456, 789], accno: 987 }, { 'Accept-Language': 'sv' }], + ['/api/2/instruments/{instrument_id}?positions={positions}', params, headers], ], response: [ 'GET', diff --git a/src/__tests__/expectations/index.js b/src/__tests__/expectations/index.js index 646b5af..0ffbc1c 100644 --- a/src/__tests__/expectations/index.js +++ b/src/__tests__/expectations/index.js @@ -1,9 +1,11 @@ import getInstrument from './get-instrument'; import getAccounts from './get-accounts'; +import postUserSettings from './post-user-settings'; import ping from './ping'; export default { getInstrument, getAccounts, + postUserSettings, ping, }; diff --git a/src/__tests__/expectations/post-user-settings.js b/src/__tests__/expectations/post-user-settings.js new file mode 100644 index 0000000..a5d9cb3 --- /dev/null +++ b/src/__tests__/expectations/post-user-settings.js @@ -0,0 +1,27 @@ +import api from '../../index'; + +const params = { key: 1, settings: { widgets: [{ id: 1, name: 'winners/losers' }] }}; +const headers = { 'Content-type': 'application/json' }; + +export default { + conditions: { + request: [ + api.post, + ['/api/2/user/settings/{key}', params, headers], + ], + response: [ + 'POST', + '/api/2/user/settings/1', + [201, { 'Content-type': 'application/json; charset=UTF-8' }, JSON.stringify(params)], + ], + }, + expected: { + url: '/api/2/user/settings/1', + headers: { 'Content-type': 'application/json', Accept: 'application/json', ntag: 'NO_NTAG_RECEIVED_YET' }, + method: 'post', + credentials: true, + body: JSON.stringify({ settings: params.settings }), + status: 201, + data: params, + }, +}; diff --git a/src/__tests__/index.test.js b/src/__tests__/index.test.js index 7532c56..6594a35 100644 --- a/src/__tests__/index.test.js +++ b/src/__tests__/index.test.js @@ -45,14 +45,9 @@ function testMethodThrows(condition) { } describe('api', function() { - const ntag = 'qwerty-12345-6789'; - describe('when url is invalid', testThrows([undefined, '', '/api/2/accounts/{accno}'])); describe('when request succeeded', test(tests.getInstrument)); describe('when request failed', test(tests.getAccounts)); describe('when response is not JSON', test(tests.ping)); - - describe('when making POST request', function() { - - }); + describe('when making POST request with JSON payload', test(tests.postUserSettings)); }); diff --git a/src/index.js b/src/index.js index 6e5a41c..48d7438 100644 --- a/src/index.js +++ b/src/index.js @@ -83,9 +83,9 @@ function httpFetch(options) { validateUrl(options.url); const path = buildPath(options.url, options.params); - const params = buildParams(omit(options.params, getPathParams(options.url))); + const params = omit(options.params, getPathParams(options.url)); - const query = hasQuery(options.method) ? params : undefined; + const query = hasQuery(options.method) ? buildParams(params) : undefined; const headers = buildHeaders(options.method, options.headers); const body = buildBody(options.method, params, headers); From 7b5730443097c6a31b9be90427e8e9006819a7b2 Mon Sep 17 00:00:00 2001 From: Dmitry Demyankov Date: Tue, 16 Feb 2016 15:26:17 +0100 Subject: [PATCH 5/6] Added tests for POST request with form-urlencoded content type Bug fixes in POST body implementation --- src/__tests__/expectations/index.js | 2 ++ src/__tests__/expectations/post-user-lists.js | 28 +++++++++++++++++++ src/__tests__/index.test.js | 1 + src/index.js | 2 +- 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/__tests__/expectations/post-user-lists.js diff --git a/src/__tests__/expectations/index.js b/src/__tests__/expectations/index.js index 0ffbc1c..6f8a935 100644 --- a/src/__tests__/expectations/index.js +++ b/src/__tests__/expectations/index.js @@ -1,11 +1,13 @@ import getInstrument from './get-instrument'; import getAccounts from './get-accounts'; import postUserSettings from './post-user-settings'; +import postUserLists from './post-user-lists'; import ping from './ping'; export default { getInstrument, getAccounts, postUserSettings, + postUserLists, ping, }; diff --git a/src/__tests__/expectations/post-user-lists.js b/src/__tests__/expectations/post-user-lists.js new file mode 100644 index 0000000..845c534 --- /dev/null +++ b/src/__tests__/expectations/post-user-lists.js @@ -0,0 +1,28 @@ +import api from '../../index'; + +const name = 'abc'; +const params = { name }; +const response = { id: 1, name } + +export default { + conditions: { + request: [ + api.post, + ['/api/2/user/lists', params], + ], + response: [ + 'POST', + '/api/2/user/lists', + [201, { 'Content-type': 'application/json; charset=UTF-8' }, JSON.stringify(response)], + ], + }, + expected: { + url: '/api/2/user/lists', + headers: { 'Content-type': 'application/x-www-form-urlencoded', Accept: 'application/json', ntag: 'NO_NTAG_RECEIVED_YET' }, + method: 'post', + credentials: true, + body: `name=${name}`, + status: 201, + data: response, + }, +}; diff --git a/src/__tests__/index.test.js b/src/__tests__/index.test.js index 6594a35..410a377 100644 --- a/src/__tests__/index.test.js +++ b/src/__tests__/index.test.js @@ -49,5 +49,6 @@ describe('api', function() { describe('when request succeeded', test(tests.getInstrument)); describe('when request failed', test(tests.getAccounts)); describe('when response is not JSON', test(tests.ping)); + describe('when making POST request', test(tests.postUserLists)); describe('when making POST request with JSON payload', test(tests.postUserSettings)); }); diff --git a/src/index.js b/src/index.js index 48d7438..5912285 100644 --- a/src/index.js +++ b/src/index.js @@ -198,7 +198,7 @@ function buildBody(method, params, headers) { return; } - return isJsonContentType(headers) ? JSON.stringify(params) : params.join('&'); + return isJsonContentType(headers) ? JSON.stringify(params) : buildParams(params).join('&'); } function isJsonContentType(headers) { From d3a3ba29135ee3c1a68db8d22f43eff6c617f21f Mon Sep 17 00:00:00 2001 From: Dmitry Demyankov Date: Tue, 16 Feb 2016 15:27:28 +0100 Subject: [PATCH 6/6] removed old tests --- src/__tests__/index.test.2.js | 228 ----------------------------- src/__tests__/index.test.back.js | 236 ------------------------------- 2 files changed, 464 deletions(-) delete mode 100644 src/__tests__/index.test.2.js delete mode 100644 src/__tests__/index.test.back.js diff --git a/src/__tests__/index.test.2.js b/src/__tests__/index.test.2.js deleted file mode 100644 index 3c0ca10..0000000 --- a/src/__tests__/index.test.2.js +++ /dev/null @@ -1,228 +0,0 @@ -import 'test-helper'; -import { expect } from 'chai'; -import { get, post, put, del } from './../index'; - -describe('next-api', () => { - const ntag = 'qwerty-12345-6789'; - - let sandbox; - let promise; - let response; - let fetchSpy; - - beforeEach(() => { - initSandbox(); - initResponses(); - initSpies(); - }); - - afterEach(() => sandbox.restore()); - - function initSandbox() { - sandbox = sinon.sandbox.create(); - sandbox.useFakeTimers(); - sandbox.useFakeServer(); - sandbox.server.respondImmediately = true; - } - - function initResponses() { - sandbox.server.respondWith('/next/2/accounts', JSON.stringify([{ accno: 123 }])); - sandbox.server.respondWith('/next/2/accounts/123', JSON.stringify({ accno: 123 })); - sandbox.server.respondWith('/next/2/accounts/456', [401, {}, '']); - sandbox.server.respondWith('/next/2/instruments/123?positions=456,789&accno=987', JSON.stringify({ instrument_id: 123 })); - sandbox.server.respondWith('/next/2/accounts/123', JSON.stringify({ accno: 123 })); - sandbox.server.respondWith('GET', '/next/2/user/settings/foo', - [204, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, '']); - sandbox.server.respondWith('POST', '/next/2/user/settings/bar', - [200, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, JSON.stringify([{ key: 'bar', value: { bar: 'bar' }}])]); - sandbox.server.respondWith('PUT', '/next/2/user/settings/bar', - [200, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, JSON.stringify([{ key: 'bar', value: { bar: 'bar' }}])]); - sandbox.server.respondWith('DELETE', '/next/2/user/settings/bar', - [200, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, '']); - sandbox.server.respondWith('/next/2/news?days=0', JSON.stringify([{ news_id: 1 }])); - } - - function initSpies() { - fetchSpy = sandbox.spy(window, 'fetch'); - } - - function settle(method, url, params, headers) { - return function settlePromise() { - promise = method(url, params, headers) - .then(res => response = res) - .catch(res => response = res); - sandbox.clock.tick(1000); - }; - } - - function expectUrl(url) { - expect(fetchSpy.args[0][0]).to.equal(url); - } - - function expectHeaders(headers) { - expect(fetchSpy.args[0][1].headers).to.deep.equal(headers); - } - - describe('URL', () => { - describe('when url is invalid', () => - it('should throw an error', () => expect(() => get('')).to.throw(Error))); - - describe('when path parameters are missing', () => - it('should throw an error', () => expect(() => get('/next/2/accounts/{accno}')).to.throw(Error))); - - describe('when path parameters are required', () => { - beforeEach(settle(get, '/next/2/accounts/{accno}', { accno: 123 })); - - it('should fetch with expected url', (done) => { - expectUrl('/next/2/accounts/123'); - done(); - }); - }); - - describe('when path parameters are not required', () => { - beforeEach(settle(get, '/next/2/accounts')); - - it('should fetch with expected url', (done) => { - expectUrl('/next/2/accounts'); - done(); - }); - }); - - describe('when path and query parameters are provided', () => { - beforeEach(settle(get, '/next/2/instruments/{instrument_id}', { instrument_id: 123, positions: [456, 789], accno: 987 })); - - it('should fetch with expected url', (done) => { - expectUrl('/next/2/instruments/123?positions=' + encodeURIComponent('456,789') + '&accno=987'); - done(); - }); - }); - - describe('when path contains query parameters', () => { - beforeEach(settle(get, '/next/2/instruments/{instrument_id}?positions={positions}', { instrument_id: 123, positions: [456, 789], accno: 987 })); - - it('should fetch with expected url', (done) => { - expectUrl('/next/2/instruments/123?positions=' + encodeURIComponent('456,789') + '&accno=987'); - done(); - }); - }); - }); - - describe('promise', () => { - describe('when HTTP request succeeded', () => { - beforeEach(settle(get, '/next/2/accounts')); - - it('should resolve promise', (done) => { - /*eslint-disable */ - expect(promise).should.be.fulfilled; - /*eslint-enable */ - done(); - }); - }); - - describe('when HTTP request fails', () => { - beforeEach(settle(get, '/next/2/accounts/{accno}', { accno: 456 })); - - it('should reject promise', (done) => { - /*eslint-disable */ - expect(promise).should.be.rejected; - /*eslint-enable */ - done(); - }); - - it('should set response status', (done) => { - expect(response.status).to.equal(401); - done(); - }); - }); - }); - - describe('get', () => { - describe('accounts', () => { - beforeEach(settle(get, '/next/2/accounts/{accno}', { accno: 123 }, { 'Accept-Language': 'sv' })); - - it('should set expected headers', () => expectHeaders({ Accept: 'application/json', 'Accept-Language': 'sv' })); - it('should set method \'get\'', () => expect(fetchSpy.args[0][1].method).to.equal('get')); - it('should include credentials', () => expect(fetchSpy.args[0][1].credentials).to.equal('include')); - it('should not set body', () => expect(fetchSpy.args[0][1].body).to.be.undefined); - it('should return expected status', () => expect(response.status).to.equal(200)); - it('should return expected response data', () => expect(response.data).to.deep.equal({ accno: 123 })); - }); - - describe('news', () => { - beforeEach(settle(get, '/next/2/news?days={days}', { days: 0 })); - - it('should return expected status', () => expect(response.status).to.equal(200)); - it('should return expected response data', () => expect(response.data).to.deep.equal([{ news_id: 1 }])); - }); - - describe('settings', () => { - beforeEach(settle(get, '/next/2/user/settings/{foo}', { foo: 'foo' })); - - it('should return expected status', () => expect(response.status).to.equal(204)); - it('should return expected response data', () => expect(response.data).to.be.undefined); - }); - }); - - describe('post', () => { - beforeEach(settle(get, '/next/2/user/settings/{key}', { key: 'foo' }, { 'Accept-Language': 'sv' })); - - describe('when parameters are missing', () => { - beforeEach(settle(post, '/next/2/user/settings/{key}', { key: 'bar' }, { 'Accept-Language': 'sv' })); - it('should set empty POST body', () => expect(fetchSpy.args[1][1].body).to.equal('')); - }); - - describe('when parameters are provided', () => { - beforeEach(settle(post, '/next/2/user/settings/{key}', { key: 'bar', value: { bar: 'bar' }}, { 'Accept-Language': 'sv' })); - it('should set POST body', () => expect(fetchSpy.args[1][1].body).to.deep.equal('value=' + encodeURIComponent(JSON.stringify({ bar: 'bar' })))); - }); - - describe('when making POST request', () => { - beforeEach(settle(post, '/next/2/user/settings/{key}', { key: 'bar', value: { bar: 'bar' }}, { 'Accept-Language': 'sv' })); - - it('should set expected headers', () => - expect(fetchSpy.args[1][1].headers).to.deep.equal( - { 'Content-type': 'application/x-www-form-urlencoded', Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); - it('should set method \'post\'', () => expect(fetchSpy.args[1][1].method).to.equal('post')); - it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); - }); - - describe('when making POST request with custom Content-type header', () => { - beforeEach(settle(post, '/next/2/user/lists/{list_id}/{instrument_id}', - { list_id: 1, instrument_id: 101}, { 'Accept-Language': 'sv', 'Content-type': 'application/json' })); - - it('should set expected headers', () => - expect(fetchSpy.args[1][1].headers).to.deep.equal( - { 'Content-type': 'application/json', Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); - it('should set method \'post\'', () => expect(fetchSpy.args[1][1].method).to.equal('post')); - it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); - }); - }); - - describe('put', () => { - beforeEach(() => { - settle(get, '/next/2/user/settings/{key}', { key: 'foo' }, { 'Accept-Language': 'sv' })(); - settle(put, '/next/2/user/settings/{key}', { key: 'bar', value: { bar: 'bar' }}, { 'Accept-Language': 'sv' })(); - }); - - it('should set ntag header', () => - expect(fetchSpy.args[1][1].headers).to.deep.equal( - { 'Content-type': 'application/x-www-form-urlencoded', Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); - it('should set PUT body', () => expect(fetchSpy.args[1][1].body).to.deep.equal('value=' + encodeURIComponent(JSON.stringify({ bar: 'bar' })))); - it('should set method \'put\'', () => expect(fetchSpy.args[1][1].method).to.equal('put')); - it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); - }); - - describe('delete', () => { - beforeEach(() => { - settle(get, '/next/2/user/settings/{key}', { key: 'foo' }, { 'Accept-Language': 'sv' })(); - settle(del, '/next/2/user/settings/{key}', { key: 'bar' }, { 'Accept-Language': 'sv' })(); - }); - - it('should set ntag header', () => - expect(fetchSpy.args[1][1].headers).to.deep.equal( - { Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); - it('should not set body', () => expect(fetchSpy.args[1][1].body).to.be.undefined); - it('should set method \'delete\'', () => expect(fetchSpy.args[1][1].method).to.equal('delete')); - it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); - }); -}); diff --git a/src/__tests__/index.test.back.js b/src/__tests__/index.test.back.js deleted file mode 100644 index 4c5b4af..0000000 --- a/src/__tests__/index.test.back.js +++ /dev/null @@ -1,236 +0,0 @@ -import 'test-helper'; -import { expect } from 'chai'; -import { get, post, put, del } from './../index'; - -describe.skip('next-api', () => { - const ntag = 'qwerty-12345-6789'; - - let sandbox; - let promise; - let response; - let fetchSpy; - - beforeEach(() => { - initSandbox(); - initResponses(); - initSpies(); - }); - - afterEach(() => sandbox.restore()); - - function initSandbox() { - sandbox = sinon.sandbox.create(); - sandbox.useFakeTimers(); - sandbox.useFakeServer(); - sandbox.server.respondImmediately = true; - } - - function initResponses() { - sandbox.server.respondWith('/next/2/accounts', JSON.stringify([{ accno: 123 }])); - sandbox.server.respondWith('/next/2/accounts/123', JSON.stringify({ accno: 123 })); - sandbox.server.respondWith('/next/2/accounts/456', [401, {}, '']); - sandbox.server.respondWith('/next/2/instruments/123?positions=456,789&accno=987', JSON.stringify({ instrument_id: 123 })); - sandbox.server.respondWith('/next/2/accounts/123', JSON.stringify({ accno: 123 })); - sandbox.server.respondWith('GET', '/next/2/user/settings/foo', - [204, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, '']); - sandbox.server.respondWith('POST', '/next/2/user/settings/bar', - [200, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, JSON.stringify([{ key: 'bar', value: { bar: 'bar' }}])]); - sandbox.server.respondWith('PUT', '/next/2/user/settings/bar', - [200, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, JSON.stringify([{ key: 'bar', value: { bar: 'bar' }}])]); - sandbox.server.respondWith('DELETE', '/next/2/user/settings/bar', - [200, { 'Content-Type': 'application/json; charset=UTF-8', ntag: ntag }, '']); - sandbox.server.respondWith('/next/2/news?days=0', JSON.stringify([{ news_id: 1 }])); - sandbox.server.respondWith('/next/2/ping', 'pong'); - } - - function initSpies() { - fetchSpy = sandbox.spy(window, 'fetch'); - } - - function settle(method, url, params, headers) { - return function settlePromise() { - promise = method(url, params, headers) - .then(res => response = res) - .catch(res => response = res); - sandbox.clock.tick(1000); - }; - } - - function expectUrl(url) { - expect(fetchSpy.args[0][0]).to.equal(url); - } - - function expectHeaders(headers) { - expect(fetchSpy.args[0][1].headers).to.deep.equal(headers); - } - - describe('URL', () => { - describe('when url is invalid', () => - it('should throw an error', () => expect(() => get('')).to.throw(Error))); - - describe('when path parameters are missing', () => - it('should throw an error', () => expect(() => get('/next/2/accounts/{accno}')).to.throw(Error))); - - describe('when path parameters are required', () => { - beforeEach(settle(get, '/next/2/accounts/{accno}', { accno: 123 })); - - it('should fetch with expected url', (done) => { - expectUrl('/next/2/accounts/123'); - done(); - }); - }); - - describe('when path parameters are not required', () => { - beforeEach(settle(get, '/next/2/accounts')); - - it('should fetch with expected url', (done) => { - expectUrl('/next/2/accounts'); - done(); - }); - }); - - describe('when path and query parameters are provided', () => { - beforeEach(settle(get, '/next/2/instruments/{instrument_id}', { instrument_id: 123, positions: [456, 789], accno: 987 })); - - it('should fetch with expected url', (done) => { - expectUrl('/next/2/instruments/123?positions=' + encodeURIComponent('456,789') + '&accno=987'); - done(); - }); - }); - - describe('when path contains query parameters', () => { - beforeEach(settle(get, '/next/2/instruments/{instrument_id}?positions={positions}', { instrument_id: 123, positions: [456, 789], accno: 987 })); - - it('should fetch with expected url', (done) => { - expectUrl('/next/2/instruments/123?positions=' + encodeURIComponent('456,789') + '&accno=987'); - done(); - }); - }); - }); - - describe('promise', () => { - describe('when HTTP request succeeded', () => { - beforeEach(settle(get, '/next/2/accounts')); - - it('should resolve promise', (done) => { - /*eslint-disable */ - expect(promise).should.be.fulfilled; - /*eslint-enable */ - done(); - }); - }); - - describe('when HTTP request fails', () => { - beforeEach(settle(get, '/next/2/accounts/{accno}', { accno: 456 })); - - it('should reject promise', (done) => { - /*eslint-disable */ - expect(promise).should.be.rejected; - /*eslint-enable */ - done(); - }); - - it('should set response status', (done) => { - expect(response.status).to.equal(401); - done(); - }); - }); - }); - - describe('get', () => { - describe('accounts', () => { - beforeEach(settle(get, '/next/2/accounts/{accno}', { accno: 123 }, { 'Accept-Language': 'sv' })); - - it('should set expected headers', () => expectHeaders({ Accept: 'application/json', 'Accept-Language': 'sv' })); - it('should set method \'get\'', () => expect(fetchSpy.args[0][1].method).to.equal('get')); - it('should include credentials', () => expect(fetchSpy.args[0][1].credentials).to.equal('include')); - it('should not set body', () => expect(fetchSpy.args[0][1].body).to.be.undefined); - it('should return expected status', () => expect(response.status).to.equal(200)); - it('should return expected response data', () => expect(response.data).to.deep.equal({ accno: 123 })); - }); - - describe('news', () => { - beforeEach(settle(get, '/next/2/news?days={days}', { days: 0 })); - - it('should return expected status', () => expect(response.status).to.equal(200)); - it('should return expected response data', () => expect(response.data).to.deep.equal([{ news_id: 1 }])); - }); - - describe('settings', () => { - beforeEach(settle(get, '/next/2/user/settings/{foo}', { foo: 'foo' })); - - it('should return expected status', () => expect(response.status).to.equal(204)); - it('should return expected response data', () => expect(response.data).to.be.undefined); - }); - }); - - describe('post', () => { - beforeEach(settle(get, '/next/2/user/settings/{key}', { key: 'foo' }, { 'Accept-Language': 'sv' })); - - describe('when parameters are missing', () => { - beforeEach(settle(post, '/next/2/user/settings/{key}', { key: 'bar' }, { 'Accept-Language': 'sv' })); - it('should set empty POST body', () => expect(fetchSpy.args[1][1].body).to.equal('')); - }); - - describe('when parameters are provided', () => { - beforeEach(settle(post, '/next/2/user/settings/{key}', { key: 'bar', value: { bar: 'bar' }}, { 'Accept-Language': 'sv' })); - it('should set POST body', () => expect(fetchSpy.args[1][1].body).to.deep.equal('value=' + encodeURIComponent(JSON.stringify({ bar: 'bar' })))); - }); - - describe('when making POST request', () => { - beforeEach(settle(post, '/next/2/user/settings/{key}', { key: 'bar', value: { bar: 'bar' }}, { 'Accept-Language': 'sv' })); - - it('should set expected headers', () => - expect(fetchSpy.args[1][1].headers).to.deep.equal( - { 'Content-type': 'application/x-www-form-urlencoded', Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); - it('should set method \'post\'', () => expect(fetchSpy.args[1][1].method).to.equal('post')); - it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); - }); - - describe('when making POST request with custom Content-type header', () => { - beforeEach(settle(post, '/next/2/user/lists/{list_id}/{instrument_id}', - { list_id: 1, instrument_id: 101}, { 'Accept-Language': 'sv', 'Content-type': 'application/json' })); - - it('should set expected headers', () => - expect(fetchSpy.args[1][1].headers).to.deep.equal( - { 'Content-type': 'application/json', Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); - it('should set method \'post\'', () => expect(fetchSpy.args[1][1].method).to.equal('post')); - it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); - }); - }); - - describe('put', () => { - beforeEach(() => { - settle(get, '/next/2/user/settings/{key}', { key: 'foo' }, { 'Accept-Language': 'sv' })(); - settle(put, '/next/2/user/settings/{key}', { key: 'bar', value: { bar: 'bar' }}, { 'Accept-Language': 'sv' })(); - }); - - it('should set ntag header', () => - expect(fetchSpy.args[1][1].headers).to.deep.equal( - { 'Content-type': 'application/x-www-form-urlencoded', Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); - it('should set PUT body', () => expect(fetchSpy.args[1][1].body).to.deep.equal('value=' + encodeURIComponent(JSON.stringify({ bar: 'bar' })))); - it('should set method \'put\'', () => expect(fetchSpy.args[1][1].method).to.equal('put')); - it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); - }); - - describe('delete', () => { - beforeEach(() => { - settle(get, '/next/2/user/settings/{key}', { key: 'foo' }, { 'Accept-Language': 'sv' })(); - settle(del, '/next/2/user/settings/{key}', { key: 'bar' }, { 'Accept-Language': 'sv' })(); - }); - - it('should set ntag header', () => - expect(fetchSpy.args[1][1].headers).to.deep.equal( - { Accept: 'application/json', 'Accept-Language': 'sv', ntag: ntag })); - it('should not set body', () => expect(fetchSpy.args[1][1].body).to.be.undefined); - it('should set method \'delete\'', () => expect(fetchSpy.args[1][1].method).to.equal('delete')); - it('should include credentials', () => expect(fetchSpy.args[1][1].credentials).to.equal('include')); - }); - - describe('when Content-type is not JSON', () => { - beforeEach(settle(get, '/next/2/ping')); - - it('should return expected status', () => expect(response.status).to.equal(200)); - it('should return expected response data', () => expect(response.data).to.equal('pong')); - }); -});