Aliases for jest.fn()? - javascript

I have two different libraries that I'm using to make mocks in Jest. The libraries have the same function called get. This is a problem for my current implementation since get is used by two different libraries is it possible to use an alias for mock functions (jest.fn()) or maybe some kind of workaround that doesn't ruin the integrity of the current implementation?
Here is my current implementation and I would I like to keep this way if possible:
let get: jest.Mock<{}>
jest.mock('rxjs/ajax', () => {
get = jest.fn()
return { ajax: { get } }
})
let get as cookieGet: jest.Mock<()> // Can I do something like this
jest.mock('js-cookie', () => {
get = jest.fn()
return { get }
})
I'm not too familiar with aliases in JS or they Jest handles things like this so any help is much appreciated.

It's unnecessary to use { get } shorthand property syntax for object literal if it results in name collisions.
Another problem is that a variable needs to have mock prefix in order to be used in the scope of jest.mock factory function. As the documentation states,
A limitation with the factory parameter is that, since calls to jest.mock() are hoisted to the top of the file, it's not possible to first define a variable and then use it in the factory. An exception is made for variables that start with the word 'mock'. It's up to you to guarantee that they will be initialized on time!
It can be:
import ... from 'rxjs/ajax';
import ... from 'js-cookie';
let mockRxAjaxGet: jest.Mock<{}>
jest.mock('rxjs/ajax', () => {
mockRxAjaxGet = jest.fn()
return { ajax: { get: mockRxAjaxGet } }
})
let mockJsCookieGet: jest.Mock<()>
jest.mock('js-cookie', () => {
mockJsCookieGet = jest.fn()
return { get: mockJsCookieGet }
})
The problem is that once jest.mock is hoisted above imports, it will be evaluated when let variables are in temporal dead zone and cannot be assigned.
So let should be preferably changed to var, which is hoisted. Or mocked function be imported as usual and used with get as jest.Mock<...> where a spy is expected. mocked helper can be used to enforce TypeScript type safety.

Related

When to use require and when to provide dependencies through arguments

I've been wondering what is the preferred way of injecting dependencies in node.js code.
I've been working on a project where there is no dependency injection. This is why i have 2 ways of providing dependencies in my code:
Through constructor/function arguments - this has the disadvantage of exploding the number of arguments in functions as i pass arguments from higher levels of my program to the lower ones,
function createListener(queue) {
return function listen() {
while (true) {
const messages = queue.receiveMessages();
...
}
};
}
Using require() - this is equivalent to hardcoding those dependencies making if harder to mock and test.
const queue = require('./queue');
function createListener() {
return function listen() {
while (true) {
const messages = queue.receiveMessages();
...
}
};
}
I've been trying to hit a sweet spot between those. When providing a dependency which is a complex mechanism i tend to inject it, when dealing with values or less crucial mechanisms i use require.
Is that ok? What would be a better approach?

Sinon Stub JavaScript Method Chain

I'm looking to use sinon stub to test the method chain below:
driver.manage().window().setSize()
I found a related question that explains how to access one method down the chain, however this does not seem to give me access to any additional methods.
t.context.webdriver = sinon.stub(new WebDriver)
sinon.stub(t.context.webdriver, "manage", () => {
return {
window: sinon.stub().returns();
};
})
which returns the error
Error: this._driver.manage(...).window(...).setSize is not a function
How to I stub multi-level method chains?
I'm not sure what your trying to to test, but the error is coming from the fact that the object your stub is returning doesn't have a window() function or a setSize(). Chains work because each part of the chain returns something with a method that matches the next call. So if you stuff something early in the chain, you need to makes sure what you return has those methods. Maybe that involves passing back the original return, or maybe you fake the whole chain.
Here's an example that at least won't throw:
const sinon = require('sinon')
// some fake object that maybe looks like what you have
let driver = {
manage(){ return this},
window() { return this},
setSize() {console.log("size set")}
}
// stubb manage and now you're resposible for the whole chain
sinon.stub(driver, "manage").callsFake(() => {
console.log("called")
return {
window(){
return { setSize: sinon.stub().returns() }
}
};
})
Of course, there are a lot of variations possible depending on what you're trying to test.

node jasmine - how to unit test on function that involve redis call?

