Jest fails even though array does contain the expected element, why - jestjs

In my jest test case, I would like to verify the json contains certain element. Following is what I tried.
My Json data is:
{"name":"foo","age": 20,"otherInfo":"http://example.com"}
I created a parser to get an array of strings out from json object:
// a parser function for transforming json object to string[]
const parseJsonElements = (jsonData: object) =>
JSON.stringify(jsonData).replace(/[{}]/g, '').split(',');
// parse my json data
const elements = parseJsonElements(myJsonDataObj);
// verify elements contains json element
expect(elements).toContain(`"otherInfo":"http://example.com"`);
Above jest run fails with error:
Expected value: "\"otherInfo\":\"http://example.com\""
Received array: ["\"name\":\"foo\"","\"age\":\"20\"","\"otherInfo\":\"http://example.com\""]
But it looks like the received array does contain that element. Why Jest fails?
========= update =======
Tried expect(jsonData).toHaveProperty("otherInfo", "http://example.com"), it works. But what if I want to verify nested element exists? For example:
my json data:
{"name":"foo","age": 20,"otherInfo":{"type":"homepage", "url":"http://example.com"}}
Then, expect(jsonData).toHaveProperty("url", "http://example.com") still fail. Any suggestion for this nested json element check?

Related

use nodejs var as json object statement?

how do I use a nodejs var inside a json statement, I dont realy have the required vocabulary to explain but here is my simplifyed code:
test.json:
{
"test1":["test1.1", "test1.2"],
"test2":["test2.1", "test2.2"]
}
test.js:
const json = require("./test.json")
function myFunction(TYPE){
return(json.TYPE[0])
}
console.log(myFunction("test1"))
as I use the "type" var it tries to uses it as an json statement or object but obviously there is no "type" there only is "test1" and "test2" but it interprets as "type" instead
Brackets to access the variable key should work
function myFunction(TYPE){
return(json[TYPE][0])
}
In JavaScript, json objects are pretty much same as plain JS objects. You need to use string as an index to access properties:
// This could be your json file, its almost the same
// Just require it like you did instead of using const JSON like i am
const json = {
"test1":["test1.1", "test1.2"],
"test2":["test2.1", "test2.2"]
}
function myFunction(TYPE){
// Access the json by using keyword directly as index string
return(json[TYPE])
// because TYPE is a string, TYPE[0] would mean first letter of TYPE string
}
function myFunctionDeeper(TYPE){
// To access a field and array in that field
return(json[TYPE][0])
}
console.log(myFunction("test1"))
console.log(myFunctionDeeper("test1"))
// example for what happens when accessing string by index
console.log("test1"[0])
Read more about objects here

How to test agains null or undefined values?

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

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.

Cannot access properties on a populate()'d object from Mongoose?

This is very odd... I'm using populate() with a ref to fill in an array within my schema, but then the properties are inaccessible. In other words, the schema is like this:
new Model('User',{
'name': String,
'installations': [ {type: String, ref: 'Installations'} ],
'count': Number,
}
Of course, Insallations is another model.
Then I find & populate a set of users...
model.find({count: 0}).populate('installations').exec( function(e, d){
for(var k in d)
{
var user = d[k];
for(var i in user.installations)
{
console.log(user.installations[i]);
}
}
} );
So far so good! I see nice data printed out, like this:
{ runs: 49,
hardware: 'macbookpro10,1/x86_64',
mode: 'debug',
version: '0.1' }
However, if I try to actually ACCESS any of those properties, they're all undefined! For example, if I add another console log:
console.log(user.installations[i].mode);
Then I see "undefined" printed for this log.
If I try to operate on the object, like this:
Object.keys(user.installations[i]).forEach(function(key) { } );
Then I get a typical "[TypeError: Object.keys called on non-object]" error, indicating that user.installations[i] is not an object (even though it is outputted to the console as if it were). So, I even tried something ugly like...
var install = JSON.parse(JSON.stringify(user.installations[i]));
console.log(install, install.mode);
And, again, the first output (install) is a nice object containing the property 'mode'... but the 2nd output is undefined.
What gives?
Finally, I solved this...
I tried doing a console.log(typeof user.installations[i]); and got "string" as the output. This seemed odd, given that printing the object directly created console output (above) that looked like a normal object, not a string. So, I tried doing a JSON.parse(); on the object, but received the error "SyntaxError: Unexpected token r"
Finally, I realized what was going on. The "pretty console output" I described above was the result of a string formatted with \n (newlines). I had not expected that, for whatever reason. The JSON.parse() error is due to the fact that there is a known necessity with the node.js parser when attempting to parse object keys without quotations; see the SO question here:
Why does JSON.parse('{"key" : "value"}') do just fine but JSON.parse('{key : "value"}') doesn't? .
Specifically, note that the JSON parser in my case is failing on the character 'r', the fist character of "runs," which is the first key in my JSON string (above). At first I was afraid I needed to get a custom JSON parser, but then the problem hit me.
Look back to my original schema. I used a String-type to define the installation ref, because the array field was storing the installations's _id property as a String. I assume the .populate() field is converting the object to a String on output.
Finally, I looked at the Mongoose docs a little closer and realized I'm supposed to be referencing the objects based upon Schema.ObjectID. This explains everything, but certainly gives me some fixing to do in my schemas and code elsewhere...

Resources