I want to be able to properly test my ES6 class, it's constructor requires another class and all this looks like this:
Class A
class A {
constructor(b) {
this.b = b;
}
doSomething(id) {
return new Promise( (resolve, reject) => {
this.b.doOther()
.then( () => {
// various things that will resolve or reject
});
});
}
}
module.exports = A;
Class B
class B {
constructor() {}
doOther() {
return new Promise( (resolve, reject) => {
// various things that will resolve or reject
});
}
module.exports = new B();
index
const A = require('A');
const b = require('b');
const a = new A(b);
a.doSomething(123)
.then(() => {
// things
});
Since I'm trying to do dependency injection rather than having requires at the top of the classes, I'm not sure how to go about mocking class B and it's functions for testing class A.
Sinon allows you to easily stub individual instance methods of objects. Of course, since b is a singleton, you'll need to roll this back after every test, along with any other changes you might make to b. If you don't, call counts and other state will leak from one test into another. If this kind of global state is handled poorly, your suite can become a hellish tangle of tests depending on other tests.
Reorder some tests? Something fails that didn't before.
Add, change or delete a test? A bunch of other tests now fail.
Try to run a single test or subset of tests? They might fail now. Or worse, they pass in isolation when you write or edit them, but fail when the whole suite runs.
Trust me, it sucks.
So, following this advice, your tests can look something like the following:
const sinon = require('sinon');
const { expect } = require('chai');
const A = require('./a');
const b = require('./b');
describe('A', function() {
describe('#doSomething', function() {
beforeEach(function() {
sinon.stub(b, 'doSomething').resolves();
});
afterEach(function() {
b.doSomething.restore();
});
it('does something', function() {
let a = new A(b);
return a.doSomething()
.then(() => {
sinon.assert.calledOnce(b.doSomething);
// Whatever other assertions you might want...
});
});
});
});
However, this isn't quite what I would recommend.
I usually try to avoid dogmatic advice, but this would be one of the few exceptions. If you're doing unit testing, TDD, or BDD, you should generally avoid singletons. They do not mix well with these practices because they make cleanup after tests much more difficult. It's pretty trivial in the example above, but as the B class has more and more functionality added to it, the cleanup becomes more and more burdensome and prone to mistakes.
So what do you do instead? Have your B module export the B class. If you want to keep your DI pattern and avoid requiring the B module in the A module, you'll just need to create a new B instance every time you make an A instance.
Following this advice, your tests could look something like this:
const sinon = require('sinon');
const { expect } = require('chai');
const A = require('./a');
const B = require('./b');
describe('A', function() {
describe('#doSomething', function() {
it('does something', function() {
let b = new B();
let a = new A(b);
sinon.stub(b, 'doSomething').resolves();
return a.doSomething()
.then(() => {
sinon.assert.calledOnce(b.doSomething);
// Whatever other assertions you might want...
});
});
});
});
You'll note that, because the B instance is recreated every time, there's no longer any need to restore the stubbed doSomething method.
Sinon also has a neat utility function called createStubInstance which allows you to avoid invoking the B constructor completely during your tests. It basically just creates an empty object with stubs in place for any prototype methods:
const sinon = require('sinon');
const { expect } = require('chai');
const A = require('./a');
const B = require('./b');
describe('A', function() {
describe('#doSomething', function() {
it('does something', function() {
let b = sinon.createStubInstance(B);
let a = new A(b);
b.doSomething.resolves();
return a.doSomething()
.then(() => {
sinon.assert.calledOnce(b.doSomething);
// Whatever other assertions you might want...
});
});
});
});
Finally, one last bit of advice that's not directly related to the question-- the Promise constructor should never be used to wrap promises. Doing so is redundant and confusing, and defeats the purpose of promises which is to make async code easier to write.
The Promise.prototype.then method comes with helpful behavior built-in so you should never have to perform this redundant wrapping. Invoking then always returns a promise (which I will hereafter call the 'chained promise') whose state will depend on the handlers:
A then handler which returns a non-promise value will cause the chained promise to resolve with that value.
A then handler which throws will cause the chained promise to reject with the thrown value.
A then handler which returns a promise will cause the chained promise to match the state of that returned promise. So if it resolves or rejects with a value, the chained promise will resolve or reject with the same value.
So your A class can be greatly simplified like so:
class A {
constructor(b) {
this.b = b;
}
doSomething(id) {
return this.b.doOther()
.then(() =>{
// various things that will return or throw
});
}
}
module.exports = A;
I think you're searching for the proxyquire library.
To demonstrate this, I edited a little bit your files to directly include b in a (I did this because of your singleton new B), but you can keep your code, it's just more easy to understand proxyquire with this.
b.js
class B {
constructor() {}
doOther(number) {
return new Promise(resolve => resolve(`B${number}`));
}
}
module.exports = new B();
a.js
const b = require('./b');
class A {
testThis(number) {
return b.doOther(number)
.then(result => `res for ${number} is ${result}`);
}
}
module.exports = A;
I want now to test a.js by mocking the behavior of b. Here you can do this:
const proxyquire = require('proxyquire');
const expect = require('chai').expect;
describe('Test A', () => {
it('should resolve with B', async() => { // Use `chai-as-promised` for Promise like tests
const bMock = {
doOther: (num) => {
expect(num).to.equal(123);
return Promise.resolve('__PROXYQUIRE_HEY__')
}
};
const A = proxyquire('./a', { './b': bMock });
const instance = new A();
const output = await instance.testThis(123);
expect(output).to.equal('res for 123 is __PROXYQUIRE_HEY__');
});
});
Using proxyquire you can easily mock a dependency's dependency and do expectations on the mocked lib. sinon is used to directly spy / stub an object, you have to use generally both of them.
Seems pretty straightforward, since sinon mocks an object by replacing one of its methods with a behavior (as described here):
(I added resolve()-s to both of the promises in your functions to be able to test)
const sinon = require('sinon');
const A = require('./A');
const b = require('./b');
describe('Test A using B', () => {
it('should verify B.doOther', async () => {
const mockB = sinon.mock(b);
mockB.expects("doOther").once().returns(Promise.resolve());
const a = new A(b);
return a.doSomething(123)
.then(() => {
// things
mockB.verify();
});
});
});
Please let me know if I misunderstood something or additional detail what you'd like to test...
Related
I have the following scenario:
file1.js:
async function fctionA(event) {
console.log('In fctionA()!');
let responseA = null;
const formattedEvent = formatEvent(event);
...
const b = await fctionB(formattedEvent);
responseA = someLogicUsing(b);
return responseA; // responseA will depend on 'b'
}
file2.js:
async function fctionB(formattedEvent) {
console.log('Now in fctionB()!');
let resB = null;
...
const c = await fctionC(formattedEvent);
...
resB = someLogicDependingOn(c); // resB will depend on 'c'
return resB;
}
async function fctionC(formattedEvent) {
console.log('AND now in fctionC()!');
let c = await someHttpRequest(formattedEvent);
...
return c;
}
Side notes:
Don't mind formatEvent(), someLogicUsing() orsomeLogicDependingOn() too much. Assume it's just sync logic using provided data)
formattedEvent would be anything depending on the original input event. Just to note functions will use it.
PROBLEM:
What i want to do is to unit test fctionA(), using Jasmine: I want to check the responseA after appying the logic on fctionB(), but mock the result of fctionC().
My (clearly) naive approach was:
file1.spec.js
import * as Handler from '../src/file1';
import * as utils from '..src//file2';
describe('fctionA', () => {
let response = null;
beforeAll(async () => {
const mockedEventA = { mockedInput: 'a' };
const mockedC = { mockedData: 1 };
const expectedResponse = { mockedResponse: 1234 };
spyOn(utils, 'fctionB').and.callThrough());
spyOn(utils, 'fctionC').and.returnValue(Promise.resolve(mockedC));
response = await Handler.fctionA(mockedEventA);
});
it('should return a proper response', () = {
expect(response).toEqual(expectedResponse);
});
});
But after checking logs, i can see that ´fctionC()´ does get executed (when as far as i understood, it shouldn't), therefore does not return the mocked result.
Then, after some try and error, i invoked fctionC() directly in fctionA() (instead of indirectly invoking it through´fctionB()´) just to see what happens, and I can spy it and return a mocked value. fctionC() does not execute (can't see log).
So, that makes me think that, at least the way I'm trying to spy on functions, only work for functions that are directly invoked by the function I'm calling, but not for nested ones-
I'm clearly not an expert in Jasmine, so I can't figure out another option. I looked a lot into docs and posts and blogs but nothing worked for me.
Is there a way to achieve what I try here? I guess I might be doing something really silly or not thinking it through.
Thanks!
I have a function, MyComposedFunction, which is the function composition of 3 functions the second function, fn2, performs a POST request (a side effect) using the result of fn1 and passes this value to fn3.
const fn2 = async (fn1Result) => {
const result = await fetch(fn1Result.url, fn1Result.payload);
// some business logic
return fn2Results;
};
const MyComposedFunction = compose(fn3, fn2, fn1);
// My Test
expect(MyComposedFunction('hello world')).toBe('expected result');
I'd like to avoid writing unit tests for fn3, fn2, and fn1 and instead only test MyComposedFunction. My rationale is that it should not matter whether MyComposedFunction uses compose(...) or is one long giant function as long as MyComposedFunction works.
Is it possible to write a test for MyComposedFunction without having to mock fn2?
I would think that this must be a relatively common situation when trying to do functional programming in JavaScript but haven't been able to find a helpful resource so far.
You can dependency inject fetch into your function like so
const fn2Thunk = (fetcher = fetch) => async (fn1Result) => {
const result = await fetcher(fn1Result.url, fn1Result.payload);
// some business logic
return fn2Results;
};
const fetchMock = async () => ({ result: "blah" })
const MyComposedFunctionTest = compose(fn3, fn2Thunk(fetchMock), fn1);
// My Test
const result = await MyComposedFunctionTest('hello world')
expect(result).toBe('expected result');
I have a situation where I need to create a test that calls a function and checks its return value. It returns an object so I have to iterate through it and check 100 or so values for correctness. If one of them fails I want to know which one.
I cannot work out how to do this with vanilla Jest such that the test is self-contained and I get a meaningful error message on a failure.
For example, I can do this: (pseudocode to illustrate, not actual code)
describe('Test for function A', () => {
beforeAll('Create class instance', () => {
this.inst = new MyClass();
});
test('Call function with no parameters', () => {
const value = this.inst.run();
for (each key=value) {
expect(value).toBe(correct); // on failure, doesn't tell me the key, only the value
}
});
});
The problem with this is that if value is not correct then the error message is not very helpful, as it doesn't tell me which of the 100 values has the problem.
I can't change to test.each() because then I get an error saying I have nested test() calls which is not allowed.
If I use an inner test() and change the parent test() to describe() then the code becomes this:
describe('Test for function A', () => {
beforeAll('Create class instance', () => {
this.inst = new MyClass();
});
describe('Call function with no parameters', () => {
const value = this.inst.run();
for (each value) {
test(`Checking ${value.name}`, () => {
expect(value).toBe(correct);
});
}
});
});
This would give me a detailed error message except this.inst.run() is called during test set up, before this.inst has been set by beforeAll(), so it fails. (Jest runs all the describe() blocks first, then beforeAll(), then test(). This means I call this.inst.run() first in a describe() block before the beforeAll() block creates the class instance.)
Is there any way that this is possible to achieve? To have a test that requires an object created and shared amongst all the child tests, a test group that calls a function to get data for that group, then a bunch of tests within the group?
Yes, it is possible according to the order of execution of describe and test blocks:
describe("Test for function A", () => {
this.inst = new MyClass();
afterAll("Create class instance", () => { //--> use this instead of beforeAll
this.inst = new MyClass();
});
test("Should be defined", () => {
//--> at least one test inside describe
expect(inst).toBeTruthy();
});
describe("Call function with no parameters", () => {
const value = this.inst.run();
test("Should be defined", () => {
//--> at least one test inside describe
expect(value).toBeTruthy();
});
for (/*...each value */) {
test(`Checking ${value.name}`, () => {
expect(value).toBe(correct);
});
}
});
});
I came up with a workaround for this. It's a bit hacky but it seems to work. Essentially you use promises to wrap the value you're interested in, so one test will sit there await-ing the result from another test.
Obviously this will only work if the tests are run in parallel, or if the sequential ordering is such that the promise is resolved before it is awaited.
The only trick below is that the await is placed in a beforeAll() block, so that the value is available to all tests within that describe() section. This avoids the need to await in each individual test.
The benefit of this is that the test set up (creating the object) is within a test() so exceptions are captured, and the checks themselves (expect().toBe()) are in separate tests so that the test name can be set to something descriptive. Otherwise if your expect() calls are in a for loop, when one fails there's no way to figure out which array entry was at fault.
It's a lot of work just because you can't supply a description on the expect() call (unlike other testing frameworks), but if you're stuck with Jest then this does at least work. Hopefully one day they will add a per-expect description to avoid all this.
Here is some sample pseudocode:
describe('Test for function A', () => {
let resolveValue;
let promiseValue = new Promise(resolve => resolveValue = resolve);
describe('Create class instance', () => {
test('Run processing', () => {
this.inst = new MyClass();
// inst.run() is now called inside a test(), so any failures will be caught.
const value = this.inst.run();
resolveValue(value); // release 'await promiseValue' below
});
});
describe('Call function with no parameters', () => {
let value; // this is global within this describe() so all tests can see it.
beforeAll(async () => {
// Wait for the above test to run and populate 'value'.
value = await promiseValue;
});
for (each value) {
// Check each value inside test() to get a meaningful test name/error message.
test(`Checking ${value.name}`, () => {
// 'value' is always valid as test() only runs after beforeAll().
expect(value).toBe(correct);
});
}
});
});
This question already has an answer here:
Asynchronous operations in constructor
(1 answer)
Closed 4 years ago.
I am working on a project in Node - a language with which I have little familiarity.
In the project, I have a class that will be responsible for reading and writing data to a database - in this case, LevelDB. Ideally, I'd like to set-up the database connection in the constructor synchronously so that methods (writeItem, readItem, etc.) don't fail if they're called too fast. Or in other words, I don't want the constructor to return and allow the next line of code to run until all the promises are fulfilled.
I think I am either missing something fundamental to the language or there is some design pattern in node that I'm not aware of. A toy example that fails in the same way is here:
class AClass {
constructor(n) {
this.name = n;
console.log('calling init.');
this.init();
console.log('init returned.');
}
func() {
return new Promise(resolve => {
setTimeout(() => {
resolve(true);
}, 2000);
});
}
async init() {
console.log('calling func()');
let x = await this.func();
console.log('after func(): ');
}
}
let x = new AClass('test');
console.log(JSON.stringify(x));
This produces the output:
calling init.
calling func()
init returned.
{"name":"test"}
after func():
This is surprising to me. I would have expected:
calling init.
calling func()
after func():
init returned.
{"name":"test"}
The final objective is to instantiate a class that connects to a levelDB instance and does not return the object until that connection is made. So the code might look something like this:
let storage = new StorageObject();
storage.addItem(key, value); // <-- this fails unless StorageObject
// finishes the db setup.
Thanks!
Sam
Your objective of not returning the instance until after the connection won't work (at least not like this). The constructor's job is to create an instance and return that. Functions need to return something synchronously. If it's performing some async operation then a function can return a promise instead, but you don't want a promise from the constructor — you need the instance.
The easy way to do this is to require your object to be initialized after it's created, then the constructor can construct and return the instance and the init function is free to return a promise:
class AClass {
constructor(n) {/* some setup */}
func() {
return new Promise(resolve => {
setTimeout(() => {
resolve("some name");
}, 1000);
});
}
async init() {
this.name = await this.func();
return this
}
}
new AClass('test').init()
.then((initialized_obj) => console.log(initialized_obj))
If you're doing this in node, you could also use eventEmitters to emit an event when the instance has been initialized. Something like:
const EventEmitter = require('events');
class AClass extends EventEmitter{
constructor(n) {
super()
this.init()
.then(() => this.emit("initialized"))
}
func() {
return new Promise(resolve => {
setTimeout(() => {
resolve("some name");
}, 1000);
});
}
async init() {
this.name = await this.func();
return this
}
}
let x = new AClass('test')
x.on('initialized', () => console.log(x.name))
Two things about your code:
When you call an async function (this.init()), it will be executed uptill its returned await statement and will return a promise and the control will go to next line (console.log('init returned.')). Understanding this will resolve your confusion.
Code after await statement (console.log('after func(): ');) will execute only after awaited promise has been resolved.
I have repurposed your code to do what you want.
async function AClass(n) {
let obj = {}
obj.func = () => {
return new Promise(resolve => {
setTimeout(() => {
resolve(true);
}, 2000);
});
};
obj.init = async function () {
console.log('calling func()');
let x = await obj.func();
console.log('after func(): ');
};
obj.name = n;
console.log('calling init.');
await obj.init();
console.log('init returned.');
return obj;
}
let x = AClass('test');
x.then((resolveValue) => {
/*
*Now the "class" has been instantiated,
* code to use the object of the "class" goes here
* */
console.log(JSON.stringify(resolveValue));
});
If you really want the constructor to return a working AClass synchronously, you can do it by rewriting other parts of code a little. I'm assuming that the methods writeItem, readItem, etc are asynchronous. All you have to do is rewrite these methods so that they wait for the object to be initialised (if necessary) before proceeding.
For example, suppose your class looks like this:
class AClass {
constructor(n) {
this.name = n;
this.init();
}
async init() {
...
}
async writeItem(item) {
return await db.writeItem(item);
}
async readItem(itemId) {
return await db.readItem(itemId);
}
}
You should then be able to rewrite it as follows:
class AClass {
constructor(n) {
this.name = n;
this.awaitInit = this.init();
}
async init() {
...
}
async writeItem(item) {
await this.awaitInit;
return await db.writeItem(item);
}
async readItem(itemId) {
await this.awaitInit;
return await db.readItem(itemId);
}
}
When designing OOP ES 5-6, where I combine prototypes with ES 6 functions. Everything is running in ElectronJS, I do not want a new version that fully supports ES 7 too, so for example the definition of import {trida} from "./cesta" must be solved require ('./ path'). My problem, but it's in Promise.
If I want to program object, I want every object to do what it has and pass the result to the main branch of the program, which contains the column of the whole procedure - object list - Content. If fun enter setTimeout (), you need to use the Promise here, which waits until the function is executed and continues to call another object.
let importing = function(){
this.name = "boot";
}
importing.prototype.start = function(resolve){
this.resolve = resolve;
setTimeout(this.test.bind(this),1000);
console.log('start -------->');
}
importing.prototype.test = function(){
this.resolve('Test');
console.log('Test -------->');
}
importing.prototype.end = function(resolve){
console.log('end -------->');
this.resolve = resolve;
this.resolve('end');
}
let geko;
let scan = new importing();
Promise.resolve(geko)
.then((geko) => new Promise(scan.start.bind(scan)))
.then((geko) => new Promise(scan.end.bind(scan)))
.catch(geko => {
console.log('Error message: ',geko)
})
Here is the problem, I do not want the features to nest in the prototype functions, I want to call every object, nicely in order, clearly. Like any book, it has its Chapter Content, and then the chapters itself and I want to have a quick entry into what I have programmed and did not look at how much a mouse was taken after a week. But for this operation, besides Promise, I also have to use the bind () function because:
importing.prototype.start = function(){
// here this acts as a window object not as importing
// why I have this object called scan.start.bind (scan)
// and here again in setTimeout i have to bind (this) to get it in this.test
// could access this importing - scan object
setTimeout(this.test.bind(this),300);
}
You would find a better way??
You should not pass methods as the argument to the new Promise constructor. If the method is asynchronous, it should return a promise by itself; if it's not asynchronous then you shouldn't be using any promises.
function importing(){
this.name = "boot";
}
importing.prototype.start = function() {
console.log('start -------->');
return new Promise(resolve => {
setTimeout(resolve, 1000); // put the native async call in here, and nothing else!
}).then(() =>
this.test()
);
};
importing.prototype.test = function() {
console.log('Test -------->');
return 'Test';
};
importing.prototype.end = function() {
console.log('end -------->');
return 'end';
}
const scan = new importing();
scan.start().then(() => scan.end()).catch(geko => {
console.log('Error message: ',geko)
});
If the whole project was created as follows:
return new Promise(resolve => {
setTimeout(resolve, 1000);
}).then(() =>
this.test()
);
I would not have much to do with the classic JS procedure, ie the nesting of functions in the functions. That's what I want to avoid. I want content, an outline, when I look at it for a year and I'm going to solve the bugs, I'll know where to start and where the mistakes are going.
let importing = function(){
this.name = "boot";
}
importing.prototype.start = function(resolve){
console.log('Start');
this.resolve = resolve;
setTimeout(this.test.bind(this),1000);
}
importing.prototype.test = function(){
console.log('Test');
this.resolve('Test');
}
importing.prototype.end = function(resolve){
console.log('End');
resolve('end');
}
let scan = new importing();
let promise = function(arg){
return new Promise((resolve, reject)=>{ // The same: new Promise(scan[arg].bind(scan))
return scan[arg].bind(scan)(resolve)
});
}
// so I would imagine chaining. Few braces, simply
// In each called object, if possible, the minimum promissory note
Promise.resolve()
.then(geko => promise('start'))
.then(geko => promise('end'))
.catch(geko => {
console.log('Error message: ',geko)
})