How to test agains null or undefined values? - node.js

I am creating an API using typescript and as usual, i am getting values from request.body. here is the thing, those values can be undefined and i need to pass those values to my factories.
Inside a factory i have a function that validates whether the value is null or undefined. (and some other validations) In this way i make sure not passing undefined or null values to my instances. But i cannot test it because of type definitions.
The value generated from request can be or not undefined, but the constructor can get that value. When i try to test it i cannot, because the interpreter do not let me pass a null or udnefined value (because of type), example:
...
const { value } = request.body;
const result = myFactory.create(value);
// This works fine because body can be anything, literaly, even undefined.
//Althought the function is waiting for a number.
...
const nullValue = null;
const result = myFactory.create(nullValue);
// this does not work, because the function want a number and is getting a null value.
// but i need to do this in order to test that case.
...
Here is the thing: how can I test that?
I cannot generate a null value for the situation where the function receibe a null or undefined and don't create the instance because of that.
should i get out of the function the code section that validate againstNullOrUndefined?

If you expect myFactory.create factory to receive number | null | undefined then it should reflect in the type signature.
If you are receiving data from api call which is always any (or better unknown) then these factories should take any or unknown parameter.
Or you can have separate function decode(value: unknown): number which you call first and then pass decoded number to myFactory.create
There are libraries which does just that (decoding data to your domain models/types) for example io-ts

Related

Getting children of an element in Puppeteer: element.children.length works but element.children returns undefined

