diff --git a/Gruntfile.js b/Gruntfile.js index d539b82cf6..6b6a5f2554 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -293,12 +293,8 @@ var path = require('path'), ] }, - api: { - src: ['core/test/functional/api/*_test.js'] - }, - routes: { - src: ['core/test/functional/routes/*_test.js'] + src: ['core/test/functional/routes/**/*_test.js'] } }, @@ -909,11 +905,9 @@ var path = require('path'), grunt.registerTask('test-functional', 'Run functional interface tests (CasperJS)', ['clean:test', 'setTestEnv', 'loadConfig', 'copy:dev', 'express:test', 'spawn-casperjs', 'express:test:stop']); - grunt.registerTask('test-api', 'Run functional api tests (mocha)', ['clean:test', 'setTestEnv', 'loadConfig', 'express:test', 'mochacli:api', 'express:test:stop']); - grunt.registerTask('test-routes', 'Run functional route tests (mocha)', ['clean:test', 'setTestEnv', 'loadConfig', 'mochacli:routes']); - grunt.registerTask('validate', 'Run tests and lint code', ['jshint', 'test-routes', 'test-unit', 'test-api', 'test-integration', 'test-functional']); + grunt.registerTask('validate', 'Run tests and lint code', ['jshint', 'test-routes', 'test-unit', 'test-integration', 'test-functional']); // ### Coverage report for Unit and Integration Tests diff --git a/core/test/functional/api/error_test.js b/core/test/functional/api/error_test.js deleted file mode 100644 index 62fb33ba74..0000000000 --- a/core/test/functional/api/error_test.js +++ /dev/null @@ -1,20 +0,0 @@ -/*globals describe, before, after, beforeEach, afterEach, it */ -var testUtils = require('../../utils'), - should = require('should'), - _ = require('lodash'), - request = require('request'); - -describe('Unauthorized', function () { - - it('can\'t retrieve posts', function (done) { - request.get(testUtils.API.getApiURL('posts/'), function (error, response, body) { - response.should.have.status(401); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.should.exist; - testUtils.API.checkResponseValue(jsonResponse, ['error']); - done(); - }); - }); -}); \ No newline at end of file diff --git a/core/test/functional/api/posts_test.js b/core/test/functional/api/posts_test.js deleted file mode 100644 index 2a3df84e80..0000000000 --- a/core/test/functional/api/posts_test.js +++ /dev/null @@ -1,496 +0,0 @@ -/*globals describe, before, after, beforeEach, afterEach, it */ -var testUtils = require('../../utils'), - should = require('should'), - _ = require('lodash'), - request = require('request'); - -request = request.defaults({jar: true}); - -describe('Post API', function () { - - var user = testUtils.DataGenerator.forModel.users[0], - csrfToken = ''; - - before(function (done) { - testUtils.clearData() - .then(function () { - return testUtils.initData(); - }) - .then(function () { - return testUtils.insertDefaultFixtures(); - }) - .then(function () { - request.get(testUtils.API.getSigninURL(), function (error, response, body) { - response.should.have.status(200); - var pattern_meta = //i; - pattern_meta.should.exist; - csrfToken = body.match(pattern_meta)[1]; - setTimeout((function () { - request.post({uri: testUtils.API.getSigninURL(), - headers: {'X-CSRF-Token': csrfToken}}, function (error, response, body) { - response.should.have.status(200); - request.get(testUtils.API.getAdminURL(), function (error, response, body) { - response.should.have.status(200); - csrfToken = body.match(pattern_meta)[1]; - done(); - }); - }).form({email: user.email, password: user.password}); - }), 2000); - }); - }, done); - }); - - // ## Browse - describe('Browse', function () { - - it('retrieves all published posts only by default', function (done) { - request.get(testUtils.API.getApiURL('posts/'), function (error, response, body) { - response.should.have.status(200); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.posts.should.exist; - testUtils.API.checkResponse(jsonResponse, 'posts'); - jsonResponse.posts.should.have.length(5); - testUtils.API.checkResponse(jsonResponse.posts[0], 'post'); - done(); - }); - }); - - it('can retrieve all published posts and pages', function (done) { - request.get(testUtils.API.getApiURL('posts/?staticPages=all'), function (error, response, body) { - response.should.have.status(200); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.posts.should.exist; - testUtils.API.checkResponse(jsonResponse, 'posts'); - jsonResponse.posts.should.have.length(6); - testUtils.API.checkResponse(jsonResponse.posts[0], 'post'); - done(); - }); - }); - - // Test bits of the API we don't use in the app yet to ensure the API behaves properly - - it('can retrieve all status posts and pages', function (done) { - request.get(testUtils.API.getApiURL('posts/?staticPages=all&status=all'), function (error, response, body) { - response.should.have.status(200); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.posts.should.exist; - testUtils.API.checkResponse(jsonResponse, 'posts'); - jsonResponse.posts.should.have.length(8); - testUtils.API.checkResponse(jsonResponse.posts[0], 'post'); - done(); - }); - }); - - it('can retrieve just published pages', function (done) { - request.get(testUtils.API.getApiURL('posts/?staticPages=true'), function (error, response, body) { - response.should.have.status(200); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.posts.should.exist; - testUtils.API.checkResponse(jsonResponse, 'posts'); - jsonResponse.posts.should.have.length(1); - testUtils.API.checkResponse(jsonResponse.posts[0], 'post'); - done(); - }); - }); - - it('can retrieve just draft posts', function (done) { - request.get(testUtils.API.getApiURL('posts/?status=draft'), function (error, response, body) { - response.should.have.status(200); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.posts.should.exist; - testUtils.API.checkResponse(jsonResponse, 'posts'); - jsonResponse.posts.should.have.length(1); - testUtils.API.checkResponse(jsonResponse.posts[0], 'post'); - done(); - }); - }); - }); - - // ## Read - describe('Read', function () { - it('can retrieve a post', function (done) { - request.get(testUtils.API.getApiURL('posts/1/'), function (error, response, body) { - response.should.have.status(200); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.should.exist; - testUtils.API.checkResponse(jsonResponse, 'post'); - jsonResponse.page.should.eql(0); - done(); - }); - }); - - it('can retrieve a static page', function (done) { - request.get(testUtils.API.getApiURL('posts/7/'), function (error, response, body) { - response.should.have.status(200); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.should.exist; - testUtils.API.checkResponse(jsonResponse, 'post'); - jsonResponse.page.should.eql(1); - done(); - }); - }); - - it('can\'t retrieve non existent post', function (done) { - request.get(testUtils.API.getApiURL('posts/99/'), function (error, response, body) { - response.should.have.status(404); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.should.exist; - testUtils.API.checkResponseValue(jsonResponse, ['error']); - done(); - }); - }); - - it('can\'t retrieve a draft post', function (done) { - request.get(testUtils.API.getApiURL('posts/5/'), function (error, response, body) { - response.should.have.status(404); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.should.exist; - testUtils.API.checkResponseValue(jsonResponse, ['error']); - done(); - }); - }); - - it('can\'t retrieve a draft page', function (done) { - request.get(testUtils.API.getApiURL('posts/8/'), function (error, response, body) { - response.should.have.status(404); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.should.exist; - testUtils.API.checkResponseValue(jsonResponse, ['error']); - done(); - }); - }); - - }); - // ## Add - describe('Add', function () { - it('can create a new draft, publish post, update post', function (done) { - var newTitle = 'My Post', - changedTitle = 'My Post changed', - publishedState = 'published', - newPost = {status: 'draft', title: newTitle, markdown: 'my post'}; - - request.post({uri: testUtils.API.getApiURL('posts/'), - headers: {'X-CSRF-Token': csrfToken}, - json: newPost}, function (error, response, draftPost) { - response.should.have.status(200); - response.should.be.json; - draftPost.should.exist; - draftPost.title.should.eql(newTitle); - draftPost.status = publishedState; - testUtils.API.checkResponse(draftPost, 'post'); - request.put({uri: testUtils.API.getApiURL('posts/' + draftPost.id + '/'), - headers: {'X-CSRF-Token': csrfToken}, - json: draftPost}, function (error, response, publishedPost) { - response.should.have.status(200); - response.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + publishedPost.slug + '/'); - response.should.be.json; - publishedPost.should.exist; - publishedPost.title.should.eql(newTitle); - publishedPost.status.should.eql(publishedState); - testUtils.API.checkResponse(publishedPost, 'post'); - request.put({uri: testUtils.API.getApiURL('posts/' + publishedPost.id + '/'), - headers: {'X-CSRF-Token': csrfToken}, - json: publishedPost}, function (error, response, updatedPost) { - response.should.have.status(200); - response.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + updatedPost.slug + '/'); - response.should.be.json; - updatedPost.should.exist; - updatedPost.title.should.eql(newTitle); - testUtils.API.checkResponse(updatedPost, 'post'); - done(); - }); - }); - }); - }); - }); - - // ## edit - describe('Edit', function () { - it('can edit a post', function (done) { - request.get(testUtils.API.getApiURL('posts/1/'), function (error, response, body) { - var jsonResponse = JSON.parse(body), - changedValue = 'My new Title'; - jsonResponse.should.exist; - jsonResponse.title = changedValue; - - request.put({uri: testUtils.API.getApiURL('posts/1/'), - headers: {'X-CSRF-Token': csrfToken}, - json: jsonResponse}, function (error, response, putBody) { - response.should.have.status(200); - response.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + putBody.slug + '/'); - response.should.be.json; - putBody.should.exist; - putBody.title.should.eql(changedValue); - - testUtils.API.checkResponse(putBody, 'post'); - done(); - }); - }); - }); - - it('can change a post to a static page', function (done) { - request.get(testUtils.API.getApiURL('posts/1/'), function (error, response, body) { - var jsonResponse = JSON.parse(body), - changedValue = true; - jsonResponse.should.exist; - jsonResponse.page.should.eql(0); - jsonResponse.page = changedValue; - - request.put({uri: testUtils.API.getApiURL('posts/1/'), - headers: {'X-CSRF-Token': csrfToken}, - json: jsonResponse}, function (error, response, putBody) { - response.should.have.status(200); - response.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + putBody.slug + '/'); - response.should.be.json; - putBody.should.exist; - putBody.page.should.eql(changedValue); - - testUtils.API.checkResponse(putBody, 'post'); - done(); - }); - }); - }); - - it('can change a static page to a post', function (done) { - request.get(testUtils.API.getApiURL('posts/7/'), function (error, response, body) { - var jsonResponse = JSON.parse(body), - changedValue = false; - jsonResponse.should.exist; - jsonResponse.page.should.eql(1); - jsonResponse.page = changedValue; - - request.put({uri: testUtils.API.getApiURL('posts/1/'), - headers: {'X-CSRF-Token': csrfToken}, - json: jsonResponse}, function (error, response, putBody) { - response.should.have.status(200); - response.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + putBody.slug + '/'); - response.should.be.json; - putBody.should.exist; - putBody.page.should.eql(changedValue); - - testUtils.API.checkResponse(putBody, 'post'); - done(); - }); - }); - }); - - it('can\'t edit a post with invalid CSRF token', function (done) { - request.get(testUtils.API.getApiURL('posts/1/'), function (error, response, body) { - var jsonResponse = JSON.parse(body); - request.put({uri: testUtils.API.getApiURL('posts/1/'), - headers: {'X-CSRF-Token': 'invalid-token'}, - json: jsonResponse}, function (error, response, putBody) { - response.should.have.status(403); - done(); - }); - }); - }); - - it('published_at = null', function (done) { - request.get(testUtils.API.getApiURL('posts/1/'), function (error, response, body) { - var jsonResponse = JSON.parse(body), - changedValue = 'My new Title'; - jsonResponse.should.exist; - jsonResponse.title = changedValue; - jsonResponse.published_at = null; - request.put({uri: testUtils.API.getApiURL('posts/1/'), - headers: {'X-CSRF-Token': csrfToken}, - json: jsonResponse}, function (error, response, putBody) { - response.should.have.status(200); - response.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + putBody.slug + '/'); - response.should.be.json; - putBody.should.exist; - putBody.title.should.eql(changedValue); - if (_.isEmpty(putBody.published_at)) { - should.fail('null', 'valid date', 'publish_at should not be empty'); - done(); - } - testUtils.API.checkResponse(putBody, 'post'); - done(); - }); - }); - }); - }); - - // ## delete - describe('Delete', function () { - it('can\'t edit non existent post', function (done) { - request.get(testUtils.API.getApiURL('posts/1/'), function (error, response, body) { - var jsonResponse = JSON.parse(body), - changedValue = 'My new Title'; - jsonResponse.title.exist; - jsonResponse.testvalue = changedValue; - jsonResponse.id = 99; - request.put({uri: testUtils.API.getApiURL('posts/99/'), - headers: {'X-CSRF-Token': csrfToken}, - json: jsonResponse}, function (error, response, putBody) { - response.should.have.status(404); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - testUtils.API.checkResponseValue(putBody, ['error']); - done(); - }); - }); - }); - - it('can delete a post', function (done) { - var deletePostId = 1; - request.del({uri: testUtils.API.getApiURL('posts/' + deletePostId + '/'), - headers: {'X-CSRF-Token': csrfToken}}, function (error, response, body) { - response.should.have.status(200); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.should.exist; - response.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + jsonResponse.slug + '/'); - testUtils.API.checkResponse(jsonResponse, 'post'); - jsonResponse.id.should.eql(deletePostId); - done(); - }); - }); - - it('can\'t delete a non existent post', function (done) { - request.del({uri: testUtils.API.getApiURL('posts/99/'), - headers: {'X-CSRF-Token': csrfToken}}, function (error, response, body) { - response.should.have.status(404); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.should.exist; - testUtils.API.checkResponseValue(jsonResponse, ['error']); - done(); - }); - }); - - it('can delete a new draft', function (done) { - var newTitle = 'My Post', - publishedState = 'draft', - newPost = {status: publishedState, title: newTitle, markdown: 'my post'}; - - request.post({uri: testUtils.API.getApiURL('posts/'), - headers: {'X-CSRF-Token': csrfToken}, - json: newPost}, function (error, response, draftPost) { - response.should.have.status(200); - - response.should.be.json; - draftPost.should.exist; - draftPost.title.should.eql(newTitle); - draftPost.status = publishedState; - testUtils.API.checkResponse(draftPost, 'post'); - request.del({uri: testUtils.API.getApiURL('posts/' + draftPost.id + '/'), - headers: {'X-CSRF-Token': csrfToken}}, function (error, response, body) { - response.should.have.status(200); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.should.exist; - testUtils.API.checkResponse(jsonResponse, 'post'); - done(); - }); - }); - }); - }); - - describe('Dated Permalinks', function () { - before(function (done) { - request.get(testUtils.API.getApiURL('settings'), function (error, response, body) { - if (error) { done(error); } - var jsonResponse = JSON.parse(body); - jsonResponse.permalinks = '/:year/:month/:day/:slug/'; - - request.put({ - uri: testUtils.API.getApiURL('settings/'), - headers: {'X-CSRF-Token': csrfToken}, - json: jsonResponse - }, function (error, response, putBody) { - if (error) { done(error); } - done(); - }); - }); - }); - - after(function (done) { - request.get(testUtils.API.getApiURL('settings'), function (error, response, body) { - if (error) { done(error); } - var jsonResponse = JSON.parse(body); - jsonResponse.permalinks = '/:slug/'; - - request.put({ - uri: testUtils.API.getApiURL('settings/'), - headers: {'X-CSRF-Token': csrfToken}, - json: jsonResponse - }, function (error, response, putBody) { - if (error) { done(error); } - done(); - }); - }); - }); - - it('Can read a post', function (done) { - // nothing should have changed here - request.get(testUtils.API.getApiURL('posts/2/'), function (error, response, body) { - if (error) { done(error); } - response.should.have.status(200); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - - var jsonResponse = JSON.parse(body); - jsonResponse.should.exist; - testUtils.API.checkResponse(jsonResponse, 'post'); - jsonResponse.slug.should.not.match(/^\/[0-9]{4}\/[0-9]{2}\/[0-9]{2}/); - jsonResponse.page.should.eql(0); - done(); - }); - }); - - it('Can edit a post', function (done) { - request.get(testUtils.API.getApiURL('posts/2/'), function (error, response, body) { - if (error) { done(error); } - var jsonResponse = JSON.parse(body), - changedValue = 'My new Title'; - jsonResponse.should.exist; - jsonResponse.title = changedValue; - - request.put({ - uri: testUtils.API.getApiURL('posts/2/'), - headers: {'X-CSRF-Token': csrfToken}, - json: jsonResponse - }, function (error, response, putBody) { - if (error) { done(error); } - var today = new Date(), - dd = ("0" + today.getDate()).slice(-2), - mm = ("0" + (today.getMonth() + 1)).slice(-2), - yyyy = today.getFullYear(), - postLink = '/' + yyyy + '/' + mm + '/' + dd + '/' + putBody.slug + '/'; - - response.should.have.status(200); - response.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, ' + postLink); - response.should.be.json; - putBody.should.exist; - putBody.title.should.eql(changedValue); - - testUtils.API.checkResponse(putBody, 'post'); - done(); - }); - }); - }); - }); -}); diff --git a/core/test/functional/api/settings_test.js b/core/test/functional/api/settings_test.js deleted file mode 100644 index c7b3f363ab..0000000000 --- a/core/test/functional/api/settings_test.js +++ /dev/null @@ -1,137 +0,0 @@ -/*globals describe, before, beforeEach, afterEach, it */ -var testUtils = require('../../utils'), - should = require('should'), - _ = require('lodash'), - request = require('request'); - -request = request.defaults({jar:true}) - -describe('Settings API', function () { - - var user = testUtils.DataGenerator.forModel.users[0], - csrfToken = ''; - - before(function (done) { - testUtils.clearData() - .then(function () { - return testUtils.initData(); - }) - .then(function () { - return testUtils.insertDefaultFixtures(); - }) - .then(function () { - request.get(testUtils.API.getSigninURL(), function (error, response, body) { - response.should.have.status(200); - var pattern_meta = //i; - pattern_meta.should.exist; - csrfToken = body.match(pattern_meta)[1]; - setTimeout((function () { - request.post({uri: testUtils.API.getSigninURL(), - headers: {'X-CSRF-Token': csrfToken}}, function (error, response, body) { - response.should.have.status(200); - request.get(testUtils.API.getAdminURL(), function (error, response, body) { - response.should.have.status(200); - csrfToken = body.match(pattern_meta)[1]; - done(); - }); - }).form({email: user.email, password: user.password}); - }), 2000); - }); - }, done); - }); - - // TODO: currently includes values of type=core - it('can retrieve all settings', function (done) { - request.get(testUtils.API.getApiURL('settings/'), function (error, response, body) { - response.should.have.status(200); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.should.exist; - - testUtils.API.checkResponse(jsonResponse, 'settings'); - done(); - }); - }); - it('can retrieve a setting', function (done) { - request.get(testUtils.API.getApiURL('settings/title/'), function (error, response, body) { - response.should.have.status(200); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - - jsonResponse.should.exist; - testUtils.API.checkResponseValue(jsonResponse, ['key','value']); - jsonResponse.key.should.eql('title'); - done(); - }); - }); - - it('can\'t retrieve non existent setting', function (done) { - request.get(testUtils.API.getApiURL('settings/testsetting/'), function (error, response, body) { - response.should.have.status(404); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.should.exist; - testUtils.API.checkResponseValue(jsonResponse, ['error']); - done(); - }); - }); - - it('can edit settings', function (done) { - request.get(testUtils.API.getApiURL('settings'), function (error, response, body) { - var jsonResponse = JSON.parse(body), - changedValue = 'Ghost changed'; - jsonResponse.should.exist; - jsonResponse.title = changedValue; - - request.put({uri: testUtils.API.getApiURL('settings/'), - headers: {'X-CSRF-Token': csrfToken}, - json: jsonResponse}, function (error, response, putBody) { - response.should.have.status(200); - response.headers['x-cache-invalidate'].should.eql('/*'); - response.should.be.json; - putBody.should.exist; - putBody.title.should.eql(changedValue); - testUtils.API.checkResponse(putBody, 'settings'); - done(); - }); - }); - }); - - it('can\'t edit settings with invalid CSRF token', function (done) { - request.get(testUtils.API.getApiURL('settings'), function (error, response, body) { - var jsonResponse = JSON.parse(body), - changedValue = 'Ghost changed'; - jsonResponse.should.exist; - jsonResponse.title = changedValue; - - request.put({uri: testUtils.API.getApiURL('settings/'), - headers: {'X-CSRF-Token': 'invalid-token'}, - json: jsonResponse}, function (error, response, putBody) { - response.should.have.status(403); - done(); - }); - }); - }); - - it('can\'t edit non existent setting', function (done) { - request.get(testUtils.API.getApiURL('settings'), function (error, response, body) { - var jsonResponse = JSON.parse(body), - newValue = 'new value'; - jsonResponse.should.exist; - jsonResponse.testvalue = newValue; - - request.put({uri: testUtils.API.getApiURL('settings/'), - headers: {'X-CSRF-Token': csrfToken}, - json: jsonResponse}, function (error, response, putBody) { - response.should.have.status(404); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - testUtils.API.checkResponseValue(putBody, ['error']); - done(); - }); - }); - }); -}); diff --git a/core/test/functional/api/tags_test.js b/core/test/functional/api/tags_test.js deleted file mode 100644 index e5aaba5468..0000000000 --- a/core/test/functional/api/tags_test.js +++ /dev/null @@ -1,55 +0,0 @@ -/*globals describe, before, beforeEach, afterEach, it */ -var testUtils = require('../../utils'), - should = require('should'), - _ = require('lodash'), - request = require('request'); - -request = request.defaults({jar:true}) - -describe('Tag API', function () { - - var user = testUtils.DataGenerator.forModel.users[0], - csrfToken = ''; - - before(function (done) { - testUtils.clearData() - .then(function () { - return testUtils.initData(); - }) - .then(function () { - return testUtils.insertDefaultFixtures(); - }) - .then(function () { - request.get(testUtils.API.getSigninURL(), function (error, response, body) { - response.should.have.status(200); - var pattern_meta = //i; - pattern_meta.should.exist; - csrfToken = body.match(pattern_meta)[1]; - setTimeout((function () { - request.post({uri: testUtils.API.getSigninURL(), - headers: {'X-CSRF-Token': csrfToken}}, function (error, response, body) { - response.should.have.status(200); - request.get(testUtils.API.getAdminURL(), function (error, response, body) { - response.should.have.status(200); - csrfToken = body.match(pattern_meta)[1]; - done(); - }); - }).form({email: user.email, password: user.password}); - }), 2000); - }); - }, done); - }); - - it('can retrieve all tags', function (done) { - request.get(testUtils.API.getApiURL('tags/'), function (error, response, body) { - response.should.have.status(200); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.should.exist; - jsonResponse.should.have.length(6); - testUtils.API.checkResponse(jsonResponse[0], 'tag'); - done(); - }); - }); -}); diff --git a/core/test/functional/api/users_test.js b/core/test/functional/api/users_test.js deleted file mode 100644 index dd710da108..0000000000 --- a/core/test/functional/api/users_test.js +++ /dev/null @@ -1,119 +0,0 @@ -/*globals describe, before, beforeEach, afterEach, it */ -var testUtils = require('../../utils'), - should = require('should'), - _ = require('lodash'), - request = require('request'); - -request = request.defaults({jar:true}) - -describe('User API', function () { - - var user = testUtils.DataGenerator.forModel.users[0], - csrfToken = ''; - - before(function (done) { - testUtils.clearData() - .then(function () { - return testUtils.initData(); - }) - .then(function () { - return testUtils.insertDefaultFixtures(); - }) - .then(function () { - request.get(testUtils.API.getSigninURL(), function (error, response, body) { - response.should.have.status(200); - var pattern_meta = //i; - pattern_meta.should.exist; - csrfToken = body.match(pattern_meta)[1]; - setTimeout((function () { - request.post({uri: testUtils.API.getSigninURL(), - headers: {'X-CSRF-Token': csrfToken}}, function (error, response, body) { - response.should.have.status(200); - request.get(testUtils.API.getAdminURL(), function (error, response, body) { - response.should.have.status(200); - csrfToken = body.match(pattern_meta)[1]; - done(); - }); - }).form({email: user.email, password: user.password}); - }), 2000); - }); - }, done); - }); - - it('can retrieve all users', function (done) { - request.get(testUtils.API.getApiURL('users/'), function (error, response, body) { - response.should.have.status(200); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse[0].should.exist; - - testUtils.API.checkResponse(jsonResponse[0], 'user'); - done(); - }); - }); - - it('can retrieve a user', function (done) { - request.get(testUtils.API.getApiURL('users/me/'), function (error, response, body) { - response.should.have.status(200); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.should.exist; - - testUtils.API.checkResponse(jsonResponse, 'user'); - done(); - }); - }); - - it('can\'t retrieve non existent user', function (done) { - request.get(testUtils.API.getApiURL('users/99/'), function (error, response, body) { - response.should.have.status(404); - should.not.exist(response.headers['x-cache-invalidate']); - response.should.be.json; - var jsonResponse = JSON.parse(body); - jsonResponse.should.exist; - - testUtils.API.checkResponseValue(jsonResponse, ['error']); - done(); - }); - }); - - it('can edit a user', function (done) { - request.get(testUtils.API.getApiURL('users/me/'), function (error, response, body) { - var jsonResponse = JSON.parse(body), - changedValue = 'joe-bloggs.ghost.org'; - jsonResponse.should.exist; - jsonResponse.website = changedValue; - - request.put({uri: testUtils.API.getApiURL('users/me/'), - headers: {'X-CSRF-Token': csrfToken}, - json: jsonResponse}, function (error, response, putBody) { - response.should.have.status(200); - response.headers['x-cache-invalidate'].should.eql('/*'); - response.should.be.json; - putBody.should.exist; - putBody.website.should.eql(changedValue); - - testUtils.API.checkResponse(putBody, 'user'); - done(); - }); - }); - }); - - it('can\'t edit a user with invalid CSRF token', function (done) { - request.get(testUtils.API.getApiURL('users/me/'), function (error, response, body) { - var jsonResponse = JSON.parse(body), - changedValue = 'joe-bloggs.ghost.org'; - jsonResponse.should.exist; - jsonResponse.website = changedValue; - - request.put({uri: testUtils.API.getApiURL('users/me/'), - headers: {'X-CSRF-Token': 'invalid-token'}, - json: jsonResponse}, function (error, response, putBody) { - response.should.have.status(403); - done(); - }); - }); - }); -}); diff --git a/core/test/functional/routes/api/error_test.js b/core/test/functional/routes/api/error_test.js new file mode 100644 index 0000000000..02db46a349 --- /dev/null +++ b/core/test/functional/routes/api/error_test.js @@ -0,0 +1,66 @@ +/*global describe, it, before, after */ + +// # Api Route tests +// As it stands, these tests depend on the database, and as such are integration tests. +// Mocking out the models to not touch the DB would turn these into unit tests, and should probably be done in future, +// But then again testing real code, rather than mock code, might be more useful... + +var supertest = require('supertest'), + express = require('express'), + should = require('should'), + _ = require('lodash'), + testUtils = require('../../../utils'), + + ghost = require('../../../../../core'), + + httpServer, + request, + agent; + +describe('Unauthorized', function () { + + before(function (done) { + var app = express(); + + ghost({app: app}).then(function (_httpServer) { + httpServer = _httpServer; + // request = supertest(app); + request = supertest.agent(app); + testUtils.clearData().then(function () { + // we initialise data, but not a user. + return testUtils.initData(); + }).then(function () { + done(); + }, done); + }); + + }); + + after(function () { + httpServer.close(); + }); + + + describe('Unauthorized', function () { + it('can\'t retrieve posts', function (done) { + request.get(testUtils.API.getApiQuery('posts/')) + .expect(401) + .end(function firstRequest(err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.should.exist; + testUtils.API.checkResponseValue(jsonResponse, ['error']); + done(); + + }); + }); + + }); + + +}); \ No newline at end of file diff --git a/core/test/functional/routes/api/posts_test.js b/core/test/functional/routes/api/posts_test.js new file mode 100644 index 0000000000..c5388acb76 --- /dev/null +++ b/core/test/functional/routes/api/posts_test.js @@ -0,0 +1,729 @@ +/*global describe, it, before, after */ +var supertest = require('supertest'), + express = require('express'), + should = require('should'), + _ = require('lodash'), + testUtils = require('../../../utils'), + + ghost = require('../../../../../core'), + + httpServer, + request, + agent; + + +describe('Post API', function () { + var user = testUtils.DataGenerator.forModel.users[0], + csrfToken = ''; + + before(function (done) { + var app = express(); + + ghost({app: app}).then(function (_httpServer) { + httpServer = _httpServer; + + request = supertest.agent(app); + + testUtils.clearData() + .then(function () { + return testUtils.initData(); + }) + .then(function () { + return testUtils.insertDefaultFixtures(); + }) + .then(function () { + + request.get('/ghost/signin/') + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + var pattern_meta = //i; + pattern_meta.should.exist; + csrfToken = res.text.match(pattern_meta)[1]; + + setTimeout(function () { + request.post('/ghost/signin/') + .set('X-CSRF-Token', csrfToken) + .send({email: user.email, password: user.password}) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + + request.saveCookies(res); + request.get('/ghost/') + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + csrfToken = res.text.match(pattern_meta)[1]; + done(); + }); + }); + + }, 2000); + + }); + }, done); + }).otherwise(function (e) { + console.log('Ghost Error: ', e); + console.log(e.stack); + }); + }); + + after(function () { + httpServer.close(); + }); + + + describe('Browse', function () { + + it('retrieves all published posts only by default', function (done) { + request.get(testUtils.API.getApiQuery('posts/')) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.posts.should.exist; + testUtils.API.checkResponse(jsonResponse, 'posts'); + jsonResponse.posts.should.have.length(5); + testUtils.API.checkResponse(jsonResponse.posts[0], 'post'); + done(); + }); + }); + + it('can retrieve all published posts and pages', function (done) { + request.get(testUtils.API.getApiQuery('posts/?staticPages=all')) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.posts.should.exist; + testUtils.API.checkResponse(jsonResponse, 'posts'); + jsonResponse.posts.should.have.length(6); + testUtils.API.checkResponse(jsonResponse.posts[0], 'post'); + done(); + }); + + }); + + // Test bits of the API we don't use in the app yet to ensure the API behaves properly + + it('can retrieve all status posts and pages', function (done) { + request.get(testUtils.API.getApiQuery('posts/?staticPages=all&status=all')) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.posts.should.exist; + testUtils.API.checkResponse(jsonResponse, 'posts'); + jsonResponse.posts.should.have.length(8); + testUtils.API.checkResponse(jsonResponse.posts[0], 'post'); + done(); + }); + }); + + it('can retrieve just published pages', function (done) { + request.get(testUtils.API.getApiQuery('posts/?staticPages=true')) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.posts.should.exist; + testUtils.API.checkResponse(jsonResponse, 'posts'); + jsonResponse.posts.should.have.length(1); + testUtils.API.checkResponse(jsonResponse.posts[0], 'post'); + done(); + }); + }); + + it('can retrieve just draft posts', function (done) { + request.get(testUtils.API.getApiQuery('posts/?status=draft')) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.posts.should.exist; + testUtils.API.checkResponse(jsonResponse, 'posts'); + jsonResponse.posts.should.have.length(1); + testUtils.API.checkResponse(jsonResponse.posts[0], 'post'); + done(); + }); + }); + }); + + + // ## Read + describe('Read', function () { + it('can retrieve a post', function (done) { + request.get(testUtils.API.getApiQuery('posts/1/')) + .end(function (err, res) { + if (err) { + return done(err); + } + + res.should.have.status(200); + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.should.exist; + testUtils.API.checkResponse(jsonResponse, 'post'); + jsonResponse.page.should.eql(0); + done(); + }); + }); + + it('can retrieve a static page', function (done) { + request.get(testUtils.API.getApiQuery('posts/7/')) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.should.exist; + testUtils.API.checkResponse(jsonResponse, 'post'); + jsonResponse.page.should.eql(1); + done(); + }); + }); + + it('can\'t retrieve non existent post', function (done) { + request.get(testUtils.API.getApiQuery('posts/99/')) + .expect(404) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.should.exist; + testUtils.API.checkResponseValue(jsonResponse, ['error']); + done(); + }); + }); + + it('can\'t retrieve a draft post', function (done) { + request.get(testUtils.API.getApiQuery('posts/5/')) + .expect(404) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.should.exist; + testUtils.API.checkResponseValue(jsonResponse, ['error']); + done(); + }); + }); + + it('can\'t retrieve a draft page', function (done) { + request.get(testUtils.API.getApiQuery('posts/8/')) + .expect(404) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.should.exist; + testUtils.API.checkResponseValue(jsonResponse, ['error']); + done(); + }); + }); + + }); + + // ## Add + describe('Add', function () { + it('can create a new draft, publish post, update post', function (done) { + var newTitle = 'My Post', + changedTitle = 'My Post changed', + publishedState = 'published', + newPost = {status: 'draft', title: newTitle, markdown: 'my post'}; + + request.post(testUtils.API.getApiQuery('posts/')) + .set('X-CSRF-Token', csrfToken) + .send(newPost) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + res.should.be.json; + var draftPost = res.body; + draftPost.should.exist; + draftPost.title.should.eql(newTitle); + draftPost.status = publishedState; + testUtils.API.checkResponse(draftPost, 'post'); + + request.put(testUtils.API.getApiQuery('posts/' + draftPost.id + '/')) + .set('X-CSRF-Token', csrfToken) + .send(draftPost) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + var publishedPost = res.body; + + res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + publishedPost.slug + '/'); + res.should.be.json; + publishedPost.should.exist; + publishedPost.title.should.eql(newTitle); + publishedPost.status.should.eql(publishedState); + testUtils.API.checkResponse(publishedPost, 'post'); + + request.put(testUtils.API.getApiQuery('posts/' + publishedPost.id + '/')) + .set('X-CSRF-Token', csrfToken) + .send(publishedPost) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + var updatedPost = res.body; + res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + updatedPost.slug + '/'); + res.should.be.json; + updatedPost.should.exist; + updatedPost.title.should.eql(newTitle); + testUtils.API.checkResponse(updatedPost, 'post'); + done(); + }); + }); + + }); + }); + + }); + + // ## edit + describe('Edit', function () { + it('can edit a post', function (done) { + request.get(testUtils.API.getApiQuery('posts/1/')) + .end(function (err, res) { + if (err) { + return done(err); + } + + var jsonResponse = res.body, + changedValue = 'My new Title'; + jsonResponse.should.exist; + jsonResponse.title = changedValue; + + request.put(testUtils.API.getApiQuery('posts/1/')) + .set('X-CSRF-Token', csrfToken) + .send(jsonResponse) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + var putBody = res.body; + res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + putBody.slug + '/'); + res.should.be.json; + putBody.should.exist; + putBody.title.should.eql(changedValue); + + testUtils.API.checkResponse(putBody, 'post'); + done(); + }); + }); + }); + + it('can change a post to a static page', function (done) { + request.get(testUtils.API.getApiQuery('posts/1/')) + .end(function (err, res) { + if (err) { + return done(err); + } + + var jsonResponse = res.body, + changedValue = true; + jsonResponse.should.exist; + jsonResponse.page.should.eql(0); + jsonResponse.page = changedValue; + + request.put(testUtils.API.getApiQuery('posts/1/')) + .set('X-CSRF-Token', csrfToken) + .send(jsonResponse) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + var putBody = res.body; + res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + putBody.slug + '/'); + res.should.be.json; + putBody.should.exist; + putBody.page.should.eql(changedValue); + + testUtils.API.checkResponse(putBody, 'post'); + done(); + }); + }); + }); + + + it('can change a static page to a post', function (done) { + request.get(testUtils.API.getApiQuery('posts/7/')) + .end(function (err, res) { + if (err) { + return done(err); + } + + var jsonResponse = res.body, + changedValue = false; + jsonResponse.should.exist; + jsonResponse.page.should.eql(1); + jsonResponse.page = changedValue; + + request.put(testUtils.API.getApiQuery('posts/1/')) + .set('X-CSRF-Token', csrfToken) + .send(jsonResponse) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + var putBody = res.body; + res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + putBody.slug + '/'); + res.should.be.json; + putBody.should.exist; + putBody.page.should.eql(changedValue); + + testUtils.API.checkResponse(putBody, 'post'); + done(); + }); + }); + }); + + it('can\'t edit a post with invalid CSRF token', function (done) { + request.get(testUtils.API.getApiQuery('posts/1/')) + .end(function (err, res) { + if (err) { + return done(err); + } + + var jsonResponse = res.body; + request.put(testUtils.API.getApiQuery('posts/1/')) + .set('X-CSRF-Token', 'invalid-token') + .send(jsonResponse) + .expect(403) + .end(function (err, res) { + if (err) { + return done(err); + } + + done(); + }); + }); + }); + + it('published_at = null', function (done) { + request.get(testUtils.API.getApiQuery('posts/1/')) + .end(function (err, res) { + if (err) { + return done(err); + } + + var jsonResponse = res.body, + changedValue = 'My new Title'; + jsonResponse.should.exist; + jsonResponse.title = changedValue; + jsonResponse.published_at = null; + + request.put(testUtils.API.getApiQuery('posts/1/')) + .set('X-CSRF-Token', csrfToken) + .send(jsonResponse) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + var putBody = res.body; + res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + putBody.slug + '/'); + res.should.be.json; + putBody.should.exist; + putBody.title.should.eql(changedValue); + if (_.isEmpty(putBody.published_at)) { + should.fail('null', 'valid date', 'publish_at should not be empty'); + done(); + } + testUtils.API.checkResponse(putBody, 'post'); + done(); + }); + }); + }); + + }); + + // ## delete + describe('Delete', function () { + it('can\'t edit non existent post', function (done) { + request.get(testUtils.API.getApiQuery('posts/1/')) + .end(function (err, res) { + if (err) { + return done(err); + } + + var jsonResponse = res.body, + changedValue = 'My new Title'; + jsonResponse.title.exist; + jsonResponse.testvalue = changedValue; + jsonResponse.id = 99; + request.put(testUtils.API.getApiQuery('posts/99/')) + .set('X-CSRF-Token', csrfToken) + .send(jsonResponse) + .expect(404) + .end(function (err, res) { + if (err) { + return done(err); + } + + var putBody = res.body; + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + testUtils.API.checkResponseValue(putBody, ['error']); + done(); + }); + }); + }); + + it('can delete a post', function (done) { + var deletePostId = 1; + request.del(testUtils.API.getApiQuery('posts/' + deletePostId + '/')) + .set('X-CSRF-Token', csrfToken) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.should.exist; + res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, /' + jsonResponse.slug + '/'); + testUtils.API.checkResponse(jsonResponse, 'post'); + jsonResponse.id.should.eql(deletePostId); + done(); + }); + }); + + it('can\'t delete a non existent post', function (done) { + request.del(testUtils.API.getApiQuery('posts/99/')) + .set('X-CSRF-Token', csrfToken) + .expect(404) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.should.exist; + testUtils.API.checkResponseValue(jsonResponse, ['error']); + done(); + }); + }); + + it('can delete a new draft', function (done) { + var newTitle = 'My Post', + publishedState = 'draft', + newPost = {status: publishedState, title: newTitle, markdown: 'my post'}; + + request.post(testUtils.API.getApiQuery('posts/')) + .set('X-CSRF-Token', csrfToken) + .send(newPost) + .expect(200) + .end(function (err ,res) { + if (err) { + return done(err); + } + + var draftPost = res.body; + + res.should.be.json; + draftPost.should.exist; + draftPost.title.should.eql(newTitle); + draftPost.status = publishedState; + testUtils.API.checkResponse(draftPost, 'post'); + + request.del(testUtils.API.getApiQuery('posts/' + draftPost.id + '/')) + .set('X-CSRF-Token', csrfToken) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + res.should.be.json; + var jsonResponse = res.body + jsonResponse.should.exist; + testUtils.API.checkResponse(jsonResponse, 'post'); + done(); + }); + }); + }); + + }); + + describe('Dated Permalinks', function () { + before(function (done) { + request.get(testUtils.API.getApiQuery('settings/')) + .end(function (err, res) { + if (err) { + return done(err); + } + + var jsonResponse = res.body; + jsonResponse.permalinks = '/:year/:month/:day/:slug/'; + + request.put(testUtils.API.getApiQuery('settings/')) + .set('X-CSRF-Token', csrfToken) + .send(jsonResponse) + .end(function (err, res) { + if (err) { + return done(err); + } + done(); + }); + }); + }); + + after(function (done) { + request.get(testUtils.API.getApiQuery('settings/')) + .end(function (err, res) { + if (err) { + return done(err); + } + + var jsonResponse = res.body; + jsonResponse.permalinks = '/:slug/'; + + request.put(testUtils.API.getApiQuery('settings/')) + .set('X-CSRF-Token', csrfToken) + .send(jsonResponse) + .end(function (err, res) { + if (err) { + return done(err); + } + + done(); + }); + }); + }); + + it('Can read a post', function (done) { + // nothing should have changed here + request.get(testUtils.API.getApiQuery('posts/2/')) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + + var jsonResponse = res.body; + jsonResponse.should.exist; + testUtils.API.checkResponse(jsonResponse, 'post'); + jsonResponse.slug.should.not.match(/^\/[0-9]{4}\/[0-9]{2}\/[0-9]{2}/); + jsonResponse.page.should.eql(0); + done(); + }); + }); + + it('Can edit a post', function (done) { + request.get(testUtils.API.getApiQuery('posts/2/')) + .end(function (err, res) { + if (err) { + return done(err); + } + + var jsonResponse = res.body, + changedValue = 'My new Title'; + jsonResponse.should.exist; + jsonResponse.title = changedValue; + + request.put(testUtils.API.getApiQuery('posts/2/')) + .set('X-CSRF-Token', csrfToken) + .send(jsonResponse) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + var putBody = res.body; + var today = new Date(), + dd = ("0" + today.getDate()).slice(-2), + mm = ("0" + (today.getMonth() + 1)).slice(-2), + yyyy = today.getFullYear(), + postLink = '/' + yyyy + '/' + mm + '/' + dd + '/' + putBody.slug + '/'; + + res.headers['x-cache-invalidate'].should.eql('/, /page/*, /rss/, /rss/*, /tag/*, ' + postLink); + res.should.be.json; + putBody.should.exist; + putBody.title.should.eql(changedValue); + + testUtils.API.checkResponse(putBody, 'post'); + done(); + }); + }); + }); + + + }); + + +}); diff --git a/core/test/functional/routes/api/settings_test.js b/core/test/functional/routes/api/settings_test.js new file mode 100644 index 0000000000..45959c3e0c --- /dev/null +++ b/core/test/functional/routes/api/settings_test.js @@ -0,0 +1,229 @@ +/*global describe, it, before, after */ +var supertest = require('supertest'), + express = require('express'), + should = require('should'), + _ = require('lodash'), + testUtils = require('../../../utils'), + + ghost = require('../../../../../core'), + + httpServer, + request, + agent; + + +describe('Settings API', function () { + var user = testUtils.DataGenerator.forModel.users[0], + csrfToken = ''; + + before(function (done) { + var app = express(); + + ghost({app: app}).then(function (_httpServer) { + httpServer = _httpServer; + // request = supertest(app); + request = supertest.agent(app); + + testUtils.clearData() + .then(function () { + return testUtils.initData(); + }) + .then(function () { + return testUtils.insertDefaultFixtures(); + }) + .then(function () { + + request.get('/ghost/signin/') + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + var pattern_meta = //i; + pattern_meta.should.exist; + csrfToken = res.text.match(pattern_meta)[1]; + + setTimeout(function () { + request.post('/ghost/signin/') + .set('X-CSRF-Token', csrfToken) + .send({email: user.email, password: user.password}) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + + request.saveCookies(res); + request.get('/ghost/') + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + // console.log('/ghost/', err, res); + csrfToken = res.text.match(pattern_meta)[1]; + done(); + }); + }); + + }, 2000); + + }); + }, done); + }).otherwise(function (e) { + console.log('Ghost Error: ', e); + console.log(e.stack); + }); + }); + + after(function () { + httpServer.close(); + }); + + // TODO: currently includes values of type=core + it('can retrieve all settings', function (done) { + request.get(testUtils.API.getApiQuery('settings/')) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.should.exist; + + testUtils.API.checkResponse(jsonResponse, 'settings'); + done(); + }); + }); + + it('can retrieve a setting', function (done) { + request.get(testUtils.API.getApiQuery('settings/title/')) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + + jsonResponse.should.exist; + testUtils.API.checkResponseValue(jsonResponse, ['key', 'value']); + jsonResponse.key.should.eql('title'); + done(); + }); + }); + + it('can\'t retrieve non existent setting', function (done) { + request.get(testUtils.API.getApiQuery('settings/testsetting/')) + .expect(404) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.should.exist; + testUtils.API.checkResponseValue(jsonResponse, ['error']); + done(); + }); + }); + + it('can edit settings', function (done) { + request.get(testUtils.API.getApiQuery('settings/')) + .end(function (err, res) { + if (err) { + return done(err); + } + + var jsonResponse = res.body, + changedValue = 'Ghost changed'; + jsonResponse.should.exist; + jsonResponse.title = changedValue; + + request.put(testUtils.API.getApiQuery('settings/')) + .set('X-CSRF-Token', csrfToken) + .send(jsonResponse) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + var putBody = res.body; + res.headers['x-cache-invalidate'].should.eql('/*'); + res.should.be.json; + putBody.should.exist; + putBody.title.should.eql(changedValue); + testUtils.API.checkResponse(putBody, 'settings'); + done(); + }); + }); + }); + + it('can\'t edit settings with invalid CSRF token', function (done) { + request.get(testUtils.API.getApiQuery('settings')) + .end(function (err, res) { + if (err) { + return done(err); + } + + var jsonResponse = res.body, + changedValue = 'Ghost changed'; + jsonResponse.should.exist; + jsonResponse.title = changedValue; + + request.put(testUtils.API.getApiQuery('settings/')) + .set('X-CSRF-Token', 'invalid-token') + .send(jsonResponse) + .expect(403) + .end(function (err, res) { + if (err) { + return done(err); + } + + done(); + }); + }); + }); + + + it('can\'t edit non existent setting', function (done) { + request.get(testUtils.API.getApiQuery('settings')) + .end(function (err, res) { + if (err) { + return done(err); + } + + var jsonResponse = res.body, + newValue = 'new value'; + jsonResponse.should.exist; + jsonResponse.testvalue = newValue; + + request.put(testUtils.API.getApiQuery('settings/')) + .set('X-CSRF-Token', csrfToken) + .send(jsonResponse) + .expect(404) + .end(function (err, res) { + if (err) { + return done(err); + } + + var putBody = res.body; + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + testUtils.API.checkResponseValue(putBody, ['error']); + done(); + }); + }); + }); + + +}); \ No newline at end of file diff --git a/core/test/functional/routes/api/tags_test.js b/core/test/functional/routes/api/tags_test.js new file mode 100644 index 0000000000..2fb5155c97 --- /dev/null +++ b/core/test/functional/routes/api/tags_test.js @@ -0,0 +1,103 @@ +/*global describe, it, before, after */ +var supertest = require('supertest'), + express = require('express'), + should = require('should'), + _ = require('lodash'), + testUtils = require('../../../utils'), + + ghost = require('../../../../../core'), + + httpServer, + request, + agent; + + +describe('Tag API', function () { + var user = testUtils.DataGenerator.forModel.users[0], + csrfToken = ''; + + before(function (done) { + var app = express(); + + ghost({app: app}).then(function (_httpServer) { + httpServer = _httpServer; + // request = supertest(app); + request = supertest.agent(app); + + testUtils.clearData() + .then(function () { + return testUtils.initData(); + }) + .then(function () { + return testUtils.insertDefaultFixtures(); + }) + .then(function () { + + request.get('/ghost/signin/') + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + var pattern_meta = //i; + pattern_meta.should.exist; + csrfToken = res.text.match(pattern_meta)[1]; + + setTimeout(function () { + request.post('/ghost/signin/') + .set('X-CSRF-Token', csrfToken) + .send({email: user.email, password: user.password}) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + + request.saveCookies(res); + request.get('/ghost/') + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + csrfToken = res.text.match(pattern_meta)[1]; + done(); + }); + }); + + }, 2000); + + }); + }, done); + }).otherwise(function (e) { + console.log('Ghost Error: ', e); + console.log(e.stack); + }); + }); + + after(function () { + httpServer.close(); + }); + + it('can retrieve all tags', function (done) { + request.get(testUtils.API.getApiQuery('tags/')) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.should.exist; + jsonResponse.should.have.length(6); + testUtils.API.checkResponse(jsonResponse[0], 'tag'); + done(); + }); + }); + + +}); \ No newline at end of file diff --git a/core/test/functional/routes/api/users_test.js b/core/test/functional/routes/api/users_test.js new file mode 100644 index 0000000000..a5ee3f401f --- /dev/null +++ b/core/test/functional/routes/api/users_test.js @@ -0,0 +1,199 @@ +/*global describe, it, before, after */ +var supertest = require('supertest'), + express = require('express'), + should = require('should'), + _ = require('lodash'), + testUtils = require('../../../utils'), + + ghost = require('../../../../../core'), + + httpServer, + request, + agent; + + +describe('User API', function () { + var user = testUtils.DataGenerator.forModel.users[0], + csrfToken = ''; + + before(function (done) { + var app = express(); + + ghost({app: app}).then(function (_httpServer) { + httpServer = _httpServer; + // request = supertest(app); + request = supertest.agent(app); + + testUtils.clearData() + .then(function () { + return testUtils.initData(); + }) + .then(function () { + return testUtils.insertDefaultFixtures(); + }) + .then(function () { + + request.get('/ghost/signin/') + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + var pattern_meta = //i; + pattern_meta.should.exist; + csrfToken = res.text.match(pattern_meta)[1]; + + setTimeout(function () { + request.post('/ghost/signin/') + .set('X-CSRF-Token', csrfToken) + .send({email: user.email, password: user.password}) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + request.saveCookies(res); + request.get('/ghost/') + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + // console.log('/ghost/', err, res); + csrfToken = res.text.match(pattern_meta)[1]; + done(); + }); + }); + + }, 2000); + + }); + }, done); + }).otherwise(function (e) { + console.log('Ghost Error: ', e); + console.log(e.stack); + }); + }); + + after(function () { + httpServer.close(); + }); + + it('can retrieve all users', function (done) { + request.get(testUtils.API.getApiQuery('users/')) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse[0].should.exist; + + testUtils.API.checkResponse(jsonResponse[0], 'user'); + done(); + }); + }); + + it('can retrieve a user', function (done) { + request.get(testUtils.API.getApiQuery('users/me/')) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.should.exist; + + testUtils.API.checkResponse(jsonResponse, 'user'); + done(); + }); + }); + + it('can\'t retrieve non existent user', function (done) { + request.get(testUtils.API.getApiQuery('users/99/')) + .expect(404) + .end(function (err, res) { + if (err) { + return done(err); + } + + should.not.exist(res.headers['x-cache-invalidate']); + res.should.be.json; + var jsonResponse = res.body; + jsonResponse.should.exist; + + testUtils.API.checkResponseValue(jsonResponse, ['error']); + done(); + }); + }); + + it('can edit a user', function (done) { + request.get(testUtils.API.getApiQuery('users/me/')) + .end(function (err, res) { + if (err) { + return done(err); + } + + var jsonResponse = res.body, + changedValue = 'joe-bloggs.ghost.org'; + jsonResponse.should.exist; + jsonResponse.website = changedValue; + + request.put(testUtils.API.getApiQuery('users/me/')) + .set('X-CSRF-Token', csrfToken) + .send(jsonResponse) + .expect(200) + .end(function (err, res) { + if (err) { + return done(err); + } + + var putBody = res.body; + res.headers['x-cache-invalidate'].should.eql('/*'); + res.should.be.json; + putBody.should.exist; + putBody.website.should.eql(changedValue); + + testUtils.API.checkResponse(putBody, 'user'); + done(); + }); + }); + }); + + it('can\'t edit a user with invalid CSRF token', function (done) { + request.get(testUtils.API.getApiQuery('users/me/')) + .end(function (err, res) { + if (err) { + return done(err); + } + + var jsonResponse = res.body, + changedValue = 'joe-bloggs.ghost.org'; + jsonResponse.should.exist; + jsonResponse.website = changedValue; + + request.put(testUtils.API.getApiQuery('users/me/')) + .set('X-CSRF-Token', 'invalid-token') + .send(jsonResponse) + .expect(403) + .end(function (err, res) { + if (err) { + return done(err); + } + + done(); + }); + + }); + }); + + +}); \ No newline at end of file diff --git a/core/test/utils/api.js b/core/test/utils/api.js index 2284ba4a73..577961c265 100644 --- a/core/test/utils/api.js +++ b/core/test/utils/api.js @@ -21,6 +21,9 @@ var _ = require('lodash'), notification: ['type', 'message', 'status', 'id'] }; +function getApiQuery (route) { + return url.resolve(ApiRouteBase, route); +} function getApiURL (route) { var baseURL = url.resolve(schema + host + ':' + port, ApiRouteBase); @@ -46,6 +49,7 @@ function checkResponseValue (jsonResponse, properties) { module.exports = { getApiURL: getApiURL, + getApiQuery: getApiQuery, getSigninURL: getSigninURL, getAdminURL: getAdminURL, checkResponse: checkResponse,