Removed unit tests who use the database (#10407)

refs #9178

## Rule

- do not use the database in unit tests
- re-add correct unit tests if you work on something which is not tested properly (we have to bring them back at some point, but without using the database)
This commit is contained in:
Katharina Irrgang 2019-01-22 13:36:30 +01:00 committed by GitHub
parent 9fc9aefa9c
commit 5921d9ce4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 31 additions and 1834 deletions

View File

@ -55,7 +55,6 @@ describe('Scheduling: Post Scheduling', function () {
afterEach(function () {
sinon.restore();
return testUtils.teardown();
});
describe('fn:init', function () {

View File

@ -5,77 +5,8 @@ const testUtils = require('../../utils');
describe('Unit: models/api_key', function () {
before(models.init);
before(testUtils.teardown);
before(testUtils.setup('roles'));
describe('Add', function () {
it('sets default secret', function () {
// roles[5] = 'Admin Integration'
const role_id = testUtils.DataGenerator.forKnex.roles[5].id;
const attrs = {
type: 'admin',
role_id
};
return models.ApiKey.add(attrs).then((api_key) => {
return models.ApiKey.findOne({id: api_key.id}, {withRelated: ['role']})
.then((api_key) => {
api_key.get('type').should.eql('admin');
api_key.related('role').get('id').should.eql(role_id);
// defaults
api_key.get('secret').length.should.eql(128);
});
});
});
it('sets default secret for content key', function () {
const attrs = {
type: 'content'
};
return models.ApiKey.add(attrs).then((api_key) => {
api_key.get('secret').length.should.eql(26);
});
});
it('sets hardcoded role for key type', function () {
// roles[5] = 'Admin Integration'
const role_id = testUtils.DataGenerator.forKnex.roles[5].id;
const adminKey = {
type: 'admin'
};
const adminCheck = models.ApiKey.add(adminKey).then((api_key) => {
return models.ApiKey.findOne({id: api_key.id}, {withRelated: ['role']})
.then((api_key) => {
api_key.get('type').should.eql('admin');
// defaults
should.exist(api_key.related('role').id);
api_key.related('role').get('id').should.eql(role_id);
});
});
const contentKey = {
type: 'content',
role_id: testUtils.DataGenerator.forKnex.roles[0].id
};
const contentCheck = models.ApiKey.add(contentKey).then((api_key) => {
return models.ApiKey.findOne({id: api_key.id}, {withRelated: ['role']})
.then((api_key) => {
api_key.get('type').should.eql('content');
// defaults
should.not.exist(api_key.related('role').id);
});
});
return Promise.all([adminCheck, contentCheck]);
});
});
describe('refreshSecret', function () {
describe('fn: refreshSecret', function () {
it('returns a call to edit passing a new secret', function () {
const editStub = sinon.stub(models.ApiKey, 'edit').resolves();

View File

@ -19,59 +19,6 @@ describe('Unit: models/invite', function () {
sinon.restore();
});
before(testUtils.teardown);
describe('add', function () {
beforeEach(testUtils.setup('roles'));
afterEach(testUtils.teardown);
it('default', function () {
return models.Invite.add({email: 'invited@test.org', role_id: testUtils.DataGenerator.forKnex.roles[1].id})
.then(function (invite) {
invite.get('status').should.eql('pending');
invite.get('email').should.eql('invited@test.org');
should.exist(invite.get('token'));
should.exist(invite.get('expires'));
});
});
it('set status with none internal context', function () {
return models.Invite.add({
email: 'invited@test.org',
role_id: testUtils.DataGenerator.forKnex.roles[1].id,
status: 'sent'
}).then(function (invite) {
invite.get('status').should.eql('pending');
invite.get('email').should.eql('invited@test.org');
should.exist(invite.get('token'));
should.exist(invite.get('expires'));
});
});
it('set status with internal context', function () {
return models.Invite.add({
email: 'invited@test.org',
role_id: testUtils.DataGenerator.forKnex.roles[1].id,
status: 'sent'
}, testUtils.context.internal).then(function (invite) {
invite.get('status').should.eql('sent');
invite.get('email').should.eql('invited@test.org');
should.exist(invite.get('token'));
should.exist(invite.get('expires'));
});
});
it('[error] no role passed', function () {
return models.Invite.add({email: 'invited@test.org'})
.then(function () {
'Should fail'.should.be.true();
})
.catch(function (err) {
(err[0] instanceof common.errors.ValidationError).should.be.true();
});
});
});
describe('permissible', function () {
describe('action: add', function () {
let inviteModel;

View File

@ -14,35 +14,7 @@ describe('Unit: models/permission', function () {
configUtils.restore();
});
before(testUtils.teardown);
describe('add', function () {
beforeEach(testUtils.setup('roles'));
afterEach(testUtils.teardown);
it('without roles', function () {
return models.Permission.add({name: 'test', object_type: 'something', action_type: 'read something'})
.then(function (permission) {
permission.get('name').should.eql('test');
permission.get('object_type').should.eql('something');
permission.get('action_type').should.eql('read something');
});
});
it('with roles', function () {
return models.Permission.add({
name: 'test',
object_type: 'something',
action_type: 'write something',
roles: [testUtils.DataGenerator.forKnex.roles[1]]
}).then(function (permission) {
permission.get('name').should.eql('test');
permission.get('object_type').should.eql('something');
permission.get('action_type').should.eql('write something');
permission.related('roles').models[0].id.should.eql(testUtils.DataGenerator.forKnex.roles[1].id);
});
});
it('[error] validation', function () {
return models.Permission.add({})
.then(function () {

File diff suppressed because it is too large Load Diff

View File

@ -1,48 +0,0 @@
const models = require('../../../server/models');
const {NoPermissionError} = require('../../../server/lib/common/errors');
const ghostBookshelf = require('../../../server/models/base');
const testUtils = require('../../utils');
const should = require('should');
describe('Unit: models/role', function () {
before(testUtils.teardown);
before(testUtils.setup('roles', 'perms:role'));
describe('destroy', function () {
it('cleans up permissions join table', function () {
const adminRole = {id: testUtils.DataGenerator.Content.roles[0].id};
function checkRolePermissionsCount(count) {
return ghostBookshelf.knex.select().table('permissions_roles').where('role_id', adminRole.id)
.then((rolePermissions) => {
rolePermissions.length.should.eql(count);
});
}
return models.Role.findOne(adminRole)
.then(role => should.exist(role, 'Administrator role not found'))
.then(() => checkRolePermissionsCount(2))
.then(() => models.Role.destroy(adminRole))
.then(() => checkRolePermissionsCount(0));
});
});
describe('permissible', function () {
it('does not let api key assign the owner role', function () {
return models.Role.permissible(
models.Role.forge({name: 'Owner'}), // Owner role
'assign', // assign action
{},
{},
{apiKey: {}}, // apiKey loaded permissions
true,
true,
true
).then(() => {
throw new Error('models.Role.permissible should have thrown!');
}, (err) => {
should.equal(err instanceof NoPermissionError, true);
});
});
});
});

View File

@ -59,24 +59,4 @@ describe('Unit: models/tag', function () {
});
});
});
describe('Edit', function () {
before(testUtils.teardown);
before(testUtils.setup('tags'));
it('resets given empty value to null', function () {
return models.Tag.findOne({slug: 'kitchen-sink'})
.then(function (tag) {
tag.get('slug').should.eql('kitchen-sink');
tag.get('feature_image').should.eql('https://example.com/super_photo.jpg');
tag.set('feature_image', '');
tag.set('description', '');
return tag.save();
})
.then(function (tag) {
should(tag.get('feature_image')).be.null();
tag.get('description').should.eql('');
});
});
});
});

View File

@ -16,9 +16,6 @@ describe('Unit: models/user', function () {
models.init();
});
before(testUtils.teardown);
before(testUtils.setup('users:roles'));
afterEach(function () {
sinon.restore();
});
@ -54,40 +51,6 @@ describe('Unit: models/user', function () {
sinon.stub(security.password, 'hash').resolves('$2a$10$we16f8rpbrFZ34xWj0/ZC.LTPUux8ler7bcdTs5qIleN6srRHhilG');
});
describe('password', function () {
it('no password', function () {
return models.User.add({email: 'test1@ghost.org', name: 'Ghosty'})
.then(function (user) {
user.get('name').should.eql('Ghosty');
should.exist(user.get('password'));
});
});
it('only numbers', function () {
return models.User.add({email: 'test2@ghost.org', name: 'Wursti', password: 109674836589})
.then(function (user) {
user.get('name').should.eql('Wursti');
should.exist(user.get('password'));
});
});
it('can change password', function () {
let oldPassword;
return models.User.findOne({slug: 'joe-bloggs'})
.then(function (user) {
user.get('slug').should.eql('joe-bloggs');
oldPassword = user.get('password');
user.set('password', '12734!!332');
return user.save();
})
.then(function (user) {
user.get('slug').should.eql('joe-bloggs');
user.get('password').should.not.eql(oldPassword);
});
});
});
describe('blank', function () {
it('name cannot be blank', function () {
return models.User.add({email: 'test@ghost.org'})
@ -95,7 +58,7 @@ describe('Unit: models/user', function () {
throw new Error('expected ValidationError');
})
.catch(function (err) {
(err instanceof common.errors.ValidationError).should.be.true;
(err instanceof common.errors.ValidationError).should.eql(true);
err.message.should.match(/users\.name/);
});
});
@ -110,7 +73,7 @@ describe('Unit: models/user', function () {
})
.catch(function (err) {
err.should.be.an.Array();
(err[0] instanceof common.errors.ValidationError).should.eql.true;
(err[0] instanceof common.errors.ValidationError).should.eql(true);
err[0].message.should.match(/users\.email/);
});
});
@ -128,50 +91,48 @@ describe('Unit: models/user', function () {
// NOTE: Add a user with a broken field to ensure we only validate changed fields on login
sinon.stub(validation, 'validateSchema').resolves();
const user = testUtils.DataGenerator.forKnex.createUser({
const user = models.User.forge(testUtils.DataGenerator.forKnex.createUser({
status: 'warn-1',
email: 'test-9@example.de',
website: '!!!!!this-is-not-a-website!!!!'
});
}));
return models.User.add(user)
.then(function (model) {
validation.validateSchema.restore();
sinon.stub(models.User, 'getByEmail').resolves(user);
sinon.stub(models.User, 'isPasswordCorrect').resolves();
return models.User.check({email: model.get('email'), password: 'test'});
});
sinon.stub(user, 'updateLastSeen').resolves();
sinon.stub(user, 'save').resolves();
return models.User.check({email: user.get('email'), password: 'test'});
});
it('user status is active', function () {
sinon.stub(security.password, 'compare').resolves(true);
const user = models.User.forge(testUtils.DataGenerator.forKnex.createUser({
status: 'active',
email: 'test@ghost.de'
}));
return models.User.check({email: testUtils.DataGenerator.Content.users[1].email, password: 'test'});
sinon.stub(models.User, 'getByEmail').resolves(user);
sinon.stub(models.User, 'isPasswordCorrect').resolves();
sinon.stub(user, 'updateLastSeen').resolves();
sinon.stub(user, 'save').resolves();
return models.User.check({email: user.get('email'), password: 'test'});
});
it('password is incorrect', function () {
sinon.stub(security.password, 'compare').resolves(false);
const user = models.User.forge(testUtils.DataGenerator.forKnex.createUser({
status: 'active',
email: 'test@ghost.de'
}));
return models.User.check({email: testUtils.DataGenerator.Content.users[1].email, password: 'test'})
sinon.stub(models.User, 'getByEmail').resolves(user);
sinon.stub(models.User, 'isPasswordCorrect').rejects(new common.errors.ValidationError());
return models.User.check({email: user.get('email'), password: 'test'})
.catch(function (err) {
(err instanceof common.errors.ValidationError).should.be.true;
});
});
it('user not found', function () {
sinon.stub(security.password, 'compare').resolves(true);
return models.User.check({email: 'notfound@example.to', password: 'test'})
.catch(function (err) {
(err instanceof common.errors.NotFoundError).should.be.true;
});
});
it('user not found', function () {
sinon.stub(security.password, 'compare').resolves(true);
return models.User.check({email: null, password: 'test'})
.catch(function (err) {
(err instanceof common.errors.NotFoundError).should.be.true;
(err instanceof common.errors.ValidationError).should.eql(true);
});
});
});
@ -463,88 +424,6 @@ describe('Unit: models/user', function () {
});
});
describe('Fetch', function () {
before(function () {
models.init();
});
after(function () {
sinon.restore();
});
it('ensure data type', function () {
return models.User.findOne({slug: 'joe-bloggs'}, testUtils.context.internal)
.then((user) => {
user.get('updated_by').should.be.a.String();
user.get('created_by').should.be.a.String();
user.get('created_at').should.be.a.Date();
user.get('updated_at').should.be.a.Date();
});
});
});
describe('Edit', function () {
before(function () {
models.init();
});
after(function () {
sinon.restore();
});
it('resets given empty value to null', function () {
return models.User.findOne({slug: 'joe-bloggs'})
.then(function (user) {
user.get('slug').should.eql('joe-bloggs');
user.get('profile_image').should.eql('https://example.com/super_photo.jpg');
user.set('profile_image', '');
user.set('bio', '');
return user.save();
})
.then(function (user) {
should(user.get('profile_image')).be.null();
user.get('bio').should.eql('');
});
});
});
describe('Add', function () {
const events = {
user: []
};
before(function () {
models.init();
sinon.stub(models.User.prototype, 'emitChange').callsFake(function (event) {
events.user.push({event: event, data: this.toJSON()});
});
});
after(function () {
sinon.restore();
});
it('defaults', function () {
return models.User.add({slug: 'joe', name: 'Joe', email: 'joe@test.com'})
.then(function (user) {
user.get('name').should.eql('Joe');
user.get('email').should.eql('joe@test.com');
user.get('slug').should.eql('joe');
user.get('visibility').should.eql('public');
user.get('status').should.eql('active');
_.each(_.keys(schema.tables.users), (key) => {
should.exist(events.user[0].data.hasOwnProperty(key));
if (['status', 'visibility'].indexOf(key) !== -1) {
events.user[0].data[key].should.eql(schema.tables.users[key].defaultTo);
}
});
});
});
});
describe('transferOwnership', function () {
let ownerRole;

View File

@ -1,26 +0,0 @@
const should = require('should');
const url = require('url');
const sinon = require('sinon');
const models = require('../../../server/models');
const testUtils = require('../../utils');
const {knex} = require('../../../server/data/db');
describe('Unit: models/webhooks', function () {
before(function () {
models.init();
});
after(function () {
sinon.restore();
});
before(testUtils.teardown);
before(testUtils.setup('webhooks'));
it('can correctly use getByEventAndTarget', function () {
return models.Webhook.getByEventAndTarget('subscriber.added', 'https://example.com/webhooks/subscriber-added')
.then(function (webhook) {
webhook.get('event').should.eql('subscriber.added');
webhook.get('target_url').should.eql('https://example.com/webhooks/subscriber-added');
});
});
});

View File

@ -9,7 +9,6 @@ const testUtils = require('../../../../utils');
describe('Admin API Key Auth', function () {
before(models.init);
before(testUtils.teardown);
beforeEach(function () {
const fakeApiKey = {

View File

@ -7,7 +7,6 @@ const testUtils = require('../../../../utils');
describe('Content API Key Auth', function () {
before(models.init);
before(testUtils.teardown);
this.beforeEach(function () {
const fakeApiKey = {

View File

@ -1,259 +0,0 @@
const should = require('should');
const _ = require('lodash');
const sinon = require('sinon');
const testUtils = require('../../../utils');
const models = require('../../../../server/models');
const common = require('../../../../server/lib/common');
const Resources = require('../../../../server/services/url/Resources');
describe('Unit: services/url/Resources', function () {
let onEvents, emitEvents, resources, queue;
before(function () {
models.init();
});
before(testUtils.teardown);
before(testUtils.setup('users:roles', 'posts'));
beforeEach(function () {
onEvents = {};
emitEvents = {};
sinon.stub(common.events, 'on').callsFake(function (eventName, callback) {
onEvents[eventName] = callback;
});
sinon.stub(common.events, 'emit').callsFake(function (eventName, data) {
emitEvents[eventName] = data;
});
queue = {
start: sinon.stub()
};
});
afterEach(function () {
sinon.restore();
resources.reset();
});
it('db.ready', function (done) {
resources = new Resources(queue);
queue.start.callsFake(function (options) {
options.event.should.eql('init');
const created = resources.getAll();
created.posts.length.should.eql(4);
should.exist(created.posts[0].data.primary_author);
should.exist(created.posts[0].data.primary_tag);
// FIXME: these fields should correspond to configuration values in withRelatedFields
Object.keys(created.posts[0].data.primary_author).sort().should.eql(['id', 'post_id', 'slug'].sort());
Object.keys(created.posts[0].data.primary_tag).sort().should.eql(['id', 'post_id', 'slug', 'visibility'].sort());
should.exist(created.posts[1].data.primary_author);
should.exist(created.posts[1].data.primary_tag);
should.exist(created.posts[2].data.primary_author);
should.exist(created.posts[2].data.primary_tag);
should.exist(created.posts[3].data.primary_author);
should.not.exist(created.posts[3].data.primary_tag);
created.pages.length.should.eql(1);
// all mocked tags are public
created.tags.length.should.eql(testUtils.DataGenerator.forKnex.tags.length);
// all mocked users are active
created.authors.length.should.eql(testUtils.DataGenerator.forKnex.users.length);
done();
});
onEvents['db.ready']();
});
it('add resource', function (done) {
resources = new Resources(queue);
queue.start.callsFake(function (options) {
options.event.should.eql('init');
queue.start.callsFake(function (options) {
options.event.should.eql('added');
const obj = _.find(resources.data.posts, {data: {slug: 'test-1234'}}).data;
Object.keys(obj).sort().should.eql([
'id',
'uuid',
'slug',
'comment_id',
'featured',
'page',
'status',
'visibility',
'created_at',
'updated_at',
'published_at',
'published_by',
'created_by',
'updated_by',
'tags',
'authors',
'author',
'primary_author',
'primary_tag',
].sort());
should.exist(resources.getByIdAndType(options.eventData.type, options.eventData.id));
obj.tags.length.should.eql(1);
// FIXME: these fields should correspond to configuration values in withRelatedFields
Object.keys(obj.tags[0]).sort().should.eql(['id', 'slug'].sort());
obj.authors.length.should.eql(1);
Object.keys(obj.authors[0]).sort().should.eql(['id', 'slug'].sort());
should.exist(obj.primary_author);
Object.keys(obj.primary_author).sort().should.eql(['id', 'slug'].sort());
should.exist(obj.primary_tag);
Object.keys(obj.primary_tag).sort().should.eql(['id', 'slug'].sort());
done();
});
models.Post.add({
slug: 'test-1234',
status: 'published',
tags: [{slug: 'tag-1', name: 'tag-name'}]
}, testUtils.context.owner)
.then(function () {
onEvents['post.published'](emitEvents['post.published']);
})
.catch(done);
});
onEvents['db.ready']();
});
it('update taken resource', function (done) {
resources = new Resources(queue);
queue.start.callsFake(function (options) {
options.event.should.eql('init');
const randomResource = resources.getAll().posts[Math.floor(Math.random() * (resources.getAll().posts.length - 0) + 0)];
randomResource.reserve();
randomResource.addListener('updated', function () {
randomResource.data.slug.should.eql('tada');
done();
});
models.Post.edit({
slug: 'tada'
}, _.merge({id: randomResource.data.id}, testUtils.context.owner))
.then(function () {
onEvents['post.published.edited'](emitEvents['post.published.edited']);
})
.catch(done);
});
onEvents['db.ready']();
});
it('update free resource', function (done) {
resources = new Resources(queue);
queue.start.callsFake(function (options) {
options.event.should.eql('init');
const resourceToUpdate = _.find(resources.getAll().posts, (resource) => {
if (resource.data.tags.length && resource.data.authors.length) {
return true;
}
return false;
});
sinon.spy(resourceToUpdate, 'update');
queue.start.callsFake(function (options) {
options.event.should.eql('added');
resourceToUpdate.update.calledOnce.should.be.true();
resourceToUpdate.data.slug.should.eql('eins-zwei');
const obj = _.find(resources.data.posts, {data: {id: resourceToUpdate.data.id}}).data;
Object.keys(obj).sort().should.eql([
'id',
'uuid',
'slug',
'comment_id',
'featured',
'page',
'status',
'visibility',
'created_at',
'created_by',
'updated_at',
'updated_by',
'published_at',
'published_by',
'tags',
'authors',
'author',
'primary_author',
'primary_tag',
].sort());
should.exist(obj.tags);
Object.keys(obj.tags[0]).sort().should.eql(['id', 'slug'].sort());
should.exist(obj.authors);
Object.keys(obj.authors[0]).sort().should.eql(['id', 'slug'].sort());
should.exist(obj.primary_author);
Object.keys(obj.primary_author).sort().should.eql(['id', 'slug'].sort());
should.exist(obj.primary_tag);
Object.keys(obj.primary_tag).sort().should.eql(['id', 'slug'].sort());
done();
});
models.Post.edit({
slug: 'eins-zwei'
}, _.merge({id: resourceToUpdate.data.id}, testUtils.context.owner))
.then(function () {
onEvents['post.published.edited'](emitEvents['post.published.edited']);
})
.catch(done);
});
onEvents['db.ready']();
});
it('remove resource', function (done) {
resources = new Resources(queue);
queue.start.callsFake(function (options) {
options.event.should.eql('init');
const randomResource = resources.getAll().posts[Math.floor(Math.random() * (resources.getAll().posts.length - 0) + 0)];
randomResource.reserve();
randomResource.addListener('removed', function () {
should.not.exist(resources.getByIdAndType('posts', randomResource.data.id));
done();
});
models.Post.destroy(_.merge({id: randomResource.data.id}, testUtils.context.owner))
.then(function () {
onEvents['post.unpublished'](emitEvents['post.unpublished']);
})
.catch(done);
});
onEvents['db.ready']();
});
});