I'm trying to write a test using JEST to a class I wrote with static properties that resembles the following:
class DataManager {
static #data = null;
static getData = () => {
return this.#data;
}
static initializeData = async () => {
await database(async (db) => {
const data = getSomeDataFromDatabase() //just example
this.#data = data;
});
}
}
Now, I want to make new implementation for my initializeData method, to returned some mocked data instead of going to the db, and then "getData" to see if I get the expected result. The problem is that my #data property is private and I don't want to expose it to the outside world. Is there any way to do it?
No, there is no way to do that. Private fields are really private. If you want to mock them in a test, don't use private fields. Or the other way round: if they're private (an implementation detail), you shouldn't mock them.
You need to either mock the entire DataManager class and its public methods, or if you want to test the DataManager itself then you'd mock the database and getSomeDataFromDatabase functions that it calls.
Related
How is it possible to make a singleton or even normal instance that will force calling a specific method?
For example:
logger.instance().configure({ logs: true });
OR
new logger();
logger.configure({ logs: true });
If calling for a logger without the configure method chained it’ll throw an Error.
Thanks!
Usually when we want to create a singleton, we need to hide constructor. We make constructor private. Why? It is necessary to avoid many instances of classes.
But next question can come to people's mind: "How to initialize variables?". We can do it through configure method:
class MyLogger
{
logs: boolean
private static _instance: MyLogger;
private constructor()
{
}
public static get Instance()
{
return this._instance || (this._instance = new this());
}
public configure({logs}){
this.logs = logs
}
}
const mySingletonInstance = MyLogger.Instance;
And you can configure it like this:
const mySingletonInstance = MyLogger.Instance.configure({logs: true});
I am trying to refactor (splitting by concepts) the following class:
import myService from "./myService"
...
export default function MyService() {
if (!isInstantiated) {
myService.configurate(configuration);
// Initialize Auth and Database
this.auth = myService.auth(); // myService.auth() has to be performed after myService.configurate()
this.database = myService.database(); // myService.database() has to be performed after myService.configurate()
isInstantiated = true;
}
}
MyService.prototype.methodAssociatedWithAuthConcept = function () {
...
};
... more mothods associated with the "Auth" concept
MyService.prototype.methodAssociatedWithDatabaseConcept = function (email, password) {
...
};
... more mothods associated with the "Database" concept
In a future, this class will be really big, so splitting it into other classes "Auth" and "Database" is my best option, but... myService.auth() and myService.database() has to be performed when myService.configurate(configuration) is done in the MyService constructor's singleton.
And, also, I have to be able to access Auth class and Database class from MyService class, instantiating them in the MyService singleton, in order to do:
const myServiceObj = new MyService();
myServiceObj.database.someMethodAssociatedWithDatabaseConcept();
Any ideas?
That sound like you need a factory.
Outsource your database and auth. Then write a factory that implements both of them on demand. Your factory can create a new constructor for every usecase. constructors are in fact just normal functions that call Object.create() and do some prototyping for you. Then they return the object created with Object.create(). But you can handle that totally by your own. So adding diffent calls in your constructor is easy.
Give your factory standard methods for accessing auth and database.
import your database and auth on demand
export an new generated class with all functions you need for your database and/or auth
I have a Javascript class (env: node.js v12 or above) defined like this:
module.exports = class MyClass extends SomeOtherClass {
// ...
static async someMethod() {
const result = await this.exampleSuperMethod()
return result
}
// ...
}
I'm extending SomeOtherClass, which defines a static method called exampleSuperMethod, which is used in my someMethod as described above.
Now, I'd like to define the someMethod method by using a function defined somewhere else. This is needed because the function is something generic and I'd like not to repeat the same code in my classes. More over, defining the function in an external module, I can test it once only and reuse everywhere my shared and tested code.
To achieve this, I'd like to have a function defined like the following:
const myMethod = (MainClass) => async () => {
const result = await MainClass.exampleSuperMethod({
// do something
})
return result
}
module.exports = myMethod
In this function, I'm allowing the dependency injection of MainClass (needed to reach the exampleSuperMethod), by exporting a high order function which defines my needed function with a closure.
With a class defined like this, I'll be able to mock simply the "main" SomeOtherClass and pass in to the high order function this mock, which exposes the exampleSuperMethod. In the real usage, my idea is to inject the this element and get back the function ready to be plugged in my class as a static method. But I'm not sure how to achieve this last point.
My main class could become something like the following:
const useMyMethod = require('./path-to-file/my-method.js')
module.exports = class MyClass extends SomeOtherClass {
// ...
// how to replace the following to use the
// function received by the call to
// useMyMethod(this) ?
//
static async someMethod() {
const result = await this.exampleSuperMethod()
return result
}
// ...
}
I'm wondering how to replace the initial definition of someMethod with the function returned by useMyMethod(this).
Thank you for your help!
I was asked to create a singleton that will have methods which it will operate on some data it holds. The data is loaded from a nearby CSV file, but I cannot find a way to do it in an asynchronous way.
This is a Vanilla JavaScript assignment.
I have this CSV file, which I want to load/ read only once, and then "hold" inside of my singleton. Since all of the singleton's methods regard this data, I don't think there is a reason to read it more than once, at the beginning.
Since reading (and parsing) it is a asynchronous work, and so are some expected methods, I can't find the right way/ place/ method to do it.
Searching the internet shows that if I choose to create a class, the constructor must NOT by asynchronous.
An IIFE pattern did not work for me as well...
I currently have no code, since nothing seems to work, unfortunately.
Any help will be highly appreciated!
There are a few ways you can do this. All of the approaches are fine, so it is personal preference.
1. Static Method
class CsvHandler {
static readFile(fileName) {
return new Promise(resolve => {
const instance = new CsvHandler()
// Process your csv file here
resolve(instance);
}
}
}
const csvHandler = CsvHandler.readFile('fileName.txt')
2. Factory Method
class CsvHandler {}
class CsvFactory {
readFile(fileName) {
return new Promise(resolve => {
const instance = new CsvHandler()
// Process your csv file here
resolve(instance);
}
}
}
var csvFactory = new CsvFactory(),
csvHandler = csvFactory.readFile('fileName.txt')
You can add a method to your class that builds an instance of the class with the required data having fetched the CSV file.an example is this:
class Importer{
private importerInstance: Importer
private constructor(private csvData){
...
}
// returns an instance of the importer
static async composeInstance(path to CSV){
... retrieve file content asynchronously
if(!this.importerInstance) {return new Importer(<result of async csv fetching>)} else {return this.importerInstance}
}
}
Let me know if it makes any sense. I could try to do a more elaborate example for you
I have a TypeScript model which contains properties and functions like:
class Person {
name: string
sayHello(){ console.log(name); }
}
When creating its instance I can make use of this sayHello() method as expected.
The problem comes when I store and get the object from the local storage or an external web service.
While the properties are still present the methods have disappeared. (obviously because it’s just text).
Is there any way to restore the completeness of the object to be able to use its functions?
Or otherwise, is there any other technique? For instance, helper class that can work with type.
When you save to a local storage, you will save a JSON representation of the class data; when you get the object back from the local storage, it will be just an object, not an instance of the original class.
You can look for an external library that will help you with this, but the simple solution is to create a new instance of the class and assign the field values to the class using Object.assign:
class Person {
public constructor(public name?: string){}
sayHello() { console.log(name); }
}
let p = new Person("Test");
let data = JSON.stringify(p);
let p2 = new Person()
Object.assign(p2, JSON.parse(data));