Accept argument in node_module require - javascript

I am creating a node module and I am hoping to force the user to pass an argument during module require.
Like this:
const sample = require('sample-module')('username')
Inside my sample-module, I have declared the public functions like this (these are imports from other files):
module.exports = {
addNewFolder: folderHandler.addNewFolder,
printToFile: printHandler.printToFile,
deleteFolder: folderHandler.deleteFolder
// more functions
}
// Here I want to add a function that will accept the argument passed.
function setUserName(name) {
// some handling here, in this case, 'name' is 'username' as we passed in during require
}
How can I do this?
Lastly, I prefer to require using like this:
const sample = require('sample-module')('username')
Rather than:
const sample = require('sample-module')
sample.setUserName('username')
Help anyone? Thanks!

You can change module.exports to function like this
const test = (arg) => {
console.log(arg);
};
module.exports = function (requireArg) {
return {
test: test(requireArg),
};
};
then require it
const { test } = require('./test')('apple');

Related

Using a function defined inside an exports function, from another file

I have some code like this in a file helperFunctions.js:
exports helperFunctions = () => {
const functionA = async(args) => {
console.log(args);
};
const functionB = async(args) => {
functionA(myArg);
};
}
How can I call functionA and functionB from a separate file altogether, say, main.js?
I've tried:
import { helperFunctions } from './helperFunctions';
//...some code
helperFunctions.functionA('hello');
// OR
functionA('hello');
The specific error is:
TypeError: _helperFunctions.helperFunctions.functionA is not a function
and when trying the second solution, it's:
ReferenceError: functionA is not defined
I'm trying to avoid importing literally every single function I'm using (by way of exporting every single function I'm using). I'd like to do something like helperFunctions.function for the functions I need.
It really need to be a function? You could export an Object:
// helperFunctions.js
let helperFunctions = {
functionA: async (args) => {
console.log(args);
},
functionB: async (args) => {
functionA(myArg);
}
}
exports helperFunctions;

Have a function from a module be exported in another module?

I have a fairly large function in my module (./myMainModule.js) that I would like to be packaged in a separate module (./mySubModule. I'm trying to figure out how to require(mySubModule) and then have a function from mySubModule be used as a function in myMainModule.
I've tried to export
mainFunction: mySubModule.subFunction(params),
but it's saying the params are not defined.
//myMainModule.js
const mySubModule = require("./mySubModule)
module.exports = {
mainFunction: mySubModule.subFunction(params),
}
//----------
//mySubModule.js
module.exports {
subFunction: function(params) {
console.log(params);
}
}
I'm getting params is not defined when assigning the function in myMainModule.
const subModule = require("./subModule");
module.exports = {
mainFunction: subModule.subFunction,
// This works ^^
//mainFunction : subModule.subFunction(params),
// Not this ^^
}
My linter was complaining that my params were not defined. I was actually calling the function when I should have been just referencing it. I did not need to worry about the parameters.
I was actually calling the function and that's why my linter was saying my params were not defined.

How to properly use types with flow and nodejs?

How to make following use case with Flow and nodejs?
Requirements:
have Type definitions in a separate file(s), for now lets say all in Types.js
to use it inside another file/module:
const MyRequiredType = require('Types').MyRequiredType;
const methodWithInputTypeCheck = function(request: MyRequiredType){ }
Tried to use flow-aliases, but this seems to work only when have the declaration in the same file.
Thanks.
Oh, it seems that at the end it is far more simpler.
Looks like we can use std. classes:
1./ Types.js
// #flow
const Types =
{
SomethingWithUserRequest: class MyClass {
userId: string; //thanks to Babel
userNick: string;
}
};
module.exports = Types;
2./ SomeModule.js:
const SomethingWithUserRequest = require('../service/Dto/Types').SomethingWithUserRequest;
const TestFacade =
{
testFlow: function(
request: SomethingWithUserRequest
) {
console.log('userId', request.userId);
}
};
module.exports = TestFacade;
Only the IDE is still confused and does not hint in this way.

Mock dependency in Jest with TypeScript

When testing a module that has a dependency in a different file and assigning that module to be a jest.mock, TypeScript gives an error that the method mockReturnThisOnce (or any other jest.mock method) does not exist on the dependency, this is because it is previously typed.
What is the proper way to get TypeScript to inherit the types from jest.mock?
Here is a quick example.
Dependency
const myDep = (name: string) => name;
export default myDep;
test.ts
import * as dep from '../depenendency';
jest.mock('../dependency');
it('should do what I need', () => {
//this throws ts error
// Property mockReturnValueOnce does not exist on type (name: string)....
dep.default.mockReturnValueOnce('return')
}
I feel like this is a very common use case and not sure how to properly type this.
You can use type casting and your test.ts should look like this:
import * as dep from '../dependency';
jest.mock('../dependency');
const mockedDependency = <jest.Mock<typeof dep.default>>dep.default;
it('should do what I need', () => {
//this throws ts error
// Property mockReturnValueOnce does not exist on type (name: string)....
mockedDependency.mockReturnValueOnce('return');
});
TS transpiler is not aware that jest.mock('../dependency'); changes type of dep thus you have to use type casting. As imported dep is not a type definition you have to get its type with typeof dep.default.
Here are some other useful patterns I've found during my work with Jest and TS
When imported element is a class then you don't have to use typeof for example:
import { SomeClass } from './SomeClass';
jest.mock('./SomeClass');
const mockedClass = <jest.Mock<SomeClass>>SomeClass;
This solution is also useful when you have to mock some node native modules:
import { existsSync } from 'fs';
jest.mock('fs');
const mockedExistsSync = <jest.Mock<typeof existsSync>>existsSync;
In case you don't want to use jest automatic mock and prefer create manual one
import TestedClass from './TestedClass';
import TestedClassDependency from './TestedClassDependency';
const testedClassDependencyMock = jest.fn<TestedClassDependency>(() => ({
// implementation
}));
it('Should throw an error when calling playSomethingCool', () => {
const testedClass = new TestedClass(testedClassDependencyMock());
});
testedClassDependencyMock() creates mocked object instance
TestedClassDependency can be either class or type or interface
Use the mocked helper
like explained here
// foo.spec.ts
import { foo } from './foo'
jest.mock('./foo')
// here the whole foo var is mocked deeply
const mockedFoo = jest.mocked(foo, true)
test('deep', () => {
// there will be no TS error here, and you'll have completion in modern IDEs
mockedFoo.a.b.c.hello('me')
// same here
expect(mockedFoo.a.b.c.hello.mock.calls).toHaveLength(1)
})
test('direct', () => {
foo.name()
// here only foo.name is mocked (or its methods if it's an object)
expect(jest.mocked(foo.name).mock.calls).toHaveLength(1)
})
There are two solutions tested for TypeScript version 3.x and 4.x, both are casting desired function
1) Use jest.MockedFunction
import * as dep from './dependency';
jest.mock('./dependency');
const mockMyFunction = dep.myFunction as jest.MockedFunction<typeof dep.myFunction>;
2) Use jest.Mock
import * as dep from './dependency';
jest.mock('./dependency');
const mockMyFunction = dep.default as jest.Mock;
There is no difference between these two solutions. The second one is shorter and I would therefore suggest using that one.
Both casting solutions allows to call any jest mock function on mockMyFunction like mockReturnValue or mockResolvedValue
https://jestjs.io/docs/en/mock-function-api.html
mockMyFunction.mockReturnValue('value');
mockMyFunction can be used normally for expect
expect(mockMyFunction).toHaveBeenCalledTimes(1);
I use the pattern from #types/jest/index.d.ts just above the type def for Mocked (line 515):
import { Api } from "../api";
jest.mock("../api");
const myApi: jest.Mocked<Api> = new Api() as any;
myApi.myApiMethod.mockImplementation(() => "test");
Cast as jest.Mock
Simply casting the function to jest.Mock should do the trick:
(dep.default as jest.Mock).mockReturnValueOnce('return')
Use as jest.Mock and nothing else
The most concise way of mocking a module exported as default in ts-jest that I can think of really boils down to casting the module as jest.Mock.
Code:
import myDep from '../dependency' // No `* as` here
jest.mock('../dependency')
it('does what I need', () => {
// Only diff with pure JavaScript is the presence of `as jest.Mock`
(myDep as jest.Mock).mockReturnValueOnce('return')
// Call function that calls the mocked module here
// Notice there's no reference to `.default` below
expect(myDep).toHaveBeenCalled()
})
Benefits:
does not require referring to the default property anywhere in the test code - you reference the actual exported function name instead,
you can use the same technique for mocking named exports,
no * as in the import statement,
no complex casting using the typeof keyword,
no extra dependencies like mocked.
The latest jest allows you to do this very easily with jest.mocked
import * as dep from '../dependency';
jest.mock('../dependency');
const mockedDependency = jest.mocked(dep);
it('should do what I need', () => {
mockedDependency.mockReturnValueOnce('return');
});
Here's what I did with jest#24.8.0 and ts-jest#24.0.2:
source:
class OAuth {
static isLogIn() {
// return true/false;
}
static getOAuthService() {
// ...
}
}
test:
import { OAuth } from '../src/to/the/OAuth'
jest.mock('../src/utils/OAuth', () => ({
OAuth: class {
public static getOAuthService() {
return {
getAuthorizationUrl() {
return '';
}
};
}
}
}));
describe('createMeeting', () => {
test('should call conferenceLoginBuild when not login', () => {
OAuth.isLogIn = jest.fn().mockImplementationOnce(() => {
return false;
});
// Other tests
});
});
This is how to mock a non-default class and it's static methods:
jest.mock('../src/to/the/OAuth', () => ({
OAuth: class {
public static getOAuthService() {
return {
getAuthorizationUrl() {
return '';
}
};
}
}
}));
Here should be some type conversion from the type of your class to jest.MockedClass or something like that. But it always ends up with errors. So I just used it directly, and it worked.
test('Some test', () => {
OAuth.isLogIn = jest.fn().mockImplementationOnce(() => {
return false;
});
});
But, if it's a function, you can mock it and do the type conversation.
jest.mock('../src/to/the/Conference', () => ({
conferenceSuccessDataBuild: jest.fn(),
conferenceLoginBuild: jest.fn()
}));
const mockedConferenceLoginBuild = conferenceLoginBuild as
jest.MockedFunction<
typeof conferenceLoginBuild
>;
const mockedConferenceSuccessDataBuild = conferenceSuccessDataBuild as
jest.MockedFunction<
typeof conferenceSuccessDataBuild
>;
As of Jest 24.9.0 here is how you can mock and correctly type both your Class/Object/function and Jest properties.
jest.MockedFunction
jest.MockedClass
What we would like for a typed mock is that the mocked object type contains the union of the mocked object type and the type of Jest mocks.
import foo from 'foo';
jest.mock('foo');
const mockedFoo = foo as jest.MockedFunction<typeof foo>;
// or: const mockedFooClass = foo as jest.MockedClass<typeof FooClass>;
mockedFoo.mockResolvedValue('mockResult');
// Or:
(mockedFoo.getSomething as jest.MockedFunction<typeof mockedFoo.getSomething>).mockResolvedValue('mockResult');
As you can see, you can either manually cast what you need or you'll need something to traverse all foo's properties/methods to type/cast everything.
To do that (deep mock types) you can use jest.mocked() introduced in Jest 27.4.0
import foo from 'foo';
jest.mock('foo');
const mockedFoo = jest.mocked(foo, true);
mockedFoo.mockImplementation() // correctly typed
mockedFoo.getSomething.mockImplementation() // also correctly typed
I have found this in #types/jest:
/**
* Wrap a function with mock definitions
*
* #example
*
* import { myFunction } from "./library";
* jest.mock("./library");
*
* const mockMyFunction = myFunction as jest.MockedFunction<typeof myFunction>;
* expect(mockMyFunction.mock.calls[0][0]).toBe(42);
*/
Note: When you do const mockMyFunction = myFunction and then something like mockFunction.mockReturnValue('foo'), you're a changing myFunction as well.
Source: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/jest/index.d.ts#L1089
The top rated solution by Artur Górski does not work with the last TS and Jest.
Use MockedClass
import SoundPlayer from '../sound-player';
jest.mock('../sound-player'); // SoundPlayer is now a mock constructor
const SoundPlayerMock = SoundPlayer as jest.MockedClass<typeof SoundPlayer>;
A recent library solves this problem with a babel plugin: https://github.com/userlike/joke
Example:
import { mock, mockSome } from 'userlike/joke';
const dep = mock(import('./dependency'));
// You can partially mock a module too, completely typesafe!
// thisIsAMock has mock related methods
// thisIsReal does not have mock related methods
const { thisIsAMock, thisIsReal } = mockSome(import('./dependency2'), () => ({
thisIsAMock: jest.fn()
}));
it('should do what I need', () => {
dep.mockReturnValueOnce('return');
}
Be aware that dep and mockReturnValueOnce are fully type safe. On top, tsserver is aware that depencency was imported and was assigned to dep so all automatic refactorings that tsserver supports will work too.
Note: I maintain the library.
This is ugly, and in fact getting away from this ugliness is why I even looked at this question, but to get strong typing from a module mock, you can do something like this:
const myDep = (require('./dependency') as import('./__mocks__/dependency')).default;
jest.mock('./dependency');
Make sure you require './dependency' rather than the mock directly, or you will get two different instantiations.
For me this was enough:
let itemQ: queueItemType
jest.mock('../dependency/queue', () => {
return {
add: async (item: queueItemType, ..._args: any) => {
// then we can use the item that would be pushed to the queue in our tests
itemQ = item
return new Promise(resolve => {
resolve('Mocked')
})
},
}
})
Then, whenever the add method is called it will execute this code above instead of pushing it to the queue, in this case.
With TypeScript 2.8 we can do like this with ReturnType:
import * as dep from "./depenendency"
jest.mock("./dependency")
const mockedDependency = <jest.Mock<ReturnType<typeof dep.default>>>dep.default
it("should do what I need", () => {
mockedDependency.mockReturnValueOnce("return")
})

Node JS call a "local" function within module.exports

How do you call a function from within another function in a module.exports declaration?
I have MVC structure node js project and a controller called TestController.js. I want to access method within controller, but using this keyword gives below error:
cannot call method getName of undefined
"use strict"
module.exports = {
myName : function(req, res, next) {
// accessing method within controller
this.getName(data);
},
getName : function(data) {
// code
}
}
How do I access methods within controller?
I found the solution :-)
"use strict"
var self = module.exports = {
myName : function(req, res, next) {
// accessing method within controller
self.getName(data);
},
getName : function(data) {
// code
}
}
You can access the getName function trough module.exports. Like so:
"use strict"
module.exports = {
myName : function(req, res, next) {
// accessing method within controller
module.exports.getName(data);
},
getName : function(data) {
// code
}
}
Maybe you could do it like this. It reduce nesting. And all your export is done at the end of your file.
"use strict";
var _getName = function() {
return 'john';
};
var _myName = function() {
return _getName();
};
module.exports = {
getName : _getName,
myName : _myName
};
If you want to use the function locally AND in other files...
function myFunc(){
return 'got it'
}
module.exports.myFunc = myFunc;
I know the answer is already accepted, but I feel the need to add my two cents on the issue.
Node modules have a "Singletonic" nature, when inside the module, you are the module.
In my opinion, at least design pattern wise, inner module methods can be accessed more cleanly, without the need for this or a copy of self for that matter.
Using this, could be dangerous, if one happens to send the separate methods around and forgets to use .bind.
Using a copy of self, is redundant, we already are inside a Singleton behaving module, why keep a reference to yourself when you can avoid that?
Consider these instead:
Option 1
// using "exports."
exports.utilityMethod = (..args) => {
// do stuff with args
}
exports.doSomething = (someParam) => {
// this always refers to the module
// no matter what context you are in
exports.utility(someParam)
}
Option 2
// using module.exports
const utility = (..args) => {
// do stuff with args
}
const doSomething = (someParam) => {
// Inside the module, the utility method is available
// to all members
utility(someParam)
}
// either this
module.exports = {
utility,
doSomething,
}
// or
module.exports = {
customNameForUtility: utility,
customNameForDoSomething: doSomething
}
This works the same for es6 modules:
Option 1 (ES6)
export const utilityMethod = (..args) => {
// do stuff with args
}
export const doSomething = (someParam) => {
// this always refers to the module
// no matter what context you are in
utility(someParam)
}
Option 2 (ES6)
const utility = (..args) => {
// do stuff with args
}
const doSomething = (someParam) => {
// Inside the module, the utility method is available
// to all members
utility(someParam)
}
export default {
doSomething,
utility
}
// or
export {
doSomething,
utility
}
Again, this is just an opinion, but it looks cleaner, and is more consistent across different implementations, and not a single this/self is used.

Categories

Resources