Reputation: 181
This is my code using mysql -
import * as mysql from 'mysql';
import {promisify} from 'util';
const connectionParams:any = {
/* set as environment variables */
host: host,
user: user,
password: password,
port: parseInt(port)
};
var connection:any;
const getRecords = async (inputValue: string) => {
//validate inputValue
const userIds: string[] = [];
logger.info("Creating mysql connection");
try {
connection = mysql.createConnection(connectionParams);
const query = promisify(connection.query).bind(connection);
const queryResult = await query({ sql: sqlQuery, timeout: 1000, values: value1, inputValue] });
if (queryResult) {
queryResult.forEach((row) => {
userIds.push(row.userid);
});
}
} catch (error) {
logger.info(error);
// console.log(error);
throw new Error('Could not retrieve user IDs');
} finally {
connection.end();
}
return userIds;
};
And this is my test -
it('should return a list of records when right inputs are given', async() => {
sinon.stub(process, 'env').value({
'database': 'TESTDB'
});
let dummyArray = [{ userid: 'xyz' }];
let createConnection = {
connect: function(connectionParams: any) {
return Promise.resolve()
},
query : sinon.stub().withArgs({}).callsFake(function (...args): Promise<Object>{
const dummyArray = [{ userid: 'xyz' }];
return new Promise(function(resolve){resolve(dummyArray)});
}),
end: function() {}
};
let mySqlStub = {
createConnection: sinon.stub().returns(createConnection)
};
const dbops = proxyquire('../../lib/dbops', {'mysql': mySqlStub}).default;
expect(await dbops.getUserIds('Delete')).to.deep.equal(['xyz']);
});
How do I write the fake function for the query?
query : sinon.stub().withArgs({}).callsFake(function (...args): Promise{ const dummyArray = [{ userid: 'xyz' }]; return new Promise(function(resolve){resolve(dummyArray)}); })
This does not work for me. How can I get this to work? I cannot get the stub function to resolve and return the intended value in the main function. The query just hangs and throws an error after the timeout. The error is happening in "matchingfakes" method within the stub.
Upvotes: 1
Views: 887
Reputation: 102277
proxyquire
is used for stubbing the standalone function exports from a module or package. Since mysql
is an object, you can stub its methods by sinon.stub(obj, 'method')
. You don't need to use use proxyquire
package.
Even if you use util.promisify
to generate promise versions for the NodeJS error-First callback method(mysql.query(sql, callback)
, the callback signature is function (error, results, ...args): void
). You need to use .callsFake()
to create a mock implementation for this method, and trigger the promise version by calling its callback.
And, you should import
the function after stubbing the environment variables. Because when you import the ./dbops
module, the code in the module scope will be executed immediately, at this time, the environment variables are not stubbed.
E.g.
dbops.ts
:
import mysql from 'mysql';
import { promisify } from 'util';
const connectionParams: any = {
host: process.env.HOST,
user: process.env.USER,
password: process.env.PASSWORD,
port: parseInt(process.env.PORT || '3306'),
};
var connection: any;
const getRecords = async (inputValue: string) => {
const sqlQuery = 'SELECT * FROM tests';
const value1 = '';
const userIds: string[] = [];
console.info('Creating mysql connection');
try {
connection = mysql.createConnection(connectionParams);
const query = promisify(connection.query).bind(connection);
const queryResult = await query({ sql: sqlQuery, timeout: 1000, values: value1, inputValue });
if (queryResult) {
queryResult.forEach((row) => {
userIds.push(row.userid);
});
}
} catch (error) {
console.info(error);
throw new Error('Could not retrieve user IDs');
} finally {
connection.end();
}
return userIds;
};
export { getRecords };
dbops.test.ts
:
import sinon from 'sinon';
import mysql from 'mysql';
describe('69702002', () => {
it('should return a list of records when right inputs are given', async () => {
sinon.stub(process, 'env').value({
HOST: '127.0.0.1',
USER: 'testuser',
PASSWORD: 'testpwd',
PORT: '3306',
});
const { getRecords } = await import('./dbops');
const dummyArray = [{ userid: 'xyz' }];
let connectionStub = {
query: sinon.stub().callsFake((sql, callback) => {
callback(null, dummyArray);
}),
end: sinon.stub(),
};
sinon.stub(mysql, 'createConnection').returns(connectionStub);
const actual = await getRecords('test input');
sinon.assert.match(actual, ['xyz']);
sinon.assert.calledWithExactly(mysql.createConnection, {
host: '127.0.0.1',
user: 'testuser',
password: 'testpwd',
port: 3306,
});
sinon.assert.calledOnce(connectionStub.end);
});
});
test result:
69702002
Creating mysql connection
✓ should return a list of records when right inputs are given (945ms)
1 passing (952ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 90.48 | 50 | 100 | 90 |
dbops.ts | 90.48 | 50 | 100 | 90 | 27-28
----------|---------|----------|---------|---------|-------------------
Upvotes: 1