Testing URL query string in nodejs - javascript

Hey everyone I made a package that can manage and control URL query strings.
I publish it throw npm. and wrote some tests to the core of the package
"parser.js" - that parse the query string to an object
"strigifyer.js" - that make an object to URL query string
I test those files for now with "mocha" and "expect"
there is one main file that manage the above files and the file is also push to query string to URL without refresh. it uses the window.history object.
what should I do to success to test the main file (index.js)?
I need the window and history objects to check if there is a change after I use my api.
here is the package if its help:
https://github.com/nevos12/query-string-manager
thank you.

If I understood correct, the module that exposes your library is src/index.js
From the code style of your index.js, I'd suggest to use sinon to test your code flow.
A unit test could be :
import sinon from 'sinon'
import qs from 'src/index.js'
it('should reset queryStringObject', () => {
const pushToUrlSpy = sinon.spy(qs, 'pushToUrl');
qs.reset(true);
expect(qs.queryStringObject).to.equal({});
expect(pushToUrlSpy.called);
pushToUrlSpy.restore();
})
This code creates a spy on pushToUrl() , invokes reset() and asserts that queryStringObject is an empty object now and pushToUrl() was invoked as least once. In the end it restores the spy, otherwise other tests might act weird.

Related

nestjs issue with variable in .env file

Im using NestJS framework to build a rest api, i have a issue getting the environment variables.
I have a .env with a variable "SMB_SHARE" with a path string, when i pass this variable to a class constructor of a smb2 libray, this throw an error, the string provided by the environment variable is invalid.
The environment variable is this:
SMB_SHARE=\\10.00.0.000\some_path
When i use console log in the code the variable is ok, is a string and has the correct string value. But when i pass it to the constructor, it throw the error.
I pass the string directly to the constructor, and it work fine, the others environment variables of the constructor are setted correctly (like the username and password). Only the SMB_SHARE variable is throwing the error.
I dont have idea what is the problem here. Can someone help me with this issue?
I show some examples:
constructor(private config: ConfigService) {
console.log('VAR', config.get<string>('SMB_SHARE'));
//This show the correctly string variable value
const share = config.get<string>('SMB_SHARE');
this.sambaClient = new SMB2({
share: '\\\\10.00.0.000\\some_path', //WORK
//share: share, FAIL
//share: config.get<string>('SMB_SHARE'), FAIL
//share: process.env.SMB_SHARE, FAIL
domain: '',
username: config.get<string>('SMB_USERNAME'),
password: config.get<string>('SMB_PASSWORD'),
debug: true,
autoCloseTimeout: 0,
})
}
The .env file is like this:
SMB_SHARE=\\\\10.00.0.000\\some_path
SMB_USERNAME=user
SMB_PASSWORD=secret
More than likely, what is happening is JavaScript is escaping the extra \. This is unescaped when the print happens, so it looks proper (i.e. console.log(process.env.SMB_SHARE) will print \\\\10.0.0.0\\some_path, but in reality, the variable is now \\\\\\\\10.0.0.0\\\\some_path). I ended up creating a mock of this using a text file called ./temp/.env and making use of the fs module from Node (which is what dotenv uses, which is what #nestjs/config uses. You can see below the cat (print) of the file, and the two different methods while using node to read the file
~/Documents/code
▶ cat ./temp/.env
HOST=\\\\127.0.0.1:3000\\path
~/Documents/code
▶ node
Welcome to Node.js v12.18.2.
Type ".help" for more information.
> const { readFileSync } = require('fs');
undefined
> readFileSync('./temp/.env').toString()
'HOST=\\\\\\\\127.0.0.1:3000\\\\path\n\n'
> console.log(readFileSync('./temp/.env').toString())
HOST=\\\\127.0.0.1:3000\\path
The solution here, would be to change your .env file to be the exact string you're wanting to pass on to the configuration (probably \\10.0.0.0\some_path)
you have to implement the config module.
start with
npm i --save #nestjs/config
then add the configModule in your appModule:
import { ConfigModule } from '#nestjs/config';
#Module({
imports: [ConfigModule.forRoot()],
})
export class AppModule {}

How can I reload an ES6 module at runtime?

