How to mock with JestJS injected dependency in class ES6? - node.js

I'm trying to get some dependance inversion going in a small NodeJS project. I want to have mocked instances of personal classes that I can inject in other classes.
This is for the lates node and jest version, I have read Jest documentation and nothing seem to be what I'm looking for.
class A {
getStr(): string {
return "bob";
}
}
class B {
private a: A;
constructor(a: A){
this.a = a;
}
getA(): string {
return a.getStr();
}
}
const b = new B(mocked instance of A)
I expect to be able to interact with the injected mock and see if it's been called in unit testing.

Assuming you would like to spy on the functions of A, you could do it as follows (if you would like to keep using classes notation):
class MockA {
constructor() {
this.getStr = jest.fn()
}
}
const mockedA = new MockA()
const b = new B(mockedA)
Then to test that it was called, you could do it as follows:
b.getA();
expect(a.getStr.mock.calls.length).toBe(1)
To create the mock without the class, you could do so as follows:
const mockedGetStr = jest.fn()
const b = new B({ getStr: mockedGetStr })
b.getA();
expect(a.getStr.mock.calls.length).toBe(1)

Related

What is the difference between a singleton and a module that instantiates an instance?

I want to add a metrics class to my code. What is the difference between
class MyMetrics {
constructor () {
if (!Singleton.instance) {
Singleton.instance = new Metrics()
}
return Singleton.instance
}
}
const metrics = new MyMetrics()
and
export const metrics = new Metrics()
Wouldn't each module that imported metrics be using the same Metrics instance?
Are they functionally the same for my usage? Which would be recommended?
Wouldn't each module that imported metrics be using the same Metrics instance?
Yes, they would.
Are they functionally the same for my usage?
As long as A) you aren't creating other instances within the module and B) you aren't exporting Metrics, yes, almost. But one thing to remember is that any code that has access to your metrics import has access to your Metrics constructor, indirectly via the constructor property metrics inherits from Metrics.prototype:
import { metrics } from "./your-module.js";
const newMetrics = new metrics.constructor();
You might think that with the singleton, you've avoided that, but that's easily defeated as instance is public:
import { metrics } from "./your-module.js";
const Metrics = metrics.constructor;
Metrics.instance = null;
const newMetrics = new Metrics();
So you might want to make it private (either using a static private property, or just using metrics itself to check if you've created it).
Which would be recommended?
That's a matter of opinion. But you might not even need a class at all. You could:
Just make an object directly without a constructor function.
Export functions and close over module-private variables.
For instance, consider this (fairly silly) class:
// stuff.js
class Stuff {
#items = new Map();
constructor() {
// ...pretend there's singleton logic here...
}
put(key, value) {
this.#items.set(key, value);
}
get(key) {
return this.#items.get(key);
}
}
export const stuff = new Stuff();
The way you use that is:
import { stuff } from "./stuff.js";
stuff.put("this", "that");
stuff.get("this"); // "that"
You could just get rid of the class entirely:
// stuff.js
const items = new Map();
export const stuff = {
put(key, value) {
items.set(key, value);
},
get(key) {
return items.get(key);
}
};
Usage would be the same:
import { stuff } from "./stuff.js";
stuff.put("this", "that");
stuff.get("this"); // "that"
Or you could just export put and get:
// stuff.js
const items = new Map();
export const put = (key, value) => {
items.set(key, value);
};
export const get = (key) => items.get(key);
Then usage is:
import { get, put } from "./stuff.js";
put("this", "that");
get("this"); // "that"
Or if those names may conflict with other things:
import { get as getStuff, put as putStuff } from "./stuff.js";
putStuff("this", "that");
getStuff("this"); // "that"
So you have lots of options to choose from. Constructor functions (including ones created with class syntax) are useful if you need to construct multiple objects with shared characteristics, but if you aren't doing that (and you aren't with a singleton), just writing the object directly or (with modules) exporting the things it can do directly may be good options for you.

What is the right way to export the class to be extended from other classes NodeJs?