I just started playing around Jasmine and I'm still struggling on the spyon/mocking things, e.g., I have a function
module.exports = (() => {
....
function getUserInfo(id) {
return new Promise((resolve, reject) => {
redis.getAsync(id).then(result => {
resolve(result)
})
})
}
return { getUserInfo: getUserInfo }
})()
Then I start writing the Jasmine spec
describe('Test user helper', () => {
let userInfo
beforeEach(done => {
userHelper.getUserInfo('userid123')
.then(info => {
userInfo = info
done()
})
})
it('return user info if user is found', () => {
expect(userInfo).toEqual('info of userid 123')
})
})
It runs well, but my question is how can I mock the redis.getAsync call, so it can become a real isolated unit test?
Thanks.
Good question. You can mock out the redis dependency but only if you rewrite you code, slightly, to be more testable.
Here, that means making redis a parameter to the factory that returns the object containing getUserInfo.
Of course, this changes the API, callers now need to call the export to get the object. To fix this, we can create a wrapper module that calls the function with the standard redis object, and returns the result. Then we move the actual factory into an inner module, which still allows it to be tested.
Here is what that might well look like
user-helper/factory.js
module.exports = redis => {
....
function getUserInfo(id) {
return redis.getAsync(id); // note simplified as new Promise was not needed
}
return {getUserInfo};
};
user-helper/index.js
// this is the wrapper that preserves existing API
module.exports = require('./factory')(redis);
And now for the test
const userHelperFactory = require('./user-helper/factory');
function createMockRedis() {
const users = [
{userId: 'userid123'},
// etc.
];
return {
getAsync: function (id) {
// Note: I do not know off hand what redis returns, or if it throws,
// if there is no matching record - adjust this to match.
return Promise.resolve(users.find(user => user.userId === id));
}
};
}
describe('Test user helper', () => {
const mockRedis = createMockRedis();
const userHelper = userHelperFactory(mockRedis);
let userInfo;
beforeEach(async () => {
userInfo = await userHelper.getUserInfo('userid123');
});
it('must return user info when a matching user exists', () => {
expect(userInfo).toEqual('info of userid 123');
});
});
NOTE: As discussed in comments, this was just my incidental approach to the situation at hand. There are plenty of other setups and conventions you can use but the primary idea was just based on the existing export of the result of an IIFE, which is a solid pattern, and I leveraged the NodeJS /index convention to preserve the existing API. You could also use one file and export via both module.exports = factory(redis) and module.exports.factory = factory, but that would, I believe, be less idiomatic in NodeJS. The broader point was that being able to mock for tests, and testability in general is just about parameterization.
Parameterization is wonderfully powerful, and its simplicity is why developers working in functional languages sometimes laugh at OOP programmers, such as yours truly, and our clandestine incantations like "Oh glorious Dependency Injection Container, bequeath unto me an instanceof X" :)
It is not that OOP or DI get it wrong it is that testability, DI, IOC, etc. are just about parameterization.
Interestingly, if we were loading redis as a module, and if we were using a configurable module loader, such as SystemJS, we could do this by simply using loader configuration at the test level. Even Webpack lets you do this to some extent, but for NodeJS you would need to monkey patch the Require Function, or create a bunch of fake packages, which are not good options.
To the OP's specific response
Thanks! That's a good idea, but practically, it seems it's quite strange when I have tons of file to test in which I will need to create a factory and index.js for each of them.
You would need to restructure your API surface and simply export factories that consuming code must call, rather than the result of applying those factories, to reduce the burden, but there are tradeoffs and default instances are helpful to consumers.

Angular 2 observable subscribe arrow functions getting big and dirty

I want to know if there is a better way to define callback functions of angular 2 observable subscribe when dealing with http calls without violating Single responsibility principle when it comes to embedded logic witch leads to an ugly dirty code.
I am trying to use function variables instead of arrow functions to separate callbacks logic but I can't access this and local function variables (state in the example).
updateState(state: string) {
let proposition = new Proposition();
proposition.id = this.id;
proposition.state = state;
this.propositionService.updateProposition(proposition).subscribe(
(data) => {
....
// instruction using local variable
this.router.navigate(['/portfolio', state]);
....
},
.....
// instrution using this
(errors) => this.toastr.warning('Error.', 'ops !');
.....}
There are many options and all have upsides and downsides. You should choose the one with the most upsides and the fewest downsides on a case by case basis.
Here are a few options (there are many more)
Create a local binding for an arrow function.
updateState(state: string) {
const withNext = (data: { values: {}[] }) => {
console.info(data.values);
....
// instruction using local variable
this.router.navigate(['/portfolio', state]);
....
};
const withError = error => {
this.toastr.warning('Error.', error);
}
this.propositionService.updateProposition(proposition)
.subscribe(withNext, withError);
}
The downsides of this approach are that you need to create the callbacks before you use them, because the assignments will not be hoisted, and that you the lose type inference of the callback arguments, needing to restate the argument types redundantly.
To get around the declaration order issue, we can create a local function declaration
updateState(state: string) {
this.propositionService.updateProposition(proposition)
.subscribe(withNext, withError);
const that = this;
function withNext(data: { values: {}[] }) {
console.info(data.values);
....
// instruction using local variable
that.router.navigate(['/portfolio', state]);
....
}
function withError(error) {
that.toastr.warning('Error.', error);
}
}
The downsides of this approach are that you need to alias this, and that again, the we lose type inference and must resort to redundantly and perhaps incorrectly manually specifying the argument types of the callbacks.
If the observable only emits a single value, for example if it represents an HTTP request, we can use toPromise and enjoy clear and clean code with full type inference and no need for callbacks.
async updateState(state: string) {
try {
const data = await this.propositionService.updateProposition(proposition)
.toPromise();
console.info(data.values);
....
// instruction using local variable
this.router.navigate(['/portfolio', state]);
....
} catch (error) {
this.toastr.warning('Error.', error);
}
}
The downside is that this approach only works for observables that emit at most a single value (e.g. HTTP requests).
The state parameter is accessible to all local declarations regardless of approach and is not a factor unless you wish to extract the success and failure logic to a location outside of the updateState method.

Stubbing nested function calls in sinon

There are three seperate questions that are similar to this one but none of them resembles the case I have.
So I basically have a function which takes a function as a parameter
var myfunc ( func_outer ) {
return func_outer().func_inner();
}
In my unit tests I want to be able to make a stub of a myfunc2. Basically I need to be able to stub a stub which is a nested stub. I currently use this kind of a manual stub but I would rather do it using sinon stubs if there is a way.
const func_outer = () => {
return {
func_inner: () => {return mockResponse;}
}
};
Has anyone ever faced this situation. Is there an easy way to solve this issue?
From sinon documentation you can check the returns section
stub.returns(obj);
Makes the stub return the provided value.
You can try the following:
First you should make sure that you stub your inner function, and then make it return the value you want.
func_innerStub = sinon.stub().returns('mockResponse')
Then stub your outer function and make it return the object with your stubbed inner function.
func_outerStub = sinon.stub().returns({func_inner: func_innerStub})
You can follow this pattern with the myfunc function, as well and pass as a param the func_outerStub.

Categories