What am I doing wrong in my module export from main.js? - javascript

Learning how to develop modules I'm trying to learn how to export one from main.js. On my renderer I can send it correctly to main with:
renderer.js:
let _object = {
foo: foo1,
bar: bar1,
}
ipcRenderer.send('channel', _object)
in main.js I can get this correctly:
ipcMain.on('channel', (e, res) => {
console.log(JSON.stringify(res))
console.log(typeof res)
})
however when I export the result from main.js and try to bring it into another file I get an undefined:
main.js:
const foobar = require('./foobar')
ipcMain.on('channel', (e, res) => {
console.log(JSON.stringify(res))
console.log(typeof res)
module.exports.res = res
foobar.testing()
})
foobar.js:
const res = require('./main')
module.exports = {
testing: function(res) {
console.log(`Attempting console.log test: ${res}`)
console.log(res)
console.log(JSON.stringify(res))
}
}
terminal result:
Attempting console.log test: undefined
undefined
undefined
I've also tried to redefine the object in main.js:
ipcMain.on('channel', (e, res) => {
module.exports = {
foo: foo,
bar: bar,
}
console.log(`Testing object ${res.foo}`)
foobar.testing()
})
My research of reference:
Node js object exports
Node module.exports returns undefined
What a I doing wrong in my export of the result in main.js so I can use it in a different file?
Edit:
My end goal is to learn how to be able to call res.foo in foobar.js.

First of all, you have an argument res in your testing function, which shadows the import. Second, the imported res object is all exports from main, which includes the res you need - so you should print res.res instead of the whole object.
Foobar.js:
const res = require('./main')
module.exports = {
testing: function() {
console.log(`Attempting console.log test: ${res.res}`)
console.log(res.res)
console.log(JSON.stringify(res.res))
}
}
The last version (where you reassign module.exports) would not work, because foobar will still have the original exports, which was an empty object.

Related

NodeJS: My jest spyOn function is not being called

I don't understand why my spy is not being used. I have used this code elsewhere and it has worked fine.
Here is my test:
const {DocumentEngine} = require('../documentEngine')
const fileUtils = require('../utils/fileUtils')
const request = {...}
const fieldConfig = {...}
test('If the Carbone addons file is not found, context is built with the carboneAddons property as an empty object', async () => {
const expectedResult = {
carboneAddons: {},
}
const fileExistSpy = jest
.spyOn(fileUtils, 'checkFileExists')
.mockResolvedValue(false)
const result = await docEngine.buildContext(request, fieldConfig)
expect(fileExistSpy).toHaveBeenCalledTimes(1)
})
Here is the code that it is being tested:
async function buildContextForLocalResources(request, fieldConfig) {
/* other code */
const addonFormatters = await getCarboneAddonFormatters()
const context = {
sourceJson,
addonFormatters,
documentFormat,
documentTemplateId,
documentTemplateFile,
responseType,
jsonTransformContext
}
return context
}
async function getCarboneAddonFormatters() {
const addOnPath = path.resolve(
docConfig.DOC_GEN_RESOURCE_LOCATION,
'library/addon-formatters.js'
)
if (await checkFileExists(addOnPath)) {
logger.info('Formatters found and are being used')
const {formatters} = require(addOnPath)
return formatters
}
logger.info('No formatters were found')
return {}
}
This is the code from my fileUtils file:
const fs = require('fs/promises')
async function checkFileExists(filePath) {
try {
await fs.stat(filePath)
return true
} catch (e) {
return false
}
}
My DocumentEngine class calls the buildContext function which in turn calls the its method getCarboneAddonFormatters. The fileUtils is outside of DocumentEngine class in a utilities folder. The original code I had this working on was TypeScript as opposed to this which is just NodeJS Javascript. The config files for both are the same. When I try to step through the code (VSCode debugger), as soon as I hit the line with await fs.stat(filePath) in the checkFileExists function, it kicks me out of the test and moves on to the next test - no error messages or warnings.
I've spent most of the day trying to figure this out. I don't think I need to do an instance wrapper for the documentEngine, because checkFileExists is not a class member, and that looks like a React thing...
Any help in getting this to work would be appreciated.

