Compare response in jest unit test case - javascript

I'm new to jest unit test case scenario, I have a scenario where in the response from the service that I called is of the below format
Artifact {
name: 'detection-v1.zip',
file_path: 'artifact\\bn-ds-anomalydetection-v1.zip',
is_tenant: false,
metadata: [
Registerfact {
name: 'ad',
_meta: [Object],
line_meta: [Object]
},
Registerfact {
name: 'ad-generic',
_meta: [Object],
line_meta: [Object]
}
]
}
how can i compare the above response in the jest service , I was trying to create a object but the Artifact name before the object is confusing how should i proceed
The test case is
test('test processArtifact method', async()=>{
const mockGetRestClient = jest.fn();
try{
const response = await factService.processfact(artifact)
console.log("response---",response)
// expect(response).toEqual()
}
catch(e){ }
})
I know its silly question ,but i'm confused hence posted it.
How should i create the static object to be put in .toEqual() ?

You can declare a global/static var with your response object on top of file. Or better declare it in some constants file and import here.
For Comparison:
Usually, if you have a simple object, you can use JSON.stringify. However, it may give error due to different order of object keys.
You should use assert for the deep comparison. There is method assert.deepEqual() which does deep comparison of objects.
an example for using assert from official docs
import assert from 'node:assert';
const obj1 = {
a: {
b: 1
}
};
const obj2 = {
a: {
b: 2
}
};
const obj3 = {
a: {
b: 1
}
};
const obj4 = Object.create(obj1);
assert.deepEqual(obj1, obj1);
// OK
// Values of b are different:
assert.deepEqual(obj1, obj2);
// AssertionError: { a: { b: 1 } } deepEqual { a: { b: 2 } }
assert.deepEqual(obj1, obj3);
// OK
// Prototypes are ignored:
assert.deepEqual(obj1, obj4);
// AssertionError: { a: { b: 1 } } deepEqual {}
Hope this helps, let me know if you have any questions.

You can use JSON.stringify in order to convert your object into a string and then compare this result to the one you expect.
console.log(JSON.stringify({
name: 'detection-v1.zip',
file_path: 'artifact\\bn-ds-anomalydetection-v1.zip',
is_tenant: false,
metadata: [
{Registerfact: {
name: 'ad',
_meta: {},
line_meta: {}
}},
{Registerfact: {
name: 'ad-generic',
_meta: {},
line_meta: {}
}}
]
}));

Related

Jest function toHaveBeenCalledWith to ignore object order

Im testing with what arguments a function was called but its not passing because the order of properties inside an object, like:
const obj = {
name: 'Bla',
infos: {
info1: '1',
info2: '2'
}
}
expect(function).toHaveBeenCalledWith(obj)
The error says that was called like this: { name: 'bla', infos: {info2: '2', info1: '1'} }
I changed orders but didn't work.
You could follow a similar approach to this SO answer.
Example:
// Assuming some mock setup like this...
const mockFuncton = jest.fn();
const expectedObj = {
name: 'Bla',
infos: {
info1: '1',
info2: '2'
}
}
// Perform operation(s) being tested...
// Expect the function to have been called at least once
expect(mockFuncton).toHaveBeenCalled();
// Get the 1st argument from the mock function call
const functionArg = mockFuncton.mock.calls[0][0];
// Expect that argument matches the expected object
expect(functionArg).toMatchObject(expectedObj);
// Comparison using toEqual() instead which might be a better approach for your usecase
expect(functionArg).toEqual(expectedObj);
Expect.toMatchObject() Docs
Expect.toEqual() Docs
it('does not care on properties ordering', () => {
const a = jest.fn();
a({ a: 1, b: 2, c: {d1: 1, d2: 2} });
expect(a).toHaveBeenCalledWith({c: {d2: 2, d1: 1}, b: 2, a: 1});
});
passes for me with Jest 24.9.0
Under the hood, Jest applies "isEqual" check, not referential check
But we cannot check for functions equality this way. Also partial matching will need custom matcher.

Redux state is being mutated with lodash's mergeWith

I am using lodash's mergeWith to merge some payload data into some of my redux state. However, when doing this, I end up directly mutating state. I don't understand how this is happening, since I am using {...state} to make the merge occur. Why is this happening and what can I do to not mutate my state directly? You can see the below snippet for an example of what is happening. Thanks!
const merger = (objectOne, objectTwo) => {
const customizer = (firstValue, secondValue) => {
return _.isArray(firstValue) ? secondValue : undefined;
};
return _.mergeWith(objectOne, objectTwo, customizer);
};
const state = {
1: {a: true, b: true, c: true},
2: {a: true, b: true, c: true},
3: {a: true, b: true, c: true},
}
const payload = {
2: {a: true, b: false, c: true},
}
console.log("Merged data:");
console.log(merger({...state}, payload));
console.log("Manipulated state:");
console.log(state);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.10/lodash.min.js"></script>
Here is in a nut shell the issue:
let a = { foo: 'A'}
let c = { ... a } // shallow copy of a
a.foo = 'boo'
console.log(a)
console.log(c) // works as expected c.foo is NOT changed and still is 'A'
As you can see from the above example with spreading and value based properties shallow copy works as expected. However when you do this:
let x = { foo: { boo: 'A' }} // object as value this time
let y = { ... x } // shallow copy of x
x.foo.boo = 'beer'
console.log(x.foo.boo)
console.log(y.foo.boo) // should be 'boo' but it is 'beer'
Shallow copy does not work as well since the clone has references pointing to the old x objects instead of cloned ones.
To remedy this and also to to make your code somewhat more concise you could:
const state = { 1: {a: true, b: true, c: true}, 2: {a: true, b: true, c: true}, 3: {a: true, b: true, c: true}, }
const payload = { 2: {a: true, b: false, c: true} }
const merger = (...args) => _.mergeWith(...args, (a,b) => _.isArray(a) ? b : undefined)
console.log("Merged data:");
console.log(merger(_.cloneDeep(state), payload));
console.log("Manipulated state:");
console.log(state);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
First switch ot lodash _.cloneDeep which would deep copy your entire object tree and also you can make your merge method more concise with ES6 spread etc.
You have to be aware that the spread syntax { ...state } does only a shallow copy of your object. So in a fact - the deeply nested properties - in your particular case { a: true, b: true, c: true } remain the same objects by reference. If you wish to avoid the state mutation error, you should use e.g. cloneDeep function from lodash.
merger(_.cloneDeep(state), payload);

