Jest- testing variables inside component methods - javascript

Let's say I have a class component that has something like this:
export class Math extends React.Component {
...
someComponentMethod = numb => {
const sample = numb * 10
...
const result = numb -5
return result
}
Is it possible to make test assertions on sample variable in Jest?

It is not possible to write assertions for the private internals of functions.
I've personally found this barrier to encourage better tests to be written. By testing only the public API for correctness, you have the ability to refactor internals without having to update any tests. The existing tests continue to enforce that internal changes work correctly.
Writing tests against internal behavior easily increases the maintenance effort of the code being tested. Since the tests become more tightly coupled to the source code, they'll need more attention when making changes. This can also degrade the reliability of the tests, since more changes to the tests increases the likelihood of bugs manifesting in the tests themselves.
If you find yourself wanting to test some internal behavior, it might be a good time to extract some functionality. In your example, the sample value calculation could be extracted into a pure function of its own:
export class Math extends React.Component {
...
computeSampleValue(input) {
return input * 10
}
someComponentMethod = numb => {
const sample = this.computeSampleValue(numb)
...
const result = numb -5
return result
}
}
You can now assert that whatever logic is being used to calculate the sample value works as expected for various inputs. This extraction of logic often makes someComponentMethod more readable as well.
If you absolutely need to test some other internal behavior and are aware of the increased code debt, you can have your method perform side effects and write assertions for those. For example, instead of defining sample as a function-scope variable, create a this.sample property on the component instance and update that. In a test you then call the target method, and afterwards assert that componentInstance.sample was changed as expected.

I've managed to test a certain variable value inside a function the following way:
sum1.js
function sum() {
result = 1 + 2;
};
module.exports = sum;
sum1.test.js
const sum = require('./sum1');
sum();
test('adds 1 + 2 to equal 3', () => {
expect(result).toBe(3);
});
Hope it helps, cheers!

Related

How is injecting an impure function different from calling it?

I am reading a book where it says one way to handle impure functions is to inject them into the function instead of calling it like the example below.
normal function call:
const getRandomFileName = (fileExtension = "") => {
...
for (let i = 0; i < NAME_LENGTH; i++) {
namePart[i] = getRandomLetter();
}
...
};
inject and then function call:
const getRandomFileName2 = (fileExtension = "", randomLetterFunc = getRandomLetter) => {
const NAME_LENGTH = 12;
let namePart = new Array(NAME_LENGTH);
for (let i = 0; i < NAME_LENGTH; i++) {
namePart[i] = randomLetterFunc();
}
return namePart.join("") + fileExtension;
};
The author says such injections could be helpful when we are trying to test the function, as we can pass a function we know the result of, to the original function to get a more predictable solution.
Is there any difference between the above two functions in terms of being pure as I understand the second function is still impure even after getting injected?
An impure function is just a function that contains one or more side effects that are not disenable from the given inputs.
That is if it mutates data outside of its scope and does not predictably produce the same output for the same input.
In the first example NAME_LENGTH is defined outside the scope of the function - so if that value changes the behaviour of getRandomFileName also changes - even if we supply the same fileExtension each time. Likewise, getRandomLetter is defined outside the scope - and almost certainly produces random output - so would be inherently impure.
In second example everything is referenced in the scope of the function or is passed to it or defined in it. This means that it could be pure - but isn't necessarily. Again this is because some functions are inherently impure - so it would depend on how randomLetterFunc is defined.
If we called it with
getRandomFileName2('test', () => 'a');
...then it would be pure - because every time we called it we would get the same result.
On the other hand if we called it with
getRandomFileName2(
'test',
() => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.charAt(Math.floor(25 * Math.random()))
);
It would be impure, because calling it each time would give a different result.
There's more than one thing at stake here. At one level, as Fraser's answer explains, assuming that getRandomLetter is impure (by being nondeterministic), then getRandomFileName also is.
At least, by making getRandomFileName2 a higher-order function, you at least give it the opportunity to be a pure function. Assuming that getRandomFileName2 performs no other impure action, if you pass it a pure function, it will, itself, transitively, be pure.
If you pass it an impure function, it will also, transitively, be impure.
Giving a function an opportunity to be pure can be useful for testing, but doesn't imply that the design is functional. You can also use dependency injection and Test Doubles to make objects deterministic, but that doesn't make them functional.
In most languages, including JavaScript, you can't get any guarantees from functions as first-class values. A function of a particular 'shape' (type) can be pure or impure, and you can check this neither at compile time nor at run time.
In Haskell, on the other hand, you can explicitly declare whether a function is pure or impure. In order to even have the option of calling an impure action, a function must itself be declared impure.
Thus, the opportunity to be impure must be declared at compile time. Even if you pass a pure 'implementation' of an impure type, the receiving, higher-order function still looks impure.
While something like described in the OP would be technically possible in Haskell, it would make everything impure, so it wouldn't be the way you go about it.
What you do instead depends on circumstances and requirements. In the OP, it looks as though you need exactly 12 random values. Instead of passing an impure action as an argument, you might instead generate 12 random values in the 'impure shell' of the program, and pass those values to a function that can then remain pure.
There's more at stake than just testing. While testability is nice, the design suggested in the OP will most certainly be impure 'in production' (i.e. when composed with a proper random value generator).
Impure actions are harder to understand, and their interactions can be surprising. Pure functions, on the other hand, are referentially transparent, and referential transparency fits in your head.
It'd be a good idea to have as a goal pure functions whenever possible. The proposed getRandomFileName2 is unlikely to be pure when composed with a 'real' random value generator, so a more functional design is warranted.
Anything that contains random (or Date or stuff like that). Will be considered impure and hard to test because what it returns doesn't strictly depends on its inputs (always different). However, if the random part of the function is injected, the function can be made "pure" in the test suite by replacing whatever injected randomness with something predictable.
function getRandomFileName(fileExtension = "", randomLetterFunc = getRandomLetter) {}
can be tested by calling it with a predictable "getLetter" function instead of a random one:
getRandomFileName("", predictableLetterFunc)

React Native const vs let vs var in Functional Components

This is a broader question about the use of different variable declarations in react native functional components (as opposed to class components), specially the use of let vs const, and how they are effected by renders and such. For this question, when I say 'render' or 're-render' I am talking about the execution of the render function (like 'MyFunctionalComponent' below), not necessarily a UI update/change.
From my understanding, unlike plain js, a const variable is not exactly 'constant' in react/react native, and can be changed (with hooks?) like so:
export default function MyFunctionalComponent() {
const [test, setTest] = useState(false);
const testFunction = () => { //some sort of function, maybe called by a button press
setTest(true); //this can change test, but something like 'test = true' throws an error
}
}
However let can take on similar behavior from my understanding:
export default function MyFunctionalComponent() {
let test = false
const testFunction = () => { //some sort of function, maybe called by a button press
test = true;
}
}
However, most react native examples and tutorials and such I have looked at, always seem to use the const syntax, even though it seems to involve much more code. Why? Personal preference, or necessity? Does the const way of doing things somehow re-render/re-call MyFunctionalComponent with a new value for the const variable?
Next, I'm not sure the exact behavior that is causing this, but sometimes when using the const syntax inside the functional component, the variables change and save state between render calls, and sometimes, a const variable is reset to its default state every time the render is called. (I know this part is vague, so feel free to ignore it if there is not enough detail) Why does this happen?
Similarly, I have seen different behavior when consts are created outside of the functional component instead of within... does scope work as you would expect with these? Are they (still?) re-instantiated on new render calls? Does 'setState' call an re-render? Shortening the previous question, why do some of my const's preserve their state on re-renders, while some seem to reset to their defaults?
Where does var fall into this, does it act the same as in regular js, or is it affected by react as well? (I feel like I have a grasp of the differences in these variable declarations in regular js, but this const behavior with react making me question it all).
So overall the question is basically, what are the differences/advantages of let, var, and const, specifically in react/react native, and how do those differ from regular javascript?
Lastly, does it differ between class components and functional components in react native?
Thank you for reading this long question.
Personal preference, or necessity?
Preference and style only.
Using const to declare a stateful variable instead of var or let makes the intent of the code clearer. It's not necessary - pretty much all components you see would work just as well if they used var or let - but it introduces a slight possibility of confusion from those reading the code.
React is written in JavaScript. Stateful variables in React, declared with const, cannot be reassigned, just like in ordinary JavaScript. The key you're missing is that the component function is called again every time there's a re-render, resulting in the call of the useState function returning a different value.
For quick example of how this could work in vanilla JS with const and calling a function multiple times:
let i = 0;
const getI = () => i;
const fn = () => {
const theValue = getI();
console.log(theValue);
i++;
setTimeout(fn, 1000);
};
fn();
It's not that the variable gets reassigned (which would be forbidden due to the use of const), it's that the whole function runs again, resulting in a new value being assigned to the variable declared with const at the moment of its new initialization.
Next, I'm not sure the exact behavior that is causing this, but sometimes when using the const syntax inside the functional component, the variables change and save state between render calls, and sometimes, a const variable is reset to its default state every time the render is called. (I know this part is vague, so feel free to ignore it if there is not enough detail) Why does this happen?
You may be referring to the stale closure issue. This can happen if the variable binding that results in a difference being seen is from a prior render, rather than the current render.
For a quick example of what that might look like in vanilla JS, adapting from the above snippet, I'll add a timeout on the first render, which will result in only the i from the first render being used:
let i = 0;
const getI = () => i;
const fn = () => {
const theValue = getI();
console.log(theValue);
if (theValue === 0) {
// first render
setTimeout(() => {
console.log('Timeout from first render running, sees a theValue of:', theValue);
}, 5000);
}
i++;
setTimeout(fn, 1000);
};
fn();
Similarly, I have seen different behavior when consts are created outside of the functional component instead of within... does scope work as you would expect with these? Are they (still?) re-instantiated on new render calls?
Depends on what block that variable is in. If it's in another component, it may get re-initialized. If it's not in another component, then it might not be. For example, it's common to have a module that exports a component with some absolutely unchanging const values that all the components use declared up top, eg
const apiKey = 'someApiKey';
export const ApiInterface = () => {
// ...
};
With regards to const vs let and var specifically, the problem with let and var is that they permit reassignment - but the only right way to change a stateful variable in React is to call the state setter, not to reassign the variable. Calling the state setter is what will result in a re-render; reassigning a variable will not result in a re-render, and reassigning a variable will result in the assigned value being lost on the next re-render. So, it's a good idea to be perfectly clear that stateful variables should not be reassigned.
Lastly, does it differ between class components and functional components in react native?
Yes, in class components, state is held as a property of the instance (the this). The state is no longer a standalone const identifier, but a property of a larger object, so there's no const vs let vs var for stateful values in class components - unless you extract values from state and put them into normal standalone variables yourself, in which case they behave just like any other standalone variable.

Test variable inside function (jestjs)

Is it possible to test simple variable inside function? I would like to test only part of my function. For example
function x(number) {
let len = number.toString().length
return 'End'
}
I would like to test if len variable is set properly. Is it possible?
It is not possible to write assertions for the private internals of js functions.
I've personally found this barrier to encourage better tests to be written. The existing tests continue to enforce that internal changes work correctly.
Writing tests against internal function behavior increases the maintenance effort of the code being tested. Since the tests become more tightly coupled to the source code, they'll need more attention when making changes.
If you find yourself wanting to test some internal behavior, it's recommended to create another function. For example
export class Math extends React.Component {
...
computeLen(input) {
return input.toString().length;
}
function x(number) {
let len = computeLen(number)
return 'End'
}
}
You can now assert that whatever logic is being used to calculate the sample length works as expected for various inputs. This extraction of logic often makes the function x(number) more readable as well.

Mock string.Format in jasmine

I am trying to write unit tests for a mobile app that has been developed in Appcelerator titanium. I am trying to unit test it with TiUnit and Jasmine.
One of my methods uses String.format(). How do I unit test that method since String.format() is not defined in Javascript?
function MyMethod(_flag, _myProperty, _propertyValue) {
if(_flag) {
_myProperty = String.format('The value :', _propertyValue);
}
}
Is it possible to mock this? Or can I add format() to the prototype of jasmine's String so that whenever it encounters format() in .js to be tested, it executes the format() which I will define in the test suite?
A way to get around this problem is to make this a pure function.
Take this small change as an example:
function MyMethod(_flag, _myProperty, _propertyValue, formatFunction) {
if(_flag) {
_myProperty = formatFunction('The value :', _propertyValue);
}
}
Now MyMethod does not have a dependency on anything external to the function. This allows you to use whatever string formatter you want, and in your case a mocked one.
In your test, you now have the ability to do something like this:
it('should format the string', () => {
const mockFormatter = () => {/*do the mock operation of your choosing here*/}
const formattedString = MyMethod(yourFlag, yourProperty, yourPropertyValue, mockFormatter)
assert(formattedString, expectedOutput)
})
What this allows is for you to not have to manipulate the global String object/prototypes, which can have implications elsewhere. Instead, you create a function that is agnostic to the formatter and are able to easily mock it.
Lastly, now that I have hopefully helped provide a path forward on your original question, I'm curious why you are after mocking the formatter? This seems like something you would always want to validate, and would have no harm in doing so. To me, and this can lead to very in depth and often pedantic discussions on testing, this already suffices as a unit test. It is not "pure", but as far as side-effects go, there are none and you are testing some basic expectations around data manipulation without.
I think mocking String.format() introduces unnecessary complexity to the test without any real gain in code-confidence.
**Edit: I assumed String.format() was a JS function I had not heard of, but that does not appear to be the case.
To achieve what you are after, and avoid the need to mock entirely, I think you should use string interpolation via string literals, or concatenation.
See here:
function MyMethod(_flag, _myProperty, _propertyValue) {
if(_flag) {
_myProperty = `The value : ${_propertyValue}`; // option 1 uses interpolation
// _myProperty = 'The value : ' + _propertyValue; // option 2 uses concatenation
}
}

JavaScript Constants - pass as argument or use directly?

I'm wondering what the best practice is regarding using declared constants in JavaScript. Is it better to pass the constant as an argument to the function or is it better to use the constant without passing?
My instinct is to not pass the constant as an argument because that produces an unnecessary local copy of the variable. However, it might be more clear where the constant is coming from if it is passed.
const myConstant = 1;
myFunc();
myOtherFunc(myConstant);
/* use constant without passing */
function myFunc() {
console.log(`${myConstant} is a constant`);
}
/* pass constant as argument */
function myOtherFunc(localCopy) {
console.log(`${localCopy} is a constant`);
}
There are tradeoffs going in both directions, though most of them are in the area of unit testing and re-usability.
The more you hard code things, the less flexibility you have in testing.
Let me give what a contrived example:
const FIRST_NAME_MAX_LEN = 20;
And, in our validation code, we look at that constant and compare it to the length of the input field...
function validateFirstName() {
return document.getElementsByName("first-name")[0].length <= FIRST_NAME_MAX_LEN;
}
Ok, this works, but we have no way to test that validateFirstName() works without invoking the entire DOM. it is harder to test.
On the other hand, if we create a function like:
function validateStringLength(s, maxLength) {
return s.length <= maxLength;
}
then we've created a function that takes passed parameters, is re-usable in other places and very easily tested in any testing framework. DOM not required.
By relying upon the constant, you have created a dependency on that value and where it live. Research JavaScript Dependency Injection for much more on this topic.

Categories