Referencing non-exportable file in node module - javascript

I am trying to reference an html document in a "self containing" module. The module is comprised of two files:
app_root/node_module/my_module/main.js
app_root/node_module/my_module/header.html
main.js contains:
module.exports.test = function() {
var doc = fs.readFileSync('./header.html');
console.log(doc);
}
when i run my program in app_root/program.js
require('my_module').test();
When i start my app, the current working directory is set to app_root. When it tries to read ./header.html it breaks because the paths aren't correct.
How would I find directory of the installed module without knowing anything about what is running it?

You can use __dirname to refer to the path of the current script.
So main.js would become:
module.exports.test = function() {
var doc = fs.readFileSync(__dirname + '/header.html');
console.log(doc);
}

Related

Error when importing .js file in one folder to spec.js file in another folder

I am new to the protractor, and trying to create a project in cucumber using POM. Following is the structure of the project:
In the addCustomerPage.js, I have mentioned the locators as well as the functions to perform a test:
var addCustomerPage = function () {
var BankManagerButton = element(by.buttonText('Bank Manager Login'));
***Other locators*****
this.create = async function(fName,lName,pCode){
await BankManagerButton.click();
****rest of the steps*****
}
}
module.exports = new addCustomerPage();
But when in the spec.js, import the above class, on running the code, it throws the error:
E/launcher - Error: Error: Cannot find module '../pages/addCustomerPage'
Following is the spec.js file's code:
var {
setDefaultTimeout
} = require('cucumber');
const {
expect
} = require('chai');
setDefaultTimeout(10 * 1000);
var addCustomerPage = require('../pages/addCustomerPage');
Given('I open the application and click on create customer button', async function () {
**code*****
});
When('I enter {string}, {string}, {string}', async function (fname, lname, pcode) {
return await addCustomerPage.create(fname, lname, pcode);
});
However, this works fine if the pages folder is under the features folder. Can anyone help on what am I doing wrong here?
../
The symbol above is signalling to go up one file directory.
When the variable is declared like this...
var addCustomerPage = require('../pages/addCustomerPage');
... your computer will go up one folder level from the current directory and search for the pages folder and not find it.
When you copied the pages folder and put it under the feature folder, it can detect it because it falls under the directory that you were searching it for
The solution is to:
Just paste your pages folder under features
or
Modify the file path in the variable to where your pages folder is located
Im guessing you have to go up a directory or two, so use this command ../ to get to where your page folder is
var addCustomerPage = require('../../pages/addCustomerPage');
The idea is to modify the file path to wherever the page folder might be

No such file or directory when exporting function from another file

src/test.js
module.exports.test = function() {
const { readFileSync } = require('fs');
console.log(readFileSync('test.txt', 'utf8').toString())
}
index.js
const { test } = require('./src/test.js');
test();
Which results in No such file or directory. Does module.exports or exports not work when requiring files in another directory?
When you do something like this:
readFileSync('test.txt', 'utf8')
that attempts to read test.txt from the current working directory. That current working directory is determined by how the main program got started and what the current working directory was when the program was launched. It will have nothing at all to do with the directory your src/test.js module is in.
So, if test.txt is inside the same directory as your src/test.js and you want to read it from there, then you need to manually build a path that references your module's directory. To do that, you can use __dirname which is a special variable set for each module that points to the directory the module is in.
In this case, you can do this:
const path = require('path');
module.exports.test = function() {
const { readFileSync } = require('fs');
console.log(readFileSync(path.join(__dirname, 'test.txt'), 'utf8').toString())
}
And, that will reliably read test.txt from your module's directory.

How to dynamically resolve nodejs required module's path based on caller script's path?

