How to test javascript class using jest? - javascript

trying to test class using jest its throwing declaration exception , what would be correct approach to test class in below scenario and test promise chain?
main.ts
export class ModuleExecutor {
public execute(moduleName: string): (param1, param2) => any {
const self = this;
return function(params: any, responseCallback: (param: any, param2: any) => any) {
let _mod;
let _httpRequest;
let _params;
Promise.resolve(getApiModule(self.identity, moduleName))
.then((mod: ModuleBase < any, any > ) => {
_mod = mod;
mod.ExecStage = ExecStage.Init;
// #ts-ignore - red squiggly for the return mismatch which are resolved in Grunt
return mod.init(getHttpModule(self.identity), params);
});
}
}
}
main.spec.ts
describe("Test promise chaining with Mock functions", () => {
const myMockFuncExecute = jest.fn((mod: ModuleBase<any, any>) => {
_mod = mod;
_mod.ExecStage = ExecStage.Init;
const ret = _mod.Init(getHttpModule(Identity.node), params);
Promise.resolve(ret);
});
jest.mock("./main.ts");
const executerClass = require("./main.ts");
executerClass.mockImplementation(() => {
return {
init: myMockFuncExecute
};
});
it('it should get Modulebase', async () => {
const _result = new executerClass(Identity.node);
_result.execute("Payments/url").then(myMockFuncExecute())
.then((module) => {
const mod = module;
expect(mod).toEqual(ModuleBase);
});
});
});

Related

mocking private methods to test an exported method fails in jest

