Skip to content
This repository has been archived by the owner on Jul 15, 2021. It is now read-only.

Commit

Permalink
Implemented the POST /trends endpoint, and added tests for it
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesMessinger committed Oct 8, 2017
1 parent 4f86549 commit c8a7a29
Show file tree
Hide file tree
Showing 4 changed files with 233 additions and 13 deletions.
27 changes: 21 additions & 6 deletions lib/handlers/createTrend.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
'use strict';

const util = require('../util');
const trendStore = require('../trendStore');
const Response = require('../Response');
const Trend = require('../Trend');

module.exports = createTrend;

Expand All @@ -10,12 +13,24 @@ module.exports = createTrend;
* @param {object} request - The incoming HTTP request
* @returns {Promsie<object>} - Resolves with the HTTP response object
*/
function createTrend () {
return new Promise((resolve) => {
let id = '12345abcdef';
function createTrend (request) {
return new Promise((resolve, reject) => {
let user = util.findHeader(request.headers, 'X-API-Key');
let trend = Trend.parse(request.body);

resolve(Response.created({
id,
}));
if (trend.id) {
throw Response.badRequest('You can\'t set "id" value when creating a trend');
}

trendStore.create(user, trend)
.then(newTrend => {
newTrend = newTrend.toResource(request);
let response = Response.created(newTrend, {
Location: newTrend.links.self,
});

resolve(response);
})
.catch(reject);
});
}
4 changes: 2 additions & 2 deletions lib/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,10 @@ let validate = module.exports = {
throw Response.badRequest(`The "${field}" value is missing`);
}
if (value < minimumYear) {
throw Response.badRequest(`${value} was too long ago. Try something newer.`);
throw Response.badRequest(`The year ${value} was too long ago. Try something newer.`);
}
if (value > nextYear) {
throw Response.badRequest(`${value} is too far away. Stick with recent trends.`);
throw Response.badRequest(`The year ${value} is too far away. Stick with recent trends.`);
}

return value;
Expand Down
8 changes: 5 additions & 3 deletions test/fixtures/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,13 @@ let assert = module.exports = {
* Asserts that the given trends match the specified test data,
* even if the test data does not contain all fields.
*
* @param {object[]} trends - An array of trends that were returned by the API
* @param {object[]} testData - An array of trend objects to compare
* @param {object|object[]} trends - One or more trends that were returned by the API
* @param {object|object[]} testData - One or more trend objects to compare
*/
matchesTestData (trends, testData) {
trends.should.be.an('array').with.lengthOf(testData.length);
trends = Array.isArray(trends) ? trends : [trends];
testData = Array.isArray(testData) ? testData : [testData];
trends.should.have.lengthOf(testData.length);

// Delete any fields from the trends that don't exist on the test data
let trendsCopy = _.cloneDeep(trends);
Expand Down
207 changes: 205 additions & 2 deletions test/specs/createTrend.spec.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,222 @@
'use strict';

const apiGateway = require('../fixtures/apiGateway');
const assert = require('../fixtures/assert');

describe('Create new trends', () => {

it('can create a new trend', () => {
let newTrend = {
name: 'My new trend',
type: 'Some Type',
from: 2000,
to: 2001,
};

return apiGateway.post('/trends', newTrend)
return apiGateway
.auth('SomeUser')
.post('/trends', newTrend)
.then(res => {
res.should.be.an('object');
let trend = assert.isSuccessfulResponse(res, 201);
assert.isValidTrend(trend);
assert.matchesTestData(trend, newTrend);
trend.should.not.equal(newTrend);
});
});

it('should set the "Location" header to the trend\'s URL', () => {
let newTrend = {
name: 'Something trendy',
type: 'test',
from: 1800,
to: 1900,
};

return apiGateway
.auth('SomeUser')
.post('/trends', newTrend)
.then(res => {
let trend = assert.isSuccessfulResponse(res, 201);
assert.isValidTrend(trend);
res.headers.should.have.property('Location', trend.links.self);
});
});

it('should return an error if the trend has an ID', () => {
let newTrend = {
id: 'abcdef1234567890abcdef1234567890',
name: 'Trend with an ID',
type: 'test',
from: 1850,
to: 1850,
};

return apiGateway
.auth('SomeUser')
.post('/trends', newTrend)
.then(res => {
let body = assert.isErrorResponse(res, 400);
body.error.should.equal('BAD_REQUEST');
body.message.should.equal('You can\'t set "id" value when creating a trend');
});
});

it('should return an error if the trend has no name', () => {
let newTrend = {
type: 'test',
from: 1850,
to: 1850,
};

return apiGateway
.auth('SomeUser')
.post('/trends', newTrend)
.then(res => {
let body = assert.isErrorResponse(res, 400);
body.error.should.equal('BAD_REQUEST');
body.message.should.equal('The "name" value is missing');
});
});

it('should return an error if the name is too long', () => {
let newTrend = {
name: 'name'.repeat(50),
type: 'test',
from: 1850,
to: 1850,
};

return apiGateway
.auth('SomeUser')
.post('/trends', newTrend)
.then(res => {
let body = assert.isErrorResponse(res, 400);
body.error.should.equal('BAD_REQUEST');
body.message.should.equal('The "name" value is too long (50 characters max)');
});
});

it('should return an error if the trend has no type', () => {
let newTrend = {
name: 'Trend with no type',
from: 1850,
to: 1850,
};

return apiGateway
.auth('SomeUser')
.post('/trends', newTrend)
.then(res => {
let body = assert.isErrorResponse(res, 400);
body.error.should.equal('BAD_REQUEST');
body.message.should.equal('The "type" value is missing');
});
});

it('should return an error if the type is too long', () => {
let newTrend = {
name: 'Trend with loooong type',
type: 'type'.repeat(50),
from: 1850,
to: 1850,
};

return apiGateway
.auth('SomeUser')
.post('/trends', newTrend)
.then(res => {
let body = assert.isErrorResponse(res, 400);
body.error.should.equal('BAD_REQUEST');
body.message.should.equal('The "type" value is too long (50 characters max)');
});
});

it('should return an error if the trend has no year', () => {
let newTrend = {
name: 'Trend with no from year',
type: 'test type',
to: 1850,
};

return apiGateway
.auth('SomeUser')
.post('/trends', newTrend)
.then(res => {
let body = assert.isErrorResponse(res, 400);
body.error.should.equal('BAD_REQUEST');
body.message.should.equal('The "from" value is missing');
});
});

it('should return an error if the trend has a non-numeric year', () => {
let newTrend = {
name: 'Trend with a non-numeric year',
type: 'test type',
from: 1850,
to: 'hello world',
};

return apiGateway
.auth('SomeUser')
.post('/trends', newTrend)
.then(res => {
let body = assert.isErrorResponse(res, 400);
body.error.should.equal('BAD_REQUEST');
body.message.should.equal('The "to" value must be a number (a 4 digit year)');
});
});

it('should return an error if the year is too long ago', () => {
let newTrend = {
name: 'Trend with a really old year',
type: 'test type',
from: 123,
to: 456,
};

return apiGateway
.auth('SomeUser')
.post('/trends', newTrend)
.then(res => {
let body = assert.isErrorResponse(res, 400);
body.error.should.equal('BAD_REQUEST');
body.message.should.equal('The year 123 was too long ago. Try something newer.');
});
});

it('should return an error if the year is too far in the future', () => {
let newTrend = {
name: 'Trend with a future year',
type: 'test type',
from: 1980,
to: 2050,
};

return apiGateway
.auth('SomeUser')
.post('/trends', newTrend)
.then(res => {
let body = assert.isErrorResponse(res, 400);
body.error.should.equal('BAD_REQUEST');
body.message.should.equal('The year 2050 is too far away. Stick with recent trends.');
});
});

it('should return an error if the date range is reversed', () => {
let newTrend = {
name: 'Trend with bad date range',
type: 'test type',
from: 2001,
to: 1990,
};

return apiGateway
.auth('SomeUser')
.post('/trends', newTrend)
.then(res => {
let body = assert.isErrorResponse(res, 400);
body.error.should.equal('BAD_REQUEST');
body.message.should.equal('The "from" year can\'t be greater than the "to" year');
});
});

Expand Down

0 comments on commit c8a7a29

Please sign in to comment.