How do I test a function that is in a class with Jest - jestjs

I have a function that is in a class :
Simplified version :
export class Button {
getAttributes(el) {
//random code that was removed for simplicity
return dataAttrs;
}
}
I was wondering how do I test this in Jest.

Here is what worked for me :
test('get attributes on element', () => {
let button= new Button();
var element = document.createElement('a');
element.setAttribute('href', 'https://www.google.ca/');
element.innerHTML = 'Test';
expect(breadcrumb.getAttributes(element)).toBe('Hello');
});

if there is simple class like the one that u define u can do:
it('We can check the class constructor', () => {
const classObject = new classObject();
expect(classObject ).toHaveBeenCalledTimes(1);
});
and use whatever the methods that Jest have.
But if there are complex classes and methods that ones are dependent from others i suggest you to read this and you can automatize it or can do it manually, mock the dependences and test it out.

Related

How can I call a function of an exported function of a module in another script? NodeJS

I want to use a function, which is inside another function (function2) in another js file (2nd.js).
My current code looks something like this:
1st.js
module.exports = {
function1(){
function2(){
//...
}
}
}
2nd.js
const { function2 } = require("1st.js")
function2()
This sadly doesn't work and I have no idea how to solve this problem.
You can work with class approach or some older syntax. Any of these approaches results in the same thing, after all, the class syntax in JavaScript is just a thing for programmers, and does not affect the code at all. It is called syntax sugar.
See in the example below how to solve your problem without classes:
Export a object "container" with your functions:
Just as you referred in your example, 1st.js
export default {
functionOne: () => {
console.log("one");
},
functionTwo: (num) => {
console.log(num);
},
functionThree: ({number}) => {
console.log(number);
},
}
And import it with any name you want
...and so on, 2nd.js
import myFunctions from "../myFunctions";
const { functionOne, functionTwo, functionThree} = myFunctions;
functionOne();
functionTwo("two");
functionThree({number: "three"});

Passing path parameters in axios