I have this code snippet:
const historicalDataTable = await findElementByClass(
"table",
elementClass,
page
); // This is a custom function I wrote. Works as expected.
const tableBody = await historicalDataTable.$eval(
"tbody",
(el) => el.children.length
);
console.log(tableBody);
This works as expected and returns the correct amount of children. However when I do
const tableBody = await historicalDataTable.$eval(
"tbody",
(el) => el.children
);
And remove the length, it returns undefined. What is going on here?
el.children (Element#children) will yield an HTMLCollection which is not serializable and can't be marshalled from the page's execution context into yours, so evaluate returns undefined instead.
Now, this isn't fully obvious when looking at the elementHandle.$eval docs as the only indication is that the return value is <Promise<Serializable>>, but it becomes clear from the executionContext.evaluate docs:
returns: <Promise<Serializable>> Promise which resolves to the return value of pageFunction
[...]
If the function passed to the executionContext.evaluate returns a non-Serializable value, then executionContext.evaluate resolves to undefined. DevTools Protocol also supports transferring some additional values that are not serializable by JSON: -0, NaN, Infinity, -Infinity, and bigint literals.
(Emphasis mine.)
el.children.length (HTMLCollection#length) on the other hand is a simple number which is serializable.
You have to do whatever you want to do with those elements inside of your pageFunction and return only some serializable value.
Alternatively, you could also use elementHandle.evaluateHandle to return a JSHandle to the HTMLCollection and use that handle later in another call to an evaluate-type function. (Note that that would be the only thing you can do with it though. You couldn't access .length for example from your own execution context, only from another pageFunction1.)
1: This is not entirely true, since you could for example use jsHandle.getProperty to get another JSHandle for the length, followed by jsHandle.jsonValue to get the value as number - but both of these operations are asynchronous and probably it's a lot more efficient to write your code in such a way that you can handle all the necessary operations inside the page's execution context in the first place, without too many context switches.

SyntaxError: Unexpected token o in JSON at position 1 - Simple Error

I am currently taking a course on node.js and I am receiving this error:
SyntaxError: Unexpected token o in JSON at position 1
The code that I anticipate is giving me this problem is:
const loadNotes = function() {
// try {
//This code is exactly the same as the video's
const dataBuffer = fs.readFileSync('notes.json')
const dataJSON = JSON.toString(dataBuffer)
return JSON.parse(dataJSON)
//} catch(e) {
//return []
// }
I checked similar answers, but they seemed more complex, and as such, I was unable to fix the problem using them.
Your JSON.toString() is not returning what you think it is.
toString() is returning a string representation of the JSON object.
The result is: [object JSON]
That is not a proper JSON string so JSON.parse() fails.
So, there are two problems:
You are incorrectly using the prototype toString() method
You are feeding a non-JSON string to JSON.parse()
Explanation:
Firstly, as was stated in the comments above, there is no toString() method defined in the JSON object. .toString() in the JSON object's prototype chain does do something when you call it but the result is a string representation of the JavaScript JSON object, not the JSON object you are attempting to read from your file. You really want to use JSON.stringify() instead of toString().
Here's the explanation in MDN:
Every object has a toString() method that is automatically called when
the object is to be represented as a text value or when an object is
referred to in a manner in which a string is expected. By default, the
toString() method is inherited by every object descended from Object.
If this method is not overridden in a custom object, toString()
returns "[object type]", where type is the object type.
So, you can call toString() on any object in JavaScript and get [object Object]. But that's not what you want. So, don't use toString(). It's not doing what you think it's doing.
Secondly, be sure that you are trying to parse a real JSON string and not trying to parse a JavaScript object. There is a significant difference between the two.
Take a look at this code:
let dataJS = {
key: "value"
}
Above, I have defined a JavaScript object called dataJS.
I can convert the dataJS JavaScript object into a JSON object by using the JSON.stringify() method like this:
let dataJSON = JSON.stringify(dataJS);
The JSON.stringify() method expects a JavaScript object and will return a JSON string. I have assigned the resulting JSON string to dataJSON. Now, I have two things: a JavaScript object called dataJS and a JSON string called dataJSON.
I can print the contents of these two things like this:
console.log("JSON:\n", dataJSON)
console.log("JS:\n", dataJS)
Notice carefully how the two appear. You'll see this:
JSON:
{"key":"value"}
JS:
{ key: 'value' }
Do you see the difference in between the JSON string and the JavaScript object?
The JSON string has double-quotes around the key and values. The JavaScript object does not have any quotes around the key and single-quotes around the value.
These make JSON strings and JavaScript objects quite different.
So, if you accidentally feed the wrong thing to the JSON.parse() method you will get an error. Note what happens when I give the JSON object to the JSON.parse() method:
console.log("Parse JSON:\n", JSON.parse(dataJSON))
/* result will be:
* Parse JSON:
* { key: 'value' }
*/
That is great! The JSON.parse() method is expecting a JSON string so it works properly.
But watch what happens then I try to feed JSON.parse() the JavaScript object we created:
console.log("Parse JS:\n", JSON.parse(dataJS))
/* result will be an ERROR:
* undefined:1
* [object Object]
* ^
*
* SyntaxError: Unexpected token o in JSON at position 1
*/
There's your error!
So, it means that what you're feeding your JSON.parse() method in your code is not a JSON string.
The "Unexpected token" error means that your JSON isn't formatted correctly. You can take a look at this site and put the contents of notes.json into it, and it will tell you whats wrong and what needs to be corrected

Firestore finds undefined value in fully defined JSON, key does not even exist

I am trying to upload a JSON-object to Google Firestore.
When setting the Object to a Firestore Document my code throws the following Error:
Error: Value for argument "data" is not a valid Firestore document.
Cannot use "undefined" as a Firestore value
(found in field audit.`20`.requests.`0`.lrEndTimeDeltaMs).
Now the first thing I did was log the Object right before the upload to check for undefined values:
console.log(JSON.stringify(resultsToUpload));
return database
.collection("foo1")
.doc("bar1")
.set(resultsToUpload);
Not only are all values defined in the object, but the mentioned field audit.`20`.requests.`0`.lrEndTimeDeltaMs does not even exist:
resultsToUpload = {
"audit":{
"20":{
"ronaldScore":3,
"id":"network-requests",
"requests":[
{
"url":"https://www.example.com/",
"startTime":0,
"endTime":62.16699999640696,
"transferSize":15794,
"resourceSize":78243,
"statusCode":200,
"mimeType":"text/html",
"resourceType":"Document"
}
]
}
}
}
The data comes from a Google Lighthouse Audit.
Calculating the UTF-8 string length of the stringified JSON objects results in a size of 30 MB.
1) All values are defined (some are null, which should not be a problem).
2) The mentioned field does not even exist in the JSON.
My question is: How can this happen? How can a field just appear?
Also: How would I fix this issue?
using JSON.stringify on a Javascript-Object hides all "undefined" values (as well as their keys) and then stringifies what is left.
That is because JSON does not have such a thing as "undefined".
So the log showed a fully defined JSON, even though the actual JS-Object did contain "undefined" values.

Applying default groovy method parameter value when passing null

In Groovy, if I have:
def say(msg = 'Hello', name = 'world') {
"$msg $name!"
}
And then call:
say() // Hello world!
say("hi") // Hi world!
say(null) // null world!
Why is the last one getting interpreted literally as null and not applying the default value? Doesn't this defeat the purpose of default method argument values? I do get that passing null is different from not passing anything w/r/t argument length.
My problem here is that if I now have a method that takes a collection as an argument:
def items(Set<String> items = []) {
new HashSet<>(items)
}
This will throw a NullPointerException if I call items(null) but work fine if I just say items(). In order for this to work right, I have to change the line to be new HashSet<>(items ?: []) which, again, seems to defeat the entire purpose of having default method argument values.
What am I missing here?
In Groovy, default parameters generates overloaded methods. Thus, this:
def items(Set<String> items = []) {
new HashSet<>(items)
}
Will generate these two methods (I used javap to get these values):
public java.lang.Object items(java.util.Set<java.lang.String>);
public java.lang.Object items();
So when you call items(null) you are, in fact, passing some value, and items(Set) method will be used.
You can also refer to this question about default parameters.

Can CQL be used to find methods that return `null`?

I want to find all methods that can explicitly return null.
Is this possible in NDepend using CQL?
Not for now, CQL so far doesn't know about value of variables, fields and values returned.
However this default rule below is proposed. The idea is that if a method returns a reference it should never be null, and a contract should be added to assert this. If you wish such a method to return null, instead use the Try... pattern, like in TryParse(string s, out T val):bool.
// <Name>Public methods returning a reference needs a contract to ensure that a non-null reference is returned</Name>
warnif count > 0
let ensureMethods = Application.Methods.WithFullName(
"System.Diagnostics.Contracts.__ContractsRuntime.Ensures(Boolean,String,String)")
from ensureMethod in ensureMethods
from m in ensureMethod.ParentAssembly.ChildMethods where
m.IsPubliclyVisible &&
!m.IsAbstract &&
m.ReturnType != null &&
// Identify that the return type is a reference type
(m.ReturnType.IsClass || m.ReturnType.IsInterface) &&
!m.IsUsing(ensureMethod) &&
// Don't match method not implemented yet!
!m.CreateA("System.NotImplementedException".AllowNoMatch())
select new {
m,
ReturnTypeReference = m.ReturnType
}
//<Description>
// **Code Contracts** are useful to decrease ambiguity between callers and callees.
// Not ensuring that a reference returned by a method is *non-null* leaves ambiguity
// for the caller. This rule matches methods returning an instance of a reference type
// (class or interface) that don't use a **Contract.Ensure()** method.
//
// *Contract.Ensure()* is defined in the **Microsoft Code Contracts for .NET**
// library, and is typically used to write a code contract on returned reference:
// *Contract.Ensures(Contract.Result<ReturnType>() != null, "returned reference is not null");*
// https://visualstudiogallery.msdn.microsoft.com/1ec7db13-3363-46c9-851f-1ce455f66970
//</Description>
//<HowToFix>
// Use *Microsoft Code Contracts for .NET* on the public surface of your API,
// to remove most ambiguity presented to your client. Most of such ambiguities
// are about *null* or *not null* references.
//
// Don't use *null* reference if you need to express that a method might not
// return a result. Use instead the **TryXXX()** pattern exposed for example
// in the *System.Int32.TryParse()* method.
//</HowToFix>

Resources