Model.knex(knex);
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(i18nextMiddleware);
I want to test method getUsers of users controller. It get data from usersModel getUsers method. I get date from MySQL by Objections ORM.
app.get(
'/',
checkFilter(['type']),
users.getUsers
);
According to instructions, I am changing the query method.
class MyQueryBuilder extends QueryBuilder {
query() {
return this.resolve({ test: 11111 });
}
}
class UsersModel extends Model {
static get QueryBuilder() {
return MyQueryBuilder;
}
}
jest.spyOn(Users, 'query')
.mockImplementation(UsersModel.query);
Describe test.
describe('get errors', () => {
beforeAll(done => {
i18next.on('initialized', () => {
done()
});
});
it('with filter', done => {
request(app)
.get('/')
.query({page: 0, perPage: 5, type: 'admin'})
.end((err, res) => {
if (err) return done(err);
expect(res.status).toBe(200);
expect(
Object.keys(res.body).sort()
).toEqual([
'items',
'itemsOnPage',
'currentPage',
'totalPage',
'totalItems'
].sort());
expect(res.body.items).toHaveLength(8);
expect(res.body.totalItems).toBe(usersMockDB.getUsers.length);
console.log(res.body);
done();
});
});
afterAll(done => {
knex.destroy();
done();
})
});
Method getUsers of users model.
const { Users } = require('../../db/models/Users');
const query = Users
.query()
.select(
'id',
'login',
'type',
'edit',
'email',
'phone',
'block'
)
.orderBy('id', 'DESC')
.page(page, perPage);
// filter
if (Object.keys(usersFilter).length) {
for (let field in usersFilter) {
if ( usersFilter.hasOwnProperty(field) ) {
query.where(field, 'like', `%${ usersFilter[field] }%`);
}
}
}
const { results, total } = await query;
return {
items: results,
itemsOnPage: Number(perPage),
currentPage: Number(page),
totalPage: Math.ceil(total/perPage),
totalItems: Number(total)
}
Should I override methods page and where ? As I understand it, they make new database queries.
This may not be desirable in every case, but I find that the easiest solution for unit tests that use objection models is to create one transaction per test. This does mean you'll need a database to run tests, but everything is rolled back between tests.
In jest.config.js
, add this line
setupFilesAfterEnv: ['./jest.setup.js'],
in jest.setup.js
:
import objection from 'objection';
import knex from './src/db/index.js'; // Change src/db/index.js to the path to the file where you export your knex instance
const {transaction, Model} = objection;
global.beforeAll(async () => {
global.knex = knex;
global.txn = null;
});
global.beforeEach(async () => {
global.txn = await transaction.start(knex);
Model.knex(global.txn);
});
global.afterEach(async () => {
await global.txn.rollback();
Model.knex(knex);
});
global.afterAll(async () => {
global.knex.destroy();
});
You can then use your models as expected in your code and unit tests
import {User} from './src/db/models/index.js';
it('creates and reads users', async () => {
const user = await User.query().insert({email: '[email protected]'});
const users = await User.query();
expect(users).toHaveLength(1);
});
it('does not persist users between tests', async () => {
const users = await User.query();
expect(users).toHaveLength(1);
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With