Mocking execSync in Jest - javascript

How do I mock out executing a child process in Jest
const execSync = require('child_process').execSync;
//...
expect(execSync)
.toHaveBeenCalledWith('npm install');
But not actually have it run the npm install during the test.

Can just do something like the following:
jest.mock("child_process", () => {
return {
execSync: () => "This is a test message"
};
});
Where the return value can be a number, string, object or whatever. It just allows you to override the actual implementation of execsync.

You can use lib mock with __mocks__ folder that will hold child_process folder which will be loaded by jest automatically.
Just create a file
// __mocks__/child_process/index.js
module.exports = {
execSync: jest.fn()
};
that will export a mock implementation of child_process.

Related

How can I call the native console.log method in a Jest test?

Jest overrides the native console.log method to collect the logging output for each test. However that can make working with the debugger quite difficult, since nothing will be printed.
Is there a way to call the native console.log method inside a Jest test?
You can achieve this by passing a custom TestEnvironment and and custom Reporter (tested with jest#24.7.1):
// debugTestEnv.js
const NodeEnvironment = require('jest-environment-node')
const console = require('console')
const vanillaConsole = new console.Console({ stdout: process.stdout, stderr: process.stderr })
class DebugTestEnv extends NodeEnvironment {
async setup() {
await super.setup()
this.prevConsole = this.global.console
this.global.console = vanillaConsole
}
async teardown() {
this.global.console = this.prevConsole
await super.teardown()
}
}
module.exports = DebugTestEnv
// debugReporter.js
// In Jest, the DefaultEnvironment constructor changes `process.stdout` and `process.stderr`
// That's why we pass a custom reporter to Jest (we use Jest's BaseReporter for this purpose)
module.exports = require('#jest/reporters/build/base_reporter').default
then to run a particular test:
jest --runInBand --no-cache --watchAll=false -t="testNameToDebug" --env="./path/to/debugTestEnv.js" --reporters="./path/to/debugReporter.js"
This works as well with create-react-app, just replace jest with react-scripts test.

How do I write unit tests for a single JS file?

I have a single js file with a function in in. I want to write unit tests for the function and deliver the tests and file to someone. It needs to be standalone.
Here is my project:
src: myFunction.js
tests: empty for now
myFunction.js:
function HelloWord() {
return 'Hello';
}
It would be great to have a test file like this:
import { func } from './myFunction.js';
describe('tests', function () {
it('returns hello', function () {
expect(func()).toEqual('Hello');
});
});
I don't know which unit test framework would be the easiest and fastest to accomplish what I need to do. The user needs to get my directory and just run the tests from the command line.
Using Mocha, a really fast set up would be:
1) Install mocha to package.json:
npm install --save-dev mocha
2)Write down the test. Let it be test.js under /tests/ , for example:
var myFunc = require('./myFunction');
var assert = require('assert');
describe('the function' , function(){
it('works' , function(){
assert.equal( myFunc() , 'hello');
});
});
3) Set up the package.json test command:
{
...
"scripts": {
"test": "node_modules/mocha/bin/mocha tests/test.js"
}
}
4) Call tests by npm test.

Testing reactjs components with mochajs

I'm trying to run a simple test with mochajs:
var assert = require('assert'),
ActionCreators = require('../src/components/Dashboard/ActionCreators.js');
describe('', function () {
it('', function () {
assert.equal(1, 1);
});
});
But it throws errors that the ActionCreators file contain import keywords. It does, becuase I run my code with webpack, and it goes through babel.
I've been trying to run this test with mocha-webpack, but it's the same. How should I do this?
Use mocha command line option --compilers js:babel-core/register. Of course you have to have babel-core npm package installed.

Run function in script from command line (Node JS)