I am kind of new to Javascript programming. Currently I am trying to write a test for Javascript files in existing codebase that contains other programming languages. The structure is like below.
src/js/path1/path2/path3/path4/path5/
Rectangle.jsx
Circle.jsx
test/js/path1/path2/path3/path4/path5/
RectangleTest.jsx
CircleTest.jsx
The content of RectangleTest.jsx is below
import Rectangle from './../../../../../../../src/js/path1/path2/path3/path4/path5/Rectangle';
describe('<Rectangle>', () => {
it('Should show content', () => {
assert.ok(true);
});
});
As you can see, I need to set the path as a very long relative path ./../../../../../../../src/js/path1/path2/path3/path4/path5. It will be very exhaustive for I prefer something like below.
import Rectangle from './Rectangle';
Since the path of the test file and the tested file is pretty similar, it should be possible to calculate the path to be resolved by the import.
Is there a way to do that?
I am using mocha for the testing framework. I uploaded the sample code to Github (link), so you can see it.
You can use the __dirname global node variable which contains the absolute path to the current file. However you have to use require() instead of import ... because import does not support dynamic paths.
if your absolute path only contains one test name you can get away with:
const path = require('path');
const retanglePath = path.join(__dirname.replace('/test/', '/src/'), 'Rectangle'));
const Rectangle = require(rectanglePath).default;
Note: the .default is for ES6 exports that are converted with babel.
Hope this helps.
Edit: Here is a solution that also works with other test folder names in the absolute path (replace the path relative for your needs):
const path = require('path');
const basePath = path.join(__dirname, '../../../../');
const srcPath = __dirname.replace(basePath + 'test', basePath + 'src');
const Rectangle = require(path.join(srcPath, 'Rectangle')).default;
After researching about how nodejs resolve module, it turns out that it's possible to override the require function behavior by overriding module module.
So I write a file called bootstrap.js that contains code below
let path = require('path');
const BASE_DIR = __dirname;
const SRC_DIR = path.resolve(BASE_DIR + '/../../src/js');
var Module = require('module');
Module.prototype.require = new Proxy(Module.prototype.require, {
apply(target, thisArg, argumentsList){
let name = argumentsList[0];
let isLocal = thisArg.filename.startsWith(BASE_DIR) &&
name.startsWith('./');
if (isLocal) {
let testFileDir = path.dirname(thisArg.filename)
let testPath = testFileDir.replace(BASE_DIR, '');
let srcPath = SRC_DIR + testPath;
let relativePath = path.relative(testFileDir, srcPath);
argumentsList[0] = relativePath + '/' + name;
}
return Reflect.apply(target, thisArg, argumentsList)
}
});
The structure now is like this
src/js/path1/path2/path3/path4/path5/
Rectangle.jsx
Circle.jsx
test/js/
bootstrap.js
path1/path2/path3/path4/path5/
RectangleTest.jsx
CircleTest.jsx
To execute the test, I use the statement below
nyc mocha --recursive \
--require test/js/bootstrap.js \
--compilers js:babel-core/register \
test/js/**/*.{js,jsx}
Using the code above, I can check the caller script and called module and see if the caller script resides in the test directory. If it does then, it will see if the module called by using relative path.
The advantage is that, we still can use import statement.
import Rectangle from './Rectangle';
describe('<Rectangle>', () => {
it('Should show content', () => {
assert.ok(true);
});
});
The downside is for now the test file cannot call relative path in the test directory. Relative path will now only resolve in source path. But it's good for now. I am wondering if we can check if a module is resolvable or not.
The updated source code can be read here.

Open Directory in Node.js and node-webkit

I have a function that should open a directory after it was created,
setTimeout(function()
{
var fs = require('fs');
console.log(newPath);
var open = fs.opensync(newPath, 'r');
}, 2500);
But this doesn't seem to work. I am getting the following errors
first is,
TypeError: undefined is not a function
at eval (eval at <anonymous> (file:///Users/proslav/Library/Developer/Xcode/DerivedData/trackingCore-ecxfviftqracjxhimcuhhhvyddso/Build/Products/Debug/trackingCore.app/Contents/Resources/timeBroFront.app/Contents/Resources/app.nw/js/jquery-1.10.2.min.js:3:4994), :43:18)
and second is,
Uncaught ReferenceError: require is not defined
I was thinking that it could be that my variable newpath is undefinded but the log shows me the right link.
The creation of the directory with var fs = require('fs'); works fine.
What am I doing wrong here?
I found out how it has to be done. Node-webkit offers a function for that. It is working on MAC and should also work on windows.
The function below is an example function. nw.gui and gui.Shell.showItemInFolder did the thing for me. Thx for the input.
/*---------
Open Folder
---------*/
function openFolder(path){
var gui = require('nw.gui');
gui.Shell.showItemInFolder(path);
}
In nw.js version 0.13 or later, use:
nw.Shell.showItemInFolder(fullpath);
Version < 0.13:
var gui = require('nw.gui');
gui.Shell.showItemInFolder(fullpath);
Note that the full path name is required. If it doesn't exist, it will fail silently.
If the path is something like c:\foo\bar.txt, it will open the folder foo and highlight the file bar.txt.
If the path is c:\foo\foo2, it will open the folder foo and highlight the folder foo2 (I expected it to open the folder foo2, but it will open the parent).
To find the fullpath of the running app, as we can't use node functions in our front-end (that's why you had the error trying to load the fs module), I've created a node module (utils.js) with the following:
exports.getFullPath = function(fileName) {
var path = require('path');
return path.resolve(__dirname, fileName);
}
In the front-end:
function openFolder(path) {
var utils = require('./utils');
var fullpath = utils.getFullPath(path);
nw.Shell.showItemInFolder(fullpath);
}

Protractor won't take screenshot in Jenkins

I am using the following code to take screenshots (in after each) when a test fails in Protractor:
function failScreenshot() {
var fs = require('fs');
var spec = jasmine.getEnv().currentSpec;
var specName = spec.description.split(' ').join('_');
if (spec.results().passed()) {
return;
} else {
browser.takeScreenshot().then(
function(png) {
var stream = fs.createWriteStream('screenshots/' + specName + '.png');
stream.write(new Buffer(png, 'base64'));
stream.end();
});
}
}
When I am running the tests locally, the screenshot works just as expected. When running the tests via Jenkins, the tests will stop at the first fail and the screenshot is not created. Also, the folders and paths are correct, I have checked them over and over again. My Jenkins version is 1532.1
Any ideeas on how could I solve this issue?
After further documentation I have found the answer. It was a problem with the path. It seems like NODE JS does not read the path as I thought.
The ./ returns the current directory, except in the require() function. When using require(), it reads ./ to the directory of the file in which it was called (obviously, the mistake was here). __dirname is always the directory of the file in which is used.
The code to be used for my path is the following:
__dirname + '/screenshots/' + specName + '.png'
You can also take the screenshots in jenkins by using the mocha-proshot reporter.
It is a npm package which can be downloaded easily and is very easy to setup.

Categories