680 lines
19 KiB
JavaScript
680 lines
19 KiB
JavaScript
|
var extend = require('util')._extend;
|
||
|
|
||
|
var expect = require('chai').expect;
|
||
|
var sinon = require('sinon');
|
||
|
var nock = require('nock');
|
||
|
var http = require('http');
|
||
|
var Promise = require('bluebird');
|
||
|
|
||
|
var Client = require('../src/Client');
|
||
|
var ArgumentError = require('../src/exceptions').ArgumentError;
|
||
|
|
||
|
var request = require('superagent');
|
||
|
|
||
|
var domain = 'http://domain.com';
|
||
|
var endpoint = '/endpoint';
|
||
|
|
||
|
|
||
|
module.exports = {
|
||
|
'Client': {
|
||
|
beforeEach:
|
||
|
function () {
|
||
|
this.client = new Client(domain + endpoint + '/:id');
|
||
|
},
|
||
|
|
||
|
'#constructor': {
|
||
|
'should require a URL as first parameter':
|
||
|
function () {
|
||
|
expect(Client).to.throw(ArgumentError);
|
||
|
},
|
||
|
|
||
|
'should not throw when a valid URL is provided':
|
||
|
function () {
|
||
|
var client = Client.bind(null, 'http://domain.com/endpoint/:id');
|
||
|
|
||
|
expect(client).to.not.throw(ArgumentError);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
'#getAll': {
|
||
|
beforeEach:
|
||
|
function () {
|
||
|
// Mock the REST resource endpoint.
|
||
|
this.nock = nock(domain).get(endpoint).reply(200, []);
|
||
|
},
|
||
|
|
||
|
afterEach:
|
||
|
function () {
|
||
|
nock.cleanAll();
|
||
|
},
|
||
|
|
||
|
'should be defined':
|
||
|
function () {
|
||
|
var getAll = this.client.getAll.bind(this.client);
|
||
|
|
||
|
expect(getAll).to.exist;
|
||
|
expect(getAll).to.be.a('Function');
|
||
|
},
|
||
|
|
||
|
'should return a promise':
|
||
|
function () {
|
||
|
var returnValue = this.client.getAll();
|
||
|
|
||
|
expect(returnValue).to.be.an.instanceOf(Promise);
|
||
|
},
|
||
|
|
||
|
'should accept a callback':
|
||
|
function (done) {
|
||
|
this.client.getAll({}, function (err, clients) {
|
||
|
if (err) return done(err);
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should perform a GET /endpoint request':
|
||
|
function () {
|
||
|
var request = null;
|
||
|
var endpoint = this.nock;
|
||
|
|
||
|
this.client.getAll({}, function (err, clients) {
|
||
|
expect(err).to.not.exist;
|
||
|
expect(endpoint.isDone()).to.be.true;
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should pass errors to the rejected promise':
|
||
|
function (done) {
|
||
|
nock.cleanAll();
|
||
|
this.nock = nock(domain).get(endpoint).replyWithError('Internal error');
|
||
|
|
||
|
this.client
|
||
|
.getAll()
|
||
|
.catch(function (err) {
|
||
|
expect(err).to.exist;
|
||
|
expect(err).to.be.an.instanceOf(Error);
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should pass the response of the API to the resolved promise':
|
||
|
function (done) {
|
||
|
nock.cleanAll();
|
||
|
this.nock = nock(domain)
|
||
|
.get(endpoint)
|
||
|
.reply(200, [{ id: 5, name: 'Test' }]);
|
||
|
|
||
|
this.client
|
||
|
.getAll()
|
||
|
.then(function (objects) {
|
||
|
expect(objects).to.be.an.instanceOf(Array);
|
||
|
expect(objects.length).to.equal(1);
|
||
|
expect(objects[0].name).to.equal('Test');
|
||
|
expect(objects[0].id).to.equal(5);
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should pass the given params in the query-string':
|
||
|
function (done) {
|
||
|
var params = {
|
||
|
first_name: 'john',
|
||
|
last_name: 'doe'
|
||
|
};
|
||
|
|
||
|
nock.cleanAll();
|
||
|
|
||
|
var request = nock(domain)
|
||
|
.get(endpoint)
|
||
|
.query(params)
|
||
|
.reply(200);
|
||
|
|
||
|
this.client
|
||
|
.getAll(params)
|
||
|
.then(function (objects) {
|
||
|
expect(request.isDone()).to.be.true;
|
||
|
done();
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
'#get': {
|
||
|
beforeEach:
|
||
|
function () {
|
||
|
this.data = { name: 'Test' };
|
||
|
this.successReq = nock(domain)
|
||
|
.get(endpoint + '/OK')
|
||
|
.reply(200, this.data);
|
||
|
this.errorReq = nock(domain)
|
||
|
.get(endpoint + '/FAIL')
|
||
|
.replyWithError({name: 'Unauthorized', message: 'Invalid token'});
|
||
|
},
|
||
|
|
||
|
afterEach:
|
||
|
function () {
|
||
|
nock.cleanAll();
|
||
|
},
|
||
|
|
||
|
'should be defined':
|
||
|
function () {
|
||
|
expect(this.client.get).to.exist;
|
||
|
expect(this.client.get).to.be.an.instanceOf(Function);
|
||
|
},
|
||
|
|
||
|
'should accept a callback':
|
||
|
function (done) {
|
||
|
this.client.get({ id: 'OK' }, done.bind(null, null));
|
||
|
},
|
||
|
|
||
|
'should return a promise when no callback is given':
|
||
|
function (done) {
|
||
|
var promise = this.client
|
||
|
.get({ id: 'OK' })
|
||
|
.then(done.bind(null, null))
|
||
|
.catch(done);
|
||
|
|
||
|
expect(promise).to.be.an.instanceOf(Promise);
|
||
|
},
|
||
|
|
||
|
'should perform a GET /endpoint/:id request':
|
||
|
function (done) {
|
||
|
var req = this.successReq;
|
||
|
|
||
|
this.client.get({ id: 'OK' }, function (err) {
|
||
|
if (err) return done(err);
|
||
|
|
||
|
expect(req.isDone()).to.be.true;
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should pass the response body to the callback':
|
||
|
function (done) {
|
||
|
var actual = null;
|
||
|
var expected = JSON.stringify(this.data);
|
||
|
|
||
|
this.client.get({ id: 'OK' }, function (err, response) {
|
||
|
if (err) return done(err);
|
||
|
|
||
|
actual = JSON.stringify(response);
|
||
|
|
||
|
expect(actual).to.equal(expected);
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should pass the response body to the promise':
|
||
|
function (done) {
|
||
|
var expected = JSON.stringify(this.data);
|
||
|
|
||
|
this.client
|
||
|
.get({ id: 'OK' })
|
||
|
.then(function (res) {
|
||
|
var response = JSON.stringify(res);
|
||
|
|
||
|
expect(response).to.equal(expected);
|
||
|
done();
|
||
|
})
|
||
|
.catch(done);
|
||
|
},
|
||
|
|
||
|
'should pass the errors to the callback':
|
||
|
function (done) {
|
||
|
this.client.get({ id: 'FAIL' }, function (err) {
|
||
|
expect(err).to.exist;
|
||
|
done();
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
'#post': {
|
||
|
beforeEach:
|
||
|
function () {
|
||
|
this.resource = {
|
||
|
name: 'Test coso'
|
||
|
};
|
||
|
|
||
|
// Mock the REST resource endpoint.
|
||
|
this.nock = nock(domain).post(endpoint).reply(201, this.resource);
|
||
|
},
|
||
|
|
||
|
afterEach:
|
||
|
function () {
|
||
|
nock.cleanAll();
|
||
|
},
|
||
|
|
||
|
'should be defined':
|
||
|
function () {
|
||
|
expect(this.client.post).to.exist;
|
||
|
expect(this.client.post).to.be.an.instanceOf(Function);
|
||
|
},
|
||
|
|
||
|
'should require a data object as first argument':
|
||
|
function () {
|
||
|
expect(this.client.post)
|
||
|
.to.throw(ArgumentError, 'Missing data object');
|
||
|
},
|
||
|
|
||
|
'should allow a callback as second argument':
|
||
|
function (done) {
|
||
|
var data = {
|
||
|
name: 'Test resource'
|
||
|
};
|
||
|
|
||
|
this.client.post({}, data, function () {
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should return a promise when no callback is provided':
|
||
|
function () {
|
||
|
var returnValue = this.client.post({}, { name: 'test' });
|
||
|
|
||
|
expect(returnValue).to.be.an.instanceOf(Promise);
|
||
|
},
|
||
|
|
||
|
'should perform a POST /endpoint request':
|
||
|
function (done) {
|
||
|
var expectedName = this.resource.name;
|
||
|
var request = this.nock;
|
||
|
|
||
|
this.client
|
||
|
.post({}, this.resource)
|
||
|
.then(function (data) {
|
||
|
expect(data).to.be.an.instanceOf(Object);
|
||
|
expect(data.name).to.equal(expectedName);
|
||
|
expect(request.isDone()).to.be.true;
|
||
|
done();
|
||
|
})
|
||
|
.catch(done);
|
||
|
},
|
||
|
|
||
|
'should pass any errors to the callback function':
|
||
|
function (done) {
|
||
|
nock.cleanAll();
|
||
|
this.nock = nock(domain).post(endpoint).replyWithError();
|
||
|
|
||
|
this.client.post({}, this.resource, function (err) {
|
||
|
expect(err).to.exist;
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should pass errors to the rejected promise':
|
||
|
function (done) {
|
||
|
nock.cleanAll();
|
||
|
this.nock = nock(domain).post(endpoint).reply(500);
|
||
|
|
||
|
this.client
|
||
|
.post(this.resource)
|
||
|
.catch(function (err) {
|
||
|
expect(err).to.exist;
|
||
|
done();
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
'#create': {
|
||
|
'should be defined':
|
||
|
function () {
|
||
|
expect(this.client.create).to.exist;
|
||
|
},
|
||
|
'should be an alias for #post':
|
||
|
function () {
|
||
|
expect(this.client.create).to.equal(this.client.post);
|
||
|
},
|
||
|
},
|
||
|
|
||
|
'#patch': {
|
||
|
beforeEach:
|
||
|
function () {
|
||
|
this.id = 1;
|
||
|
this.data = { name: 'Updated' };
|
||
|
this.response = extend({ id: this.id }, this.data);
|
||
|
|
||
|
this.nock = nock(domain)
|
||
|
.patch(endpoint + '/' + this.id)
|
||
|
.reply(200, this.response);
|
||
|
},
|
||
|
|
||
|
afterEach:
|
||
|
function () {
|
||
|
nock.cleanAll();
|
||
|
},
|
||
|
|
||
|
'should be defined':
|
||
|
function () {
|
||
|
expect(this.client.patch).to.exist;
|
||
|
},
|
||
|
|
||
|
'should accept a callback':
|
||
|
function (done) {
|
||
|
this.client.patch({ id: 1 }, {}, function () {
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should require an object as second argument':
|
||
|
function () {
|
||
|
var updateWithoutData = this.client.patch.bind(this.client, { id: this.id });
|
||
|
|
||
|
expect(updateWithoutData).to.throw(ArgumentError, 'The data must be an object');
|
||
|
},
|
||
|
|
||
|
'should perform a PATCH /endpoint/:id':
|
||
|
function (done) {
|
||
|
var request = this.nock;
|
||
|
|
||
|
this.client
|
||
|
.patch({ id: this.id }, this.data)
|
||
|
.then(function () {
|
||
|
expect(request.isDone()).to.be.true;
|
||
|
done();
|
||
|
})
|
||
|
.catch(done);
|
||
|
},
|
||
|
|
||
|
'should pass the body of the response to the resolved promise':
|
||
|
function (done) {
|
||
|
var expectedData = JSON.stringify(this.response);
|
||
|
|
||
|
this.client
|
||
|
.patch({ id: this.id }, this.data)
|
||
|
.then(function (data) {
|
||
|
expect(JSON.stringify(data)).to.equal(expectedData);
|
||
|
done();
|
||
|
})
|
||
|
},
|
||
|
|
||
|
'should pass the body of the response to the callback':
|
||
|
function (done) {
|
||
|
var expectedData = JSON.stringify(this.response);
|
||
|
|
||
|
this.client.patch({ id: this.id }, this.data, function (err, data) {
|
||
|
expect(JSON.stringify(data)).to.equal(expectedData);
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should pass any errors to the rejected promise':
|
||
|
function (done) {
|
||
|
nock.cleanAll();
|
||
|
this.nock = nock(domain).post(endpoint + '/' + this.id).reply(500);
|
||
|
|
||
|
this.client
|
||
|
.patch({ id: this.id }, this.data)
|
||
|
.catch(function (err) {
|
||
|
expect(err).to.exist;
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should pass any errors to the callback function':
|
||
|
function (done) {
|
||
|
nock.cleanAll();
|
||
|
this.nock = nock(domain).post(endpoint + '/' + this.id).reply(500);
|
||
|
|
||
|
this.client.patch({ id: this.id }, this.data, function (err) {
|
||
|
expect(err).to.exist;
|
||
|
done();
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
'#put': {
|
||
|
beforeEach:
|
||
|
function () {
|
||
|
this.id = 1;
|
||
|
this.data = { name: 'Updated' };
|
||
|
this.response = extend({ id: this.id }, this.data);
|
||
|
|
||
|
this.nock = nock(domain)
|
||
|
.put(endpoint + '/' + this.id)
|
||
|
.reply(200, this.response);
|
||
|
},
|
||
|
|
||
|
afterEach:
|
||
|
function () {
|
||
|
nock.cleanAll();
|
||
|
},
|
||
|
|
||
|
'should be defined':
|
||
|
function () {
|
||
|
expect(this.client.put).to.exist;
|
||
|
},
|
||
|
|
||
|
'should accept a callback':
|
||
|
function (done) {
|
||
|
this.client.put({ id: 1 }, {}, function () {
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should require an object as second argument':
|
||
|
function () {
|
||
|
var updateWithoutData = this.client.put.bind(this.client, { id: this.id });
|
||
|
|
||
|
expect(updateWithoutData).to.throw(ArgumentError, 'The data must be an object');
|
||
|
},
|
||
|
|
||
|
'should perform a PUT /endpoint/:id':
|
||
|
function (done) {
|
||
|
var request = this.nock;
|
||
|
|
||
|
this.client
|
||
|
.put({ id: this.id }, this.data)
|
||
|
.then(function () {
|
||
|
expect(request.isDone()).to.be.true;
|
||
|
done();
|
||
|
})
|
||
|
.catch(done);
|
||
|
},
|
||
|
|
||
|
'should pass the body of the response to the resolved promise':
|
||
|
function (done) {
|
||
|
var expectedData = JSON.stringify(this.response);
|
||
|
|
||
|
this.client
|
||
|
.put({ id: this.id }, this.data)
|
||
|
.then(function (data) {
|
||
|
expect(JSON.stringify(data)).to.equal(expectedData);
|
||
|
done();
|
||
|
})
|
||
|
},
|
||
|
|
||
|
'should pass the body of the response to the callback':
|
||
|
function (done) {
|
||
|
var expectedData = JSON.stringify(this.response);
|
||
|
|
||
|
this.client.put({ id: this.id }, this.data, function (err, data) {
|
||
|
expect(JSON.stringify(data)).to.equal(expectedData);
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should pass any errors to the rejected promise':
|
||
|
function (done) {
|
||
|
nock.cleanAll();
|
||
|
this.nock = nock(domain).post(endpoint + '/' + this.id).reply(500);
|
||
|
|
||
|
this.client
|
||
|
.put({ id: this.id }, this.data)
|
||
|
.catch(function (err) {
|
||
|
expect(err).to.exist;
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should pass any errors to the callback function':
|
||
|
function (done) {
|
||
|
nock.cleanAll();
|
||
|
this.nock = nock(domain).post(endpoint + '/' + this.id).reply(500);
|
||
|
|
||
|
this.client.put({ id: this.id }, this.data, function (err) {
|
||
|
expect(err).to.exist;
|
||
|
done();
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
'#update': {
|
||
|
'should be defined':
|
||
|
function () {
|
||
|
expect(this.client.update).to.exist;
|
||
|
},
|
||
|
'should be an alias for #put':
|
||
|
function () {
|
||
|
expect(this.client.update).to.equal(this.client.put);
|
||
|
},
|
||
|
},
|
||
|
|
||
|
'#delete': {
|
||
|
beforeEach:
|
||
|
function () {
|
||
|
this.id = 1;
|
||
|
this.nock = nock(domain).delete(endpoint + '/' + this.id).reply(200);
|
||
|
},
|
||
|
|
||
|
afterEach:
|
||
|
function () {
|
||
|
nock.cleanAll();
|
||
|
},
|
||
|
|
||
|
'should be defined':
|
||
|
function () {
|
||
|
expect(this.client.delete).to.exist;
|
||
|
expect(this.client.delete).to.be.an.instanceOf(Function);
|
||
|
},
|
||
|
|
||
|
'should require an id as first argument':
|
||
|
function () {
|
||
|
var deleteFunc = this.client.delete.bind(this.client);
|
||
|
|
||
|
expect(deleteFunc).to.throw;
|
||
|
},
|
||
|
|
||
|
'should accept a callback':
|
||
|
function (done) {
|
||
|
this.client.delete({ id: 1 }, function () {
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should return a promise if no callback is given':
|
||
|
function () {
|
||
|
var returnValue = this.client.delete({ id: 1 });
|
||
|
|
||
|
expect(returnValue).to.be.an.instanceOf(Promise);
|
||
|
},
|
||
|
|
||
|
'should pass any errors to the rejected promise':
|
||
|
function (done) {
|
||
|
nock.cleanAll();
|
||
|
var request = nock(domain).delete(endpoint + '/1').reply(500);
|
||
|
|
||
|
this.client.delete({ id: 1 }).catch(function (err) {
|
||
|
expect(err).to.exist;
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should pass any errors to the callback function':
|
||
|
function (done) {
|
||
|
nock.cleanAll();
|
||
|
var request = nock(domain).delete(endpoint + '/1').reply(500);
|
||
|
|
||
|
this.client.delete({ id: 1 }, function (err) {
|
||
|
expect(err).to.exist;
|
||
|
done();
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
'#request': {
|
||
|
beforeEach: function () {
|
||
|
nock.cleanAll();
|
||
|
},
|
||
|
|
||
|
'should convert the body of the request when case-conversion is enabled':
|
||
|
function (done) {
|
||
|
var options = { request: { body: { convertCase: 'snakeCase' }}};
|
||
|
var expected = { first_name: 'John', last_name: 'Doe' };
|
||
|
var client = this.client = new Client(domain + endpoint, options);
|
||
|
var request = nock(domain).post(endpoint, expected).reply(200);
|
||
|
|
||
|
client.create({ firstName: 'John', lastName: 'Doe' }, function (err) {
|
||
|
expect(request.isDone()).to.be.true;
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should convert the body of the response when case-conversion is enabled':
|
||
|
function (done) {
|
||
|
var options = { response: { body: { convertCase: 'camelCase' }}};
|
||
|
var id = 1;
|
||
|
var original = { first_name: 'John', last_name: 'Doe' };
|
||
|
var client = this.client = new Client(domain + endpoint + '/:id', options);
|
||
|
var request = nock(domain).get(endpoint + '/' + id).reply(200, original);
|
||
|
|
||
|
client
|
||
|
.get({ id: id })
|
||
|
.then(function(data) {
|
||
|
expect(data.first_name).to.be.undefined;
|
||
|
expect(data.last_name).to.be.undefined;
|
||
|
expect(data.firstName).to.equal('John');
|
||
|
expect(data.lastName).to.equal('Doe');
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should allow for a request customizer, that is called for each request, in constructor options':
|
||
|
function (done) {
|
||
|
|
||
|
var options = { request: { customizer : function(req, params) {
|
||
|
req.send({alias: 'John Doe'});
|
||
|
} }};
|
||
|
|
||
|
var expected = { first_name: 'Kevin', last_name: 'Spacey', alias: 'John Doe' };
|
||
|
var client = this.client = new Client(domain + endpoint, options);
|
||
|
var request = nock(domain).post(endpoint, expected).reply(200);
|
||
|
|
||
|
client.create({ first_name: 'Kevin', last_name: 'Spacey' }, function (err) {
|
||
|
expect(request.isDone()).to.be.true;
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should call a request customizer function given in params':
|
||
|
function (done) {
|
||
|
var expected = { first_name: 'John', last_name: 'Doe' };
|
||
|
var client = this.client = new Client(domain + endpoint);
|
||
|
var request = nock(domain, { reqheaders : {
|
||
|
'X-Fake': '1'
|
||
|
} }).post(endpoint, expected).reply(200);
|
||
|
|
||
|
var reqfn = function(req, params) { req.set('X-Fake', '1'); };
|
||
|
|
||
|
client.create({_requestCustomizer : reqfn}, { first_name: 'John', last_name: 'Doe' }, function (err) {
|
||
|
expect(request.isDone()).to.be.true;
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
'should use the proxy defined in the global settings':
|
||
|
function (done) {
|
||
|
var proxy = 'https://proxyserver.com';
|
||
|
var client = this.client = new Client(domain + endpoint, { proxy: proxy });
|
||
|
var req = nock(domain).get(endpoint).reply(200);
|
||
|
|
||
|
var spy = sinon.spy(request.Request.prototype, 'proxy');
|
||
|
|
||
|
client
|
||
|
.getAll()
|
||
|
.then(function(data) {
|
||
|
expect(request.Request.prototype.proxy.calledWithMatch(proxy)).to.be.true;
|
||
|
done();
|
||
|
});
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
};
|