From e23fd511eb34f741dfdf9c4b8866f41671f5366a Mon Sep 17 00:00:00 2001 From: Katharina Irrgang Date: Wed, 25 Apr 2018 17:13:35 +0200 Subject: [PATCH] Use Bookshelf in our test env (#9592) refs #9601 - replace raw knex queries by Bookshelf queries - optimise lot's of test setups, so we don't experience a massive slow down in the test run - this has troubled in the past e.g. with normalisation, any custom model logic - the test env always had to simulate things - there are for sure thousands things which can be optimised now, but because of time, we do them step by step - this is especially important for the url service (https://github.com/TryGhost/Ghost/issues/9601), because we have to ensure that inserting/updating/removing resources will trigger model events `grunt test-all` with SQLite finishes in 2,5-3min. (on master: 1-2min) `grunt test-all` with MySQL finishes in 4min. (on master: 3min) **NOTE: We want to move as much as possible routing and integration tests to unit tests. This will speed up the test run again.** See #9342. But we need to find time for that. Any help is welcome! --- .../routes/api/authentication_spec.js | 13 +- core/test/functional/routes/api/posts_spec.js | 4 +- .../functional/routes/api/public_api_spec.js | 10 +- .../routes/api/spam_prevention_spec.js | 2 +- .../test/functional/routes/api/themes_spec.js | 4 +- core/test/functional/routes/api/users_spec.js | 62 +- core/test/functional/routes/channel_spec.js | 6 +- core/test/integration/api/api_invites_spec.js | 54 +- .../integration/api/api_notifications_spec.js | 9 +- core/test/integration/api/api_posts_spec.js | 48 +- core/test/integration/api/api_roles_spec.js | 5 +- .../integration/api/api_schedules_spec.js | 4 +- .../test/integration/api/api_settings_spec.js | 4 +- core/test/integration/api/api_slugs_spec.js | 4 +- .../integration/api/api_subscribers_spec.js | 54 +- core/test/integration/api/api_tags_spec.js | 43 +- core/test/integration/api/api_users_spec.js | 347 ++++--- .../data/importer/importers/data_spec.js | 339 ++++--- .../model/model_accesstoken_spec.js | 2 +- .../model/model_app-fields_spec.js | 4 +- .../model/model_app-settings_spec.js | 4 +- .../test/integration/model/model_apps_spec.js | 4 +- .../model/model_permissions_spec.js | 4 +- .../integration/model/model_posts_spec.js | 875 +++++++++--------- .../test/integration/model/model_tags_spec.js | 58 +- core/test/integration/update_check_spec.js | 20 +- core/test/utils/fixtures/data-generator.js | 26 +- core/test/utils/index.js | 435 ++++----- 28 files changed, 1339 insertions(+), 1105 deletions(-) diff --git a/core/test/functional/routes/api/authentication_spec.js b/core/test/functional/routes/api/authentication_spec.js index fb3d6da219..42fea550f2 100644 --- a/core/test/functional/routes/api/authentication_spec.js +++ b/core/test/functional/routes/api/authentication_spec.js @@ -1,13 +1,15 @@ +'use strict'; + var should = require('should'), supertest = require('supertest'), testUtils = require('../../../utils'), moment = require('moment'), user = testUtils.DataGenerator.forModel.users[0], - userForKnex = testUtils.DataGenerator.forKnex.users[0], models = require('../../../../../core/server/models'), constants = require('../../../../../core/server/lib/constants'), config = require('../../../../../core/server/config'), security = require('../../../../../core/server/lib/security'), + settingsCache = require('../../../../../core/server/services/settings/cache'), ghost = testUtils.startGhost, request; @@ -217,14 +219,13 @@ describe('Authentication API', function () { }); it('reset password', function (done) { - models.Settings - .findOne({key: 'db_hash'}) - .then(function (response) { + models.User.getOwnerUser(testUtils.context.internal) + .then(function (ownerUser) { var token = security.tokens.resetToken.generateHash({ expires: Date.now() + (1000 * 60), email: user.email, - dbHash: response.attributes.value, - password: userForKnex.password + dbHash: settingsCache.get('db_hash'), + password: ownerUser.get('password') }); request.put(testUtils.API.getApiQuery('authentication/passwordreset')) diff --git a/core/test/functional/routes/api/posts_spec.js b/core/test/functional/routes/api/posts_spec.js index 17e5e6d793..3a4429ba6e 100644 --- a/core/test/functional/routes/api/posts_spec.js +++ b/core/test/functional/routes/api/posts_spec.js @@ -1415,7 +1415,7 @@ describe('Post API', function () { // create author return testUtils.createUser({ user: testUtils.DataGenerator.forKnex.createUser({email: 'test+2@ghost.org'}), - role: testUtils.DataGenerator.Content.roles[2] + role: testUtils.DataGenerator.Content.roles[2].name }); }) .then(function (_author) { @@ -1555,7 +1555,7 @@ describe('Post API', function () { // create contributor return testUtils.createUser({ user: testUtils.DataGenerator.forKnex.createUser({email: 'test+3@ghost.org'}), - role: testUtils.DataGenerator.Content.roles[4] + role: testUtils.DataGenerator.Content.roles[4].name }); }) .then(function (_contributor) { diff --git a/core/test/functional/routes/api/public_api_spec.js b/core/test/functional/routes/api/public_api_spec.js index 6c8ac25aad..db4ee4cf89 100644 --- a/core/test/functional/routes/api/public_api_spec.js +++ b/core/test/functional/routes/api/public_api_spec.js @@ -18,7 +18,7 @@ describe('Public API', function () { request = supertest.agent(config.get('url')); }) .then(function () { - return testUtils.doAuth(request, 'posts', 'tags:extra', 'client:trusted-domain'); + return testUtils.doAuth(request, 'users:no-owner', 'posts', 'tags:extra', 'client:trusted-domain'); }); }); @@ -312,7 +312,7 @@ describe('Public API', function () { var jsonResponse = res.body; should.exist(jsonResponse.users); testUtils.API.checkResponse(jsonResponse, 'users'); - jsonResponse.users.should.have.length(2); + jsonResponse.users.should.have.length(6); // We don't expose the email address. testUtils.API.checkResponse(jsonResponse.users[0], 'user', null, null, null, {public: true}); @@ -335,7 +335,7 @@ describe('Public API', function () { var jsonResponse = res.body; should.exist(jsonResponse.users); testUtils.API.checkResponse(jsonResponse, 'users'); - jsonResponse.users.should.have.length(2); + jsonResponse.users.should.have.length(6); // We don't expose the email address. testUtils.API.checkResponse(jsonResponse.users[0], 'user', null, null, null, {public: true}); @@ -466,7 +466,7 @@ describe('Public API', function () { var jsonResponse = res.body; should.exist(jsonResponse.users); testUtils.API.checkResponse(jsonResponse, 'users'); - jsonResponse.users.should.have.length(2); + jsonResponse.users.should.have.length(6); // We don't expose the email address. testUtils.API.checkResponse(jsonResponse.users[0], 'user', ['count'], null, null, {public: true}); @@ -489,7 +489,7 @@ describe('Public API', function () { var jsonResponse = res.body; should.exist(jsonResponse.users); testUtils.API.checkResponse(jsonResponse, 'users'); - jsonResponse.users.should.have.length(2); + jsonResponse.users.should.have.length(6); // We don't expose the email address. testUtils.API.checkResponse(jsonResponse.users[0], 'user', null, null, null, {public: true}); diff --git a/core/test/functional/routes/api/spam_prevention_spec.js b/core/test/functional/routes/api/spam_prevention_spec.js index 46fba75ff1..33bf2706fb 100644 --- a/core/test/functional/routes/api/spam_prevention_spec.js +++ b/core/test/functional/routes/api/spam_prevention_spec.js @@ -30,7 +30,7 @@ describe('Spam Prevention API', function () { .then(function () { return testUtils.createUser({ user: testUtils.DataGenerator.forKnex.createUser({email: 'test+1@ghost.org'}), - role: testUtils.DataGenerator.Content.roles[1] + role: testUtils.DataGenerator.Content.roles[1].name }); }) .then(function (user) { diff --git a/core/test/functional/routes/api/themes_spec.js b/core/test/functional/routes/api/themes_spec.js index e1b71d95dd..6af4197992 100644 --- a/core/test/functional/routes/api/themes_spec.js +++ b/core/test/functional/routes/api/themes_spec.js @@ -74,7 +74,7 @@ describe('Themes API', function () { return testUtils.createUser({ user: testUtils.DataGenerator.forKnex.createUser({email: 'test+1@ghost.org'}), - role: testUtils.DataGenerator.Content.roles[1] + role: testUtils.DataGenerator.Content.roles[1].name }); }) .then(function (user) { @@ -88,7 +88,7 @@ describe('Themes API', function () { return testUtils.createUser({ user: testUtils.DataGenerator.forKnex.createUser({email: 'test+author@ghost.org'}), - role: testUtils.DataGenerator.Content.roles[2] + role: testUtils.DataGenerator.Content.roles[2].name }); }) .then(function (user) { diff --git a/core/test/functional/routes/api/users_spec.js b/core/test/functional/routes/api/users_spec.js index 3aff7fcdc7..769cc38873 100644 --- a/core/test/functional/routes/api/users_spec.js +++ b/core/test/functional/routes/api/users_spec.js @@ -14,7 +14,7 @@ describe('User API', function () { authorAccessToken = '', editor, author, ghostServer, inactiveUser; - beforeEach(function () { + before(function () { return ghost() .then(function (_ghostServer) { ghostServer = _ghostServer; @@ -24,7 +24,7 @@ describe('User API', function () { // create editor return testUtils.createUser({ user: testUtils.DataGenerator.forKnex.createUser({email: 'test+1@ghost.org'}), - role: testUtils.DataGenerator.Content.roles[1] + role: testUtils.DataGenerator.Content.roles[1].name }); }) .then(function (_user1) { @@ -33,7 +33,7 @@ describe('User API', function () { // create author return testUtils.createUser({ user: testUtils.DataGenerator.forKnex.createUser({email: 'test+2@ghost.org'}), - role: testUtils.DataGenerator.Content.roles[2] + role: testUtils.DataGenerator.Content.roles[2].name }); }) .then(function (_user2) { @@ -42,7 +42,7 @@ describe('User API', function () { // create inactive user return testUtils.createUser({ user: testUtils.DataGenerator.forKnex.createUser({email: 'test+3@ghost.org', status: 'inactive'}), - role: testUtils.DataGenerator.Content.roles[2] + role: testUtils.DataGenerator.Content.roles[2].name }); }) .then(function (_user3) { @@ -558,6 +558,60 @@ describe('User API', function () { }); describe('As Editor', function () { + before(function () { + return ghost() + .then(function (_ghostServer) { + ghostServer = _ghostServer; + request = supertest.agent(config.get('url')); + }) + .then(function () { + // create editor + return testUtils.createUser({ + user: testUtils.DataGenerator.forKnex.createUser({email: 'test+1@ghost.org'}), + role: testUtils.DataGenerator.Content.roles[1].name + }); + }) + .then(function (_user1) { + editor = _user1; + + // create author + return testUtils.createUser({ + user: testUtils.DataGenerator.forKnex.createUser({email: 'test+2@ghost.org'}), + role: testUtils.DataGenerator.Content.roles[2].name + }); + }) + .then(function (_user2) { + author = _user2; + + // create inactive user + return testUtils.createUser({ + user: testUtils.DataGenerator.forKnex.createUser({email: 'test+3@ghost.org', status: 'inactive'}), + role: testUtils.DataGenerator.Content.roles[2].name + }); + }) + .then(function (_user3) { + inactiveUser = _user3; + + // by default we login with the owner + return testUtils.doAuth(request); + }) + .then(function (token) { + ownerAccessToken = token; + + request.user = editor; + return testUtils.doAuth(request); + }) + .then(function (token) { + editorAccessToken = token; + + request.user = author; + return testUtils.doAuth(request); + }) + .then(function (token) { + authorAccessToken = token; + }); + }); + describe('success cases', function () { it('can edit himself', function (done) { request.put(testUtils.API.getApiQuery('users/' + editor.id + '/')) diff --git a/core/test/functional/routes/channel_spec.js b/core/test/functional/routes/channel_spec.js index 155a1d52d7..9f4d11a30e 100644 --- a/core/test/functional/routes/channel_spec.js +++ b/core/test/functional/routes/channel_spec.js @@ -439,11 +439,13 @@ describe('Channel Routes', function () { describe('Author', function () { var lockedUser = { + name: 'Locked so what', slug: 'locked-so-what', email: 'locked@example.com', status: 'locked' }, suspendedUser = { + name: 'Suspended meeh', slug: 'suspended-meeh', email: 'suspended@example.com', status: 'inactive' @@ -553,12 +555,12 @@ describe('Channel Routes', function () { 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 () { - return testUtils.fixtures.overrideOwnerUser('ghost-owner'); }).then(function () { return testUtils.fixtures.insertPostsAndTags(); }).then(function () { return testUtils.fixtures.insertExtraPosts(9); + }).then(function () { + return testUtils.fixtures.overrideOwnerUser('ghost-owner'); }).then(function () { done(); }).catch(done); diff --git a/core/test/integration/api/api_invites_spec.js b/core/test/integration/api/api_invites_spec.js index 14b8466471..e6b909848e 100644 --- a/core/test/integration/api/api_invites_spec.js +++ b/core/test/integration/api/api_invites_spec.js @@ -12,8 +12,8 @@ var should = require('should'), sandbox = sinon.sandbox.create(); describe('Invites API', function () { - beforeEach(testUtils.teardown); - beforeEach(testUtils.setup('invites', 'settings', 'users:roles', 'perms:invite', 'perms:init')); + before(testUtils.teardown); + before(testUtils.setup('invites', 'settings', 'users:roles', 'perms:invite', 'perms:init')); beforeEach(function () { sandbox.stub(mail, 'send').callsFake(function () { @@ -28,6 +28,31 @@ describe('Invites API', function () { after(testUtils.teardown); describe('CRUD', function () { + describe('Browse', function () { + it('browse invites', function (done) { + InvitesAPI.browse(testUtils.context.owner) + .then(function (response) { + response.invites.length.should.eql(2); + + response.invites[0].status.should.eql('sent'); + response.invites[0].email.should.eql('test1@ghost.org'); + response.invites[0].role_id.should.eql(testUtils.roles.ids.admin); + + response.invites[1].status.should.eql('sent'); + response.invites[1].email.should.eql('test2@ghost.org'); + response.invites[1].role_id.should.eql(testUtils.roles.ids.author); + + should.not.exist(response.invites[0].token); + should.exist(response.invites[0].expires); + + should.not.exist(response.invites[1].token); + should.exist(response.invites[1].expires); + + done(); + }).catch(done); + }); + }); + describe('Add', function () { it('add invite 1', function (done) { InvitesAPI.add({ @@ -101,31 +126,6 @@ describe('Invites API', function () { }); }); - describe('Browse', function () { - it('browse invites', function (done) { - InvitesAPI.browse(testUtils.context.owner) - .then(function (response) { - response.invites.length.should.eql(2); - - response.invites[0].status.should.eql('sent'); - response.invites[0].email.should.eql('test1@ghost.org'); - response.invites[0].role_id.should.eql(testUtils.roles.ids.admin); - - response.invites[1].status.should.eql('sent'); - response.invites[1].email.should.eql('test2@ghost.org'); - response.invites[1].role_id.should.eql(testUtils.roles.ids.author); - - should.not.exist(response.invites[0].token); - should.exist(response.invites[0].expires); - - should.not.exist(response.invites[1].token); - should.exist(response.invites[1].expires); - - done(); - }).catch(done); - }); - }); - describe('Read', function () { it('read invites: not found', function (done) { InvitesAPI.read(_.merge({}, testUtils.context.owner, { diff --git a/core/test/integration/api/api_notifications_spec.js b/core/test/integration/api/api_notifications_spec.js index 75ec99dc41..eb0a3109a1 100644 --- a/core/test/integration/api/api_notifications_spec.js +++ b/core/test/integration/api/api_notifications_spec.js @@ -3,13 +3,18 @@ var should = require('should'), uuid = require('uuid'), ObjectId = require('bson-objectid'), testUtils = require('../../utils'), + models = require('../../../server/models'), NotificationsAPI = require('../../../server/api/notifications'); describe('Notifications API', function () { // Keep the DB clean before(testUtils.teardown); - afterEach(testUtils.teardown); - beforeEach(testUtils.setup('settings', 'users:roles', 'perms:setting', 'perms:notification', 'perms:init')); + after(testUtils.teardown); + before(testUtils.setup('settings', 'users:roles', 'perms:setting', 'perms:notification', 'perms:init')); + + beforeEach(function () { + return models.Settings.edit({key: 'notifications', value: '[]'}, testUtils.context.internal); + }); should.exist(NotificationsAPI); diff --git a/core/test/integration/api/api_posts_spec.js b/core/test/integration/api/api_posts_spec.js index b124327034..d3cf838a0e 100644 --- a/core/test/integration/api/api_posts_spec.js +++ b/core/test/integration/api/api_posts_spec.js @@ -17,34 +17,9 @@ describe('Post API', function () { var localSettingsCache = {}; before(testUtils.teardown); - afterEach(testUtils.teardown); - beforeEach(testUtils.setup('users:roles', 'perms:post', 'perms:init')); + after(testUtils.teardown); - // @TODO: remove when https://github.com/TryGhost/Ghost/issues/6930 is fixed - // we insert the posts via the model layer, because right now the test utils insert dates wrong - beforeEach(function (done) { - Promise.mapSeries(testUtils.DataGenerator.forKnex.posts, function (post) { - return models.Post.add(post, {context: {internal: true}}); - }).then(function () { - done(); - }).catch(done); - }); - - beforeEach(function (done) { - Promise.mapSeries(testUtils.DataGenerator.forKnex.tags, function (tag) { - return models.Tag.add(tag, {context: {internal: true}}); - }).then(function () { - done(); - }).catch(done); - }); - - beforeEach(function (done) { - db.knex('posts_tags').insert(testUtils.DataGenerator.forKnex.posts_tags) - .then(function () { - done(); - }) - .catch(done); - }); + before(testUtils.setup('users:roles', 'perms:post', 'perms:init', 'posts')); beforeEach(function () { sandbox.stub(settingsCache, 'get').callsFake(function (key) { @@ -60,14 +35,6 @@ describe('Post API', function () { should.exist(PostAPI); describe('Browse', function () { - beforeEach(function () { - return db.knex('posts_authors').insert({ - id: ObjectId.generate(), - post_id: testUtils.DataGenerator.forKnex.posts[0].id, - author_id: testUtils.DataGenerator.forKnex.users[1].id - }); - }); - beforeEach(function () { localSettingsCache.permalinks = '/:slug/'; }); @@ -396,7 +363,8 @@ describe('Post API', function () { post.primary_author.slug.should.eql('joe-bloggs'); }); - _.find(results.posts, {id: testUtils.DataGenerator.forKnex.posts[0].id}).authors.length.should.eql(2); + _.find(results.posts, {id: testUtils.DataGenerator.forKnex.posts[0].id}).authors.length.should.eql(1); + _.find(results.posts, {id: testUtils.DataGenerator.forKnex.posts[3].id}).authors.length.should.eql(2); done(); }).catch(done); @@ -682,6 +650,10 @@ describe('Post API', function () { }); describe('Destroy', function () { + beforeEach(testUtils.teardown); + beforeEach(testUtils.setup('users:roles', 'perms:post', 'perms:init', 'posts')); + after(testUtils.teardown); + it('can delete a post', function (done) { var options = { context: {user: testUtils.DataGenerator.Content.users[1].id}, @@ -717,6 +689,10 @@ describe('Post API', function () { }); describe('Edit', function () { + beforeEach(testUtils.teardown); + beforeEach(testUtils.setup('users:roles', 'perms:post', 'perms:init', 'posts')); + after(testUtils.teardown); + it('can edit own post', function (done) { PostAPI.edit({posts: [{status: 'test'}]}, { context: {user: testUtils.DataGenerator.Content.users[1].id}, diff --git a/core/test/integration/api/api_roles_spec.js b/core/test/integration/api/api_roles_spec.js index 42aebdd4af..10439ce85c 100644 --- a/core/test/integration/api/api_roles_spec.js +++ b/core/test/integration/api/api_roles_spec.js @@ -7,8 +7,9 @@ var should = require('should'), describe('Roles API', function () { // Keep the DB clean before(testUtils.teardown); - afterEach(testUtils.teardown); - beforeEach(testUtils.setup('users:roles', 'perms:role', 'perms:init')); + after(testUtils.teardown); + + before(testUtils.setup('users:roles', 'perms:role', 'perms:init')); describe('Browse', function () { function checkBrowseResponse(response) { diff --git a/core/test/integration/api/api_schedules_spec.js b/core/test/integration/api/api_schedules_spec.js index 0e6ab7ae75..75dda1d51e 100644 --- a/core/test/integration/api/api_schedules_spec.js +++ b/core/test/integration/api/api_schedules_spec.js @@ -174,7 +174,7 @@ describe('Schedules API', function () { describe('fn: publishPost', function () { var originalCannotScheduleAPostBeforeInMinutes; - beforeEach(function (done) { + before(function (done) { originalCannotScheduleAPostBeforeInMinutes = config.get('times').cannotScheduleAPostBeforeInMinutes; // we can insert published_at less then 5minutes @@ -407,7 +407,7 @@ describe('Schedules API', function () { }); it('other user has no access', function (done) { - testUtils.fixtures.insertOne('users', 'createUser', 4) + testUtils.fixtures.insertOne('User', 'users', 'createUser', 4) .then(function (result) { api.schedules.publishPost({id: scope.posts[0].id, context: {user: result[0]}}) .then(function () { diff --git a/core/test/integration/api/api_settings_spec.js b/core/test/integration/api/api_settings_spec.js index 03f75fc63f..2f00f72135 100644 --- a/core/test/integration/api/api_settings_spec.js +++ b/core/test/integration/api/api_settings_spec.js @@ -13,8 +13,8 @@ var should = require('should'), describe('Settings API', function () { // Keep the DB clean before(testUtils.teardown); - afterEach(testUtils.teardown); - beforeEach(testUtils.setup('users:roles', 'perms:setting', 'settings', 'perms:init')); + after(testUtils.teardown); + before(testUtils.setup('settings', 'users:roles', 'perms:setting', 'perms:init')); should.exist(SettingsAPI); diff --git a/core/test/integration/api/api_slugs_spec.js b/core/test/integration/api/api_slugs_spec.js index cccb5ae147..7501fca143 100644 --- a/core/test/integration/api/api_slugs_spec.js +++ b/core/test/integration/api/api_slugs_spec.js @@ -6,9 +6,9 @@ var should = require('should'), describe('Slug API', function () { // Keep the DB clean before(testUtils.teardown); - afterEach(testUtils.teardown); + after(testUtils.teardown); - beforeEach(testUtils.setup('users:roles', 'perms:slug', 'perms:init')); + before(testUtils.setup('settings', 'users:roles', 'perms:slug', 'perms:init')); should.exist(SlugAPI); diff --git a/core/test/integration/api/api_subscribers_spec.js b/core/test/integration/api/api_subscribers_spec.js index 5f50b89fae..b2ba13bd44 100644 --- a/core/test/integration/api/api_subscribers_spec.js +++ b/core/test/integration/api/api_subscribers_spec.js @@ -14,17 +14,27 @@ var should = require('should'), describe('Subscribers API', function () { // Keep the DB clean before(testUtils.teardown); - afterEach(testUtils.teardown); + after(testUtils.teardown); + afterEach(function () { sandbox.restore(); }); - beforeEach(testUtils.setup('users:roles', 'perms:subscriber', 'perms:init', 'posts', 'subscriber')); + + before(testUtils.setup('settings', 'users:roles', 'perms:subscriber', 'perms:init', 'posts')); should.exist(SubscribersAPI); describe('Add', function () { var newSubscriber; + beforeEach(function () { + return testUtils.fixtures.insertOne('Subscriber', 'subscribers', 'createSubscriber'); + }); + + afterEach(function () { + return testUtils.truncate('subscribers'); + }); + beforeEach(function () { newSubscriber = _.clone(testUtils.DataGenerator.forKnex.createSubscriber(testUtils.DataGenerator.Content.subscribers[1])); Promise.resolve(newSubscriber); @@ -95,6 +105,14 @@ describe('Subscribers API', function () { }); describe('Edit', function () { + beforeEach(function () { + return testUtils.fixtures.insertOne('Subscriber', 'subscribers', 'createSubscriber'); + }); + + afterEach(function () { + return testUtils.truncate('subscribers'); + }); + var newSubscriberEmail = 'subscriber@updated.com', firstSubscriber = testUtils.DataGenerator.Content.subscribers[0].id; @@ -153,6 +171,14 @@ describe('Subscribers API', function () { }); describe('Destroy', function () { + beforeEach(function () { + return testUtils.fixtures.insertOne('Subscriber', 'subscribers', 'createSubscriber'); + }); + + afterEach(function () { + return testUtils.truncate('subscribers'); + }); + var firstSubscriber = testUtils.DataGenerator.Content.subscribers[0]; it('can destroy subscriber as admin', function (done) { @@ -197,6 +223,14 @@ describe('Subscribers API', function () { }); describe('Browse', function () { + beforeEach(function () { + return testUtils.fixtures.insertOne('Subscriber', 'subscribers', 'createSubscriber'); + }); + + afterEach(function () { + return testUtils.truncate('subscribers'); + }); + it('can browse (internal)', function (done) { SubscribersAPI.browse(testUtils.context.internal).then(function (results) { should.exist(results); @@ -229,6 +263,14 @@ describe('Subscribers API', function () { }); describe('Read', function () { + beforeEach(function () { + return testUtils.fixtures.insertOne('Subscriber', 'subscribers', 'createSubscriber'); + }); + + afterEach(function () { + return testUtils.truncate('subscribers'); + }); + it('with id', function (done) { SubscribersAPI.browse({context: {user: 1}}).then(function (results) { should.exist(results); @@ -275,6 +317,14 @@ describe('Subscribers API', function () { describe('Read CSV', function () { var scope = {}; + beforeEach(function () { + return testUtils.fixtures.insertOne('Subscriber', 'subscribers', 'createSubscriber'); + }); + + afterEach(function () { + return testUtils.truncate('subscribers'); + }); + beforeEach(function () { sandbox.stub(fs, 'unlink').resolves(); sandbox.stub(fsLib, 'readCSV').value(function () { diff --git a/core/test/integration/api/api_tags_spec.js b/core/test/integration/api/api_tags_spec.js index 2203e2637e..938a9544c6 100644 --- a/core/test/integration/api/api_tags_spec.js +++ b/core/test/integration/api/api_tags_spec.js @@ -17,14 +17,23 @@ function onlyFixtures(slug) { describe('Tags API', function () { // Keep the DB clean before(testUtils.teardown); - afterEach(testUtils.teardown); - beforeEach(testUtils.setup('users:roles', 'perms:tag', 'perms:init', 'posts')); + after(testUtils.teardown); + + before(testUtils.setup('settings', 'users:roles', 'perms:tag', 'perms:init')); should.exist(TagAPI); describe('Add', function () { var newTag; + beforeEach(function () { + return testUtils.fixtures.insertTags(); + }); + + afterEach(function () { + return testUtils.truncate('tags'); + }); + beforeEach(function () { newTag = _.clone(_.omit(testUtils.DataGenerator.forKnex.createTag(testUtils.DataGenerator.Content.tags[0]), 'id')); }); @@ -108,6 +117,14 @@ describe('Tags API', function () { }); describe('Edit', function () { + beforeEach(function () { + return testUtils.fixtures.insertTags(); + }); + + afterEach(function () { + return testUtils.truncate('tags'); + }); + var newTagName = 'tagNameUpdated', firstTag = testUtils.DataGenerator.Content.tags[0].id; @@ -163,6 +180,14 @@ describe('Tags API', function () { }); describe('Destroy', function () { + beforeEach(function () { + return testUtils.fixtures.insertTags(); + }); + + afterEach(function () { + return testUtils.truncate('tags'); + }); + var firstTag = testUtils.DataGenerator.Content.tags[0].id; it('can destroy Tag', function (done) { @@ -176,10 +201,14 @@ describe('Tags API', function () { }); describe('Browse', function () { - beforeEach(function (done) { - testUtils.fixtures.insertExtraTags().then(function () { - done(); - }); + before(function () { + return testUtils.fixtures.insertPostsAndTags(); + }); + + after(testUtils.teardown); + + before(function () { + return testUtils.fixtures.insertExtraTags(); }); it('can browse (internal)', function (done) { @@ -356,6 +385,8 @@ describe('Tags API', function () { }); describe('Read', function () { + before(testUtils.setup('users:roles', 'posts')); + it('returns count.posts with include count.posts', function (done) { TagAPI.read({context: {user: 1}, include: 'count.posts', slug: 'kitchen-sink'}).then(function (results) { should.exist(results); diff --git a/core/test/integration/api/api_users_spec.js b/core/test/integration/api/api_users_spec.js index 84aeba0638..e46900a258 100644 --- a/core/test/integration/api/api_users_spec.js +++ b/core/test/integration/api/api_users_spec.js @@ -19,6 +19,10 @@ describe('Users API', function () { // Keep the DB clean before(testUtils.teardown); + before(testUtils.setup( + 'settings', 'users:roles', 'users:extra', 'user-token', 'perms:user', 'perms:role', 'perms:setting', 'perms:init', 'posts' + )); + beforeEach(function () { eventsTriggered = {}; @@ -31,15 +35,12 @@ describe('Users API', function () { }); }); - beforeEach(testUtils.setup( - 'users:roles', 'users:extra', 'user-token', 'perms:user', 'perms:role', 'perms:setting', 'perms:init', 'posts' - )); - afterEach(function () { sandbox.restore(); - return testUtils.teardown(); }); + after(testUtils.teardown); + function checkForErrorType(type, done) { return function checkForErrorType(error) { if (error.errorType) { @@ -51,20 +52,6 @@ describe('Users API', function () { }; } - it('dateTime fields are returned as Date objects', function (done) { - var userData = testUtils.DataGenerator.forModel.users[0]; - - models.User.check({email: userData.email, password: userData.password}).then(function (user) { - return UserAPI.read(_.merge({id: user.id}, context.internal)); - }).then(function (response) { - response.users[0].created_at.should.be.an.instanceof(Date); - response.users[0].updated_at.should.be.an.instanceof(Date); - response.users[0].last_seen.should.be.an.instanceof(Date); - - done(); - }).catch(done); - }); - describe('Browse', function () { function checkBrowseResponse(response, count, additional, missing, only, options) { should.exist(response); @@ -519,6 +506,20 @@ describe('Users API', function () { }).catch(done); }); + it('dateTime fields are returned as Date objects', function (done) { + var userData = testUtils.DataGenerator.forModel.users[0]; + + models.User.check({email: userData.email, password: userData.password}).then(function (user) { + return UserAPI.read(_.merge({id: user.id}, context.internal)); + }).then(function (response) { + response.users[0].created_at.should.be.an.instanceof(Date); + response.users[0].updated_at.should.be.an.instanceof(Date); + response.users[0].last_seen.should.be.an.instanceof(Date); + + done(); + }).catch(done); + }); + describe('Change status', function () { describe('as owner', function () { it('[success] can change status to inactive for admin', function () { @@ -841,7 +842,15 @@ describe('Users API', function () { }); describe('Destroy', function () { + before(testUtils.teardown); + describe('General Tests', function () { + beforeEach(testUtils.setup( + 'settings', 'users:roles', 'users:extra', 'user-token', 'perms:user', 'perms:role', 'perms:setting', 'perms:init', 'posts' + )); + + afterEach(testUtils.teardown); + it('ensure posts get deleted', function (done) { var postIdsToDelete = [], postIsToKeep = [], options = {}; @@ -971,160 +980,168 @@ describe('Users API', function () { }); }); - describe('Owner', function () { - it('CANNOT destroy self', function (done) { - UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.owner})) - .then(function () { - done(new Error('Owner should not be able to delete itself')); - }).catch(checkForErrorType('NoPermissionError', done)); - }); + describe('Permissions', function () { + beforeEach(testUtils.setup( + 'settings', 'users:roles', 'users:extra', 'perms:user', 'perms:role', 'perms:setting', 'perms:init' + )); - it('Can destroy admin, editor, author, contributor', function (done) { - // Admin - UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.admin})) - .then(function (response) { - should.not.exist(response); - // Editor - return UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.editor})); - }).then(function (response) { - should.not.exist(response); + afterEach(testUtils.teardown); - // Author - return UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.author})); - }).then(function (response) { - should.not.exist(response); + describe('Owner', function () { + it('CANNOT destroy self', function (done) { + UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.owner})) + .then(function () { + done(new Error('Owner should not be able to delete itself')); + }).catch(checkForErrorType('NoPermissionError', done)); + }); - // Contributor - return UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.contributor})); - }).then(function (response) { - should.not.exist(response); - done(); - }).catch(done); - }); - }); - - describe('Admin', function () { - it('CANNOT destroy owner', function (done) { - UserAPI.destroy(_.extend({}, context.admin, {id: userIdFor.owner})) - .then(function () { - done(new Error('Admin should not be able to delete owner')); - }).catch(checkForErrorType('NoPermissionError', done)); - }); - - it('Can destroy admin, editor, author, contributor', function (done) { - // Admin - UserAPI.destroy(_.extend({}, context.admin, {id: testUtils.DataGenerator.Content.extraUsers[0].id})) - .then(function (response) { + it('Can destroy admin, editor, author, contributor', function (done) { + // Admin + UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.admin})) + .then(function (response) { + should.not.exist(response); + // Editor + return UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.editor})); + }).then(function (response) { should.not.exist(response); - // Editor - return UserAPI.destroy(_.extend({}, context.admin, {id: testUtils.DataGenerator.Content.extraUsers[1].id})); + // Author + return UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.author})); }).then(function (response) { - should.not.exist(response); + should.not.exist(response); - // Author - return UserAPI.destroy(_.extend({}, context.admin, {id: testUtils.DataGenerator.Content.extraUsers[2].id})); - }).then(function (response) { - should.not.exist(response); - - // Contributor - return UserAPI.destroy(_.extend({}, context.admin, {id: testUtils.DataGenerator.Content.extraUsers[3].id})); - }).then(function (response) { - should.not.exist(response); - done(); - }).catch(done); - }); - }); - - describe('Editor', function () { - it('CANNOT destroy owner', function (done) { - UserAPI.destroy(_.extend({}, context.editor, {id: userIdFor.owner})) - .then(function () { - done(new Error('Editor should not be able to delete owner')); - }).catch(checkForErrorType('NoPermissionError', done)); - }); - - it('CANNOT destroy admin', function (done) { - UserAPI.destroy(_.extend({}, context.editor, {id: userIdFor.admin})) - .then(function () { - done(new Error('Editor should not be able to delete admin')); - }).catch(checkForErrorType('NoPermissionError', done)); - }); - - it('CANNOT destroy other editor', function (done) { - UserAPI.destroy(_.extend({}, context.editor, {id: testUtils.DataGenerator.Content.extraUsers[1].id})) - .then(function () { - done(new Error('Editor should not be able to delete other editor')); - }).catch(checkForErrorType('NoPermissionError', done)); - }); - - it('Can destroy self', function (done) { - UserAPI.destroy(_.extend({}, context.editor, {id: userIdFor.editor})) - .then(function (response) { + // Contributor + return UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.contributor})); + }).then(function (response) { should.not.exist(response); done(); }).catch(done); + }); }); - it('Can destroy author', function (done) { - UserAPI.destroy(_.extend({}, context.editor, {id: userIdFor.author})) - .then(function (response) { + describe('Admin', function () { + it('CANNOT destroy owner', function (done) { + UserAPI.destroy(_.extend({}, context.admin, {id: userIdFor.owner})) + .then(function () { + done(new Error('Admin should not be able to delete owner')); + }).catch(checkForErrorType('NoPermissionError', done)); + }); + + it('Can destroy admin, editor, author, contributor', function (done) { + // Admin + UserAPI.destroy(_.extend({}, context.admin, {id: testUtils.DataGenerator.Content.extraUsers[0].id})) + .then(function (response) { + should.not.exist(response); + + // Editor + return UserAPI.destroy(_.extend({}, context.admin, {id: testUtils.DataGenerator.Content.extraUsers[1].id})); + }).then(function (response) { + should.not.exist(response); + + // Author + return UserAPI.destroy(_.extend({}, context.admin, {id: testUtils.DataGenerator.Content.extraUsers[2].id})); + }).then(function (response) { + should.not.exist(response); + + // Contributor + return UserAPI.destroy(_.extend({}, context.admin, {id: testUtils.DataGenerator.Content.extraUsers[3].id})); + }).then(function (response) { should.not.exist(response); done(); }).catch(done); - }); - }); - - describe('Author', function () { - it('CANNOT destroy owner', function (done) { - UserAPI.destroy(_.extend({}, context.author, {id: userIdFor.owner})) - .then(function () { - done(new Error('Author should not be able to delete owner')); - }).catch(checkForErrorType('NoPermissionError', done)); + }); }); - it('CANNOT destroy admin', function (done) { - UserAPI.destroy(_.extend({}, context.author, {id: userIdFor.admin})) - .then(function () { - done(new Error('Author should not be able to delete admin')); - }).catch(checkForErrorType('NoPermissionError', done)); + describe('Editor', function () { + it('CANNOT destroy owner', function (done) { + UserAPI.destroy(_.extend({}, context.editor, {id: userIdFor.owner})) + .then(function () { + done(new Error('Editor should not be able to delete owner')); + }).catch(checkForErrorType('NoPermissionError', done)); + }); + + it('CANNOT destroy admin', function (done) { + UserAPI.destroy(_.extend({}, context.editor, {id: userIdFor.admin})) + .then(function () { + done(new Error('Editor should not be able to delete admin')); + }).catch(checkForErrorType('NoPermissionError', done)); + }); + + it('CANNOT destroy other editor', function (done) { + UserAPI.destroy(_.extend({}, context.editor, {id: testUtils.DataGenerator.Content.extraUsers[1].id})) + .then(function () { + done(new Error('Editor should not be able to delete other editor')); + }).catch(checkForErrorType('NoPermissionError', done)); + }); + + it('Can destroy self', function (done) { + UserAPI.destroy(_.extend({}, context.editor, {id: userIdFor.editor})) + .then(function (response) { + should.not.exist(response); + done(); + }).catch(done); + }); + + it('Can destroy author', function (done) { + UserAPI.destroy(_.extend({}, context.editor, {id: userIdFor.author})) + .then(function (response) { + should.not.exist(response); + done(); + }).catch(done); + }); }); - it('CANNOT destroy editor', function (done) { - UserAPI.destroy(_.extend({}, context.author, {id: userIdFor.editor})) - .then(function () { - done(new Error('Author should not be able to delete editor')); - }).catch(checkForErrorType('NoPermissionError', done)); + describe('Author', function () { + it('CANNOT destroy owner', function (done) { + UserAPI.destroy(_.extend({}, context.author, {id: userIdFor.owner})) + .then(function () { + done(new Error('Author should not be able to delete owner')); + }).catch(checkForErrorType('NoPermissionError', done)); + }); + + it('CANNOT destroy admin', function (done) { + UserAPI.destroy(_.extend({}, context.author, {id: userIdFor.admin})) + .then(function () { + done(new Error('Author should not be able to delete admin')); + }).catch(checkForErrorType('NoPermissionError', done)); + }); + + it('CANNOT destroy editor', function (done) { + UserAPI.destroy(_.extend({}, context.author, {id: userIdFor.editor})) + .then(function () { + done(new Error('Author should not be able to delete editor')); + }).catch(checkForErrorType('NoPermissionError', done)); + }); + + it('CANNOT destroy other author', function (done) { + UserAPI.destroy(_.extend({}, context.author, {id: testUtils.DataGenerator.Content.extraUsers[2].id})) + .then(function () { + done(new Error('Author should not be able to delete other author')); + }).catch(checkForErrorType('NoPermissionError', done)); + }); + + it('CANNOT destroy self', function (done) { + UserAPI.destroy(_.extend({}, context.author, {id: userIdFor.author})) + .then(function () { + done(new Error('Author should not be able to delete self')); + }).catch(checkForErrorType('NoPermissionError', done)); + }); }); - it('CANNOT destroy other author', function (done) { - UserAPI.destroy(_.extend({}, context.author, {id: testUtils.DataGenerator.Content.extraUsers[2].id})) - .then(function () { - done(new Error('Author should not be able to delete other author')); - }).catch(checkForErrorType('NoPermissionError', done)); - }); + describe('Contributor', function () { + it('CANNOT destroy owner', function (done) { + UserAPI.destroy(_.extend({}, context.contributor, {id: userIdFor.owner})) + .then(function () { + done(new Error('Contributor should not be able to delete owner')); + }).catch(checkForErrorType('NoPermissionError', done)); + }); - it('CANNOT destroy self', function (done) { - UserAPI.destroy(_.extend({}, context.author, {id: userIdFor.author})) - .then(function () { - done(new Error('Author should not be able to delete self')); - }).catch(checkForErrorType('NoPermissionError', done)); - }); - }); - - describe('Contributor', function () { - it('CANNOT destroy owner', function (done) { - UserAPI.destroy(_.extend({}, context.contributor, {id: userIdFor.owner})) - .then(function () { - done(new Error('Contributor should not be able to delete owner')); - }).catch(checkForErrorType('NoPermissionError', done)); - }); - - it('CANNOT destroy self', function (done) { - UserAPI.destroy(_.extend({}, context.contributor, {id: userIdFor.contributor})) - .then(function () { - done(new Error('Contributor should not be able to delete self')); - }).catch(checkForErrorType('NoPermissionError', done)); + it('CANNOT destroy self', function (done) { + UserAPI.destroy(_.extend({}, context.contributor, {id: userIdFor.contributor})) + .then(function () { + done(new Error('Contributor should not be able to delete self')); + }).catch(checkForErrorType('NoPermissionError', done)); + }); }); }); }); @@ -1132,6 +1149,18 @@ describe('Users API', function () { describe('Edit and assign role', function () { var newName = 'Jo McBlogger'; + before(testUtils.teardown); + + before(testUtils.setup( + 'settings', 'users:roles', 'users:extra', 'perms:user', 'perms:role', 'perms:setting', 'perms:init' + )); + + beforeEach(function () { + return testUtils.fixtures.resetRoles(); + }); + + after(testUtils.teardown); + function checkEditResponse(response) { should.exist(response); should.not.exist(response.meta); @@ -1465,6 +1494,14 @@ describe('Users API', function () { }); describe('Transfer ownership', function () { + before(testUtils.teardown); + + beforeEach(testUtils.setup( + 'settings', 'users:roles', 'perms:user', 'perms:role', 'perms:setting', 'perms:init' + )); + + afterEach(testUtils.teardown); + it('Owner can transfer ownership', function (done) { // transfer ownership to admin user id:2 UserAPI.transferOwnership( @@ -1564,6 +1601,14 @@ describe('Users API', function () { }); describe('Change Password', function () { + before(testUtils.teardown); + + beforeEach(testUtils.setup( + 'settings', 'users:roles', 'perms:user', 'perms:role', 'perms:setting', 'perms:init' + )); + + afterEach(testUtils.teardown); + it('Owner can change own password', function (done) { var payload = { password: [{ diff --git a/core/test/integration/data/importer/importers/data_spec.js b/core/test/integration/data/importer/importers/data_spec.js index 9145badab8..eb82d110ac 100644 --- a/core/test/integration/data/importer/importers/data_spec.js +++ b/core/test/integration/data/importer/importers/data_spec.js @@ -243,31 +243,36 @@ describe('Import', function () { // user should still have the credentials from the original insert, not the import users[0].email.should.equal(testUtils.DataGenerator.Content.users[0].email); - users[0].password.should.equal(testUtils.DataGenerator.Content.users[0].password); - // but the name, slug, and bio should have been overridden - users[0].name.should.equal(exportData.data.users[0].name); - users[0].slug.should.equal(exportData.data.users[0].slug); - should.not.exist(users[0].bio, 'bio is not imported'); - // import no longer requires all data to be dropped, and adds posts - posts.length.should.equal(exportData.data.posts.length, 'Wrong number of posts'); + models.User.isPasswordCorrect({ + hashedPassword: users[0].password, + plainPassword: testUtils.DataGenerator.Content.users[0].password + }).then(function () { + // but the name, slug, and bio should have been overridden + users[0].name.should.equal(exportData.data.users[0].name); + users[0].slug.should.equal(exportData.data.users[0].slug); + should.not.exist(users[0].bio, 'bio is not imported'); - // active_theme should NOT have been overridden - _.find(settings, {key: 'active_theme'}).value.should.equal('casper', 'Wrong theme'); + // import no longer requires all data to be dropped, and adds posts + posts.length.should.equal(exportData.data.posts.length, 'Wrong number of posts'); - // test tags - tags.length.should.equal(exportData.data.tags.length, 'no new tags'); + // active_theme should NOT have been overridden + _.find(settings, {key: 'active_theme'}).value.should.equal('casper', 'Wrong theme'); - // Ensure imported post retains set timestamp - // When in sqlite we are returned a unix timestamp number, - // in MySQL we're returned a date object. - // We pass the returned post always through the date object - // to ensure the return is consistent for all DBs. - assert.equal(moment(posts[0].created_at).valueOf(), 1388318310000); - assert.equal(moment(posts[0].updated_at).valueOf(), 1388318310000); - assert.equal(moment(posts[0].published_at).valueOf(), 1388404710000); + // test tags + tags.length.should.equal(exportData.data.tags.length, 'no new tags'); - done(); + // Ensure imported post retains set timestamp + // When in sqlite we are returned a unix timestamp number, + // in MySQL we're returned a date object. + // We pass the returned post always through the date object + // to ensure the return is consistent for all DBs. + assert.equal(moment(posts[0].created_at).valueOf(), 1388318310000); + assert.equal(moment(posts[0].updated_at).valueOf(), 1388318310000); + assert.equal(moment(posts[0].published_at).valueOf(), 1388404710000); + + done(); + }); }).catch(done); }); @@ -341,32 +346,37 @@ describe('Import', function () { // user should still have the credentials from the original insert, not the import users[0].email.should.equal(testUtils.DataGenerator.Content.users[0].email); - users[0].password.should.equal(testUtils.DataGenerator.Content.users[0].password); - // but the name, slug, and bio should have been overridden - users[0].name.should.equal(exportData.data.users[0].name); - users[0].slug.should.equal(exportData.data.users[0].slug); - should.not.exist(users[0].bio, 'bio is not imported'); - // import no longer requires all data to be dropped, and adds posts - posts.length.should.equal(exportData.data.posts.length, 'Wrong number of posts'); - posts[0].comment_id.should.eql(exportData.data.posts[0].id.toString()); + models.User.isPasswordCorrect({ + hashedPassword: users[0].password, + plainPassword: testUtils.DataGenerator.Content.users[0].password + }).then(function () { + // but the name, slug, and bio should have been overridden + users[0].name.should.equal(exportData.data.users[0].name); + users[0].slug.should.equal(exportData.data.users[0].slug); + should.not.exist(users[0].bio, 'bio is not imported'); - // active_theme should NOT have been overridden - _.find(settings, {key: 'active_theme'}).value.should.equal('casper', 'Wrong theme'); + // import no longer requires all data to be dropped, and adds posts + posts.length.should.equal(exportData.data.posts.length, 'Wrong number of posts'); + posts[0].comment_id.should.eql(exportData.data.posts[0].id.toString()); - // test tags - tags.length.should.equal(exportData.data.tags.length, 'no new tags'); + // active_theme should NOT have been overridden + _.find(settings, {key: 'active_theme'}).value.should.equal('casper', 'Wrong theme'); - // Ensure imported post retains set timestamp - // When in sqlite we are returned a unix timestamp number, - // in MySQL we're returned a date object. - // We pass the returned post always through the date object - // to ensure the return is consistant for all DBs. - assert.equal(moment(posts[0].created_at).valueOf(), 1419940710000); - assert.equal(moment(posts[0].updated_at).valueOf(), 1420027110000); - assert.equal(moment(posts[0].published_at).valueOf(), 1420027110000); + // test tags + tags.length.should.equal(exportData.data.tags.length, 'no new tags'); - done(); + // Ensure imported post retains set timestamp + // When in sqlite we are returned a unix timestamp number, + // in MySQL we're returned a date object. + // We pass the returned post always through the date object + // to ensure the return is consistant for all DBs. + assert.equal(moment(posts[0].created_at).valueOf(), 1419940710000); + assert.equal(moment(posts[0].updated_at).valueOf(), 1420027110000); + assert.equal(moment(posts[0].published_at).valueOf(), 1420027110000); + + done(); + }); }).catch(done); }); }); @@ -398,18 +408,23 @@ describe('Import', function () { // user should still have the credentials from the original insert, not the import users[0].email.should.equal(testUtils.DataGenerator.Content.users[0].email); - users[0].password.should.equal(testUtils.DataGenerator.Content.users[0].password); - // but the name, slug, and bio should have been overridden - users[0].name.should.equal(exportData.data.users[0].name); - users[0].slug.should.equal(exportData.data.users[0].slug); - should.not.exist(users[0].bio, 'bio is not imported'); - // test posts - posts.length.should.equal(1, 'Wrong number of posts'); - // test tags - tags.length.should.equal(1, 'no new tags'); + models.User.isPasswordCorrect({ + hashedPassword: users[0].password, + plainPassword: testUtils.DataGenerator.Content.users[0].password + }).then(function () { + // but the name, slug, and bio should have been overridden + users[0].name.should.equal(exportData.data.users[0].name); + users[0].slug.should.equal(exportData.data.users[0].slug); + should.not.exist(users[0].bio, 'bio is not imported'); - done(); + // test posts + posts.length.should.equal(1, 'Wrong number of posts'); + // test tags + tags.length.should.equal(1, 'no new tags'); + + done(); + }); }).catch(done); }); @@ -501,23 +516,28 @@ describe('Import', function () { // user should still have the credentials from the original insert, not the import users[0].email.should.equal(testUtils.DataGenerator.Content.users[0].email); - users[0].password.should.equal(testUtils.DataGenerator.Content.users[0].password); - // but the name, slug, and bio should have been overridden - users[0].name.should.equal('Joe Bloggs'); - users[0].slug.should.equal('joe-bloggs'); - should.not.exist(users[0].bio, 'bio is not imported'); - // test posts - posts.length.should.equal(1, 'Wrong number of posts'); + models.User.isPasswordCorrect({ + hashedPassword: users[0].password, + plainPassword: testUtils.DataGenerator.Content.users[0].password + }).then(function () { + // but the name, slug, and bio should have been overridden + users[0].name.should.equal('Joe Bloggs'); + users[0].slug.should.equal('joe-bloggs'); + should.not.exist(users[0].bio, 'bio is not imported'); - // we fallback to owner user - // NOTE: ember can handle unknown author_id, but still a fallback to an existing user is better. - posts[0].author_id.should.eql('1'); + // test posts + posts.length.should.equal(1, 'Wrong number of posts'); - // test tags - tags.length.should.equal(0, 'no tags'); + // we fallback to owner user + // NOTE: ember can handle unknown author_id, but still a fallback to an existing user is better. + posts[0].author_id.should.eql('1'); - done(); + // test tags + tags.length.should.equal(0, 'no tags'); + + done(); + }); }).catch(done); }); @@ -861,42 +881,47 @@ describe('Import (new test structure)', function () { }); ownerUser.email.should.equal(testUtils.DataGenerator.Content.users[0].email); - ownerUser.password.should.equal(testUtils.DataGenerator.Content.users[0].password); - ownerUser.status.should.equal('active'); - user1.email.should.equal(exportData.data.users[0].email); - user2.email.should.equal(exportData.data.users[1].email); - user3.email.should.equal(exportData.data.users[2].email); + models.User.isPasswordCorrect({ + hashedPassword: users[0].password, + plainPassword: testUtils.DataGenerator.Content.users[0].password + }).then(function () { + ownerUser.status.should.equal('active'); - // Newly created users should have a status of locked - user2.status.should.equal('locked'); - user3.status.should.equal('locked'); + user1.email.should.equal(exportData.data.users[0].email); + user2.email.should.equal(exportData.data.users[1].email); + user3.email.should.equal(exportData.data.users[2].email); - // Newly created users should have created_at/_by and updated_at/_by set to when they were imported - user2.created_by.should.equal(user1.id); - user2.created_at.should.not.equal(exportData.data.users[1].created_at); - user2.updated_by.should.equal(ownerUser.id); - user2.updated_at.should.not.equal(exportData.data.users[1].updated_at); - user3.created_by.should.equal(user1.id); - user3.created_at.should.not.equal(exportData.data.users[2].created_at); - user3.updated_by.should.equal(ownerUser.id); - user3.updated_at.should.not.equal(exportData.data.users[2].updated_at); + // Newly created users should have a status of locked + user2.status.should.equal('locked'); + user3.status.should.equal('locked'); - rolesUsers.length.should.equal(4, 'There should be 4 role relations'); + // Newly created users should have created_at/_by and updated_at/_by set to when they were imported + user2.created_by.should.equal(user1.id); + user2.created_at.should.not.equal(exportData.data.users[1].created_at); + user2.updated_by.should.equal(ownerUser.id); + user2.updated_at.should.not.equal(exportData.data.users[1].updated_at); + user3.created_by.should.equal(user1.id); + user3.created_at.should.not.equal(exportData.data.users[2].created_at); + user3.updated_by.should.equal(ownerUser.id); + user3.updated_at.should.not.equal(exportData.data.users[2].updated_at); - _.each(rolesUsers, function (roleUser) { - if (roleUser.user_id === ownerUser.id) { - roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[3].id, 'Original user should be an owner'); - } - if (roleUser.user_id === user2.id) { - roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'Josephine should be an admin'); - } - if (roleUser.user_id === user3.id) { - roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[2].id, 'Smith should be an author by default'); - } + rolesUsers.length.should.equal(4, 'There should be 4 role relations'); + + _.each(rolesUsers, function (roleUser) { + if (roleUser.user_id === ownerUser.id) { + roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[3].id, 'Original user should be an owner'); + } + if (roleUser.user_id === user2.id) { + roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'Josephine should be an admin'); + } + if (roleUser.user_id === user3.id) { + roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[2].id, 'Smith should be an author by default'); + } + }); + + done(); }); - - done(); }).catch(done); }); @@ -1098,40 +1123,45 @@ describe('Import (new test structure)', function () { }); user1.email.should.equal(testUtils.DataGenerator.Content.users[0].email); - user1.password.should.equal(testUtils.DataGenerator.Content.users[0].password); - user1.status.should.equal('active'); - user2.email.should.equal(exportData.data.users[0].email); - user3.email.should.equal(exportData.data.users[1].email); - // Newly created users should have a status of locked - user2.status.should.equal('locked'); - user3.status.should.equal('locked'); + models.User.isPasswordCorrect({ + hashedPassword: users[0].password, + plainPassword: testUtils.DataGenerator.Content.users[0].password + }).then(function () { + user1.status.should.equal('active'); + user2.email.should.equal(exportData.data.users[0].email); + user3.email.should.equal(exportData.data.users[1].email); - // Newly created users should have created_at/_by and updated_at/_by set to when they were imported - user2.created_by.should.equal(user1.id); - user2.created_at.should.not.equal(exportData.data.users[0].created_at); - user2.updated_by.should.equal(user1.id); - user2.updated_at.should.not.equal(exportData.data.users[0].updated_at); - user3.created_by.should.equal(user1.id); - user3.created_at.should.not.equal(exportData.data.users[1].created_at); - user3.updated_by.should.equal(user1.id); - user3.updated_at.should.not.equal(exportData.data.users[1].updated_at); + // Newly created users should have a status of locked + user2.status.should.equal('locked'); + user3.status.should.equal('locked'); - rolesUsers.length.should.equal(3, 'There should be 3 role relations'); + // Newly created users should have created_at/_by and updated_at/_by set to when they were imported + user2.created_by.should.equal(user1.id); + user2.created_at.should.not.equal(exportData.data.users[0].created_at); + user2.updated_by.should.equal(user1.id); + user2.updated_at.should.not.equal(exportData.data.users[0].updated_at); + user3.created_by.should.equal(user1.id); + user3.created_at.should.not.equal(exportData.data.users[1].created_at); + user3.updated_by.should.equal(user1.id); + user3.updated_at.should.not.equal(exportData.data.users[1].updated_at); - _.each(rolesUsers, function (roleUser) { - if (roleUser.user_id === user1.id) { - roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[3].id, 'Original user should be an owner'); - } - if (roleUser.user_id === user2.id) { - roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'Josephine should be an admin'); - } - if (roleUser.user_id === user3.id) { - roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[2].id, 'Smith should be an author by default'); - } + rolesUsers.length.should.equal(3, 'There should be 3 role relations'); + + _.each(rolesUsers, function (roleUser) { + if (roleUser.user_id === user1.id) { + roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[3].id, 'Original user should be an owner'); + } + if (roleUser.user_id === user2.id) { + roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'Josephine should be an admin'); + } + if (roleUser.user_id === user3.id) { + roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[2].id, 'Smith should be an author by default'); + } + }); + + done(); }); - - done(); }).catch(done); }); @@ -1331,40 +1361,45 @@ describe('Import (new test structure)', function () { }); ownerUser.email.should.equal(testUtils.DataGenerator.Content.users[0].email); - ownerUser.password.should.equal(testUtils.DataGenerator.Content.users[0].password); - ownerUser.status.should.equal('active'); - newUser.email.should.equal(exportData.data.users[1].email); - existingUser.email.should.equal(exportData.data.users[2].email); - // Newly created users should have a status of locked - newUser.status.should.equal('locked'); - // The already existing user should still have a status of active - existingUser.status.should.equal('active'); + models.User.isPasswordCorrect({ + hashedPassword: users[0].password, + plainPassword: testUtils.DataGenerator.Content.users[0].password + }).then(function () { + ownerUser.status.should.equal('active'); + newUser.email.should.equal(exportData.data.users[1].email); + existingUser.email.should.equal(exportData.data.users[2].email); - // Newly created users should have created_at/_by and updated_at/_by set to when they were imported - newUser.created_by.should.equal(importedOwnerUser.id); - newUser.created_at.should.not.equal(exportData.data.users[1].created_at); - newUser.updated_by.should.equal(ownerUser.id); - newUser.updated_at.should.not.equal(exportData.data.users[1].updated_at); + // Newly created users should have a status of locked + newUser.status.should.equal('locked'); + // The already existing user should still have a status of active + existingUser.status.should.equal('active'); - rolesUsers.length.should.equal(7, 'There should be 7 role relations'); + // Newly created users should have created_at/_by and updated_at/_by set to when they were imported + newUser.created_by.should.equal(importedOwnerUser.id); + newUser.created_at.should.not.equal(exportData.data.users[1].created_at); + newUser.updated_by.should.equal(ownerUser.id); + newUser.updated_at.should.not.equal(exportData.data.users[1].updated_at); - _.each(rolesUsers, function (roleUser) { - if (roleUser.user_id === ownerUser.id) { - roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[3].id, 'Original user should be an owner'); - } - if (roleUser.user_id === importedOwnerUser.id) { - roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'Imported owner should be an admin now.'); - } - if (roleUser.user_id === newUser.id) { - roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'New user should be an admin'); - } - if (roleUser.user_id === existingUser.id) { - roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'Existing user was an admin'); - } + rolesUsers.length.should.equal(7, 'There should be 7 role relations'); + + _.each(rolesUsers, function (roleUser) { + if (roleUser.user_id === ownerUser.id) { + roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[3].id, 'Original user should be an owner'); + } + if (roleUser.user_id === importedOwnerUser.id) { + roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'Imported owner should be an admin now.'); + } + if (roleUser.user_id === newUser.id) { + roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'New user should be an admin'); + } + if (roleUser.user_id === existingUser.id) { + roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'Existing user was an admin'); + } + }); + + done(); }); - - done(); }).catch(done); }); diff --git a/core/test/integration/model/model_accesstoken_spec.js b/core/test/integration/model/model_accesstoken_spec.js index 1fb6c5fa18..8b78411d84 100644 --- a/core/test/integration/model/model_accesstoken_spec.js +++ b/core/test/integration/model/model_accesstoken_spec.js @@ -18,7 +18,7 @@ describe('Accesstoken Model', function () { sandbox.restore(); }); - beforeEach(testUtils.setup('users:roles', 'clients')); + beforeEach(testUtils.setup('owner', 'clients')); it('on creation emits token.added event', function (done) { // Setup diff --git a/core/test/integration/model/model_app-fields_spec.js b/core/test/integration/model/model_app-fields_spec.js index ae592660e4..74d5d2517d 100644 --- a/core/test/integration/model/model_app-fields_spec.js +++ b/core/test/integration/model/model_app-fields_spec.js @@ -8,8 +8,8 @@ var should = require('should'), describe('App Fields Model', function () { // Keep the DB clean before(testUtils.teardown); - afterEach(testUtils.teardown); - beforeEach(testUtils.setup('app_field')); + after(testUtils.teardown); + before(testUtils.setup('app_field')); before(function () { should.exist(AppFieldsModel); diff --git a/core/test/integration/model/model_app-settings_spec.js b/core/test/integration/model/model_app-settings_spec.js index 9c186f5a83..bcd433fa5c 100644 --- a/core/test/integration/model/model_app-settings_spec.js +++ b/core/test/integration/model/model_app-settings_spec.js @@ -8,8 +8,8 @@ var should = require('should'), describe('App Setting Model', function () { // Keep the DB clean before(testUtils.teardown); - afterEach(testUtils.teardown); - beforeEach(testUtils.setup('app_setting')); + after(testUtils.teardown); + before(testUtils.setup('app_setting')); before(function () { should.exist(AppSettingModel); diff --git a/core/test/integration/model/model_apps_spec.js b/core/test/integration/model/model_apps_spec.js index afa7561060..46a8c859e9 100644 --- a/core/test/integration/model/model_apps_spec.js +++ b/core/test/integration/model/model_apps_spec.js @@ -10,8 +10,8 @@ var should = require('should'), describe('App Model', function () { // Keep the DB clean before(testUtils.teardown); - afterEach(testUtils.teardown); - beforeEach(testUtils.setup('app')); + after(testUtils.teardown); + before(testUtils.setup('app')); before(function () { should.exist(AppModel); diff --git a/core/test/integration/model/model_permissions_spec.js b/core/test/integration/model/model_permissions_spec.js index 1854447d4e..10a6824ed1 100644 --- a/core/test/integration/model/model_permissions_spec.js +++ b/core/test/integration/model/model_permissions_spec.js @@ -8,8 +8,8 @@ var should = require('should'), describe('Permission Model', function () { // Keep the DB clean before(testUtils.teardown); - afterEach(testUtils.teardown); - beforeEach(testUtils.setup('permission')); + after(testUtils.teardown); + before(testUtils.setup('permission')); before(function () { should.exist(PermissionModel); diff --git a/core/test/integration/model/model_posts_spec.js b/core/test/integration/model/model_posts_spec.js index 88af0a05f8..c66715008b 100644 --- a/core/test/integration/model/model_posts_spec.js +++ b/core/test/integration/model/model_posts_spec.js @@ -26,152 +26,144 @@ describe('Post Model', function () { var eventsTriggered = {}; before(testUtils.teardown); - afterEach(testUtils.teardown); + after(testUtils.teardown); + + before(testUtils.setup('users:roles')); afterEach(function () { sandbox.restore(); }); + function checkFirstPostData(firstPost, options) { + options = options || {}; + + should.not.exist(firstPost.author_id); + firstPost.author.should.be.an.Object(); + + if (options.withRelated && options.withRelated.indexOf('authors') !== -1) { + firstPost.authors.length.should.eql(1); + firstPost.authors[0].should.eql(firstPost.author); + } + + firstPost.url.should.equal('/html-ipsum/'); + firstPost.tags.should.be.an.Array(); + + firstPost.author.name.should.equal(DataGenerator.Content.users[0].name); + firstPost.created_at.should.be.an.instanceof(Date); + firstPost.created_by.should.be.an.Object(); + firstPost.updated_by.should.be.an.Object(); + firstPost.published_by.should.be.an.Object(); + firstPost.created_by.name.should.equal(DataGenerator.Content.users[0].name); + firstPost.updated_by.name.should.equal(DataGenerator.Content.users[0].name); + firstPost.published_by.name.should.equal(DataGenerator.Content.users[0].name); + firstPost.tags[0].name.should.equal(DataGenerator.Content.tags[0].name); + firstPost.custom_excerpt.should.equal(DataGenerator.Content.posts[0].custom_excerpt); + + if (options.formats) { + if (options.formats.indexOf('mobiledoc') !== -1) { + firstPost.mobiledoc.should.match(/HTML Ipsum Presents/); + } + + if (options.formats.indexOf('html') !== -1) { + firstPost.html.should.match(/HTML Ipsum Presents/); + } + + if (options.formats.indexOf('plaintext') !== -1) { + firstPost.plaintext.should.match(/HTML Ipsum Presents/); + } + } else { + firstPost.html.should.match(/HTML Ipsum Presents/); + should.equal(firstPost.plaintext, undefined); + should.equal(firstPost.mobiledoc, undefined); + should.equal(firstPost.amp, undefined); + } + } + describe('Single author posts', function () { afterEach(function () { configUtils.restore(); }); - beforeEach(testUtils.setup('owner', 'posts', 'apps')); + describe('fetchOne/fetchAll/fetchPage', function () { + before(testUtils.fixtures.insertPostsAndTags); + after(function () { + return testUtils.truncate('posts_tags') + .then(function () { + return testUtils.truncate('tags'); + }) + .then(function () { + return testUtils.truncate('posts'); + }); + }); - function checkFirstPostData(firstPost, options) { - options = options || {}; + describe('findAll', function () { + beforeEach(function () { + sandbox.stub(settingsCache, 'get').callsFake(function (key) { + return { + permalinks: '/:slug/' + }[key]; + }); + }); - should.not.exist(firstPost.author_id); - firstPost.author.should.be.an.Object(); + it('can findAll', function (done) { + models.Post.findAll().then(function (results) { + should.exist(results); + results.length.should.be.above(1); + done(); + }).catch(done); + }); - if (options.withRelated && options.withRelated.indexOf('authors') !== -1) { - firstPost.authors.length.should.eql(1); - firstPost.authors[0].should.eql(firstPost.author); - } + it('can findAll, returning all related data', function (done) { + var options = {withRelated: ['author', 'authors', 'tags', 'created_by', 'updated_by', 'published_by']}; - firstPost.url.should.equal('/html-ipsum/'); - firstPost.fields.should.be.an.Array(); - firstPost.tags.should.be.an.Array(); + models.Post.findAll(options) + .then(function (results) { + should.exist(results); + results.length.should.be.above(0); - firstPost.author.name.should.equal(DataGenerator.Content.users[0].name); - firstPost.fields[0].key.should.equal(DataGenerator.Content.app_fields[0].key); - firstPost.created_at.should.be.an.instanceof(Date); - firstPost.created_by.should.be.an.Object(); - firstPost.updated_by.should.be.an.Object(); - firstPost.published_by.should.be.an.Object(); - firstPost.created_by.name.should.equal(DataGenerator.Content.users[0].name); - firstPost.updated_by.name.should.equal(DataGenerator.Content.users[0].name); - firstPost.published_by.name.should.equal(DataGenerator.Content.users[0].name); - firstPost.tags[0].name.should.equal(DataGenerator.Content.tags[0].name); - firstPost.custom_excerpt.should.equal(DataGenerator.Content.posts[0].custom_excerpt); + var posts = results.models.map(function (model) { + return model.toJSON(); + }), firstPost = _.find(posts, {title: testUtils.DataGenerator.Content.posts[0].title}); - if (options.formats) { - if (options.formats.indexOf('mobiledoc') !== -1) { - firstPost.mobiledoc.should.match(/HTML Ipsum Presents/); - } + checkFirstPostData(firstPost, options); - if (options.formats.indexOf('html') !== -1) { - firstPost.html.should.match(/HTML Ipsum Presents/); - } + done(); + }).catch(done); + }); - if (options.formats.indexOf('plaintext') !== -1) { - /** - * NOTE: this is null, not undefined, so it was returned - * The plaintext value is generated. - */ - should.equal(firstPost.plaintext, null); - } - } else { - firstPost.html.should.match(/HTML Ipsum Presents/); - should.equal(firstPost.plaintext, undefined); - should.equal(firstPost.mobiledoc, undefined); - should.equal(firstPost.amp, undefined); - } - } + it('can findAll, use formats option', function (done) { + var options = { + formats: ['mobiledoc', 'plaintext'], + withRelated: ['author', 'fields', 'tags', 'created_by', 'updated_by', 'published_by'] + }; - describe('findAll', function () { - beforeEach(function () { - sandbox.stub(settingsCache, 'get').callsFake(function (key) { - return { - permalinks: '/:slug/' - }[key]; + models.Post.findAll(options) + .then(function (results) { + should.exist(results); + results.length.should.be.above(0); + + var posts = results.models.map(function (model) { + return model.toJSON(options); + }), firstPost = _.find(posts, {title: testUtils.DataGenerator.Content.posts[0].title}); + + checkFirstPostData(firstPost, options); + + done(); + }).catch(done); }); }); - it('can findAll', function (done) { - models.Post.findAll().then(function (results) { - should.exist(results); - results.length.should.be.above(1); - done(); - }).catch(done); - }); - - it('can findAll, returning all related data', function (done) { - var options = {withRelated: ['author', 'authors', 'fields', 'tags', 'created_by', 'updated_by', 'published_by']}; - - models.Post.findAll(options) - .then(function (results) { - should.exist(results); - results.length.should.be.above(0); - - var posts = results.models.map(function (model) { - return model.toJSON(); - }), firstPost = _.find(posts, {title: testUtils.DataGenerator.Content.posts[0].title}); - - checkFirstPostData(firstPost, options); - - done(); - }).catch(done); - }); - - it('can findAll, use formats option', function (done) { - var options = { - formats: ['mobiledoc', 'plaintext'], - withRelated: ['author', 'fields', 'tags', 'created_by', 'updated_by', 'published_by'] - }; - - models.Post.findAll(options) - .then(function (results) { - should.exist(results); - results.length.should.be.above(0); - - var posts = results.models.map(function (model) { - return model.toJSON(options); - }), firstPost = _.find(posts, {title: testUtils.DataGenerator.Content.posts[0].title}); - - checkFirstPostData(firstPost, options); - - done(); - }).catch(done); - }); - }); - - describe('findPage', function () { - beforeEach(function () { - sandbox.stub(settingsCache, 'get').callsFake(function (key) { - return { - permalinks: '/:slug/' - }[key]; + describe('findPage', function () { + beforeEach(function () { + sandbox.stub(settingsCache, 'get').callsFake(function (key) { + return { + permalinks: '/:slug/' + }[key]; + }); }); - }); - it('can findPage (default)', function (done) { - models.Post.findPage().then(function (results) { - should.exist(results); - - results.meta.pagination.page.should.equal(1); - results.meta.pagination.limit.should.equal(15); - results.meta.pagination.pages.should.equal(1); - results.posts.length.should.equal(4); - - done(); - }).catch(done); - }); - - it('can findPage, returning all related data', function (done) { - models.Post.findPage({withRelated: ['author', 'fields', 'tags', 'created_by', 'updated_by', 'published_by']}) - .then(function (results) { + it('can findPage (default)', function (done) { + models.Post.findPage().then(function (results) { should.exist(results); results.meta.pagination.page.should.equal(1); @@ -179,239 +171,282 @@ describe('Post Model', function () { results.meta.pagination.pages.should.equal(1); results.posts.length.should.equal(4); - var firstPost = _.find(results.posts, {title: testUtils.DataGenerator.Content.posts[0].title}); - checkFirstPostData(firstPost); + done(); + }).catch(done); + }); + + it('can findPage, returning all related data', function (done) { + models.Post.findPage({withRelated: ['author', 'fields', 'tags', 'created_by', 'updated_by', 'published_by']}) + .then(function (results) { + should.exist(results); + + results.meta.pagination.page.should.equal(1); + results.meta.pagination.limit.should.equal(15); + results.meta.pagination.pages.should.equal(1); + results.posts.length.should.equal(4); + + var firstPost = _.find(results.posts, {title: testUtils.DataGenerator.Content.posts[0].title}); + checkFirstPostData(firstPost); + + done(); + }).catch(done); + }); + + it('returns computed fields when columns are asked for explicitly', function (done) { + models.Post.findPage({columns: ['id', 'slug', 'url', 'mobiledoc']}).then(function (results) { + should.exist(results); + + var post = _.find(results.posts, {slug: testUtils.DataGenerator.Content.posts[0].slug}); + post.url.should.equal('/html-ipsum/'); + + // If a computed property is inadvertently passed into a "fetch" operation, + // there's a bug in bookshelf where the model will come back with it as + // a column enclosed in quotes. + should.not.exist(post['"url"']); done(); }).catch(done); - }); + }); - it('returns computed fields when columns are asked for explicitly', function (done) { - models.Post.findPage({columns: ['id', 'slug', 'url', 'mobiledoc']}).then(function (results) { - should.exist(results); + it('ignores columns that do not exist', function (done) { + models.Post.findPage({columns: ['id', 'slug', 'doesnotexist']}).then(function (results) { + should.exist(results); - var post = _.find(results.posts, {slug: testUtils.DataGenerator.Content.posts[0].slug}); - post.url.should.equal('/html-ipsum/'); - - // If a computed property is inadvertently passed into a "fetch" operation, - // there's a bug in bookshelf where the model will come back with it as - // a column enclosed in quotes. - should.not.exist(post['"url"']); - - done(); - }).catch(done); - }); - - it('ignores columns that do not exist', function (done) { - models.Post.findPage({columns: ['id', 'slug', 'doesnotexist']}).then(function (results) { - should.exist(results); - - var post = _.find(results.posts, {slug: testUtils.DataGenerator.Content.posts[0].slug}); - post.id.should.equal(testUtils.DataGenerator.Content.posts[0].id); - post.slug.should.equal('html-ipsum'); - should.not.exist(post.doesnotexist); - - done(); - }).catch(done); - }); - - it('can findPage, with various options', function (done) { - testUtils.fixtures.insertExtraPosts().then(function () { - return testUtils.fixtures.insertExtraPostsTags(); - }).then(function () { - return models.Post.findPage({page: 2}); - }).then(function (paginationResult) { - paginationResult.meta.pagination.page.should.equal(2); - paginationResult.meta.pagination.limit.should.equal(15); - paginationResult.meta.pagination.pages.should.equal(4); - paginationResult.posts.length.should.equal(15); - - return models.Post.findPage({page: 5}); - }).then(function (paginationResult) { - paginationResult.meta.pagination.page.should.equal(5); - paginationResult.meta.pagination.limit.should.equal(15); - paginationResult.meta.pagination.pages.should.equal(4); - paginationResult.posts.length.should.equal(0); - - return models.Post.findPage({limit: 30}); - }).then(function (paginationResult) { - paginationResult.meta.pagination.page.should.equal(1); - paginationResult.meta.pagination.limit.should.equal(30); - paginationResult.meta.pagination.pages.should.equal(2); - paginationResult.posts.length.should.equal(30); - - // Test both boolean formats - return models.Post.findPage({limit: 10, staticPages: true}); - }).then(function (paginationResult) { - paginationResult.meta.pagination.page.should.equal(1); - paginationResult.meta.pagination.limit.should.equal(10); - paginationResult.meta.pagination.pages.should.equal(1); - paginationResult.posts.length.should.equal(1); - - // Test both boolean formats - return models.Post.findPage({limit: 10, staticPages: '1'}); - }).then(function (paginationResult) { - paginationResult.meta.pagination.page.should.equal(1); - paginationResult.meta.pagination.limit.should.equal(10); - paginationResult.meta.pagination.pages.should.equal(1); - paginationResult.posts.length.should.equal(1); - - // Test featured pages - return models.Post.findPage({limit: 10, filter: 'featured:true'}); - }).then(function (paginationResult) { - paginationResult.meta.pagination.page.should.equal(1); - paginationResult.meta.pagination.limit.should.equal(10); - paginationResult.meta.pagination.pages.should.equal(1); - paginationResult.posts.length.should.equal(2); - - // Test both boolean formats for featured pages - return models.Post.findPage({limit: 10, filter: 'featured:1'}); - }).then(function (paginationResult) { - paginationResult.meta.pagination.page.should.equal(1); - paginationResult.meta.pagination.limit.should.equal(10); - paginationResult.meta.pagination.pages.should.equal(1); - paginationResult.posts.length.should.equal(2); - - return models.Post.findPage({limit: 10, page: 2, status: 'all'}); - }).then(function (paginationResult) { - paginationResult.meta.pagination.pages.should.equal(11); - - return models.Post.findPage({limit: 'all', status: 'all'}); - }).then(function (paginationResult) { - paginationResult.meta.pagination.page.should.equal(1); - paginationResult.meta.pagination.limit.should.equal('all'); - paginationResult.meta.pagination.pages.should.equal(1); - paginationResult.posts.length.should.equal(108); - - done(); - }).catch(done); - }); - - it('can findPage for tag, with various options', function (done) { - testUtils.fixtures.insertExtraPosts().then(function () { - return testUtils.fixtures.insertExtraPostsTags(); - }).then(function () { - // Test tag filter - return models.Post.findPage({page: 1, filter: 'tags:bacon'}); - }).then(function (paginationResult) { - paginationResult.meta.pagination.page.should.equal(1); - paginationResult.meta.pagination.limit.should.equal(15); - paginationResult.meta.pagination.pages.should.equal(1); - paginationResult.posts.length.should.equal(2); - - return models.Post.findPage({page: 1, filter: 'tags:kitchen-sink'}); - }).then(function (paginationResult) { - paginationResult.meta.pagination.page.should.equal(1); - paginationResult.meta.pagination.limit.should.equal(15); - paginationResult.meta.pagination.pages.should.equal(1); - paginationResult.posts.length.should.equal(2); - - return models.Post.findPage({page: 1, filter: 'tags:injection'}); - }).then(function (paginationResult) { - paginationResult.meta.pagination.page.should.equal(1); - paginationResult.meta.pagination.limit.should.equal(15); - paginationResult.meta.pagination.pages.should.equal(2); - paginationResult.posts.length.should.equal(15); - - return models.Post.findPage({page: 2, filter: 'tags:injection'}); - }).then(function (paginationResult) { - paginationResult.meta.pagination.page.should.equal(2); - paginationResult.meta.pagination.limit.should.equal(15); - paginationResult.meta.pagination.pages.should.equal(2); - paginationResult.posts.length.should.equal(10); - - done(); - }).catch(done); - }); - - it('can NOT findPage for a page that overflows the datatype', function (done) { - models.Post.findPage({page: 5700000000055345439587894375457849375284932759842375894372589243758947325894375894275894275894725897432859724309}) - .then(function (paginationResult) { - should.exist(paginationResult.meta); - - paginationResult.meta.pagination.page.should.be.a.Number(); + var post = _.find(results.posts, {slug: testUtils.DataGenerator.Content.posts[0].slug}); + post.id.should.equal(testUtils.DataGenerator.Content.posts[0].id); + post.slug.should.equal('html-ipsum'); + should.not.exist(post.doesnotexist); done(); }).catch(done); - }); - }); + }); - describe('findOne', function () { - beforeEach(function () { - sandbox.stub(settingsCache, 'get').callsFake(function (key) { - return { - permalinks: '/:slug/' - }[key]; + it('can NOT findPage for a page that overflows the datatype', function (done) { + models.Post.findPage({page: 5700000000055345439587894375457849375284932759842375894372589243758947325894375894275894275894725897432859724309}) + .then(function (paginationResult) { + should.exist(paginationResult.meta); + + paginationResult.meta.pagination.page.should.be.a.Number(); + + done(); + }).catch(done); + }); + + describe('with more posts/tags', function () { + beforeEach(function () { + return testUtils.truncate('posts_tags') + .then(function () { + return testUtils.truncate('tags'); + }) + .then(function () { + return testUtils.truncate('posts'); + }); + }); + + beforeEach(function () { + return testUtils.fixtures.insertPostsAndTags() + .then(function () { + return testUtils.fixtures.insertExtraPosts(); + }) + .then(function () { + return testUtils.fixtures.insertExtraPostsTags(); + }); + }); + + it('can findPage, with various options', function (done) { + models.Post.findPage({page: 2}) + .then(function (paginationResult) { + paginationResult.meta.pagination.page.should.equal(2); + paginationResult.meta.pagination.limit.should.equal(15); + paginationResult.meta.pagination.pages.should.equal(4); + paginationResult.posts.length.should.equal(15); + + return models.Post.findPage({page: 5}); + }).then(function (paginationResult) { + paginationResult.meta.pagination.page.should.equal(5); + paginationResult.meta.pagination.limit.should.equal(15); + paginationResult.meta.pagination.pages.should.equal(4); + paginationResult.posts.length.should.equal(0); + + return models.Post.findPage({limit: 30}); + }).then(function (paginationResult) { + paginationResult.meta.pagination.page.should.equal(1); + paginationResult.meta.pagination.limit.should.equal(30); + paginationResult.meta.pagination.pages.should.equal(2); + paginationResult.posts.length.should.equal(30); + + // Test both boolean formats + return models.Post.findPage({limit: 10, staticPages: true}); + }).then(function (paginationResult) { + paginationResult.meta.pagination.page.should.equal(1); + paginationResult.meta.pagination.limit.should.equal(10); + paginationResult.meta.pagination.pages.should.equal(1); + paginationResult.posts.length.should.equal(1); + + // Test both boolean formats + return models.Post.findPage({limit: 10, staticPages: '1'}); + }).then(function (paginationResult) { + paginationResult.meta.pagination.page.should.equal(1); + paginationResult.meta.pagination.limit.should.equal(10); + paginationResult.meta.pagination.pages.should.equal(1); + paginationResult.posts.length.should.equal(1); + + // Test featured pages + return models.Post.findPage({limit: 10, filter: 'featured:true'}); + }).then(function (paginationResult) { + paginationResult.meta.pagination.page.should.equal(1); + paginationResult.meta.pagination.limit.should.equal(10); + paginationResult.meta.pagination.pages.should.equal(1); + paginationResult.posts.length.should.equal(2); + + // Test both boolean formats for featured pages + return models.Post.findPage({limit: 10, filter: 'featured:1'}); + }).then(function (paginationResult) { + paginationResult.meta.pagination.page.should.equal(1); + paginationResult.meta.pagination.limit.should.equal(10); + paginationResult.meta.pagination.pages.should.equal(1); + paginationResult.posts.length.should.equal(2); + + return models.Post.findPage({limit: 10, page: 2, status: 'all'}); + }).then(function (paginationResult) { + paginationResult.meta.pagination.pages.should.equal(11); + + return models.Post.findPage({limit: 'all', status: 'all'}); + }).then(function (paginationResult) { + paginationResult.meta.pagination.page.should.equal(1); + paginationResult.meta.pagination.limit.should.equal('all'); + paginationResult.meta.pagination.pages.should.equal(1); + paginationResult.posts.length.should.equal(108); + + done(); + }).catch(done); + }); + + it('can findPage for tag, with various options', function (done) { + // Test tag filter + models.Post.findPage({page: 1, filter: 'tags:bacon'}) + .then(function (paginationResult) { + paginationResult.meta.pagination.page.should.equal(1); + paginationResult.meta.pagination.limit.should.equal(15); + paginationResult.meta.pagination.pages.should.equal(1); + paginationResult.posts.length.should.equal(2); + + return models.Post.findPage({page: 1, filter: 'tags:kitchen-sink'}); + }).then(function (paginationResult) { + paginationResult.meta.pagination.page.should.equal(1); + paginationResult.meta.pagination.limit.should.equal(15); + paginationResult.meta.pagination.pages.should.equal(1); + paginationResult.posts.length.should.equal(2); + + return models.Post.findPage({page: 1, filter: 'tags:injection'}); + }).then(function (paginationResult) { + paginationResult.meta.pagination.page.should.equal(1); + paginationResult.meta.pagination.limit.should.equal(15); + paginationResult.meta.pagination.pages.should.equal(2); + paginationResult.posts.length.should.equal(15); + + return models.Post.findPage({page: 2, filter: 'tags:injection'}); + }).then(function (paginationResult) { + paginationResult.meta.pagination.page.should.equal(2); + paginationResult.meta.pagination.limit.should.equal(15); + paginationResult.meta.pagination.pages.should.equal(2); + paginationResult.posts.length.should.equal(10); + + done(); + }).catch(done); + }); }); }); - it('can findOne', function (done) { - var firstPost; - - models.Post.findPage().then(function (results) { - should.exist(results); - should.exist(results.posts); - results.posts.length.should.be.above(0); - firstPost = results.posts[0]; - - return models.Post.findOne({slug: firstPost.slug}); - }).then(function (found) { - should.exist(found); - found.attributes.title.should.equal(firstPost.title); - - done(); - }).catch(done); - }); - - it('can findOne, returning all related data', function (done) { - var firstPost; - - models.Post.findOne({}, {withRelated: ['author', 'fields', 'tags', 'created_by', 'updated_by', 'published_by']}) - .then(function (result) { - should.exist(result); - firstPost = result.toJSON(); - - checkFirstPostData(firstPost); - - done(); - }).catch(done); - }); - - it('can findOne, returning a slug only permalink', function (done) { - models.Post.findOne({id: testUtils.DataGenerator.Content.posts[0].id}) - .then(function (result) { - should.exist(result); - var firstPost = result.toJSON(); - firstPost.url.should.equal('/html-ipsum/'); - - done(); - }).catch(done); - }); - - it('can findOne, returning a dated permalink', function (done) { - settingsCache.get.restore(); - - sandbox.stub(settingsCache, 'get').callsFake(function (key) { - return { - permalinks: '/:year/:month/:day/:slug/' - }[key]; + describe('findOne', function () { + beforeEach(function () { + sandbox.stub(settingsCache, 'get').callsFake(function (key) { + return { + permalinks: '/:slug/' + }[key]; + }); }); - models.Post.findOne({id: testUtils.DataGenerator.Content.posts[0].id}) - .then(function (result) { - should.exist(result); - var firstPost = result.toJSON(); + it('can findOne', function (done) { + var firstPost; - // published_at of post 1 is 2015-01-01 00:00:00 - // default blog TZ is UTC - firstPost.url.should.equal('/2015/01/01/html-ipsum/'); + models.Post.findPage().then(function (results) { + should.exist(results); + should.exist(results.posts); + results.posts.length.should.be.above(0); + firstPost = results.posts[0]; + + return models.Post.findOne({slug: firstPost.slug}); + }).then(function (found) { + should.exist(found); + found.attributes.title.should.equal(firstPost.title); done(); }).catch(done); + }); + + it('can findOne, returning all related data', function (done) { + var firstPost; + + models.Post.findOne({}, {withRelated: ['author', 'fields', 'tags', 'created_by', 'updated_by', 'published_by']}) + .then(function (result) { + should.exist(result); + firstPost = result.toJSON(); + + checkFirstPostData(firstPost); + + done(); + }).catch(done); + }); + + it('can findOne, returning a slug only permalink', function (done) { + models.Post.findOne({id: testUtils.DataGenerator.Content.posts[0].id}) + .then(function (result) { + should.exist(result); + var firstPost = result.toJSON(); + firstPost.url.should.equal('/html-ipsum/'); + + done(); + }).catch(done); + }); + + it('can findOne, returning a dated permalink', function (done) { + settingsCache.get.restore(); + + sandbox.stub(settingsCache, 'get').callsFake(function (key) { + return { + permalinks: '/:year/:month/:day/:slug/' + }[key]; + }); + + models.Post.findOne({id: testUtils.DataGenerator.Content.posts[0].id}) + .then(function (result) { + should.exist(result); + var firstPost = result.toJSON(); + + // published_at of post 1 is 2015-01-01 00:00:00 + // default blog TZ is UTC + firstPost.url.should.equal('/2015/01/01/html-ipsum/'); + + done(); + }).catch(done); + }); }); }); describe('edit', function () { + beforeEach(testUtils.fixtures.insertPostsAndTags); + + afterEach(function () { + return testUtils.truncate('posts_tags') + .then(function () { + return testUtils.truncate('tags'); + }) + .then(function () { + return testUtils.truncate('posts'); + }); + }); + beforeEach(function () { eventsTriggered = {}; @@ -548,7 +583,7 @@ describe('Post Model', function () { models.Post.findOne({id: postId}).then(function (results) { should.exist(results); results.attributes.html.should.match(/HTML Ipsum Presents/); - should.not.exist(results.attributes.plaintext); + should.exist(results.attributes.plaintext); return models.Post.edit({updated_at: results.attributes.updated_at}, _.extend({}, context, {id: postId})); }).then(function (edited) { should.exist(edited); @@ -1020,6 +1055,18 @@ describe('Post Model', function () { }); describe('add', function () { + before(testUtils.fixtures.insertPostsAndTags); + + after(function () { + return testUtils.truncate('posts_tags') + .then(function () { + return testUtils.truncate('tags'); + }) + .then(function () { + return testUtils.truncate('posts'); + }); + }); + beforeEach(function () { eventsTriggered = {}; @@ -1424,6 +1471,18 @@ describe('Post Model', function () { }); describe('destroy', function () { + beforeEach(testUtils.fixtures.insertPostsAndTags); + + afterEach(function () { + return testUtils.truncate('posts_tags') + .then(function () { + return testUtils.truncate('tags'); + }) + .then(function () { + return testUtils.truncate('posts'); + }); + }); + beforeEach(function () { eventsTriggered = {}; sandbox.stub(common.events, 'emit').callsFake(function (eventName, eventObj) { @@ -1586,136 +1645,104 @@ describe('Post Model', function () { }); describe('Collision Protection', function () { - it('update post title, but updated_at is out of sync', function (done) { - var postToUpdate = {id: testUtils.DataGenerator.Content.posts[1].id}; + before(testUtils.fixtures.insertPostsAndTags); - models.Post.findOne({id: postToUpdate.id, status: 'all'}) + after(function () { + return testUtils.truncate('posts_tags') .then(function () { - return Promise.delay(1000); + return testUtils.truncate('tags'); }) .then(function () { - return models.Post.edit({ - title: 'New Post Title', - updated_at: moment().subtract(1, 'day').format() - }, _.extend({}, context, {id: postToUpdate.id})); - }) - .then(function () { - done(new Error('expected no success')); - }) - .catch(function (err) { - err.code.should.eql('UPDATE_COLLISION'); - done(); + return testUtils.truncate('posts'); }); }); - it('update post tags and updated_at is out of sync', function (done) { + it('update post title, but updated_at is out of sync', function () { var postToUpdate = {id: testUtils.DataGenerator.Content.posts[1].id}; - models.Post.findOne({id: postToUpdate.id, status: 'all'}) + return models.Post.edit({ + title: 'New Post Title', + updated_at: moment().subtract(1, 'day').format() + }, _.extend({}, context, {id: postToUpdate.id})) .then(function () { - return Promise.delay(1000); - }) - .then(function () { - return models.Post.edit({ - tags: [{name: 'new-tag-1'}], - updated_at: moment().subtract(1, 'day').format() - }, _.extend({}, context, {id: postToUpdate.id})); - }) - .then(function () { - done(new Error('expected no success')); + throw new Error('expected no success'); }) .catch(function (err) { err.code.should.eql('UPDATE_COLLISION'); - done(); }); }); - it('update post authors and updated_at is out of sync', function (done) { + it('update post tags and updated_at is out of sync', function () { var postToUpdate = {id: testUtils.DataGenerator.Content.posts[1].id}; - models.Post.findOne({id: postToUpdate.id, status: 'all'}) + return models.Post.edit({ + tags: [{name: 'new-tag-1'}], + updated_at: moment().subtract(1, 'day').format() + }, _.extend({}, context, {id: postToUpdate.id})) .then(function () { - return Promise.delay(1000); - }) - .then(function () { - return models.Post.edit({ - authors: [testUtils.DataGenerator.Content.users[3]], - updated_at: moment().subtract(1, 'day').format() - }, _.extend({}, context, {id: postToUpdate.id})); - }) - .then(function () { - done(new Error('expected no success')); + throw new Error('expected no success'); }) .catch(function (err) { err.code.should.eql('UPDATE_COLLISION'); - done(); }); }); - it('update post tags and updated_at is NOT out of sync', function (done) { + it('update post authors and updated_at is out of sync', function () { var postToUpdate = {id: testUtils.DataGenerator.Content.posts[1].id}; - models.Post.findOne({id: postToUpdate.id, status: 'all'}) + return models.Post.edit({ + authors: [testUtils.DataGenerator.Content.users[3]], + updated_at: moment().subtract(1, 'day').format() + }, _.extend({}, context, {id: postToUpdate.id})) .then(function () { - return Promise.delay(1000); + throw new Error('expected no success'); }) - .then(function () { - return models.Post.edit({ - tags: [{name: 'new-tag-1'}] - }, _.extend({}, context, {id: postToUpdate.id})); - }) - .then(function () { - done(); - }) - .catch(done); + .catch(function (err) { + err.code.should.eql('UPDATE_COLLISION'); + }); }); - it('update post with no changes, but updated_at is out of sync', function (done) { + it('update post tags and updated_at is NOT out of sync', function () { var postToUpdate = {id: testUtils.DataGenerator.Content.posts[1].id}; - models.Post.findOne({id: postToUpdate.id, status: 'all'}) - .then(function () { - return Promise.delay(1000); - }) - .then(function () { - return models.Post.edit({ - updated_at: moment().subtract(1, 'day').format() - }, _.extend({}, context, {id: postToUpdate.id})); - }) - .then(function () { - done(); - }) - .catch(done); + return models.Post.edit({ + tags: [{name: 'new-tag-1'}] + }, _.extend({}, context, {id: postToUpdate.id})); }); - it('update post with old post title, but updated_at is out of sync', function (done) { + it('update post with no changes, but updated_at is out of sync', function () { + var postToUpdate = {id: testUtils.DataGenerator.Content.posts[1].id}; + + return models.Post.edit({ + updated_at: moment().subtract(1, 'day').format() + }, _.extend({}, context, {id: postToUpdate.id})); + }); + + it('update post with old post title, but updated_at is out of sync', function () { var postToUpdate = { id: testUtils.DataGenerator.Content.posts[1].id, title: testUtils.DataGenerator.forModel.posts[1].title }; - models.Post.findOne({id: postToUpdate.id, status: 'all'}) - .then(function () { - return Promise.delay(1000); - }) - .then(function () { - return models.Post.edit({ - title: postToUpdate.title, - updated_at: moment().subtract(1, 'day').format() - }, _.extend({}, context, {id: postToUpdate.id})); - }) - .then(function () { - done(); - }) - .catch(done); + return models.Post.edit({ + title: postToUpdate.title, + updated_at: moment().subtract(1, 'day').format() + }, _.extend({}, context, {id: postToUpdate.id})); }); }); }); describe('Multiauthor Posts', function () { before(testUtils.teardown); - afterEach(testUtils.teardown); - beforeEach(testUtils.setup('posts:mu')); + + after(function () { + return testUtils.teardown() + .then(function () { + return testUtils.setup('users:roles')(); + }); + }); + + before(testUtils.setup('posts:mu')); it('can destroy multiple posts by author', function (done) { // We're going to delete all posts by user 1 @@ -1738,14 +1765,20 @@ describe('Post Model', function () { }); describe('Post tag handling edge cases', function () { - before(testUtils.teardown); - var postJSON, tagJSON, editOptions, createTag = testUtils.DataGenerator.forKnex.createTag; - beforeEach(testUtils.setup('owner')); + beforeEach(function () { + return testUtils.truncate('posts_tags') + .then(function () { + return testUtils.truncate('tags'); + }) + .then(function () { + return testUtils.truncate('posts'); + }); + }); beforeEach(function () { tagJSON = []; diff --git a/core/test/integration/model/model_tags_spec.js b/core/test/integration/model/model_tags_spec.js index f4bfc11a00..4f9bb39ca1 100644 --- a/core/test/integration/model/model_tags_spec.js +++ b/core/test/integration/model/model_tags_spec.js @@ -15,8 +15,8 @@ describe('Tag Model', function () { // Keep the DB clean before(testUtils.teardown); - afterEach(testUtils.teardown); - beforeEach(testUtils.setup('users:roles', 'posts')); + after(testUtils.teardown); + before(testUtils.setup('users:roles', 'posts')); afterEach(function () { sandbox.restore(); @@ -26,33 +26,6 @@ describe('Tag Model', function () { eventSpy = sandbox.spy(common.events, 'emit'); }); - describe('add', function () { - it('uses Date objects for dateTime fields', function (done) { - models.Tag.add(_.omit(testUtils.DataGenerator.forModel.tags[0], 'id'), context) - .then(function (tag) { - return models.Tag.findOne({id: tag.id}); - }) - .then(function (tag) { - should.exist(tag); - tag.get('created_at').should.be.an.instanceof(Date); - - done(); - }) - .catch(done); - }); - - it('returns count.posts if include count.posts', function (done) { - models.Tag.findOne({slug: 'kitchen-sink'}, {withRelated: ['count.posts']}) - .then(function (tag) { - should.exist(tag); - tag.toJSON().count.posts.should.equal(2); - - done(); - }) - .catch(done); - }); - }); - describe('findPage', function () { it('with limit all', function (done) { models.Tag.findPage({limit: 'all'}) @@ -104,6 +77,33 @@ describe('Tag Model', function () { }); }); + describe('add', function () { + it('uses Date objects for dateTime fields', function (done) { + models.Tag.add(_.omit(testUtils.DataGenerator.forModel.tags[0], 'id'), context) + .then(function (tag) { + return models.Tag.findOne({id: tag.id}); + }) + .then(function (tag) { + should.exist(tag); + tag.get('created_at').should.be.an.instanceof(Date); + + done(); + }) + .catch(done); + }); + + it('returns count.posts if include count.posts', function (done) { + models.Tag.findOne({slug: 'kitchen-sink'}, {withRelated: ['count.posts']}) + .then(function (tag) { + should.exist(tag); + tag.toJSON().count.posts.should.equal(2); + + done(); + }) + .catch(done); + }); + }); + describe('destroy', function () { it('can destroy Tag (using transaction)', function () { var firstTag = testUtils.DataGenerator.Content.tags[0].id; diff --git a/core/test/integration/update_check_spec.js b/core/test/integration/update_check_spec.js index a3994c7cf6..c94f08b0ec 100644 --- a/core/test/integration/update_check_spec.js +++ b/core/test/integration/update_check_spec.js @@ -25,13 +25,15 @@ describe('Update Check', function () { configUtils.restore(); }); + after(testUtils.teardown); + describe('fn: updateCheck', function () { var updateCheckRequestSpy, updateCheckResponseSpy, updateCheckErrorSpy; - beforeEach(testUtils.setup('owner', 'posts', 'perms:setting', 'perms:user', 'perms:init')); - afterEach(testUtils.teardown); + beforeEach(testUtils.teardown); + beforeEach(testUtils.setup('roles', 'owner')); beforeEach(function () { updateCheckRequestSpy = sandbox.stub().returns(Promise.resolve()); @@ -107,9 +109,8 @@ describe('Update Check', function () { configUtils.restore(); }); - beforeEach(testUtils.setup('owner', 'settings', 'posts', 'perms:setting', 'perms:user', 'perms:init')); - - afterEach(testUtils.teardown); + beforeEach(testUtils.teardown); + beforeEach(testUtils.setup('roles', 'owner', 'settings', 'posts', 'perms:setting', 'perms:user', 'perms:init')); it('should report the correct data', function (done) { var updateCheckData = updateCheck.__get__('updateCheckData'); @@ -148,14 +149,13 @@ describe('Update Check', function () { updateCheck.__set__('ghostVersion.original', currentVersionOrig); }); - beforeEach(testUtils.setup('owner', 'posts', 'settings', 'perms:setting', 'perms:notification', 'perms:user', 'perms:init')); + beforeEach(testUtils.teardown); + beforeEach(testUtils.setup('settings', 'roles', 'owner', 'perms:setting', 'perms:notification', 'perms:user', 'perms:init')); beforeEach(function () { return NotificationsAPI.destroyAll(testUtils.context.internal); }); - afterEach(testUtils.teardown); - it('should create a release notification for target version', function (done) { var createCustomNotification = updateCheck.__get__('createCustomNotification'), notification = { @@ -315,8 +315,8 @@ describe('Update Check', function () { }); describe('fn: updateCheckResponse', function () { - beforeEach(testUtils.setup('settings', 'perms:setting', 'perms:init')); - afterEach(testUtils.teardown); + beforeEach(testUtils.teardown); + beforeEach(testUtils.setup('roles', 'settings', 'perms:setting', 'perms:init')); it('receives a notifications with messages', function (done) { var updateCheckResponse = updateCheck.__get__('updateCheckResponse'), diff --git a/core/test/utils/fixtures/data-generator.js b/core/test/utils/fixtures/data-generator.js index 2b1a785236..b7c5df398c 100644 --- a/core/test/utils/fixtures/data-generator.js +++ b/core/test/utils/fixtures/data-generator.js @@ -52,8 +52,8 @@ DataGenerator.Content = { feature_image: 'http://placekitten.com/500/200', meta_description: 'test stuff', published_at: new Date('2015-01-03'), - uuid: '2ac6b4f6-e1f3-406c-9247-c94a0496d39d', - featured: true + featured: true, + uuid: '2ac6b4f6-e1f3-406c-9247-c94a0496d39d' }, { id: ObjectId.generate(), @@ -132,7 +132,7 @@ DataGenerator.Content = { name: 'Joe Bloggs', slug: 'joe-bloggs', email: 'jbloggs@example.com', - password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS', + password: 'Sl1m3rson99', profile_image: 'https://example.com/super_photo.jpg' }, { @@ -141,7 +141,7 @@ DataGenerator.Content = { name: 'Smith Wellingsworth', slug: 'smith-wellingsworth', email: 'swellingsworth@example.com', - password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS' + password: 'Sl1m3rson99' }, { // editor @@ -149,7 +149,7 @@ DataGenerator.Content = { name: 'Jimothy Bogendath', slug: 'jimothy-bogendath', email: 'jbOgendAth@example.com', - password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS' + password: 'Sl1m3rson99' }, { // author @@ -157,7 +157,7 @@ DataGenerator.Content = { name: 'Slimer McEctoplasm', slug: 'slimer-mcectoplasm', email: 'smcectoplasm@example.com', - password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS' + password: 'Sl1m3rson99' }, { // editor 2 @@ -165,7 +165,7 @@ DataGenerator.Content = { name: 'Ivan Email', slug: 'ivan-email', email: 'info1@ghost.org', - password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS' + password: 'Sl1m3rson99' }, { // author 2 @@ -173,7 +173,7 @@ DataGenerator.Content = { name: 'Author2', slug: 'a-2', email: 'info2@ghost.org', - password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS' + password: 'Sl1m3rson99' }, { // admin 2 @@ -181,7 +181,7 @@ DataGenerator.Content = { name: 'admin2', slug: 'ad-2', email: 'info3@ghost.org', - password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS' + password: 'Sl1m3rson99' }, { // contributor @@ -189,7 +189,7 @@ DataGenerator.Content = { name: 'Contributor', slug: 'contributor', email: 'contributor@ghost.org', - password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS' + password: 'Sl1m3rson99' }, { // contributor @@ -197,7 +197,7 @@ DataGenerator.Content = { name: 'contributor2', slug: 'contrib-2', email: 'contributor2@ghost.org', - password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS' + password: 'Sl1m3rson99' } ], @@ -472,7 +472,7 @@ DataGenerator.forKnex = (function () { name: 'name', slug: 'slug_' + Date.now(), status: 'active', - password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS', + password: 'Sl1m3rson99', created_by: DataGenerator.Content.users[0].id, created_at: new Date(), updated_at: new Date(), @@ -505,7 +505,7 @@ DataGenerator.forKnex = (function () { name: 'Joe Bloggs', slug: 'joe-blogs', email: 'joe_' + uniqueInteger + '@example.com', - password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS' + password: 'Sl1m3rson99' }); } diff --git a/core/test/utils/index.js b/core/test/utils/index.js index 4cb7cb7f95..8735b7f7c2 100644 --- a/core/test/utils/index.js +++ b/core/test/utils/index.js @@ -1,4 +1,5 @@ -/*jshint expr:true*/ +'use strict'; + var Promise = require('bluebird'), _ = require('lodash'), fs = require('fs-extra'), @@ -12,8 +13,8 @@ var Promise = require('bluebird'), KnexMigrator = require('knex-migrator'), ghost = require('../../server'), common = require('../../server/lib/common'), - db = require('../../server/data/db'), fixtureUtils = require('../../server/data/schema/fixtures/utils'), + db = require('../../server/data/db'), schema = require('../../server/data/schema').tables, schemaTables = Object.keys(schema), models = require('../../server/models'), @@ -41,6 +42,7 @@ var Promise = require('bluebird'), unmockNotExistingModule, teardown, setup, + truncate, doAuth, createUser, createPost, @@ -60,102 +62,72 @@ require('./assertions'); /** TEST FIXTURES **/ fixtures = { insertPosts: function insertPosts(posts) { - return Promise.resolve(db.knex('posts').insert(posts)); + return Promise.map(posts, function (post) { + return models.Post.add(post, module.exports.context.internal); + }); }, insertPostsAndTags: function insertPostsAndTags() { - return Promise.resolve(db.knex('posts').insert(DataGenerator.forKnex.posts)).then(function () { - return db.knex('tags').insert(DataGenerator.forKnex.tags); + return Promise.map(DataGenerator.forKnex.tags, function (tag) { + return models.Tag.add(tag, module.exports.context.internal); }).then(function () { - return db.knex('posts_tags').insert(DataGenerator.forKnex.posts_tags); - }).then(function () { - return db.knex('posts_authors').insert(DataGenerator.forKnex.posts_authors) - .catch(function (err) { - var clonedPostsAuthors; + return Promise.map(_.cloneDeep(DataGenerator.forKnex.posts), function (post) { + let postTagRelations = _.filter(DataGenerator.forKnex.posts_tags, {post_id: post.id}); + let postAuthorsRelations = _.filter(DataGenerator.forKnex.posts_authors, {post_id: post.id}); - // CASE: routing tests insert extra posts, but some tests don't add the users from the data generator - // The only users which exist via the default Ghost fixtures are the Owner and the Ghost author - // This results a MySQL error: `ER_NO_REFERENCED_ROW_2` - // @TODO: rework if we overhaul the test env - if (err.errno === 1452) { - clonedPostsAuthors = _.cloneDeep(DataGenerator.forKnex.posts_authors); - - // Fallback to owner user - this user does exist for sure - _.each(clonedPostsAuthors, function (postsAuthorRelation) { - postsAuthorRelation.author_id = DataGenerator.forKnex.users[0].id; - }); - - return db.knex('posts_authors').insert(clonedPostsAuthors); - } - - throw err; + postTagRelations = _.map(postTagRelations, function (postTagRelation) { + return _.find(DataGenerator.forKnex.tags, {id: postTagRelation.tag_id}); }); + + postAuthorsRelations = _.map(postAuthorsRelations, function (postAuthorsRelation) { + return _.find(DataGenerator.forKnex.users, {id: postAuthorsRelation.author_id}); + }); + + post.tags = postTagRelations; + post.authors = postAuthorsRelations; + return models.Post.add(post, module.exports.context.internal); + }); }); }, insertMultiAuthorPosts: function insertMultiAuthorPosts(max) { /*jshint unused:false*/ - var author, - authors, - i, j, k = postsInserted, + let i, j, k = 0, posts = []; max = max || 50; + // insert users of different roles return Promise.resolve(fixtures.createUsersWithRoles()).then(function () { - // create the tags - return db.knex('tags').insert(DataGenerator.forKnex.tags); + return Promise.map(DataGenerator.forKnex.tags, function (tag) { + return models.Tag.add(tag, module.exports.context.internal); + }); }).then(function () { - return db.knex('users').select('id'); + return Promise.all([ + models.User.fetchAll(_.merge({columns: ['id']}, module.exports.context.internal)), + models.Tag.fetchAll(_.merge({columns: ['id']}, module.exports.context.internal)) + ]); }).then(function (results) { - authors = _.map(results, 'id'); + let users = results[0], + tags = results[1]; + + tags = tags.toJSON(); + + users = users.toJSON(); + users = _.map(users, 'id'); // Let's insert posts with random authors for (i = 0; i < max; i += 1) { - author = authors[i % authors.length]; + const author = users[i % users.length]; posts.push(DataGenerator.forKnex.createGenericPost(k, null, null, author)); k = k + 1; } - // Keep track so we can run this function again safely - postsInserted = k; - - return sequence(_.times(posts.length, function (index) { - return function () { - return db.knex('posts').insert(posts[index]) - .then(function () { - return db.knex('posts_authors').insert({ - id: ObjectId.generate(), - post_id: posts[index].id, - author_id: posts[index].author_id - }); - }); - }; - })); - }).then(function () { - return Promise.all([ - db.knex('posts').orderBy('id', 'asc').select('id'), - db.knex('tags').select('id') - ]); - }).then(function (results) { - var posts = _.map(results[0], 'id'), - tags = _.map(results[1], 'id'), - promises = [], - i; - - if (max > posts.length) { - throw new Error('Trying to add more posts_tags than the number of posts. ' + max + ' ' + posts.length); - } - - for (i = 0; i < max; i += 1) { - promises.push(DataGenerator.forKnex.createPostsTags(posts[i], tags[i % tags.length])); - } - - return sequence(_.times(promises.length, function (index) { - return function () { - return db.knex('posts_tags').insert(promises[index]); - }; - })); + return Promise.map(posts, function (post, index) { + posts[index].authors = [{id: posts[index].author_id}]; + posts[index].tags = [tags[Math.floor(Math.random() * (tags.length - 1))]]; + return models.Post.add(posts[index], module.exports.context.internal); + }); }); }, @@ -182,22 +154,19 @@ fixtures = { // Keep track so we can run this function again safely postsInserted = k; - return sequence(_.times(posts.length, function (index) { - return function () { - return db.knex('posts').insert(posts[index]) - .then(function () { - return db.knex('posts_authors').insert({ - id: ObjectId.generate(), - post_id: posts[index].id, - author_id: posts[index].author_id - }); - }); - }; - })); + return models.User.getOwnerUser(module.exports.context.internal) + .then(function (ownerUser) { + return Promise.map(posts, function (post, index) { + posts[index].authors = [ownerUser.toJSON()]; + return models.Post.add(posts[index], module.exports.context.internal); + }); + }); }, insertTags: function insertTags() { - return db.knex('tags').insert(DataGenerator.forKnex.tags); + return Promise.map(DataGenerator.forKnex.tags, function (tag) { + return models.Tag.add(tag, module.exports.context.internal); + }); }, insertExtraTags: function insertExtraTags(max) { @@ -211,46 +180,44 @@ fixtures = { tags.push(DataGenerator.forKnex.createBasic({name: tagName, slug: tagName})); } - return sequence(_.times(tags.length, function (index) { - return function () { - return db.knex('tags').insert(tags[index]); - }; - })); + return Promise.map(tags, function (tag, index) { + return models.Tag.add(tags[index], module.exports.context.internal); + }); }, insertExtraPostsTags: function insertExtraPostsTags(max) { max = max || 50; return Promise.all([ - db.knex('posts').orderBy('id', 'asc').select('id'), - db.knex('tags').select('id', 'name') + models.Post.fetchAll(_.merge({columns: ['id'], withRelated: 'tags'}, module.exports.context.internal)), + models.Tag.fetchAll(_.merge({columns: ['id', 'name']}, module.exports.context.internal)) ]).then(function (results) { - var posts = _.map(results[0], 'id'), - injectionTagId = _.chain(results[1]) + let posts = results[0].toJSON(); + let tags = results[1].toJSON(); + + const injectionTagId = _.chain(tags) .filter({name: 'injection'}) .map('id') - .value()[0], - promises = [], - i; + .value()[0]; if (max > posts.length) { throw new Error('Trying to add more posts_tags than the number of posts.'); } - for (i = 0; i < max; i += 1) { - promises.push(DataGenerator.forKnex.createPostsTags(posts[i], injectionTagId)); - } + return Promise.map(posts.slice(0, max), function (post) { + post.tags = post.tags ? post.tags : []; - return sequence(_.times(promises.length, function (index) { - return function () { - return db.knex('posts_tags').insert(promises[index]); - }; - })); + return models.Post.edit({ + tags: post.tags.concat([_.find(DataGenerator.Content.tags, {id: injectionTagId})]) + }, _.merge({id: post.id}, module.exports.context.internal)); + }); }); }, insertRoles: function insertRoles() { - return db.knex('roles').insert(DataGenerator.forKnex.roles); + return Promise.map(DataGenerator.forKnex.roles, function (role) { + return models.Role.add(role, module.exports.context.internal); + }); }, initOwnerUser: function initOwnerUser() { @@ -259,65 +226,89 @@ fixtures = { user = DataGenerator.forKnex.createBasic(user); user = _.extend({}, user, {status: 'inactive'}); - return db.knex('roles').insert(DataGenerator.forKnex.roles).then(function () { - return db.knex('users').insert(user); + return Promise.map(DataGenerator.forKnex.roles, function (role) { + return models.Role.add(role, module.exports.context.internal); }).then(function () { - return db.knex('roles_users').insert(DataGenerator.forKnex.roles_users[0]); + const userRolesRelation = _.cloneDeep(DataGenerator.forKnex.roles_users[0]); + user.roles = _.filter(DataGenerator.forKnex.roles, {id: userRolesRelation.role_id}); + return models.User.add(user, module.exports.context.internal); }); }, insertOwnerUser: function insertOwnerUser() { - var user; - - user = DataGenerator.forKnex.createUser(DataGenerator.Content.users[0]); - - return db.knex('users').insert(user).then(function () { - return db.knex('roles_users').insert(DataGenerator.forKnex.roles_users[0]); - }); + const user = _.cloneDeep(DataGenerator.forKnex.users[0]); + user.roles = [DataGenerator.forKnex.roles[3]]; + return models.User.add(user, module.exports.context.internal); }, overrideOwnerUser: function overrideOwnerUser(slug) { - var user; - user = DataGenerator.forKnex.createUser(DataGenerator.Content.users[0]); + return models.User.getOwnerUser(module.exports.context.internal) + .then(function (ownerUser) { + var user = DataGenerator.forKnex.createUser(DataGenerator.Content.users[0]); - if (slug) { - user.slug = slug; - } + if (slug) { + user.slug = slug; + } - return db.knex('users') - .where('id', '=', DataGenerator.Content.users[0].id) - .update(user); + return models.User.edit(user, _.merge({id: ownerUser.id}, module.exports.context.internal)); + }); }, changeOwnerUserStatus: function changeOwnerUserStatus(options) { - return db.knex('users') - .where('slug', '=', options.slug) - .update({ - status: options.status + return models.User.getOwnerUser(module.exports.context.internal) + .then(function (user) { + return models.User.edit({status: options.status}, _.merge({id: user.id}, module.exports.context.internal)); }); }, createUsersWithRoles: function createUsersWithRoles() { - return db.knex('roles').insert(DataGenerator.forKnex.roles).then(function () { - return db.knex('users').insert(DataGenerator.forKnex.users); + return Promise.map(DataGenerator.forKnex.roles, function (role) { + return models.Role.add(role, module.exports.context.internal); }).then(function () { - return db.knex('roles_users').insert(DataGenerator.forKnex.roles_users); + return Promise.map(_.cloneDeep(DataGenerator.forKnex.users), function (user) { + let userRolesRelations = _.filter(DataGenerator.forKnex.roles_users, {user_id: user.id}); + + userRolesRelations = _.map(userRolesRelations, function (userRolesRelation) { + return _.find(DataGenerator.forKnex.roles, {id: userRolesRelation.role_id}); + }); + + user.roles = userRolesRelations; + return models.User.add(user, module.exports.context.internal); + }); + }); + }, + + resetRoles: function resetRoles() { + return Promise.map(_.cloneDeep(DataGenerator.forKnex.users), function (user) { + let userRolesRelations = _.filter(DataGenerator.forKnex.roles_users, {user_id: user.id}); + + userRolesRelations = _.map(userRolesRelations, function (userRolesRelation) { + return _.find(DataGenerator.forKnex.roles, {id: userRolesRelation.role_id}); + }); + + user.roles = userRolesRelations; + return models.User.edit(user, _.merge({id: user.id}, module.exports.context.internal)); }); }, createUsersWithoutOwner: function createUsersWithoutOwner() { - var usersWithoutOwner = DataGenerator.forKnex.users.slice(1); + var usersWithoutOwner = _.cloneDeep(DataGenerator.forKnex.users.slice(1)); - return db.knex('users').insert(usersWithoutOwner) - .then(function () { - return db.knex('roles_users').insert(DataGenerator.forKnex.roles_users); + return Promise.map(usersWithoutOwner, function (user) { + let userRolesRelations = _.filter(DataGenerator.forKnex.roles_users, {user_id: user.id}); + + userRolesRelations = _.map(userRolesRelations, function (userRolesRelation) { + return _.find(DataGenerator.forKnex.roles, {id: userRolesRelation.role_id}); }); + + user.roles = userRolesRelations; + return models.User.add(user, module.exports.context.internal); + }); }, createExtraUsers: function createExtraUsers() { // grab 3 more users - var extraUsers = DataGenerator.Content.users.slice(2, 6); - + var extraUsers = _.cloneDeep(DataGenerator.Content.users.slice(2, 6)); extraUsers = _.map(extraUsers, function (user) { return DataGenerator.forKnex.createUser(_.extend({}, user, { id: ObjectId.generate(), @@ -326,53 +317,52 @@ fixtures = { })); }); + const roles = {}; + roles[extraUsers[0].id] = DataGenerator.Content.roles[0]; + roles[extraUsers[1].id] = DataGenerator.Content.roles[1]; + roles[extraUsers[2].id] = DataGenerator.Content.roles[2]; + roles[extraUsers[3].id] = DataGenerator.Content.roles[4]; + // @TODO: remove when overhauling test env // tests need access to the extra created users (especially to the created id) // replacement for admin2, editor2 etc DataGenerator.Content.extraUsers = extraUsers; - return db.knex('users').insert(extraUsers).then(function () { - return db.knex('roles_users').insert([ - {id: ObjectId.generate(), user_id: extraUsers[0].id, role_id: DataGenerator.Content.roles[0].id}, - {id: ObjectId.generate(), user_id: extraUsers[1].id, role_id: DataGenerator.Content.roles[1].id}, - {id: ObjectId.generate(), user_id: extraUsers[2].id, role_id: DataGenerator.Content.roles[2].id}, - {id: ObjectId.generate(), user_id: extraUsers[3].id, role_id: DataGenerator.Content.roles[4].id} - ]); + return Promise.map(extraUsers, function (user) { + user.roles = roles[user.id]; + return models.User.add(user, module.exports.context.internal); }); }, insertOneUser: function insertOneUser(options) { options = options || {}; - return db.knex('users').insert(DataGenerator.forKnex.createUser({ + return models.User.add({ + name: options.name, email: options.email, slug: options.slug, status: options.status - })); + }, module.exports.context.internal); }, // Creates a client, and access and refresh tokens for user with index or 2 by default createTokensForUser: function createTokensForUser(index) { - return db.knex('clients').insert(DataGenerator.forKnex.clients).then(function () { - return db.knex('accesstokens').insert(DataGenerator.forKnex.createToken({ - user_id: DataGenerator.Content.users[index || 2].id - })); + return Promise.map(DataGenerator.forKnex.clients, function (client) { + return models.Client.add(client, module.exports.context.internal); }).then(function () { - return db.knex('refreshtokens').insert(DataGenerator.forKnex.createToken({ + return models.Accesstoken.add(DataGenerator.forKnex.createToken({ user_id: DataGenerator.Content.users[index || 2].id - })); + }), module.exports.context.internal); + }).then(function () { + return models.Refreshtoken.add(DataGenerator.forKnex.createToken({ + user_id: DataGenerator.Content.users[index || 2].id + }), module.exports.context.internal); }); }, - insertOne: function insertOne(obj, fn, index) { - return db.knex(obj) - .insert(DataGenerator.forKnex[fn](DataGenerator.Content[obj][index || 0])); - }, - - insertApps: function insertApps() { - return db.knex('apps').insert(DataGenerator.forKnex.apps).then(function () { - return db.knex('app_fields').insert(DataGenerator.forKnex.app_fields); - }); + insertOne: function insertOne(modelName, tableName, fn, index) { + const obj = DataGenerator.forKnex[fn](DataGenerator.Content[tableName][index || 0]); + return models[modelName].add(obj, module.exports.context.internal); }, getImportFixturePath: function (filename) { @@ -404,10 +394,10 @@ fixtures = { }, permissionsFor: function permissionsFor(obj) { - var permsToInsert = fixtureUtils.findModelFixtures('Permission', {object_type: obj}).entries, + var permsToInsert = _.cloneDeep(fixtureUtils.findModelFixtures('Permission', {object_type: obj}).entries), permsRolesToInsert = fixtureUtils.findPermissionRelationsForObject(obj).entries, actions = [], - permissionsRoles = [], + permissionsRoles = {}, roles = { Administrator: DataGenerator.Content.roles[0].id, Editor: DataGenerator.Content.roles[1].id, @@ -432,58 +422,64 @@ fixtures = { if (perms[obj]) { if (perms[obj] === 'all') { _.each(actions, function (action) { - permissionsRoles.push({ - id: ObjectId.generate(), - permission_id: action.permissionId, - role_id: roles[role] - }); + if (!permissionsRoles[action.permissionId]) { + permissionsRoles[action.permissionId] = []; + } + + permissionsRoles[action.permissionId].push(_.find(DataGenerator.Content.roles, {id: roles[role]})); }); } else { _.each(perms[obj], function (action) { - permissionsRoles.push({ - id: ObjectId.generate(), - permission_id: _.find(actions, {type: action}).permissionId, - role_id: roles[role] - }); + if (!permissionsRoles[_.find(actions, {type: action}).permissionId]) { + permissionsRoles[_.find(actions, {type: action}).permissionId] = []; + } + + permissionsRoles[_.find(actions, {type: action}).permissionId].push(_.find(DataGenerator.Content.roles, {id: roles[role]})); }); } } }); - return db.knex('permissions').insert(permsToInsert).then(function () { - if (_.isEmpty(permissionsRoles)) { - return Promise.resolve(); + return Promise.map(permsToInsert, function (perm) { + if (!_.isEmpty(permissionsRoles)) { + perm.roles = permissionsRoles[perm.id]; } - return db.knex('permissions_roles').insert(permissionsRoles); + return models.Permission.add(perm, module.exports.context.internal); }); }, insertClients: function insertClients() { - return db.knex('clients').insert(DataGenerator.forKnex.clients); + return Promise.map(DataGenerator.forKnex.clients, function (client) { + return models.Client.add(client, module.exports.context.internal); + }); }, insertClientWithTrustedDomain: function insertClientWithTrustedDomain() { - var client = DataGenerator.forKnex.createClient({slug: 'ghost-test'}); + const client = DataGenerator.forKnex.createClient({slug: 'ghost-test'}); - return db.knex('clients') - .insert(client) + return models.Client.add(client, module.exports.context.internal) .then(function () { - return db.knex('client_trusted_domains') - .insert(DataGenerator.forKnex.createTrustedDomain({client_id: client.id})); + return models.ClientTrustedDomain.add(DataGenerator.forKnex.createTrustedDomain({ + client_id: client.id + }), module.exports.context.internal); }); }, insertAccessToken: function insertAccessToken(override) { - return db.knex('accesstokens').insert(DataGenerator.forKnex.createToken(override)); + return models.Accesstoken.insert(DataGenerator.forKnex.createToken(override), module.exports.context.internal); }, insertInvites: function insertInvites() { - return db.knex('invites').insert(DataGenerator.forKnex.invites); + return Promise.map(DataGenerator.forKnex.invites, function (invite) { + return models.Invite.add(invite, module.exports.context.internal); + }); }, insertWebhooks: function insertWebhooks() { - return db.knex('webhooks').insert(DataGenerator.forKnex.webhooks); + return Promise.map(DataGenerator.forKnex.webhooks, function (webhook) { + return models.Webhook.add(webhook, module.exports.context.internal); + }); } }; @@ -496,6 +492,20 @@ clearBruteData = function clearBruteData() { return db.knex('brute').truncate(); }; +truncate = function truncate(tableName) { + if (config.get('database:client') === 'sqlite3') { + return db.knex(tableName).truncate(); + } + + return db.knex.raw('SET FOREIGN_KEY_CHECKS=0;') + .then(function () { + return db.knex(tableName).truncate(); + }) + .then(function () { + return db.knex.raw('SET FOREIGN_KEY_CHECKS=1;'); + }); +}; + // we must always try to delete all tables clearData = function clearData() { debug('Database reset'); @@ -504,34 +514,34 @@ clearData = function clearData() { toDoList = { app: function insertApp() { - return fixtures.insertOne('apps', 'createApp'); + return fixtures.insertOne('App', 'apps', 'createApp'); }, app_field: function insertAppField() { // TODO: use the actual app ID to create the field - return fixtures.insertOne('apps', 'createApp').then(function () { - return fixtures.insertOne('app_fields', 'createAppField'); + return fixtures.insertOne('App', 'apps', 'createApp').then(function () { + return fixtures.insertOne('AppField', 'app_fields', 'createAppField'); }); }, app_setting: function insertAppSetting() { // TODO: use the actual app ID to create the field - return fixtures.insertOne('apps', 'createApp').then(function () { - return fixtures.insertOne('app_settings', 'createAppSetting'); + return fixtures.insertOne('App', 'apps', 'createApp').then(function () { + return fixtures.insertOne('AppSetting', 'app_settings', 'createAppSetting'); }); }, permission: function insertPermission() { - return fixtures.insertOne('permissions', 'createPermission'); + return fixtures.insertOne('Permission', 'permissions', 'createPermission'); }, role: function insertRole() { - return fixtures.insertOne('roles', 'createRole'); + return fixtures.insertOne('Role', 'roles', 'createRole'); }, roles: function insertRoles() { return fixtures.insertRoles(); }, tag: function insertTag() { - return fixtures.insertOne('tags', 'createTag'); + return fixtures.insertOne('Tag', 'tags', 'createTag'); }, subscriber: function insertSubscriber() { - return fixtures.insertOne('subscribers', 'createSubscriber'); + return fixtures.insertOne('Subscriber', 'subscribers', 'createSubscriber'); }, posts: function insertPostsAndTags() { return fixtures.insertPostsAndTags(); @@ -671,6 +681,7 @@ initFixtures = function initFixtures() { * @returns {Function} */ setup = function setup() { + /*eslint no-invalid-this: "off"*/ const self = this, args = arguments; @@ -713,19 +724,15 @@ createUser = function createUser(options) { var user = options.user, role = options.role; - return db.knex('users').insert(user) - .then(function () { - return db.knex('roles'); - }) + return models.Role.fetchAll(module.exports.context.internal) .then(function (roles) { - return db.knex('roles_users').insert({ - id: ObjectId.generate(), - role_id: _.find(roles, {name: role.name}).id, - user_id: user.id - }); - }) - .then(function () { - return user; + roles = roles.toJSON(); + user.roles = [_.find(roles, {name: role})]; + + return models.User.add(user, module.exports.context.internal) + .then(function () { + return user; + }); }); }; @@ -736,15 +743,8 @@ createPost = function createPost(options) { post.author_id = options.author.id; } - return db.knex('posts') - .insert(post) - .then(function () { - return db.knex('posts_authors').insert({ - id: ObjectId.generate(), - author_id: post.author_id, - post_id: post.id - }).return(post); - }); + post.authors = [{id: post.author_id}]; + return models.Post.add(post, module.exports.context.internal); }; login = function login(request) { @@ -989,6 +989,7 @@ module.exports = { startGhost: startGhost, configureGhost: configureGhost, teardown: teardown, + truncate: truncate, setup: setup, doAuth: doAuth, createUser: createUser,