0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-24 23:48:13 -05:00
ghost/core/test/utils/mocks/knex.js
Katharina Irrgang 0aff9f33d9
Improved validation layer (#9427)
refs https://github.com/TryGhost/Ghost/issues/3658

- the `validateSchema` helper was a bit broken
  - if you add a user without email, you will receive a database error
  - but the validation error should catch that email is passed with null
- it was broken, because:
  - A: it called `toJSON` -> this can remove properties from the output (e.g. password)
  - B: we only validated fields, which were part of the JSON data (model.hasOwnProperty)
- we now differentiate between schema validation for update and insert
- fixed one broken import test
  - if you import a post without a status, it should not error
  - it falls back to the default value
- removed user model `onValidate`
  - the user model added a custom implementation of `onValidate`, because of a bug which we experienced (see https://github.com/TryGhost/Ghost/issues/3638)
  - with the refactoring this is no longer required - we only validate fields which have changed when updating resources
  - also, removed extra safe catch when logging in (no longer needed - unit tested)
- add lot's of unit tests to proof the code change
- always call the base class, except you have a good reason
2018-02-16 00:49:15 +01:00

130 lines
4.6 KiB
JavaScript

'use strict';
const mockKnex = require('mock-knex'),
_ = require('lodash'),
DataGenerator = require('../fixtures/data-generator'),
knex = require('../../../server/data/db').knex;
/**
* Knex mock. The database is our Datagenerator.
* You can either self register queries or you simply rely on the data generator data.
*
* Please extend if you use-case does not work.
*/
class KnexMock {
initialiseDb() {
this.db = {};
_.each(_.pick(DataGenerator.Content, ['posts', 'users', 'tags', 'permissions', 'roles']), (objects, tableName) => {
this.db[tableName] = [];
_.each(objects, (object) => {
const lookup = {
users: DataGenerator.forKnex.createUser,
posts: DataGenerator.forKnex.createPost,
tags: DataGenerator.forKnex.createTag,
permissions: DataGenerator.forKnex.createPermission,
roles: DataGenerator.forKnex.createRole,
};
this.db[tableName].push(lookup[tableName](object));
});
});
}
mock(options) {
options = options || {autoMock: true};
mockKnex.mock(knex);
this.initialiseDb();
this.tracker = mockKnex.getTracker();
this.tracker.install();
if (options.autoMock) {
this.tracker.on('query', (query) => {
query.sql = query.sql.replace(/`/g, '"');
if (query.method === 'select') {
if (query.bindings.length && query.sql.match(/where/)) {
const tableName = query.sql.match(/from\s\"(\w+)\"/)[1],
where = query.sql.match(/\"(\w+)\"\s\=\s\?/)[1],
value = query.bindings[0],
dbEntry = _.find(this.db[tableName], ((existing) => {
if (existing[where] === value) {
return true;
}
}));
if (dbEntry) {
query.response([dbEntry]);
} else {
query.response([]);
}
} else {
const tableName = query.sql.match(/from\s\"(\w+)\"/)[1];
query.response(this.db[tableName]);
}
} else if (query.method === 'insert') {
const tableName = query.sql.match(/into\s\"(\w+)\"/)[1];
let keys = query.sql.match(/\(([^)]+)\)/)[1],
entry = {};
keys = keys.replace(/"/g, '');
keys = keys.replace(/\s/g, '');
keys = keys.split(',');
_.each(keys, (key, index) => {
entry[key] = query.bindings[index];
});
if (!this.db[tableName]) {
this.db[tableName] = [];
}
this.db[tableName].push(entry);
query.response(entry);
} else if (query.method === 'update') {
const tableName = query.sql.match(/update\s\"(\w+)\"/)[1],
where = query.sql.match(/where\s\"(\w+)\"\s\=\s\?/)[1],
value = query.bindings.slice(-1)[0],
dbEntry = _.find(this.db[tableName], ((existing) => {
if (existing[where] === value) {
return true;
}
}));
if (!dbEntry) {
query.reject(new Error('not found'));
} else {
let keys = query.sql.match(/set(.*)where/)[1],
entry = {};
keys = keys.match(/\"\w+\"/g).join(',');
keys = keys.replace(/"/g, '');
keys = keys.replace(/\s/g, '');
keys = keys.split(',');
_.each(keys, (key, index) => {
entry[key] = query.bindings[index];
dbEntry[key] = entry[key];
});
query.response(entry);
}
} else {
query.reject(new Error('not implemented.'));
}
});
}
return this.tracker;
}
unmock() {
this.tracker.uninstall();
mockKnex.unmock(knex);
}
}
module.exports = KnexMock;