Understanding module.exports in regard to JavaScript Classes - javascript

While I'm not huge into forcing OOP into a functional language, I'm struggling to understand what a peer of mine did to export modules from a Class. All I'm looking for is what to call this so I can continue to do research. From what I understand they were including some external SDK to be passed into an internal class which would inherit everything into the LibIncludes. This is suppose to allow all of the classes to inherit into the LibIncludes and LibIncludes inherits from Object. What I'm running into now is that anytime I try to call LibIncludes.Handlers; and execute a function included in Handlers I'm getting undefined. I can't figure out what pattern he applied to make this work and everything in ES6 shows an entirely different approach to exporting and importing between classes for inheritance. Any help would be greatly appreciated.
// index.js
const ExternalSdk = new SDK.Function();
const HandlerService = require('./hander/handler.js');
class LibIncludes {
static compose() {
const Handler = new HandlerSvc(ExternalSdk);
return {
Handler
};
}
}
module.exports = LibIncludes;
let function = LibIncludes.sdkFunciton;
// function should be invoked and return some object

Here's the solution I came up with for refactoring. It seems cleaner and without the static members:
// index.js
const ExternalSdk = new SDK.Function();
const HandlerService = require('./hander/handler.js');
module.exports = class LibIncludes {
constructor(handler) {
this.handler = new HandlerSvc(ExternalSdk);
}
}
// app.js
const lib = require('./index');
var getSomething = new lib();
console.log(getSomething.handler);
// function should be invoked and return some object

Related

Am I using React hooks wrong?

