From 7155d95f9d1dcc78bb1a1a16decff782323b7416 Mon Sep 17 00:00:00 2001 From: Sebastian Gierlinger Date: Wed, 26 Feb 2014 18:51:01 +0100 Subject: [PATCH] Add JSON API tests & cleanup first 10 % of #2124 - added initial version of JSON API tests - renamed error.errorCode to error.code - renamed tags.all to tags.browse for consistency --- Gruntfile.js | 5 +- core/server/api/db.js | 6 +- core/server/api/index.js | 2 +- core/server/api/posts.js | 25 ++++---- core/server/api/settings.js | 6 +- core/server/api/tags.js | 8 ++- core/server/api/users.js | 10 +--- core/server/apps/proxy.js | 2 +- core/server/controllers/frontend.js | 2 +- core/server/filters.js | 2 +- core/server/middleware/ghost-busboy.js | 2 +- core/server/routes/api.js | 2 +- .../integration/api/api_notifications_spec.js | 49 +++++++++++++++ core/test/integration/api/api_posts_spec.js | 59 +++++++++++++++++++ .../test/integration/api/api_settings_spec.js | 42 +++++++++++++ core/test/integration/api/api_tags_spec.js | 41 +++++++++++++ core/test/integration/api/api_users_spec.js | 41 +++++++++++++ .../integration/model/model_posts_spec.js | 12 ++-- core/test/utils/api.js | 3 +- 19 files changed, 276 insertions(+), 43 deletions(-) create mode 100644 core/test/integration/api/api_notifications_spec.js create mode 100644 core/test/integration/api/api_posts_spec.js create mode 100644 core/test/integration/api/api_settings_spec.js create mode 100644 core/test/integration/api/api_tags_spec.js create mode 100644 core/test/integration/api/api_users_spec.js diff --git a/Gruntfile.js b/Gruntfile.js index d1c60be155..ed5777da3d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -227,7 +227,10 @@ var path = require('path'), }, integration: { - src: ['core/test/integration/**/model*_spec.js'] + src: [ + 'core/test/integration/**/model*_spec.js', + 'core/test/integration/**/api*_spec.js' + ] }, api: { diff --git a/core/server/api/db.js b/core/server/api/db.js index 3d1bb83d09..5db32833ca 100644 --- a/core/server/api/db.js +++ b/core/server/api/db.js @@ -34,7 +34,7 @@ db = { * - If there is no path * - If the name doesn't have json in it */ - return when.reject({errorCode: 500, message: 'Please select a .json file to import.'}); + return when.reject({code: 500, message: 'Please select a .json file to import.'}); } return api.settings.read({ key: 'databaseVersion' }).then(function (setting) { @@ -99,7 +99,7 @@ db = { }).then(function () { return when.resolve({message: 'Posts, tags and other data successfully imported'}); }).otherwise(function importFailure(error) { - return when.reject({errorCode: 500, message: error.message || error}); + return when.reject({code: 500, message: error.message || error}); }); }, 'deleteAllContent': function () { @@ -107,7 +107,7 @@ db = { .then(function () { return when.resolve({message: 'Successfully deleted all content from your blog.'}); }, function (error) { - return when.reject({errorCode: 500, message: error.message || error}); + return when.reject({code: 500, message: error.message || error}); }); } }; diff --git a/core/server/api/index.js b/core/server/api/index.js index 67fc05b290..ccea747840 100644 --- a/core/server/api/index.js +++ b/core/server/api/index.js @@ -61,7 +61,7 @@ requestHandler = function (apiMethod) { } }); }, function (error) { - var errorCode = error.errorCode || 500, + var errorCode = error.code || 500, errorMsg = {error: _.isString(error) ? error : (_.isObject(error) ? error.message : 'Unknown API Error')}; res.json(errorCode, errorMsg); }); diff --git a/core/server/api/posts.js b/core/server/api/posts.js index b4be27853d..96ad75932c 100644 --- a/core/server/api/posts.js +++ b/core/server/api/posts.js @@ -1,8 +1,7 @@ var when = require('when'), _ = require('lodash'), dataProvider = require('../models'), - permissions = require('../permissions'), - canThis = permissions.canThis, + canThis = require('../permissions').canThis, filteredUserAttributes = require('./users').filteredAttributes, posts; @@ -15,7 +14,7 @@ posts = { options = options || {}; // **returns:** a promise for a page of posts in a json object - //return dataProvider.Post.findPage(options); + return dataProvider.Post.findPage(options).then(function (result) { var i = 0, omitted = result; @@ -43,7 +42,7 @@ posts = { omitted.user = _.omit(omitted.user, filteredUserAttributes); return omitted; } - return when.reject({errorCode: 404, message: 'Post not found'}); + return when.reject({code: 404, message: 'Post not found'}); }); }, @@ -53,7 +52,7 @@ posts = { if (slug) { return slug; } - return when.reject({errorCode: 500, message: 'Could not generate slug'}); + return when.reject({code: 500, message: 'Could not generate slug'}); }); }, @@ -63,7 +62,7 @@ posts = { edit: function edit(postData) { // **returns:** a promise for the resulting post in a json object if (!this.user) { - return when.reject({errorCode: 403, message: 'You do not have permission to edit this post.'}); + return when.reject({code: 403, message: 'You do not have permission to edit this post.'}); } var self = this; return canThis(self.user).edit.post(postData.id).then(function () { @@ -74,17 +73,17 @@ posts = { omitted.user = _.omit(omitted.user, filteredUserAttributes); return omitted; } - return when.reject({errorCode: 404, message: 'Post not found'}); + return when.reject({code: 404, message: 'Post not found'}); }).otherwise(function (error) { return dataProvider.Post.findOne({id: postData.id, status: 'all'}).then(function (result) { if (!result) { - return when.reject({errorCode: 404, message: 'Post not found'}); + return when.reject({code: 404, message: 'Post not found'}); } return when.reject({message: error.message}); }); }); }, function () { - return when.reject({errorCode: 403, message: 'You do not have permission to edit this post.'}); + return when.reject({code: 403, message: 'You do not have permission to edit this post.'}); }); }, @@ -94,13 +93,13 @@ posts = { add: function add(postData) { // **returns:** a promise for the resulting post in a json object if (!this.user) { - return when.reject({errorCode: 403, message: 'You do not have permission to add posts.'}); + return when.reject({code: 403, message: 'You do not have permission to add posts.'}); } return canThis(this.user).create.post().then(function () { return dataProvider.Post.add(postData); }, function () { - return when.reject({errorCode: 403, message: 'You do not have permission to add posts.'}); + return when.reject({code: 403, message: 'You do not have permission to add posts.'}); }); }, @@ -110,7 +109,7 @@ posts = { destroy: function destroy(args) { // **returns:** a promise for a json response with the id of the deleted post if (!this.user) { - return when.reject({errorCode: 403, message: 'You do not have permission to remove posts.'}); + return when.reject({code: 403, message: 'You do not have permission to remove posts.'}); } return canThis(this.user).remove.post(args.id).then(function () { @@ -121,7 +120,7 @@ posts = { }); }); }, function () { - return when.reject({errorCode: 403, message: 'You do not have permission to remove posts.'}); + return when.reject({code: 403, message: 'You do not have permission to remove posts.'}); }); } }; diff --git a/core/server/api/settings.js b/core/server/api/settings.js index f74d67d54f..ab8d4bb1ca 100644 --- a/core/server/api/settings.js +++ b/core/server/api/settings.js @@ -167,7 +167,7 @@ settings = { if (settingsCache) { return when(settingsCache[options.key]).then(function (setting) { if (!setting) { - return when.reject({errorCode: 404, message: 'Unable to find setting: ' + options.key}); + return when.reject({code: 404, message: 'Unable to find setting: ' + options.key}); } var res = {}; res.key = options.key; @@ -202,7 +202,7 @@ settings = { }).otherwise(function (error) { return dataProvider.Settings.read(key.key).then(function (result) { if (!result) { - return when.reject({errorCode: 404, message: 'Unable to find setting: ' + key}); + return when.reject({code: 404, message: 'Unable to find setting: ' + key}); } return when.reject({message: error.message}); }); @@ -210,7 +210,7 @@ settings = { } return dataProvider.Settings.read(key).then(function (setting) { if (!setting) { - return when.reject({errorCode: 404, message: 'Unable to find setting: ' + key}); + return when.reject({code: 404, message: 'Unable to find setting: ' + key}); } if (!_.isString(value)) { value = JSON.stringify(value); diff --git a/core/server/api/tags.js b/core/server/api/tags.js index ae0f0561b3..f73936585e 100644 --- a/core/server/api/tags.js +++ b/core/server/api/tags.js @@ -3,12 +3,14 @@ var dataProvider = require('../models'), tags = { - // #### All + // #### Browse // **takes:** Nothing yet - all: function browse() { + browse: function browse() { // **returns:** a promise for all tags which have previously been used in a json object - return dataProvider.Tag.findAll(); + return dataProvider.Tag.findAll().then(function (result) { + return result.toJSON(); + }); } }; diff --git a/core/server/api/users.js b/core/server/api/users.js index 1ed3c095da..d77a3071dd 100644 --- a/core/server/api/users.js +++ b/core/server/api/users.js @@ -8,8 +8,8 @@ var when = require('when'), // ## Users users = { - // #### Browse + // #### Browse // **takes:** options object browse: function browse(options) { // **returns:** a promise for a collection of users in a json object @@ -31,7 +31,6 @@ users = { }, // #### Read - // **takes:** an identifier (id or slug?) read: function read(args) { // **returns:** a promise for a single user in a json object @@ -45,12 +44,11 @@ users = { return omitted; } - return when.reject({errorCode: 404, message: 'User not found'}); + return when.reject({code: 404, message: 'User not found'}); }); }, // #### Edit - // **takes:** a json object representing a user edit: function edit(userData) { // **returns:** a promise for the resulting user in a json object @@ -60,12 +58,11 @@ users = { var omitted = _.omit(result.toJSON(), filteredAttributes); return omitted; } - return when.reject({errorCode: 404, message: 'User not found'}); + return when.reject({code: 404, message: 'User not found'}); }); }, // #### Add - // **takes:** a json object representing a user add: function add(userData) { @@ -83,7 +80,6 @@ users = { }, // #### Change Password - // **takes:** a json object representing a user changePassword: function changePassword(userData) { // **returns:** on success, returns a promise for the resulting user in a json object diff --git a/core/server/apps/proxy.js b/core/server/apps/proxy.js index 6689dbe7fe..fdf6e2e48b 100644 --- a/core/server/apps/proxy.js +++ b/core/server/apps/proxy.js @@ -15,7 +15,7 @@ var proxy = { }, api: { posts: _.pick(api.posts, 'browse', 'read'), - tags: api.tags, + tags: _.pick(api.tags, 'browse'), notifications: _.pick(api.notifications, 'add'), settings: _.pick(api.settings, 'read') } diff --git a/core/server/controllers/frontend.js b/core/server/controllers/frontend.js index 609d6e6f8c..90310596cd 100644 --- a/core/server/controllers/frontend.js +++ b/core/server/controllers/frontend.js @@ -59,7 +59,7 @@ function formatPageResponse(posts, page) { function handleError(next) { return function (err) { var e = new Error(err.message); - e.status = err.errorCode; + e.status = err.code; return next(e); }; } diff --git a/core/server/filters.js b/core/server/filters.js index 49e63ac0d4..393fdaf670 100644 --- a/core/server/filters.js +++ b/core/server/filters.js @@ -25,7 +25,7 @@ var Filters = function () { // Register a new filter callback function Filters.prototype.registerFilter = function (name, priority, fn) { - // Curry the priority optional parameter to a default of 5 + // Carry the priority optional parameter to a default of 5 if (_.isFunction(priority)) { fn = priority; priority = null; diff --git a/core/server/middleware/ghost-busboy.js b/core/server/middleware/ghost-busboy.js index 4531dec15f..a55d3be67c 100644 --- a/core/server/middleware/ghost-busboy.js +++ b/core/server/middleware/ghost-busboy.js @@ -55,7 +55,7 @@ function ghostBusBoy(req, res, next) { busboy.on('limit', function () { hasError = true; - res.send(413, { errorCode: 413, message: 'File size limit breached.' }); + res.send(413, {code: 413, message: 'File size limit breached.'}); }); busboy.on('error', function (error) { diff --git a/core/server/routes/api.js b/core/server/routes/api.js index b5b3cb8bb8..e14f97f824 100644 --- a/core/server/routes/api.js +++ b/core/server/routes/api.js @@ -19,7 +19,7 @@ module.exports = function (server) { server.get('/ghost/api/v0.1/users/:id/', api.requestHandler(api.users.read)); server.put('/ghost/api/v0.1/users/:id/', api.requestHandler(api.users.edit)); // #### Tags - server.get('/ghost/api/v0.1/tags/', api.requestHandler(api.tags.all)); + server.get('/ghost/api/v0.1/tags/', api.requestHandler(api.tags.browse)); // #### Notifications server.del('/ghost/api/v0.1/notifications/:id', api.requestHandler(api.notifications.destroy)); server.post('/ghost/api/v0.1/notifications/', api.requestHandler(api.notifications.add)); diff --git a/core/test/integration/api/api_notifications_spec.js b/core/test/integration/api/api_notifications_spec.js new file mode 100644 index 0000000000..82155b48ae --- /dev/null +++ b/core/test/integration/api/api_notifications_spec.js @@ -0,0 +1,49 @@ +/*globals describe, before, beforeEach, afterEach, it */ +var testUtils = require('../../utils'), + should = require('should'), + + // Stuff we are testing + DataGenerator = require('../../utils/fixtures/data-generator'), + NotificationsAPI = require('../../../server/api/notifications'); + +describe('Notifications API', function () { + + before(function (done) { + testUtils.clearData().then(function () { + done(); + }, done); + }); + + beforeEach(function (done) { + testUtils.initData() + .then(function () { + return testUtils.insertDefaultFixtures(); + }) + .then(function () { + done(); + }, done); + }); + + afterEach(function (done) { + testUtils.clearData().then(function () { + done(); + }, done); + }); + + it('can browse', function (done) { + var msg = { + type: 'error', // this can be 'error', 'success', 'warn' and 'info' + message: 'This is an error', // A string. Should fit in one line. + status: 'persistent', // or 'passive' + id: 'auniqueid' // A unique ID + }; + NotificationsAPI.add(msg).then(function (notification){ + NotificationsAPI.browse().then(function (results) { + should.exist(results); + results.length.should.be.above(0); + testUtils.API.checkResponse(results[0], 'notification'); + done(); + }); + }); + }); +}); \ No newline at end of file diff --git a/core/test/integration/api/api_posts_spec.js b/core/test/integration/api/api_posts_spec.js new file mode 100644 index 0000000000..107316dbdd --- /dev/null +++ b/core/test/integration/api/api_posts_spec.js @@ -0,0 +1,59 @@ +/*globals describe, before, beforeEach, afterEach, it */ +var testUtils = require('../../utils'), + should = require('should'), + + // Stuff we are testing + DataGenerator = require('../../utils/fixtures/data-generator'), + PostAPI = require('../../../server/api/posts'); + +describe('Post API', function () { + + before(function (done) { + testUtils.clearData().then(function () { + done(); + }, done); + }); + + beforeEach(function (done) { + testUtils.initData() + .then(function () { + return testUtils.insertDefaultFixtures(); + }) + .then(function () { + done(); + }, done); + }); + + afterEach(function (done) { + testUtils.clearData().then(function () { + done(); + }, done); + }); + + it('can browse', function (done) { + PostAPI.browse().then(function (results) { + should.exist(results); + testUtils.API.checkResponse(results, 'posts'); + should.exist(results.posts); + results.posts.length.should.be.above(0); + testUtils.API.checkResponse(results.posts[0], 'post'); + done(); + }).then(null, done); + }); + + it('can read', function (done) { + var firstPost; + + PostAPI.browse().then(function (results) { + should.exist(results); + should.exist(results.posts); + results.posts.length.should.be.above(0); + firstPost = results.posts[0]; + return PostAPI.read({slug: firstPost.slug}); + }).then(function (found) { + should.exist(found); + testUtils.API.checkResponse(found, 'post'); + done(); + }).then(null, done); + }); +}); \ No newline at end of file diff --git a/core/test/integration/api/api_settings_spec.js b/core/test/integration/api/api_settings_spec.js new file mode 100644 index 0000000000..7e302f4c0f --- /dev/null +++ b/core/test/integration/api/api_settings_spec.js @@ -0,0 +1,42 @@ +/*globals describe, before, beforeEach, afterEach, it */ +var testUtils = require('../../utils'), + should = require('should'), + + // Stuff we are testing + DataGenerator = require('../../utils/fixtures/data-generator'), + SettingsAPI = require('../../../server/api/settings'); + +describe('Settings API', function () { + + before(function (done) { + testUtils.clearData().then(function () { + done(); + }, done); + }); + + beforeEach(function (done) { + testUtils.initData() + .then(function () { + return testUtils.insertDefaultFixtures(); + }) + .then(function () { + done(); + }, done); + }); + + afterEach(function (done) { + testUtils.clearData().then(function () { + done(); + }, done); + }); + + it('can browse', function (done) { + SettingsAPI.updateSettingsCache().then(function () { + SettingsAPI.browse('blog').then(function (results) { + should.exist(results); + testUtils.API.checkResponse(results, 'settings'); + done(); + }); + }); + }); +}); \ No newline at end of file diff --git a/core/test/integration/api/api_tags_spec.js b/core/test/integration/api/api_tags_spec.js new file mode 100644 index 0000000000..dd34a975ac --- /dev/null +++ b/core/test/integration/api/api_tags_spec.js @@ -0,0 +1,41 @@ +/*globals describe, before, beforeEach, afterEach, it */ +var testUtils = require('../../utils'), + should = require('should'), + + // Stuff we are testing + DataGenerator = require('../../utils/fixtures/data-generator'), + TagsAPI = require('../../../server/api/tags'); + +describe('Tags API', function () { + + before(function (done) { + testUtils.clearData().then(function () { + done(); + }, done); + }); + + beforeEach(function (done) { + testUtils.initData() + .then(function () { + return testUtils.insertDefaultFixtures(); + }) + .then(function () { + done(); + }, done); + }); + + afterEach(function (done) { + testUtils.clearData().then(function () { + done(); + }, done); + }); + + it('can browse', function (done) { + TagsAPI.browse().then(function (results) { + should.exist(results); + results.length.should.be.above(0); + testUtils.API.checkResponse(results[0], 'tag'); + done(); + }).then(null, done); + }); +}); \ No newline at end of file diff --git a/core/test/integration/api/api_users_spec.js b/core/test/integration/api/api_users_spec.js new file mode 100644 index 0000000000..9dfe467248 --- /dev/null +++ b/core/test/integration/api/api_users_spec.js @@ -0,0 +1,41 @@ +/*globals describe, before, beforeEach, afterEach, it */ +var testUtils = require('../../utils'), + should = require('should'), + + // Stuff we are testing + DataGenerator = require('../../utils/fixtures/data-generator'), + UsersAPI = require('../../../server/api/users'); + +describe('Users API', function () { + + before(function (done) { + testUtils.clearData().then(function () { + done(); + }, done); + }); + + beforeEach(function (done) { + testUtils.initData() + .then(function () { + return testUtils.insertDefaultFixtures(); + }) + .then(function () { + done(); + }, done); + }); + + afterEach(function (done) { + testUtils.clearData().then(function () { + done(); + }, done); + }); + + it('can browse', function (done) { + UsersAPI.browse().then(function (results) { + should.exist(results); + results.length.should.be.above(0); + testUtils.API.checkResponse(results[0], 'user'); + done(); + }).then(null, done); + }); +}); \ No newline at end of file diff --git a/core/test/integration/model/model_posts_spec.js b/core/test/integration/model/model_posts_spec.js index 98acee32fb..e702019150 100644 --- a/core/test/integration/model/model_posts_spec.js +++ b/core/test/integration/model/model_posts_spec.js @@ -1,13 +1,13 @@ /*globals describe, before, beforeEach, afterEach, it */ -var testUtils = require('../../utils'), - should = require('should'), - _ = require('lodash'), - when = require('when'), - sequence = require('when/sequence'), +var testUtils = require('../../utils'), + should = require('should'), + _ = require('lodash'), + when = require('when'), + sequence = require('when/sequence'), // Stuff we are testing DataGenerator = require('../../utils/fixtures/data-generator'), - Models = require('../../../server/models'); + Models = require('../../../server/models'); describe('Post Model', function () { diff --git a/core/test/utils/api.js b/core/test/utils/api.js index 92a21c3e89..2284ba4a73 100644 --- a/core/test/utils/api.js +++ b/core/test/utils/api.js @@ -17,7 +17,8 @@ var _ = require('lodash'), 'meta_title', 'meta_description', 'created_at', 'created_by', 'updated_at', 'updated_by'], user: ['id', 'uuid', 'name', 'slug', 'email', 'image', 'cover', 'bio', 'website', 'location', 'accessibility', 'status', 'language', 'meta_title', 'meta_description', - 'created_at', 'updated_at'] + 'created_at', 'updated_at'], + notification: ['type', 'message', 'status', 'id'] };