Module.exports in JavaScript

What is different between module.exports = testMethod ; and module.exports = { testMethod } ; Because when I am using module.exports = testMethod ; it is throwing error as below.
Error: Route.get() requires a callback function but got a [object Undefined]
But I am okay with module.exports = { testMethod } ;
Whole codes are
const testMethod = asyncErrorWrapper(async (req, res, next) => {
const information = req.body;
const question = await Question.create({
title: information.title,
content: information.content,
user: req.user.id,
});
res.status(200).json({
success: true,
data: question,
});
});
module.exports = { testMethod };
From VSCode, change between the ES5 or ES6 version to Js can take you on a bad way.
So, be carreful, i have the same problem recently, and after refactoring by use on ES6 module.exports = router to the end of some Js file (Node project using express) it was done.
Strange for me, on Cloud9 on Aws i have no problems.
Both are worked to export your module to outside function. But when you are using any callback function with
module.exports = somectrl
then it will fail but
module.exports = { somectrl }
because when you create an object, it actually instanciate it but when you pass a ref function/ const function name then it will behave as a existing function which does not work right.
you can do something like this to work,
module.exports = somectrl()
or
module.exports = new somectrl()

Cypress: cy.task() with multiple arguments

What I am trying: Pass multiple arguments in cy.task() command and print those argument values declared in function mentioned in plugins/index.js file
Issue: The function print prints only the first argument value and undefined for a second argument
Code:
//test file with cy.task() command
class LoginPage {
let site = abc
let userDetails = xyz
openPage(env, site, userDetails) {
cy.task('loadUserAccountDetails', site, userDetails)
}
}
module.exports = LoginPage
// plugins/index.js file where the event is registered with declared function
const validUserDetails = (site, userDetails) => {
console.log('--->' + site) // This prints abc
console.log('--->' + userDetails) // This prints undefined
}
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
on('task', {
loadUserAccountDetails: validUserDetails
})
}
Kindly help.
Looks like only one param is handled. But you can always pass in an object with the vars as properties.
on("task", {
async "rename"({var1, var2, var2}) {
}
and in the .spec call it as
cy.task('rename', {var1: 'val1', var2:'val2', var3: 'val3'}, ()=>{
console.log('renamed');
})
This worked by passing arguments on task registered at index.js file.
on('task', {
loadUserAccountDetails(site, userDetails): validUserDetails(site, userDetails)
})

Refactoring probot event functions into seperate file causes error: TypeError: handler is not a function

I have the vanilla probot event function from the docs that comments on new issues:
const probotApp = app => {
app.on("issues.opened", async context => {
const params = context.issue({ body: "Hello World!" });
return context.github.issues.createComment(params);
});
}
This works fine.
I refactor the code into a separate file:
index.js
const { createComment } = require("./src/event/probot.event");
const probotApp = app => {
app.on("issues.opened", createComment);
}
probot.event.js
module.exports.createComment = async context => {
const params = context.issue({ body: "Hello World!" });
return context.github.issues.createComment(params);
};
But I receive this error:
ERROR (event): handler is not a function
TypeError: handler is not a function
at C:\Users\User\probot\node_modules\#octokit\webhooks\dist-node\index.js:103:14
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async Promise.all (index 0)
When I create a test as recommended in the docs with a fixture and mock the event webhook call with nock this works fine. But when I create a real issue on GitHub this error is thrown.
How can I refactor the code into a separate file without causing the error?
This was my mistake.
This is the whole probot.event.js file:
module.exports.createComment = async context => {
const params = context.issue({ body: "Hello World!" });
return context.github.issues.createComment(params);
};
module.exports = app => {
// some other event definitions
}
By defining module.exports = app I overwrote the previous module.export. The createComment function was therefore never exported.
Removing module.exports = app = { ... } fixed it!

Invalidate node cache when using Jest

I have a file with object that gets populated with process.env properties:
env.js
console.log('LOADING env.js');
const {
PROXY_PREFIX = '/api/',
USE_PROXY = 'true',
APP_PORT = '8080',
API_URL = 'https://api.address.com/',
NODE_ENV = 'production',
} = process.env;
const ENV = {
PROXY_PREFIX,
USE_PROXY,
APP_PORT,
API_URL,
NODE_ENV,
};
module.exports.ENV = ENV;
Now I try to test this file with different process.env properties:
env.test.js
const envFilePath = '../../config/env';
describe('environmental variables', () => {
const OLD_ENV = process.env;
beforeEach(() => {
process.env = { ...OLD_ENV };
delete process.env.NODE_ENV;
});
afterEach(() => {
process.env = OLD_ENV;
});
test('have default values', () => {
const { ENV } = require(envFilePath);
expect(ENV).toMatchSnapshot();
});
test('are string values (to avoid casting errors)', () => {
const { ENV } = require(envFilePath);
Object.values(ENV).forEach(val => expect(typeof val).toEqual('string'));
});
test('will receive process.env variables', () => {
process.env.NODE_ENV = 'dev';
process.env.PROXY_PREFIX = '/new-prefix/';
process.env.API_URL = 'https://new-api.com/';
process.env.APP_PORT = '7080';
process.env.USE_PROXY = 'false';
const { ENV } = require(envFilePath);
expect(ENV.NODE_ENV).toEqual('dev');
expect(ENV.PROXY_PREFIX).toEqual('/new-prefix/');
expect(ENV.API_URL).toEqual('https://new-api.com/');
expect(ENV.APP_PORT).toEqual('7080');
expect(ENV.USE_PROXY).toEqual('false');
});
});
Unfortunately, even though I try to load the file in every test separately the file gets loaded only once, making the third test fail with:
Expected value to equal:
"dev"
Received:
"production"
P.S. It doesn't fail when I run the test alone.
I also know that env.js loads only once because console.log('LOADING env.js'); gets fired only once.
I tried to invalidate Nodes cache like:
beforeEach(() => {
delete require.cache[require.resolve(envFilePath)];
process.env = { ...OLD_ENV };
delete process.env.NODE_ENV;
});
but require.cache is empty {} before each test so it seems that Jest is somehow responsible for importing the file.
I also tried to run yarn jest --no-cache but didn't help.
So what I want is to load env.js before each test so I can test how it behaves with different node environmental variables.
jest#^22.0.4
You can use jest.resetModules() in beforeEach method to reset the already required modules
beforeEach(() => {
jest.resetModules()
process.env = { ...OLD_ENV };
delete process.env.NODE_ENV;
});
Instead of resetting all modules, you can require modules in isolation by using jest.isolateModules(fn).
For example:
test('are string values (to avoid casting errors)', () => {
jest.isolateModules(() => {
const { ENV } = require(envFilePath);
Object.values(ENV).forEach(val => expect(typeof val).toEqual('string'));
});
});
jest version is: "jest": "^26.6.3". Other answers are correct but didn't explain the reason. The reason why delete require.cache[require.resolve(MODULE_PATH)] does NOT work is because jest doesn't implement the require.cache. See issue#5741.
We should use jest.resetModules() or jest.isolateModules(fn) instead.
E.g.
index.js:
module.exports = { name: 'main' };
index.test.js:
describe('71254501', () => {
let obj1, obj2;
beforeEach(() => {
// This will work
// jest.resetModules();
// This doesn't work
delete require.cache[require.resolve('.')];
});
test('should pass 1', () => {
obj1 = require('.');
obj1.name = 'b';
console.log(obj1);
});
test('should pass 2', () => {
obj2 = require('.');
console.log(obj2);
});
});
Test result:
PASS stackoverflow/71254501/index.test.js
71254501
✓ should pass 1 (13 ms)
✓ should pass 2 (1 ms)
console.log
{ name: 'b' }
at Object.<anonymous> (stackoverflow/71254501/index.test.js:10:13)
console.log
{ name: 'b' }
at Object.<anonymous> (stackoverflow/71254501/index.test.js:14:13)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 0.606 s, estimated 8 s
As you can see, the require cache of module .is NOT deleted. When test case 1 mutates the obj, test case 2 still requires the same instance of the module which is not expected. We want a fresh module .

Categories

Resources