I am using Axios with NodeJs and trying to pass path parameters in axios.get() method. For example, if URL is url = '/fetch/{date}', I want to replace {date} with the actual date while calling axios.get(url).
I went through the source code on Github and StackOverflow, but couldn't find any method.
Is it possible to keep URLs with parameters as a placeholder and replace them while actually calling the get method of Axios?
Axios doesn't have this feature and it looks like the team don't want to add it.
With credit to previous responders for inspiration, to me this seems like the solution closest to what you (and me) are looking for:
1 - Where you want to store all your URLs and their parameters, define them as functions which use a template string to return the composed URL:
export var fetchDateUrl = (date) => `/fetch/${date}`;
If you need any type-specific formatting of the value being concatenated into the URL, this function is a good place to do it.
2 - Where you want to make the request, call the function with the correct parameters:
import { fetchDateUrl } from 'my-urls';
axios.get(fetchDateUrl(someDateVariable))...;
Another variation, if you really like the idea of naming the parameters at the call site, you can define the URL function to destructure an object like this:
var fetchDateUrl = ({date}) => `/fetch/${date}`;
which you'd then use like this:
axios.get(fetchDateUrl({date: someDateVariable}));
Use template strings
url = `/fetch/${date}`
Or just tag it on
url = '/fetch/'+ date
I think using axios interceptors is better to do this :
//create your instance
const instanceAxios = axios.create({
baseUrl: 'http://localhost:3001'
]);
instanceAxios.interceptors.request.use(config => {
if (!config.url) {
return config;
}
const currentUrl = new URL(config.url, config.baseURL);
// parse pathName to implement variables
Object.entries(config.urlParams || {}).forEach(([
k,
v,
]) => {
currentUrl.pathname = currentUrl.pathname.replace(`:${k}`, encodeURIComponent(v));
});
const authPart = currentUrl.username && currentUrl.password ? `${currentUrl.username}:${currentUrl.password}` : '';
return {
...config,
baseURL: `${currentUrl.protocol}//${authPart}${currentUrl.host}`,
url: currentUrl.pathname,
};
});
// use like :
instanceAxios.get('/issues/:uuid', {
urlParams : {
uuid: '123456789'
}
})
For typescript users, you will need to add this, in one of your .d.ts
declare module 'axios' {
interface AxiosRequestConfig {
urlParams?: Record<string, string>;
}
}
( this is a POC, not really tested, doesn't hesitate if you see something wrong )
You can use template strings ie:
let sellerId = 317737
function getSellerAnalyticsTotals() {
return axios.get(`http://localhost:8000/api/v1/seller/${sellerId}/analytics`);
}
Given some API /fetch/${date} you likely want to wrap your axios call in a function.
const fetchData = (date) => axios.get(`/fetch/${date}`);
fetchData(dateObject.toFormat('yyyy-mm-dd'))
.then(result => { ... });
This requires the calling code to format date correctly however. You can avoid this by using a DateTime library that handles date string parsing and do the format enforcement in the function.
const fetchData = (date) => axios.get(`/fetch/${date.toFormat('yyyy-mm-dd')}`);
fetchData(dateObject)
.then(result => { ... });
you can do like this:
getProduct = (id) => axios.get(`product/${id}`);
I always do it like this:
const res = await axios.get('https://localhost:3000/get', { params: { myParam: 123 } });
I find this to be much clearer than template strings.
More explanation here

Fabricjs - clarification with extending toObject method with additional attributes

I got the following code form fabric JS site as mentioned this code is for extending rectangle class with additional property, But I can't understand how it works clearly can someone please explain this piece of code
var rect = new fabric.Rect();
rect.toObject = (function(toObject) {
return function() {
return fabric.util.object.extend(toObject.call(this), {
name: this.name
});
};
})(rect.toObject);
canvas.add(rect);
rect.name = 'trololo';
This code is not extending the toObject method of all the fabric.Rect(s).
Is overwriting the toObject method of your particular instance of fabric.Rect, hosted in the rect var you just created.
(function(toObject) {
return function() {
return fabric.util.object.extend(toObject.call(this), {
name: this.name
});
};
})(rect.toObject);
fabric.util.object.extend is like lodash merge. It takes an object as first argument and adds to it the properties of the object from the second argument.
to.Object.call(this) is calling the function toObject that is the first argument of the wrapping function, that is rect.toObject before being modified.
Fabric support this functionality without modifying the code but using:
rect.toObject(['name']);
Or a nicer way to write this would be:
var originalToObject = fabric.Rect.prototype.toObject;
fabric.Rect.prototype.toObject = function(additionalProps) {
var originalObject = originalToObject.call(this, additionalProps);
originalObject.name = this.name;
return originalObject;
};
In this case can be more clear.

How to work around the require(“../../../../../../../”) frustration In NodeJS?

Any better ways of solving this kind of problem in node.js below?
import foo from "../../../modules/home/models/index.js"
import bar from "../../../modules/about/models/index.js"
import baz from "../../../modules/contact/models/index.js"
At least making them into something like this?
import foo from "/home/models/index.js"
import bar from "/about/models/index.js"
import baz from "/contact/models/index.js"
Any ideas?
You need inversion of control.
./modules/home/index.js
const homeModel1 = () => {
//...
}
const homeModel2 = () => {
//...
}
module.exports = Object.assign({}, { homeModel1, homeModel2 })
1. An object will be exported of the following shape:
{
homeModel1: () => {},
homeModel2: () => {}
}
2. When you add a new model, simply add it or import it into this file and then add it to the export object.
./modules/index.js
import { homeModels } from './modules/home'
import { aboutModels } from './modules/about'
import { contactModels } from './modules/contact'
module.exports = Object.assign({}, { homeModels, aboutModels, contactModels })
The models are destructured out and then exported as methods on a new object.
Likewise, same shape object is exported with all your models cultivated together, bringing all their dependencies with them.
somewhere else
import modules from './modules'
const query = modules.homeModels.homeModel1()
Bonus:
To clarify, Object.assign({}, obj1, obj2) creates a new object with the prototype set to the Object prototype, and merges the properties and methods of obj1 and obj2. In this simple form, it is essentially the same as const obj = {}.
A bit more advanced, is Object.assign({}, { obj1, obj2 }) which makes obj1 and obj2 properties on the new object. You can do some simple testing to get a feel for the data structures.
We also used some destructuring. If you are having issues getting things lined up properly, you should look at those aspects plus how you are importing them into a file. For example, import obj1 from './modules' will bring the entire object in from ./modules, but import { obj1 } from './modules' will destructure obj1 from the object that it pulls in, so obj1 was a method/property of the object.
Do some research into inversion of control and dependency injection.

Export class and instanciate it immediately on import

I have a ES6 class in NodeJS 4 :
vehicule.js
"use strict";
class Vehicule {
constructor(color) {
this.color = color;
}
}
module.exports = Vehicule;
When I need to instanciate in another file, I find myself doing this :
var _Vehicule = require("./vehicule.js");
var Vehicule = new _Vehicule();
I'm new to nodeJs, is there a way to do this in one line, or at least in a more readable way ?
A class is really supposed to be reused for many objects. So you should require the class itself:
var Vehicule = require("./vehicule.js");
and then create objects from it:
var vehicle1 = new Vehicule('some data here');
var vehicle2 = new Vehicule('other data here');
Usually classes start with an upper case letter, and instances of classes (objects themselves) with a lower case one.
If you want a "class" for just one objects, you can just create an inline object:
var vehicle = {
myProperty: 'something'
};
module.exports = vehicle;
//in some other file
var vehicle = require('vehicle');
Though if you really, really want to do that in one line, you can do:
var vehicle = new (require('vehicle'))('some constructor data here');
But that is not recommended. Pretty much ever.
If you really want to do this in one line:
var Vehicule = new (require('./vehicule'))('red');
but personally i would prefer two lines for the same reasons mentioned by #ralh.

Resources