From a697a631c224cf292331262304fb529e8db2d343 Mon Sep 17 00:00:00 2001 From: Hannah Wolfe Date: Tue, 31 Dec 2013 17:09:49 +0000 Subject: [PATCH] Route tests issue #1773 - Adds functional tests for frontend routing - Tests the request-response contract - Requires db access at the moment - Tests #1790 --- Gruntfile.js | 10 +- core/test/functional/routes/frontend_test.js | 245 +++++++++++++++++++ core/test/utils/index.js | 8 +- package.json | 5 +- 4 files changed, 261 insertions(+), 7 deletions(-) create mode 100644 core/test/functional/routes/frontend_test.js diff --git a/Gruntfile.js b/Gruntfile.js index ad305fc118..f96521fbc8 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -249,6 +249,10 @@ var path = require('path'), api: { src: ['core/test/functional/api/*_test.js'] + }, + + routes: { + src: ['core/test/functional/routes/*_test.js'] } }, @@ -827,12 +831,14 @@ var path = require('path'), grunt.registerTask('test-api', 'Run functional api tests (mocha)', ['clean:test', 'setTestEnv', 'loadConfig', 'express:test', 'mochacli:api', 'express:test:stop']); - grunt.registerTask('validate', 'Run tests and lint code', ['jslint', 'test-unit', 'test-api', 'test-integration', 'test-functional']); + grunt.registerTask('test-routes', 'Run functional route tests (mocha)', ['clean:test', 'setTestEnv', 'loadConfig', 'express:test', 'mochacli:routes', 'express:test:stop']); + + grunt.registerTask('validate', 'Run tests and lint code', ['jslint', 'test-routes', 'test-unit', 'test-api', 'test-integration', 'test-functional']); // ### Coverage report for Unit and Integration Tests - grunt.registerTask('test-coverage', 'Generate unit and integration (mocha) tests coverage report', ['clean:test', 'setTestEnv', 'loadConfig', 'express:test', 'shell:coverage']); + grunt.registerTask('test-coverage', 'Generate unit and integration (mocha) tests coverage report', ['clean:test', 'setTestEnv', 'loadConfig', 'express:test', 'shell:coverage', 'express:test:stop']); // ### Documentation diff --git a/core/test/functional/routes/frontend_test.js b/core/test/functional/routes/frontend_test.js new file mode 100644 index 0000000000..6323bbb7ae --- /dev/null +++ b/core/test/functional/routes/frontend_test.js @@ -0,0 +1,245 @@ +/*global describe, it, before, after */ + +// # Frontend 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 request = require('supertest'), + should = require('should'), + moment = require('moment'), + + testUtils = require('../../utils'), + config = require('../../../server/config'); + +describe('Frontend Routing', function () { + function doEnd(done) { + return function (err, res) { + if (err) { + return done(err); + } + done(); + }; + } + + before(function (done) { + testUtils.clearData().then(function () { + // we initialise data, but not a user. No user should be required for navigating the frontend + return testUtils.initData(); + }).then(function () { + done(); + }, done); + + // Setup the request object with the correct URL + request = request(config().url); + }); + + describe('Home', function () { + it('should respond with html', function (done) { + request.get('/') + .expect('Content-Type', /html/) + .expect(200) + .end(doEnd(done)); + }); + + it('should not have as second page', function (done) { + request.get('/page/2/') + .expect('Location', '/') + .expect(302) + .end(doEnd(done)); + }); + }); + + describe('Welcome post', function () { + it('should redirect without slash', function (done) { + request.get('/welcome-to-ghost') + .expect('Location', '/welcome-to-ghost/') + .expect(301) + .end(doEnd(done)); + }); + + it('should respond with html', function (done) { + request.get('/welcome-to-ghost/') + .expect('Content-Type', /html/) + .expect(200) + .end(doEnd(done)); + }); + + it('should not work with date permalinks', function (done) { + // get today's date + var date = moment().format("YYYY/MM/DD"); + + console.log('date', date); + + request.get('/' + date + '/welcome-to-ghost/') + .expect(404) + // TODO this error message is inconsistent + .expect(/Page Not Found/) + .end(doEnd(done)); + }); + + it('should 404 for unknown post', function (done) { + request.get('/spectacular/') + .expect(404) + // TODO this error message is inconsistent + .expect(/Post not found/) + .end(doEnd(done)); + }); + }); + + describe('RSS', function () { + it('should redirect without slash', function (done) { + request.get('/rss') + .expect('Location', '/rss/') + .expect(301) + .end(doEnd(done)); + }); + + it('should respond with xml', function (done) { + request.get('/rss/') + .expect('Content-Type', /xml/) + .expect(200) + .end(doEnd(done)); + }); + + it('should not have as second page', function (done) { + request.get('/rss/2/') + // TODO this should probably redirect straight to /rss/ ? + .expect('Location', '/rss/1/') + .expect(302) + .end(doEnd(done)); + }); + }); + + // ### The rest of the tests require more data + + describe('Archive pages', function () { + + // Add enough posts to trigger pages for both the archive (6 pp) and rss (15 pp) + // insertPosts adds 5 published posts, 1 draft post, 1 published static page and one draft page + // we then insert with max 11 which ensures we have 16 published posts + before(function (done) { + testUtils.insertPosts().then(function () { + return testUtils.insertMorePosts(11); + }).then(function () { + done(); + }).then(null, done); + }); + + it('should redirect without slash', function (done) { + request.get('/page/2') + .expect('Location', '/page/2/') + .expect(301) + .end(doEnd(done)); + }); + + it('should respond with html', function (done) { + request.get('/page/2/') + .expect('Content-Type', /html/) + .expect(200) + .end(doEnd(done)); + }); + + it('should redirect page 1', function (done) { + request.get('/page/1/') + .expect('Location', '/') + // TODO: This should probably be a 301? + .expect(302) + .end(doEnd(done)); + }); + + it('should redirect to last page is page too high', function (done) { + request.get('/page/4/') + .expect('Location', '/page/3/') + .expect(302) + .end(doEnd(done)); + }); + + it('should redirect to first page is page too low', function (done) { + request.get('/page/0/') + .expect('Location', '/') + .expect(302) + .end(doEnd(done)); + }); + }); + + describe('RSS pages', function () { + it('should redirect without slash', function (done) { + request.get('/rss/2') + .expect('Location', '/rss/2/') + .expect(301) + .end(doEnd(done)); + }); + + it('should respond with xml', function (done) { + request.get('/rss/2/') + .expect('Content-Type', /xml/) + .expect(200) + .end(doEnd(done)); + }); + + it('should redirect page 1', function (done) { + request.get('/rss/1/') + .expect('Location', '/rss/') + // TODO: This should probably be a 301? + .expect(302) + .end(doEnd(done)); + }); + + it('should redirect to last page is page too high', function (done) { + request.get('/rss/3/') + .expect('Location', '/rss/2/') + .expect(302) + .end(doEnd(done)); + }); + + it('should redirect to first page is page too low', function (done) { + request.get('/rss/0/') + .expect('Location', '/rss/') + .expect(302) + .end(doEnd(done)); + }); + }); + + describe('Static page', function () { + it('should redirect without slash', function (done) { + request.get('/static-page-test') + .expect('Location', '/static-page-test/') + .expect(301) + .end(doEnd(done)); + }); + + it('should respond with xml', function (done) { + request.get('/static-page-test/') + .expect('Content-Type', /html/) + .expect(200) + .end(doEnd(done)); + }); + }); + + // ### The rest of the tests switch to date permalinks + +// describe('Date permalinks', function () { +// before(function (done) { +// // Only way to swap permalinks setting is to login and visit the URL because +// // poking the database doesn't work as settings are cached +// }); +// +// it('should load a post with date permalink', function (done) { +// +// // get today's date +// var date = moment().format("YYYY/MM/DD"); +// +// console.log('date', date); +// +// request.get('/' + date + '/welcome-to-ghost/') +// .expect(200) +// .expect('Content-Type', /html/) +// .end(doEnd(done)); +// }); +// }); + +}); + + + diff --git a/core/test/utils/index.js b/core/test/utils/index.js index 5d8084edb4..b5405f29a6 100644 --- a/core/test/utils/index.js +++ b/core/test/utils/index.js @@ -25,20 +25,22 @@ function insertPosts() { })); } -function insertMorePosts() { +function insertMorePosts(max) { var lang, status, posts, promises = [], i, j, k = 0; + max = max || 50; + for (i = 0; i < 2; i += 1) { posts = []; lang = i % 2 ? 'en' : 'fr'; posts.push(DataGenerator.forKnex.createGenericPost(k++, null, lang)); - for (j = 0; j < 50; j += 1) { - status = j % 2 ? 'published' : 'draft'; + for (j = 0; j < max; j += 1) { + status = j % 2 ? 'draft' : 'published'; posts.push(DataGenerator.forKnex.createGenericPost(k++, status, lang)); } diff --git a/package.json b/package.json index 6b307e811f..483393c108 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "grunt-contrib-sass": "~0.5.0", "grunt-contrib-uglify": "~0.2.5", "grunt-contrib-watch": "~0.5.3", - "grunt-express-server": "~0.4.5", + "grunt-express-server": "~0.4.11", "grunt-groc": "~0.4.0", "grunt-jslint": "~1.1.1", "grunt-mocha-cli": "~1.4.0", @@ -81,6 +81,7 @@ "request": "~2.29.0", "require-dir": "~0.1.0", "should": "~2.1.1", - "sinon": "~1.7.3" + "sinon": "~1.7.3", + "supertest": "~0.8.2" } }