Base class looks like this:
class BaseReport {
constructor(reportName) {
this.reportName = reportName;
}
async generateReport(accountId, request) {
let results = await this.getDataFromDb(request);
results = this.formatResults(results);
return updatedResults;
}
formatResults(data) {
//Some logig here
return result
}
getDataFromDb(request) {
//Logic to get data from database
return errorRequest;
}
}
module.exports = BaseReport;
The I have another class that extends Base class:
const BaseReport = require("./base.service");
class DataReport extends BaseReport {
constructor() {
super('dataReport');
}
formatResults(data) {
//Logic to format results in a different way
return data;
}
}
module.exports = new DataReport();
So far everything works well. DataReport class doesn't need to implement the method getDataFromDB because it is inherited from BaseReport class.
The problem starts when I am writing unit/integration tests.
When I try to stub function getData() it is not working (it is not being stubbed but instead it is calling the method and making the database call.
I understand WHY is happening... In BaseReport class I am exporting the class itself. So when I create an object on my unit tests and try to stub the function, that is not the same method and object which is initialized when the application is running. Every time you use the keyword "new" creates a new object and has its own methods.
If I want to stub a method from DataReport class it works fine because in there I am exporting an object of that class (module.exports = new DataReport();). In this case, it can only exist one copy of the object and so only one copy of the methods as well.
Now I can not do the same for BaseReport class because my understanding is that you CAN NOT extend BaseReport class if I exported a new object (module.exports = new BaseReport();).
What is the proper way to implement this in order to also have the unit tests working??

How to use class functions in another class?

How can i use class instance in another class like a pointer in C++ to class instance functions?
Example:
class A {
constructor()
{
this.block = [];
}
method()
{
return this.blocks.length;
}
}
another class:
class B {
constructor(instance)
{
this.instance = instance;
}
method()
{
this.instance.method(); // here i'm getting cannot get length of undefined
}
}
If i'm trying to to like that i'm getting problems to call it
You can try this. Here, when creating B class's instance I give into it an A class's instance as argument. Then inside B we can call A instance's methods, and access its properties.
Also, as #ViaTech posted you can use static methods to access them without needing to initialize an object of the class. That is what static methods is. Refer Static Methods
class B {
constructor(instance)
{
this.instance = instance;
}
method()
{
this.instance.method();
}
}
class A {
constructor()
{
}
method()
{
console.log("A's method");
}
}
var a = new A();
var b = new B(a);
b.method(); // A's method
You can easily do this in JS by calling a static method like so:
class A {
static write(){ //static method
console.log("Called write from A");
}
}
class B {
doIt(){
A.write();
}
}
let b = new B();
b.doIt();
Option 2, you instantiate the class in the constructor of the other like so:
class A {
write(){
console.log("Non-static write() called from class A");
}
}
class B {
constructor() {
this.a = new A();
}
doIt(){
this.a.write();
}
}
let b = new B();
b.doIt();
There are a few ways:
I accidentally switched between PHP and Javascript, but the principles are the same for both)
Use static functions:
Normally, you have a this in the class. Say you have this code:
class Car {
let color;
public function setColor(newColor){ this.color = newColor;}
}
let car = new Car();
car->setColor('green')`
The setColor function's this refers to that car. You can make let anotherCar = new Car(), then when you do anotherCar->setColor('red') you only change that car, not the first one. Simplistic: You can create multiple instances.
If you do not need that, but need the class once, you can make it static. A simple way to explain would be "you have a collection of seperate functions, just put into a wrapping class (which doesn't do a lot really)". For instance, you might have some sanatizing methods:
class Sanitize {
static function makeHtmlSave(input){
return doYourMagicHere(input);
}
static function removeXssCode(input){
return doMoreMagicHere(input);
}
}
This way, you can reuse it multiple times. If you want to use it, you do Sanitize::makeHtmlSave(someCode) where you need it. There isn't a Sanitize thing, it's just a wrapper to access the frunctions inside it.
Use extend:
You can extend a class. Say you have a generic class Vehicle, which has some properties (eg a motor, numberWeels, color) and you can extend that with more specific classes:
class Vehicle {
let color;
public function setColor(newColor){ this.color = newColor}
}
class Car extends Vehicle {
let hasAirco = false;
public function hasAirco(newValue){ this.hasAirco = newValue};
}
If you do let car = new Car(), you get a Car object, that extends/enlarges/complements the Vehicle class, so you can use both its (public) functions. Internally, Car can use the functions of Vehicle too.
Just pass it
class One {
// some stuff
}
class Two{
let otherObject;
construct(givenObject){
this.otherObject = givenObject;
}
}
You can now do this let a = new One(); let b = new Two(a);. You can not use the functions of One inside Two, but you can still use a->doSomething(). This solution feels like the easiest, but it almost never is. Classes/objects are tricky stuff, but I've rarely uses this solutions. There are use cases, but often it's a bad smell indicator.

Why is the constructor invoked despite calling createStubInstance?

I want to prevent the constructor of a class being called during a test so I used createStubInstance(MyClass) as per the docs, but the constructor still gets invoked. Why?
If you want to create a stub object of MyConstructor, but don’t want
the constructor to be invoked, use this utility function.
var stub = sinon.createStubInstance(MyConstructor)
Test
const sinon = require('sinon')
const Fizz = require('../Fizz')
const Buzz = require('../Buzz')
describe('Fizz', () => {
it('should mock the constructor', () => {
sinon.createStubInstance(Fizz)
const doStuffFakeFizz = sinon.stub(Fizz.prototype, 'doStuff').returns({ src: 'mock' })
const buzz = new Buzz()
buzz.doStuff()
expect(doStuffFakeFizz.called).toBeTruthy()
})
})
Buzz
const Fizz = require('./Fizz')
class Buzz {
doStuff() {
const fizz = new Fizz()
return fizz.doStuff()
}
}
module.exports = Buzz
Fizz
class Fizz {
constructor() {
console.log('CALLED')
this.thing = { src: 'real' }
}
doStuff() {
return this.thing
}
}
module.exports = Fizz
sinon.createStubInstance can't replace references like that. All it does is return a plain object with a stub in place for each property in the constructor's prototype. You'll usually make this object the return value of some stub, or provide it as an argument somewhere, in order to get it into place.
In order to actually stub the Fizz constructor, your code under test needs to invoke it by means of a reference that can be replaced. See my answer here:
Can ES6 constructors be stubbed more easily with Sinon?

How to make Module Functions access a Class context in node.js

I am trying to use a more object oriented approach with node.js "embedding" functions ( if that is the right word ) so that I can use functions and objects as if they are in the objects context. It might be easier to show in code.
I realise you can assign individual functions in the constructor - and this would work.. but I am not sure how to assign a whole module with functions to all the functions can access values in the objects context.
So , my question is : How can I assign a module to a class so that all the functions within the module can access everything within the objects context.
app.js
const myFunctions = require('./functions');
class myClass{
constructor() {
this.myFunctions = myFunctions ;
}
}
var mc = new myClass();
mc.myObject = { aaa: 'test'}
mc.myFunctions.outputValue(); // << should output the previous value set.
functions.js
function outputValue(){
console.log(this.myObject)
}
module.exports = {
outputValue
}
You could do it in two ways:
1 - Bound your class instance this to each one of the external functions:
class myClass {
constructor() {
this.myFunctions = {
outputValue: myFunctions.outputValue.bind(this),
};
}
}
2 - Define a method in your class to call the external functions, like:
class myClass {
constructor() {
}
callFunction(fnName) {
const fn = myFunctions[fnName];
if (fn) fn.apply(this);
}
}
Said that I will recommend avoiding using classes and this at all (at least it's completely necessary) and instead use pure functions, functions that only receive parameters does some processing and return some value.
The best way to do this which also follows the injection pattern,
const myClass = new myClass(myFunctions);
myClass.outputValue.bind(myClass);
Here it binds and inject all the class objects so it is accessible to other methods in different class .
Note : Look at "bind" usage.

Resources