Execute function conditionally with && syntax JS - javascript

Can I execute functions this way?
const test = testFunc() // returns "value" or undefined
test && anotherFunction()
Basically I want to execute anotherFunction() if test const is defined, otherwise just skip it.
I know that I can use something like this:
if (test) {
anotherFunction()
}
but I'm interested why the first method isn't working.
I will appreciate if someone explain me the difference between if () {} and &&.
// I'm confused because if I trying to use the first method I get:
Expected an assignment or function call and instead saw an expression
in my IDE.

The approach will work as expected you can see the below two cases as you mentioned.
First Case - testFunc returns some value
const testFunc = () => 1
const anotherFunction = () => 2
const test = testFunc()
test && anotherFunction()
Second Case - testFunc returns undefined
const testFunc = () => undefined
const anotherFunction = () => 2
const test = testFunc()
test && anotherFunction()
I hope this will help to understand it better.

Related

Jasmine - How to spy on a deep nested function

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!

How to make Bootstrapper object of window be available for unit testing?

I have a function in my project which calls a function from bootstrapper object of window. Below is the function:
export default function measurement(analObj) {
if (window.Bootsrapper._trackAnalytics === function) {
window.Bootstrapper._trackAnalytics(analObj);
}
}
I wrote below code to unit test this function in jest:
import measurement from "../helpers/measurement";
describe('Test measurement', () => {
beforeAll(() => {
const Bootstrapper = {
_trackAnalytics: function(obj) {
return obj;
},
};
window.Bootstrapper = Bootstrapper;
})
test('should send analytics object to rtrack analyitics', () => {
const testObj = {
pageName: "Leave Abasence"
}
const result = measurement(testObj);
expect(testObj).toEqual(result);
})
})
I get "undefined" for result variable that comes from measurement function call as I am unable to make window.measurement._trackAnalytics function available for measurement function at run time.
I would like to know:
Is my approach correct to unit test this scenario? If Yes, How to make the _trackAnalytics function available for measurement function while unit test run time.
Please suggest any other better approach if you know.
The window.measurement._trackAnalytics function is indeed available for measurement function when your test runs. Otherwise, you would get a TypeError for calling something that is not a function.
The problem is that in the measurement method there is nothing being returned. The _trackAnalytics method is called but its result is not returned. That's why you get undefined as a result.
In order to check that it is indeed being called I would use a jest mock function. The test would look like:
test('should send analytics object to rtrack analyitics', () => {
const testObj = {
pageName: 'Leave Abasence'
};
measurement(testObj);
expect(window.Bootstrapper._trackAnalytics).toHaveBeenCalledTimes(1);
expect(window.Bootstrapper._trackAnalytics).toHaveBeenCalledWith(testObj);
});
Note that your code has some problems (which I expect are typos). In the if condition you are checking Bootsrapper instead of Bootstrapper. And you are checking if it is equal to function instead of checking with typeof. I think the line should look:
if (typeof window.Bootstrapper._trackAnalytics === 'function') {

Will nested function be called in mocha unit test after stubbing :AssertionError: expected 'some data' to equal 'stubbed string'

I am new to unit testing using mocha and sinon , just to learn more I have stubbed a function to return some string, in my code I call this function as inner function. My test is to see if the stubbed return string is assigned to a variable. Please look at the code snippet to understand more
file.specjs
let sinon = require("sinon");
let filejs = require('./file.js');
let expect = require ("chai").expect;
it('should run only the outer function' ,function() {
// I try to stub my function here
sinon.stub(filejs,'test1').callsFake ((someArg) => {
return "stubbed string";
});
// Now I will call my test outer function
filejs.test();
expect(filejs.param).to.equal("stubbed string");
})
let param;
module.exports = {
test,
test1
}
function test () {
module.exports.param = test1();
}
function test1() {
console.log("should not be called);
let data = "some data";
return data;
}
As I have already stubbed the function test1, I don't expect this to be called, and return from test1 is assigned to param and since we have faked the function to return a different string, I expect this string to be set to param variable.
But when I run the test I see this error
AssertionError: expected 'some data' to equal 'stubbed string'
Try the following edit...
function test () {
module.exports.param = module.exports.test1();
}
For what you are trying to do to have a chance at working. You need sinon to modify the module.exports and the code under test needs to read test1() from that object. It may need to be nested deeper in order to modify it... I don't know. I had troubles using sinon.stub(require('./something'))
I think I got it working in a repl.it
https://repl.it/repls/NegativeEnragedMainframe

Sinon Spies -- Testing a recursive (and possibly const) function expression

I am using Mocha with Sinon and attempting to test a recursive call (fibonacci). My code is:
'use strict';
let sinon = require('sinon'),
chai = require('chai'),
expect = chai.expect;
chai.use(require('sinon-chai'));
let fib = function (n) {
if (n === 0) {
return 0;
} else if (n === 1) {
return 1;
} else {
return fib(n-2) + fib(n-1);
}
};
describe('fib', function() {
it('should repeat calculations', function() {
let originalFib = fib;
fib = sinon.spy(fib)
expect(fib(6)).to.equal(8);
expect(fib).to.have.callCount(25);
fib = originalFib;
});
});
This code works as-is, however, if I replace the line:
let fib = function (n) {
with:
const fib = function (n) {
I get the following error:
TypeError: Assignment to constant variable.
This is as expected, but it raises the question, how would I test a recursive function that was declared const using Sinon?
Edited Jasmine has something called .callThrough() which seems to allow testing of recursive function.
It seems to me there is no way to replicate this behavior with Sinon? I have looked at the following bug reports / feature requests:
https://github.com/sinonjs/sinon/issues/668
https://github.com/sinonjs/sinon/issues/989
Thank you.
Calling sinon.spy directly on a function creates a wrapper around the original function that tracks calls and returned values but does not modify it, so you do not need to remember it and restore it.
With that information, the obvious answer would be to simply name your spy something else:
describe('fib', function() {
it('should repeat calculations', function() {
const spy = sinon.spy(fib);
expect(spy(6)).to.equal(8);
expect(spy).to.have.callCount(25);
});
});
This approach works fine for non-recursive functions, but as you might notice, while the first assertion passes, the second fails with only 1 call having been made to spy.
The problem is that there is one more issue at play here. The function fib calls itself directly and those direct recursive calls are not tracked by wrapping the function with sinon.spy.
More details on this issue as well as the corresponding solution is presented in the answer here.
The main issue when you changed the code into const fib = function(n) is because you have this subsequent code fib = sinon.spy(fib). We can't redeclare assignment for any variable with const.
For this kind of test, based on my experience, I feel that using spy is not necessary unless you have other function to call inside fib. We can just execute and check the value for all possible cases.
'use strict';
const sinon = require('sinon'),
chai = require('chai'),
expect = chai.expect;
chai.use(require('sinon-chai'));
const fib = function (n) {
if (n === 0) {
return 0;
} else if (n === 1) {
return 1;
} else {
return fib(n - 2) + fib(n - 1);
}
};
describe('fib', function () {
it('should repeat calculations', function () {
expect(fib(0)).to.equal(0); // add more cases
expect(fib(1)).to.equal(1);
expect(fib(6)).to.equal(8);
});
});
Hope it helps.

Why wont the function run?

Can someone explain why the function below is not working (giving me an alert) when I try to call first(), however it works fine when I assign it to a new const?
const first = () => {
const greet = "Hi";
const second = () => {
alert("greet");
}
return second;
}
first() // does not work
const newFunc = first();
newFunc(); // works
Is this something specific to ES6 or am I missing something?
Thank you everyone! I had a brain fart, I kept focusing on the new syntax thinking that I made a mistake or it works in a different way, but I was never calling the second function returned by the first one. I changed it to:
const first = () => {
const greet = "Hi";
const second = () => {
alert("greet");
}
return second;
}
first()
It works now!
first() works just fine and returns the second() function, but I don't think you expected this. And your try to copy it used () and thus called it, returning the second function. After that newFunc contains second and calling it gives you the intended result.
first() only returns a function object - therefor another set of () is needed to actually call that returned function.
It doesn't need assignment to const newFunc though - first()(); would get you your alert as well.
This technique of having a function return another function, or an object that exposes several functions that can then in turn be called, is know as Revealing Module Pattern.
You're returning "second" as a function, but you never execute, you have 2 options, return "second()" or execute after receive it.
const first = () => {
const greet = "Hi";
const second = () => {
alert("greet");
}
return second;
}
first()(); // does work
//Alternative
const secondTime = () => {
const greet = "Hi";
const second = () => {
alert("greet");
}
return second();
}
secondTime();
Hope this works.

Categories

Resources