I have class that is used to create a mysql connection pool and insert records in a database. The inserts work correctly but I'm having trouble getting full coverage through unit tests.
Here is the Connection class:
const mysql2 = require('mysql2');
class Connection {
constructor(options = {}) {
this.options = options;
}
createPool () {
this.pool = mysql2.createPool({
host: this.options.host,
user: this.options.user,
database: 'my_database',
ssl: 'Amazon RDS',
password: this.options.password,
authPlugins: {
mysql_clear_password: () => () => Buffer.from(this.options.password + '\0')
}
});
}
async insert (sql, values) {
const promise = new Promise( (resolve, reject) => {
try {
this.pool.query(sql, [values],function (error, results, fields) {
if (error) throw error;
console.log(results.affectedRows); //Show 1
resolve (results.affectedRows);
});
} catch (e) {
reject(e);
}
})
return promise;
}
}
module.exports = { Connection };
And here is my failing test:
const conns = require('../src/connection');
const sinon = require('sinon');
const mysql2 = require('mysql2');
describe('handler', () => {
test('Test insert from Connection', async () => {
const options = {
host: 'testHost',
user: 'testUser',
password: 'testPassword'
};
const poolStub = {
getConnection: sinon.stub().returnsThis(),
query: sinon.stub().returnsThis(),
};
const createPoolStub = sinon.stub(mysql2, 'createPool').returns(poolStub);
const conn = new conns.Connection(options);
await conn.createPool();
await conn.insert( 'select 1 + 1 as solution', [])
sinon.restore();
});
});
The test just times out.
: Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.
I'm pretty sure that I'm not stubbing query
correctly in the poolStub
, but I'm not sure how to account for the callback method. How can I unit test this insert
method so i can have full coverage?
Here is the unit test solution:
connection.js
:
const mysql2 = require('mysql2');
class Connection {
constructor(options = {}) {
this.options = options;
}
createPool() {
this.pool = mysql2.createPool({
host: this.options.host,
user: this.options.user,
database: 'my_database',
ssl: 'Amazon RDS',
password: this.options.password,
authPlugins: {
mysql_clear_password: () => () => Buffer.from(this.options.password + '\0'),
},
});
}
async insert(sql, values) {
const promise = new Promise((resolve, reject) => {
try {
this.pool.query(sql, [values], function(error, results, fields) {
if (error) throw error;
console.log(results.affectedRows); //Show 1
resolve(results.affectedRows);
});
} catch (e) {
reject(e);
}
});
return promise;
}
}
module.exports = { Connection };
connection.test.js
:
const conns = require('./connection');
const sinon = require('sinon');
const mysql2 = require('mysql2');
const { expect } = require('chai');
describe('handler', () => {
it('Test insert from Connection', async () => {
const options = {
host: 'testHost',
user: 'testUser',
password: 'testPassword',
};
const results = { affectedRows: 1 };
const poolStub = {
getConnection: sinon.stub().returnsThis(),
query: sinon.stub().callsFake((sql, values, callback) => {
callback(null, results);
}),
};
const createPoolStub = sinon.stub(mysql2, 'createPool').returns(poolStub);
const conn = new conns.Connection(options);
conn.createPool();
const actual = await conn.insert('select 1 + 1 as solution', []);
expect(actual).to.be.eql(1);
sinon.assert.calledWithExactly(poolStub.query, 'select 1 + 1 as solution', [[]], sinon.match.func);
sinon.assert.calledWithExactly(createPoolStub, {
host: 'testHost',
user: 'testUser',
password: 'testPassword',
database: 'my_database',
ssl: 'Amazon RDS',
authPlugins: {
mysql_clear_password: sinon.match.func,
},
});
sinon.restore();
});
});
unit test result with coverage report:
handler
1
✓ Test insert from Connection
1 passing (15ms)
---------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
---------------|---------|----------|---------|---------|-------------------
All files | 73.33 | 33.33 | 71.43 | 84.62 |
connection.js | 73.33 | 33.33 | 71.43 | 84.62 | 16,30