Prior to ES6 modules, it was (I'm told by other Stack answers) easy to force a JS script to be reloaded, by deleting its require cache:
delete require.cache[require.resolve('./mymodule.js')]
However, I can't find an equivalent for ES6 modules loaded via import.
That might be enough to make this question clear, but just in case, here's a simplified version of the code. What I have is a node server running something like:
-- look.mjs --
var look = function(user) { console.log(user + " looks arond.") }
export { look };
-- parser.mjs --
import { look } from './look.mjs';
function parse(user, str) {
if (str == "look") return look(user);
}
What I want is to be able to manually change the look.mjs file (e.g. to fix a misspelled word), trigger a function that causes look.mjs to be reimported during runtime, such that parse() returns the new value without having to restart the node server.
I tried changing to dynamic import, like this:
-- parser.mjs --
function parse(user, str) {
if (str == "look") {
import('./look.mjs').then(m => m.look(user))
}
}
This doesn't work either. (I mean, it does, but it doesn't reload look.mjs each time it's called, just on the first time) And I'd prefer to keep using static imports if possible.
Also, in case this is not clear, this is all server side. I'm not trying to pass a new module to the client, just get one node module to reload another node module.
I don't know what the reason behind doing this,
I think this is not safe to change the context of modules at runtime and cause unexpected behaviors and this is one of the reasons that Deno came to.
If you want to run some code evaluation at runtime you can use something like this using vm:
https://nodejs.org/dist/latest-v16.x/docs/api/vm.html
You could try using nodemon to dynamically refresh when you make code changes
https://www.npmjs.com/package/nodemon
I agree with #tarek-salem that it's better to use vm library. But there is another way to solve your problem.
There is no way to clear the dynamic import cache which you use in question (btw there is a way to clear the common import cache because require and common import has the same cache and the dynamic import has its own cache). But you can use require instead of dynamic import. To do it first create require in parser.mjs
import Module from "module";
const require = Module.createRequire(import.meta.url);
Then you have 2 options:
Easier: convert look.mjs into commonjs format (rename it look.cjs and use module.exports).
If want to make it possible to either import AND require look.mjs you should create the npm package with package.json
{
"main": "./look.cjs",
"type": "commonjs"
}
In this case in parser.mjs you will be able to use require('look') and in other files import('look') or import * as look from 'look'.

How to determine if JEST is running the code or not?

I am creating a JS test on my react-native project. I'm specifically using firebase for react native, in which I would like to replace firebase instance with a mockfirebase instance if JS is running the code of my class.
For example I have class setup like below.
import firebase from 'react-native-firebase';
class Database() {
/// use the firebase instance
}
I'd like to have a check if jest is the running environment then I'd replace the import line with appropriate mock class.
jest sets an environment variable called JEST_WORKER_ID so you check if this is set:
function areWeTestingWithJest() {
return process.env.JEST_WORKER_ID !== undefined;
}
I also see that if NODE_ENV is not set the jest CLI sets it to the value 'test'. This might be another way to check.
I usually have NODE_ENV=development set globally on my shell. This works for me:
typeof jest !== 'undefined'
(note that global.jest and 'jest' in global don't work, as this doesn't seem to be a global variable, just a value made available on all modules much like node's require or __filename)
you could add parameter to global for example global.isJest and check on the front end if it is defined
For me best way is checking two things - 0 and undefined:
[0, undefined].includes(process.env.JEST_WORKER_ID)
so it's based on https://stackoverflow.com/a/52231746/3012785

How to import `isOneline` function?

I need to create a custom matcher for Jest test framework, specifically same as .toEqual() but with optional message parameter.
I started with copying everything from actual .toEqual() matcher from here.
I managed to bring all of the the used in this matcher functions except isOneline. It is defined here.
But I do not see how can I import/require it to my code. Is it possible?
Have you tried?
const { isOneline} = require('<path to util.js file>');
Or
const isOneline= require('<path to util.js file>').isOneline;
EDIT:
This works (see comment):
const isOneline = require('expect/build/utils').isOneline;

Mock doesn't work, while reassignment does

I have the following Jest/Enzyme test:
const mockCheckMyFunctionality = jest.fn();
jest.mock('../modules/MyFunctionality', () => ({
checkMyFunctionality: mockCheckMyFunctionality
}));
const wrapper = shallow(
<App initialProps={mockInitialProps} />
);
expect(mockCheckMyFunctionality).toHaveBeenCalledTimes(1);
This will fail with TypeError: Cannot read property 'onNextTick' of undefined. The error message itself is not relevant, but it just shows that the real MyFunctionality.checkMyFunctionality is called instead of mockCheckMyFunctionality.
However, if I replace:
jest.mock('../modules/MyFunctionality', () => ({
checkMyFunctionality: mockCheckMyFunctionality
}));
With:
MyFunctionality.checkMyFunctionality = mockCheckMyFunctionality;
The test will pass, showing that mockCheckMyFunctionality is actually called. However, this is hacky and fails EsLint checking.
The method I am testing is just this:
setupMyFunctionality() {
checkMyFunctionality(this.props.something);
}
How can I modify the mocking such that it is visible inside App?
Reassignment seems to work but mocking doesn't.
Maybe you forgot to create a manual mock for the MyFuncionality module.
As in the documentation for mocking a module:
Manual mocks are defined by writing a module in a __mocks__/
subdirectory immediately adjacent to the module. For example, to mock a module called user in the models directory, create a file called user.js and put it in the models/__mocks__ directory.
...
When a manual mock exists for a given module, Jest's module system will use that module when explicitly calling jest.mock('moduleName').
If that's the case, you can create a folder named __mocks__ adjacent to the MyFunctionality file, then create a MyFunctionality file within that folder, containing the mock implementation as in the code snippet, and explicitly call the mock by calling jest.mock('../modules/MyFunctionality') before the tests.
Another solution, which I started using in my projects, is passing the dependencies as props to the components. To implement that you could change the App component and pass the MyFunctionality as props, thus in the above test you would need just to pass the mock implemented as props, avoiding the necessity of creating __mocks__/ folder to accomplish the test.

Categories