How do i use spread syntax to copy the values of only specific keys from json object (returned from API)

In React Redux, Reducers state change needs to copy values of only specific keys. How do i do that using spread syntax.
const initialState = {
Information: {
Manufacturer: undefined,
Model: undefined
}
};
My structure is as above. I get a response from REST as below:
{
"#odata.context": "/redfish/v1/$metadata#ComputerSystem.ComputerSystem",
"#odata.id": "/redfish/v1/Systems/1/",
"Bios":{
"#odata.id": "/redfish/v1/systems/1/bios/"
"Manufacturer": "ABC"
}
How do i extract value of only Manufacturer.
If you have a code example, I could give a better answer, but here's a shot:
function getSpecificKeys (input) {
const { foo, bar, baz, ...other } = input
return { foo, bar, baz } // to return only foo, bar baz
// or, return every other key/value
// return other
}
Update
This is what I understood from your comment.
// You have a data structure like this:
const info = { a: undefined, b: undefined }
// You want to write a function that updates info with payload
// where payload looks like this
const payload = {
model: { a: "a value" },
date: { b: "b value" }
}
// therefore the function should look like this
function mergePayload (info, payload) {
const { model: { a }, date: { b } } = payload
return { ...info, a, b }
// NOTE that this will return a new object and not modify info reference
// if you want to MODIFY info, then do this:
// info.a = a
// info.b = b
}

Object not found in heapdump comparison

I've installed heapdump nodejs module in order to dump the heap object.
Using this code (nodejs6.9.1),
'use strict'
const heapdump = require('heapdump')
heapdump.writeSnapshot()
const obj = {
test: 2,
foo: 6.4,
wow: true,
a: { }
}
heapdump.writeSnapshot()
console.log(obj) // <-- make sure obj lives until here
I've printed two heap dumps.
Importing both of them into chrome dev tools and switching to the comparison mode, I'm aspecting to see the obj object at least (with some other values).
Instead, I see only those values:
(compiled code)
(array)
(system)
(concatenated
(string)
Why?
EDIT:
moving the code into a setTimeout, the dump diff shows the two Objects correctly
setTimeout(() => {
heapdump.writeSnapshot()
const obj = {
test: 2,
foo: 6.4,
wow: true,
a: { }
}
heapdump.writeSnapshot()
console.log(obj)
}, 1000)
NB: test and foo property is not in dump diff.
This code illustrates my comment for this question
heapdump.writeSnapshot()
const obj = {
test: 2,
foo: 6.4,
wow: true,
a: { }
}
heapdump.writeSnapshot(function(err, filename) { // this is the callback
console.log(obj);
})

underscore _.each not adding property to object element

This is kind of a newb question as there are still some small things about javascript that baffle me.
I have the following code:
db.units.find({}, { _id: 1, type: 1, name: 1 }).sort({ type: 1, name: 1}).exec(function(err, units) {
if(err) return next(err);
_.each(units, function(u, i) {
this[i]["available"] = !_.contains(_.pluck(_.pluck(req.workorder.units, 'unit'), 'name'), u.name);
console.log(this[i].available);
console.log(this[i]);
console.log(_.extend(this[i],{available:this[i].available}));
}, units);
return res.render('workorder/show', {
workorder: req.workorder,
invoices: db.invoices.find({ workorders: req.params.id }),
units: units
});
});
and here is the result:
true
{ _id: 513bd489b0e7e2634b60dc47,
name: 'Visual Sump Inspection UST-22C NC',
type: 'Service' }
its is logging the available property but not in the object alone, why is this?
The problem is related to how mongoose treats objects. the object can only be modified with the usage of document.toObject()
http://mongoosejs.com/docs/api.html#document_Document-toObject
Likeso:
_.each(units, function(u, i) {
u = _.extend(u.toObject(), {'available': !_.contains(_.pluck(_.pluck(req.workorder.units, 'unit'), 'name'), u.name)});
});
I suspect that Mongoose is defining the available property in a way that makes it readable but non-enumerable. It could be using a getter, or it could be setting enumerable: false with an Object.defineProperty() or Object.defineProperties call.
For a quick test, try pasting this code into the Chrome console or in your node.js app:
var obj = { a: 1 };
Object.defineProperties( obj, {
b: {
get: function() {
return 2;
}
},
c: {
value: 3,
enumerable: false
}
});
console.log( obj );
console.log( obj.a );
console.log( obj.b );
console.log( obj.c );
In Chrome, the code logs:
Object {a: 1}
1
2
3
So all three properties are showing up when read explicitly, but b and c are not enumerated when the object as a whole is logged.

Categories