I'm writing a web app in Node. If I've got some JS file db.js with a function init in it how could I call that function from the command line?
No comment on why you want to do this, or what might be a more standard practice: here is a solution to your question.... Keep in mind that the type of quotes required by your command line may vary.
In your db.js, export the init function. There are many ways, but for example:
module.exports.init = function () {
console.log('hi');
};
Then call it like this, assuming your db.js is in the same directory as your command prompt:
node -e 'require("./db").init()'
If your db.js were a module db.mjs, use a dynamic import to load the module:
node -e 'import("./db.mjs").then( loadedModule => loadedModule.init() )'
To other readers, the OP's init function could have been called anything, it is not important, it is just the specific name used in the question.
Update 2020 - CLI
As #mix3d pointed out you can just run a command where file.js is your file and someFunction is your function optionally followed by parameters separated with spaces
npx run-func file.js someFunction "just some parameter"
That's it.
file.js called in the example above
const someFunction = (param) => console.log('Welcome, your param is', param)
// exporting is crucial
module.exports = { someFunction }
More detailed description
Run directly from CLI (global)
Install
npm i -g run-func
Usage i.e. run function "init", it must be exported, see the bottom
run-func db.js init
or
Run from package.json script (local)
Install
npm i -S run-func
Setup
"scripts": {
"init": "run-func db.js init"
}
Usage
npm run init
Params
Any following arguments will be passed as function parameters init(param1, param2)
run-func db.js init param1 param2
Important
the function (in this example init) must be exported in the file containing it
module.exports = { init };
or ES6 export
export { init };
As per the other answers, add the following to someFile.js
module.exports.someFunction = function () {
console.log('hi');
};
You can then add the following to package.json
"scripts": {
"myScript": "node -e 'require(\"./someFile\").someFunction()'"
}
From the terminal, you can then call
npm run myScript
I find this a much easier way to remember the commands and use them
Try make-runnable.
In db.js, add require('make-runnable'); to the end.
Now you can do:
node db.js init
Any further args would get passed to the init method, in the form of a list or key-value pairs.
Sometimes you want to run a function via CLI, sometimes you want to require it from another module. Here's how to do both.
// file to run
const runMe = () => {}
if (require.main === module) {
runMe()
}
module.exports = runMe
This one is dirty but works :)
I will be calling main() function from my script. Previously I just put calls to main at the end of script. However I did add some other functions and exported them from script (to use functions in some other parts of code) - but I dont want to execute main() function every time I import other functions in other scripts.
So I did this,
in my script i removed call to main(), and instead at the end of script I put this check:
if (process.argv.includes('main')) {
main();
}
So when I want to call that function in CLI: node src/myScript.js main
simple way:
let's say you have db.js file in a helpers directory in project structure.
now go inside helpers directory and go to node console
helpers $ node
2) require db.js file
> var db = require("./db")
3) call your function (in your case its init())
> db.init()
hope this helps
Updated for 2022 - If you've switched to ES Modules, you can't use the require tricks, you'd need to use dynamic imports:
node -e 'import("./db.js").then(dbMod => dbMod.init());'
or with the --experimental-specifier-resolution=node flag:
node --experimental-specifier-resolution=node -e 'import("./db").then(dbMod => dbMod.init());'
If you turn db.js into a module you can require it from db_init.js and just: node db_init.js.
db.js:
module.exports = {
method1: function () { ... },
method2: function () { ... }
}
db_init.js:
var db = require('./db');
db.method1();
db.method2();
I do a IIFE, something like that:
(() => init())();
this code will be executed immediately and invoke the init function.
You can also run TypeScript with ts-node similar to #LeeGoddard answer.
In my case, I wanted to use app and init separately for testing purposes.
// app.ts
export const app = express();
export async function init(): Promise<void> {
// app init logic...
}
npx ts-node -e 'require("./src/app").init();'
npx ts-node -e 'import("./src/app").then(a => a.init());' // esmodule
maybe this method is not what you mean, but who knows it can help
index.js
const arg = process.argv.splice(2);
function printToCli(text){
console.log(text)
}
switch(arg[0]){
case "--run":
printToCli("how are you")
break;
default: console.log("use --run flag");
}
and run command node . --run
command line
probuss-MacBook-Air:fb_v8 probus$ node . --run
how are you
probuss-MacBook-Air:fb_v8 probus$
and you can add more arg[0] , arg[1], arg[2] ... and more
for node . --run -myarg1 -myarg2
If you want to include environment variables from your .env files, you can use env-cmd:
npx env-cmd node -e 'require("./db").init()'
If you want run a specific function in the file too, use run-func:
npx env-cmd npx run-func db.js init someArg
Or, to provide an argument for the accepted answer you'd have to do something like:
npx env-cmd node -e 'require("./db").init(someArg)'
Writing/updating an expression here is less explicit (so easier to miss when you're checking back, for example) than providing different arguments to the commands, so I recommend using env-cmd with run-func.
Note: I also usually add --experimental-modules on the end when necessary.
Inspired by https://github.com/DVLP/run-func/blob/master/index.js
I create https://github.com/JiangWeixian/esrua
if file index.ts
export const welcome = (msg: string) => {
console.log(`hello ${msg}`)
}
just run
esrua ./index.ts welcome -p world
will output hello world
If your file just contains your function, for example:
myFile.js:
function myMethod(someVariable) {
console.log(someVariable)
}
Calling it from the command line like this nothing will happen:
node myFile.js
But if you change your file:
myFile.js:
myMethod("Hello World");
function myMethod(someVariable) {
console.log(someVariable)
}
Now this will work from the command line:
node myFile.js

How to test an ES7 async function using mocha/chai/chai-as-promised

I have the following function to test:
// ...
const local = new WeakMap();
export default class User {
// ...
async password(password) {
if (!password) return local.get(this).get('hash'); // remove this for security reasons!
if (password.length < 6) throw new Error('New password must be at least 6 characters long');
if (!password.match(passwordPattern)) throw new Error(`New password must match ${passwordPattern}`);
local.get(this).set('hash', await Password.hash(password));
}
// ...
}
Now I want to test this function with mocha, chai and chai-as-promised doing this test-case:
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import User from '../../../server/User';
chai.use(chaiAsPromised);
const expect = chai.expect;
describe('.password()', () => {
const testuser = new User({username: 'Testuser', password: '123abc'});
// FINDME
it(`should throw when too short`, () => {
return expect(testuser.password('1a')).to.eventually.throw();
});
// ...
});
Look for the // FINDME comment in the above code to get the context I'm referring to.
So what happens is that the test(s) do not wait for the async password() function to finish. As I found out ECMAScript7 async functions immediatelly return a thenable, so it should be fine since chai-as-promised use exactly this feature. My guess is, that async functions don't throw errors into this said promise rather than throwing it into the enclosing function itself, not being able to capture it through expect().
For the eager folks: I transpile this code on-the-fly with babel using the following command:
babel-node --experimental node_modules/mocha/bin/_mocha --watch --recursive -R spec --check-leaks
Update for Babel 6:
Using babel-node 6.4.0, the following worked:
npm install --save-dev babel-preset-stage-0
Then run:
./node_modules/.bin/babel-node --presets stage-0 node_modules/mocha/bin/_mocha --
recursive -R spec --check-leaks
We solved this issue by replacing eventually.throw() with .be.rejected provided by chai-as-promised, since an async function always returns a Promise. That wasn't clear to me in the first place. Have a look at the discussion on github if you like.

Categories

Resources