I wanted to create a sevice-like hook that doesn't hold state, it just exports an object with funtions.
I first started with this:
export default useFoo = () => ({ // some functions here... });
But then I realized that this wouldn't be the best approach because a new object is going to be created every time the hook is called and I don't want that - I need one global object with the same reference across all components, so then I tried this:
const foo = { // some functions here... };
export default useFoo = () => foo;
It works as expected, but I'm not sure if it's the right way to do it. Is there a better way to achieve this? Or should I use context maybe?
EDIT: I know that I can just export a plain JS object and not bother myself with hooks, but I need it to be a hook because I use other hooks inside.
It works as expected, but I'm not sure if it's the right way to do it. Is there a better way to achieve this?
If foo never changes, and doesn't need to close over any values from the other hooks you're calling in useFoo, then that's fine. If it does need to change based on other values, then you can use useCallback and/or useMemo to only recreate the object when relevant things change.
export default useFoo = () => {
const something = useSomeHook();
const foo = useMemo(() => {
return { /* some functions that use `something` */ }
}, [something]);
return foo;
}

Private methods in React service function component

I'm a bit new to React and I'm currently developing a Proyect which has a service layer. To do so, I created a function component which would have the methods as variables:
const CustomComponent = () => {
method1 = () => {...},
method2 = () => {...},
method3 = () => {...}
}
export default CustomComponent;
This component would then be imported to the component that will use it.
To make my architecture as clean as possible, I wanted to make some of the methods private. However, as you may already know, that is not possible to do in the solution I proposed. Do hoy have an idea on how to achieve this, or maybe there is a convention to make a service layer I'm not aware of?
Thank you so much in advance!
The architecture which I find particularly clean and maintainable is one where you split off logic from presentation into two files like this:
Service layer (ts):
export class Service implements ServiceInterface {
constructor(private instanceVariable: string = "foo") { }
private methodOne(): string {
return this.instanceVariable
}
public methodTwo(argumentVariable: string): string {
const importantString = this.methodOne();
return importantString + argumentVariable;
}
}
interface ServiceInterface {
methodTwo(argumentVariable: string): string;
}
export default new Service();
Service layer (js):
export class Service {
instanceVariable;
constructor(contructorArgument) {
this.instanceVariable = contructorArgument;
}
methodOne() {
return this.instanceVariable
}
methodTwo(argumentVariable) {
const importantString = this.methodOne();
return importantString + argumentVariable;
}
}
export default new Service();
Presentation layer:
import Service from "./service.ts";
const FunctionalComponent = () => {
const [localState, setLocalState] = useState(localStateInit);
return (
<>
<div>{Service.methodTwo("bar")}</div>
</>
)
}
Few things happen here (mostly regarding ts implementation).
Keep component's service and presentation layers in separate files.
Use an interface to describe the service class and its methods. This will help to work with your service layer in your component as you'll get Typescript's IntelliSense.
For this example I'm exporting an instance of the service as default export from its file. This gives you a cleaner API in your component's file, where you can call methods without having to "pollute" component file with instance creation. This has at least the following two drawbacks:
you mostly lose ability to work nicely with static class members
preconfigured instance variable (initiated as a private member in constructor) means its value cannot be replaced in testing.
If any of above are a no go, then clean up the constructor, export just the class itself and instantiate it as required in component file.
I'm also exporting the class itself. This is for testing purposes. In testing you want to be able to swap out arguments passed into class' constructor and you need to have class definition to do that.
You'll notice the shorthand notation for declaring and instantiating a private class variable in the constructor: private instanceVariable: string = "foo". This is equivalent to something like this:
class Service {
private instanceVariable: string;
constructor(constructorArgument: string) {
this.instanceVariable = constructorArgument;
}
Such notation is particularly nice when used with dependency injection.
Overall, this setup will help you with unit testing logic in your service layer, as you can test it like any other class. This comes particularly handy when there's a lot of conditional rendering logic.
Let me know if this is what you've been looking for. Maybe we could tailor it better for your use case.

TypeScript and Jest - auto creation of full mocks?

I am working with NestJS and to make testing easier I am trying to create something like Moq in .NET which gives complete mock based on the class with all methods mocked etc.
To clarify: when I have ClassA with methods testA and testB, I want my function to return an object which has these methods mocked with jest.fn() without having to create these objects every time by the hand.
I can get it working with pure JS without any issues:
export function getMockedClass<T>(classDef: T): MyAutoMock<T> {
const methods = Object.getOwnPropertyNames(classDef);
const constructorIndex = methods.findIndex((m) => 'constructor');
if (constructorIndex >= 0) {
methods.slice(constructorIndex, 1);
}
const mock: any = {};
methods.forEach((methodName) => {
mock[methodName] = jest.fn();
});
return mock;
}
However I am struggling to create type for MyAutoMock to get it accepted by TS as proper instance of the given class. Replacing MyAutoMock<T> with just :T obviously does not work.
Anyone with an idea?

Mocking functions in Jest

I am new to JavaScript testing and currently trying to write some test cases for a store (just an ES6 class) I created. I am using Jest as this is what we usually use for React projects, although here I am not testing a React Component but just a class wrapping a functionality.
The class I am testing extends another class, and has various methods defined in it. I want to test these methods (whether they are called or not), and also whether the properties declared in the class change as and when the corresponding class methods are called.
Now I have read about mocking functions, but from what I understand, they can only do checks like how many times a function is called, but can't replicate the functionality. But in my case, I need the functionality of the methods because I will be checking the class member values these methods change when called.
I am not sure if this is the right approach. Is it wrong to test functions in Jest without mocking? And inferentially, to test the internal workings of functions? When do we mock functions while testing?
The issue I am facing is that the project I am working on is a large one where there are multiple levels of dependencies of classes/functions, and it becomes difficult to test it through Jest as it will need to go through all of them. As I am using alias for file paths in the project, Jest throws errors if it doesn't find any module. I know its possible to use Webpack with Jest, but many of the dependent classes/functions in the code are not in React, and their alias file paths are not maintained by Webpack.
import { getData } from 'service/common/getData';
class Wrapper extends baseClass {
someVariable = false;
payload = null;
changeVariable() {
this.someVariable = true;
}
async getData() {
super.start();
response = await fetchData();
this.payload = response;
super.end();
}
}
This is a small representation of the actual code I have. Can't post the entire class here as I am working on a remote machine. Basically, I want to test whether changeVariable gets called when invoked, and whether it successfully changes someVariable to true when called; and similarly, check the value of payload after network request is complete. Note that fetchData is defined in some other file, but is critical to testing getData method. Also the path used here (service/common/getData) for importing getData is not the absolute path but an alias NOT defined in Webpack, but somewhere else. Jest can't resolve getData because of this. I will not have to worry about this if I mock getData, but then I will not be able to test its functionality I believe.
#maverick It's perfectly okay to test your class methods using jest. Check the code example in the link -
https://repl.it/repls/ClumsyCumbersomeAdware
index.js
class Wrapper {
constructor(){
this.someVariable = false;
}
changeVariable(){
this.someVariable = true;
}
getData(){
return new Promise(resolve => resolve('some data'));
}
}
module.exports = Wrapper;
index.test.js
const Wrapper = require('./index');
const wrapper = new Wrapper();
describe('Wrapper tests', () => {
it('should changeVariable', () => {
wrapper.changeVariable();
expect(wrapper.someVariable).toBe(true);
});
it('should get some data', () => {
wrapper.getData().then( res => expect(res).toBe('some data'));
});
});
This is a very simplistic example and in real life the async calls are much more complicated and dependent of 3rd party libraries or other project modules. In such cases it makes sense to have all the dependencies injected in out class and then mocked individually. For Example -
class GMapService {
constructor(placesApi, directionApi){
this.placesApi = placesApi;
this.directionApi = directionApi;
}
getPlaceDetails(){
this.placesApi.getDetails('NYC');
}
getDirections(){
this.directionApi.getDirections('A', 'B');
}
}
Now you can easily mock placesApi and directionApi, and test them individually without actually requiring Google Map dependencies.
Hope this helps ! 😇

What are the differences between using Object.assign and class/extends?

I am trying to understand how Facebook Flux works by looking at the source code of their flux chat example.
There, I saw this code:
var MessageStore = assign({}, EventEmitter.prototype, {
emitChange: function() {
this.emit(CHANGE_EVENT);
},
/**
* #param {function} callback
*/
addChangeListener: function(callback) {
this.on(CHANGE_EVENT, callback);
},
...
}
...
module.exports = MessageStore;
...where assign is just polyfilled Object.assign from ES6 spec.
Hm. Would this code, using classes and extends instead, work? Would it mean the same thing? What are differences and advantages/disadvantages of this approach?
class MessageStore extends EventEmitter {
emitChange() {
this.emit(CHANGE_EVENT);
}
addChangeListener(callback) {
this.on(CHANGE_EVENT, callback);
}
...
}
module.exports = new MessageStore();
I am asking, because, coming from other languages, I intuitively understand class/extends, while prototype-based inheritance is always a little unclear to me.
Here is working code that you can use with regards to ES6 syntax and your situation:
import EventEmitter from 'events';
const CHANGE_EVENT = 'change';
class MessageStore extends EventEmitter {
constructor() {
super();
}
addChangeListener = (callback) => {
this.on(CHANGE_EVENT, callback);
}
removeChangeListener = (callback) => {
this.removeListener(CHANGE_EVENT, callback);
}
emitChange = () => {
this.emit(CHANGE_EVENT);
}
}
Note, I prefer the ES6 function literal syntax because it ensures that "this" is always bound to the enclosing object context.
For a fully working ES6 store example, please feel free to review the stores code in my Babel React Starter App
This is also a useful reference on ES6 classes that visually explains what is going on inside the body of a class definition.
class extends:*
You are extending a generic class, which is sometimes exactly what you want, e.g. a button extends a domElement, but a button should not extend an EventEmitter because they have nothing in common.
Object.assign:
With Object.assign you are "mixin" a new functionality into the target object, e.g. a Store may mixin an EventEmitter. In Java you would use Store implements EventEmitter which is a bit more self explaining.

Categories