Skip to content

Commit

Permalink
Added knex mock for unit testing
Browse files Browse the repository at this point in the history
no issue

- added https://github.com/colonyamerican/mock-knex as dev dependency
- the mock serves our data generator test data by default
  - but you can define your own if you want
- we need a proper mock for unit testing
- we should not mock bookshelf if possible, otherwise we can't test event flows
  • Loading branch information
kirrg001 committed Feb 15, 2018
1 parent 2b76d7a commit 0b5cfd9
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 0 deletions.
1 change: 1 addition & 0 deletions core/test/utils/mocks/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
exports.utils = require('./utils');
exports.express = require('./express');
exports.knex = require('./knex');
131 changes: 131 additions & 0 deletions core/test/utils/mocks/knex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
'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) => {
if (query.method === 'select') {
if (query.bindings.length && query.sql.match(/where/)) {
query.sql = query.sql.replace(/`/g, '"');

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 if (query.method === 'insert') {
query.sql = query.sql.replace(/`/g, '"');

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') {
query.sql = query.sql.replace(/`/g, '"');

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;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
"matchdep": "2.0.0",
"minimist": "1.2.0",
"mocha": "4.1.0",
"mock-knex": "0.4.0",
"nock": "9.1.6",
"rewire": "3.0.2",
"should": "13.2.1",
Expand Down
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3690,6 +3690,10 @@ lodash@^3.10.1, lodash@~3.10.1:
version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"

lodash@^4.14.2:
version "4.17.5"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"

lodash@~0.9.2:
version "0.9.2"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-0.9.2.tgz#8f3499c5245d346d682e5b0d3b40767e09f1a92c"
Expand Down Expand Up @@ -4041,6 +4045,14 @@ mocha@^3.1.2:
mkdirp "0.5.1"
supports-color "3.1.2"

mock-knex@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/mock-knex/-/mock-knex-0.4.0.tgz#32c4ed97ff7cf9c86eca2400902f34e1f7f88de1"
dependencies:
bluebird "^3.4.1"
lodash "^4.14.2"
semver "^5.3.0"

moment-timezone@0.5.14:
version "0.5.14"
resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.14.tgz#4eb38ff9538b80108ba467a458f3ed4268ccfcb1"
Expand Down

0 comments on commit 0b5cfd9

Please sign in to comment.