I'm having an actual class like this
my-file.js
const methodA = () => { return 'output-from-methodA'; }
const methodB = () => { const b = methodA(); b.c = "out-put bind"; return b; }
module.exports = {
methodB
}
my-file.test.js
const { methodA, methodB } = require('./my-file.js');
describe('methodB testing', () => {
it('should call methodA', () => {
methodB();
expect(methodA).toHaveBeenCalled()
}
});
here methodA is private method, so it is not explicit to the test file, then how i ensure it is called or not in the test files
There is no way to test the private function, only the alternative way found is to test the outputs like
const { methodA, methodB } = require('./my-file.js');
describe('methodB testing', () => {
it('should call methodA', () => {
const result = methodB();
expect(result.b.c).toBe("out-put bind")
}
});

How to test class with chain promises using jest?

I have use case where i have to test promise chaining so in below code i tried to mock all the function that are being called in actual code and using jest.fn() but getting some error TypeError: Cannot read property 'then' of undefined
any what is implemented wrong in below code or any better approach to write async promises chaining ?
main.ts
export class ModuleExecutor {
public execute(moduleName: string): (param1, param2) => any {
const self = this;
return function (params: any, responseCallback: (param: any, param2: any) => any) {
let _mod;
let _httpRequest;
let _params;
Promise.resolve(getApiModule(self.identity, moduleName))
.then((mod: ModuleBase<any, any>) => {
_mod = mod;
mod.ExecStage = ExecStage.Init;
// #ts-ignore - red squiggly for the return mismatch which are resolved in Grunt
return mod.init(getHttpModule(self.identity), params);
})
.then((httpRequest: HttpRequestBase) => {
_httpRequest = httpRequest;
if (_mod.Response().Summary.Header) {
throw _mod.Response().Summary;
}
return httpRequest;
})
.then((params1: any) => {
_params = params2;
_mod.ExecStage = ExecStage.Core;
return _mod.core(_params, _httpRequest);
})
.catch((e) => {
return e;
});
};
}
}
main.spec.ts
import {ModuleExecuter} . from './main.ts';
const _executer = new ModuleExecutor(Identity.node);
const myMockFunc = jest.fn(() => {
// _executer.execute("Payments/accountBalance/GetAccount001");
executer = new ModuleExecutor(Identity.node);
executerSpy = executer.execute("Payments/accountBalance/GetAccount001");
const _promise1 = new Promise(function(resolve) {
// moduleExecutor.execute(params, callback function)
executerSpy(params, function(data) {
resolve(data);
}).catch((e) => {
expect(e).toBeTruthy();
});
});
Promise.resolve(_promise1);
});
const myMockFuncExecute = jest.fn(() => {
Promise.resolve(getApiModule(Identity.node, "Payments/accountBalance/GetAccount"));
});
const myMockModuleBase = jest.fn((mod: ModuleBase<any, any>) => {
// _executer.execute("Payments/accountBalance/GetAccount001");
mod.ExecStage = ExecStage.Init;
// #ts-ignore - red squiggly for the return mismatch which are resolved in Grunt
Promise.resolve(mod.init(getHttpModule(Identity.node), params));
});
const myMockHttpRequest = jest.fn((httpRequest: HttpRequestBase) => {
Promise.resolve(httpRequest);
});
it('should your test scenario', (done) => {
myMockFunc()
.then((data) => {
expect(myMockFuncExecute).toBeCalledWith("Payments/accountBalance/GetAccount001");
expect(myMockModuleBase).toBeCalledWith(ModuleBase);
expect(myMockHttpRequest).toBeCalledWith(HttpRequestBase);
expect(data).toEqual({test: "test"});
done();
});
});

Mocking complex module using Jest.js

This is what the module I want to mock looks like:
class TheModule {
constructor() {
this.subClass = new SubClass();
}
}
class SubClass {
constructor() {
this.someMethod = () => 'Did Something great';
}
}
module.exports = TheModule;
This is TheModule usage I want to test:
const TheModule = require('./TheModule');
const method = () => {
const theModule = new TheModule();
return theModule.subClass.someMethod();
}
module.exports = method;
This is my test:
describe('method test', () => {
it('should return "Test pass"', () => {
jest.doMock('./TheModule');
const theModuleMock = require('./TheModule');
const method = require('./TheModuleUsage');
const mock = () => 'Test pass';
theModuleMock.subClass.someMethod.mockImplementation(() => mock);
expect(method()).toEqual('Test pass');
});
});
When I run this test I get TypeError: Cannot read property 'someMethod' of undefined
Is it possible to mock this module without changing TheModule implementation?
If you will export SubClass you can mock it without changing TheModule but in your case you should mock SubClass property in TheModule explicitly with factory for example:
describe('method test', () => {
it('should return "Test pass"', () => {
let mockedSomeMethod = jest.fn().mockImplementation(() => 'Test pass');
jest.doMock('./TheModule', () => {
// mock constructor
return jest.fn().mockImplementation(() => {
return { subClass: { someMethod: mockedSomeMethod } }
});
});
const method = require('./TheModuleUsage');
expect(method()).toEqual('Test pass');
});
});

Mocking chained methods

(I use Jest for testing)
For example, I have this function:
const find = () => {
return {
where: () => {
in: () => {}
}
};
};
and I call that in different place:
find('me').where('id').in(['123']);
How to mock and test calls in find(), where() and in()?
Here's a dirt simple mock interface:
const find = (findData) => {
const data = {
find: findData
};
const self = {
where: (whereData) => {
data.where = whereData;
return self;
},
in: (inData) => {
data.in = inData;
return self;
},
data
};
return self;
};
const res = find('me').where('id').in(['123']);
console.log(res.data);

How can I write a unit test with streams, promises and pipes together?

My function is
exports.downloadFromBucket = function(fileKey) {
const localPath = `${process.cwd()}/data/${fileKey}`
return new Promise((resolve, reject) => {
const localFile = fs.createWriteStream(localPath)
const awsStream = s3.getObject({
Bucket: process.env.UPLOAD_BUCKET,
Key: fileKey
})
.createReadStream()
.on('error', (err) => {
logger.info('Error downloading file', err)
return reject(err)
})
.on('finish', () => {
logger.info('Completed downloading')
return resolve(localPath)
})
.pipe(localFile)
})
}
How would I go about writing a unit test for this using mocha and sinon?
This may not be the prettiest solution but assuming you want to mock s3 and fs and test the on('error') and on('finish') behavior:
You could use a custom s3 mocking class, stub the original s3 and fs with sinon and trigger the events you want to test.
// Custom S3 Mocking Library
class S3MockLibrary {
constructor() {
this.events = {};
}
getObject(options) {
return this;
}
createReadStream() {
return this;
}
on(event, func) {
this.events[event] = func;
return this;
}
pipe(file) {
return this;
}
emit(event, err) {
this.events[event](err);
}
}
Test on('finish')
it('should verify', async () => {
const s3Mock = new S3MockLibrary();
const fsStub = sinon.stub(fs, 'createWriteStream').returns('success');
const s3Stub = sinon.stub(s3, 'getObject').returns(s3Mock);
// Emit the finish event async
setTimeout(() => {
s3Mock.emit('finish');
}, 0);
const result = await downloadFromBucket('test');
fsStub.restore();
s3Stub.restore();
sinon.assert.calledOnce(fsStub);
sinon.assert.calledOnce(s3Stub);
assert.equal(result, `${process.cwd()}/data/test`);
});
Test on('error)
it('should fail', async () => {
const s3Mock = new S3MockLibrary();
const fsStub = sinon.stub(fs, 'createWriteStream').returns('success');
const s3Stub = sinon.stub(s3, 'getObject').returns(s3Mock);
setTimeout(() => {
s3Mock.emit('error', 'testError');
}, 0);
let error;
await downloadFromBucket('test').catch((err) => {
error = err;
});
fsStub.restore();
s3Stub.restore();
sinon.assert.calledOnce(fsStub);
sinon.assert.calledOnce(s3Stub);
assert.equal(error, 'testError');
});

Categories