How can I stop Jest wrapping `console.log` in test output? - jestjs

I'm making a Jest test with request
describe("GET /user ", () => {
test("It should respond with a array of users", done => {
return request(url, (err, res, body) => {
if (err) {
console.log(err)
} else {
console.log("GET on " + url);
body = JSON.parse(body);
expect(body.length).toBeGreaterThan(0);
done();
}
})
})
});
and it's weird because in the terminal, jest is showing console.log line as part of the output:
...test output...
console.log test/modules/user.test.js:18
GET on https://xpto/api/user
...more test output...
I need to hide the line:
console.log test/modules/user.test.js:18
How to hide console.log line in Jest output?

You can replace Jest's console implementation with the "normal" console like this:
const jestConsole = console;
beforeEach(() => {
global.console = require('console');
});
afterEach(() => {
global.console = jestConsole;
});

If it's a test you've written, why do you even need to log the error? You can rely on jest assertions for that.
If you have no other solution, you can stub out the console.log function like so:
const log = console.log;
console.log = () => {};
/** Test logic goes here **/
console.log = log; // Return things to normal so other tests aren't affected.

You can use jest.spyOn to mock the console methods:
const spy = jest.spyOn(console,'warn').mockReturnValue()
// after you are done with the test, restore the console
spy.mockRestore()
You can create a utility function to mock the console:
function mockConsole(method = 'warn', value){
return jest.spyOn(console,method).mockReturnValue(value).mockRestore
}
const restore = mockConsole() //mock it
// later when you are done
restore() // unmock it
Also, you can combine above code answers with jest.beforeEach to automatically restore the console:
beforeEach(()=>{
// beware that this will restore all mocks, not just the console mock
jest.restoreAllMocks()
})

You need to create your own log function with process.stdout.write or use it instead of console.log because jest is spying on all console functions.
While ago I have been trying to bring to Typescript one utility that I really like in Scala; GivenWhenThen annotations in tests and I encountered the same problem as you. I don't understand why jest prints these "consol.log + line", it doesn't make sense because you can easily find them with Crt + Find and there is no option to switch them off with --silent and --verbose=false options (of course silent will work but it will remove all log so what is the point).
Finally, I came up with:
const colors = require('colors');
const testLog = (str : string) => process.stdout.write(str)
export const Given = (givenMsg: string) => testLog(`\n+ Given ${givenMsg}\n`)
export const When = (whenMsg: string) => testLog(`+ When ${whenMsg}\n`)
export const Then = (thenMsg: string) => testLog(`+ Then ${thenMsg}\n`)
export const And = (andMsg: string) => testLog(`- And ${andMsg}\n`)
export const testCase = (description: string, testFunction: Function) => it (description, () => {
testLog(colors.yellow(`\n\nTest: ${description}\n`))
testFunction()
testLog('\n')
})
Looked like this:
given when then typescript

You could try running jest with the --silent argument.
In package.json, use two scripts:
"scripts": {
"test": "jest --silent",
"testVerbose": "jest"
},

Related

Typescript import module.exports sub function

I'm using mocha to test a function and I'm facing an error while running the test file.
The file structure is as follows
server
|-test
| |-customer.test.ts
|-customer.js
This is the customer.js file function
module.exports = (instance) => {
instance.validate = async (ctx) => {
// some code here
}
}
This is the mocha test case file customer.test.ts
const instance = require("../customer")
/* eslint-disable no-undef */
describe('customer', () => {
describe('/POST customers', () => {
it('Create Buy customer', (done) => {
instance.validate({
})
done();
});
})
});
But when I run the file using the command mocha .\customer.test.ts it shows me the following error
TypeError: instance.validate is not a function
How do I make the above function execute?
What you're exporting and what you're doing with the import don't match. The problem is (probably) the export. What you have is this:
module.exports = (instance) => {
instance.validate = async (ctx) => {
// some code here
}
}
That exports a function that, when called, will add a validate method to the object that you pass to it. It does not export an object with a validate method, that would look like this:
module.exports = {
validate: async (ctx) => {
// some code here
},
};
So you need to either fix the export (which I suspect is the problem), or (if the export is really meant to do that), test what it actually does by passing in an object and then checking that, after the call, the object has a validate method.

How to use jest.each asynchronously

I am having problems loading filenames into jest.each asynchronously.
My code:
let files: string[][]
function getFilesWorking() {
files = [["test1"], ["test2"]]
}
async function getFilesAsync() {
files = await Promise.resolve([["test1"], ["test2"]])
}
beforeAll(() => {
console.log("before")
})
describe.only("Name of the group", () => {
getFilesAsync()
test.each(files)("runs", f => {})
})
beforeAll is executed before each test but NOT before initialization of test.each, so I end up with undefined.
How can I load files before using test.each?
You can pass an async callback to beforeAll and await getFilesAsync within it
beforeAll(async () => {
await getFilesAsync();
})
As of Jest 28.1.3 and prior, this is not possible. There is an open issue documenting this behavior.
The best thing you can do for now is put your tests in a regular it() test and do a deep value comparison:
it('tests an array of cases', async () => {
const data = await getSomeAsyncData()
const expectedData = [ ... ]
expect(data).toEqual(expectedData)
})
You can use beforeEach to set up code that will run prior to tests for any given scope, https://jestjs.io/docs/setup-teardown:
beforeEach(() => {
console.log('before every test');
});
describe.only(('Name of the group') => {
beforeEach(() => {
console.log('before tests in this describe block');
})
})
Jest is only going to run the tests in your describe.only block. If you want to use beforeEach in other blocks and run those tests as well, change describe.only to describe.
(Edit: I know this is a year late, I'm just trying to look for a similar problem/solution set and thought I could answer this.)

How to use jest.spyOn function to test a function from another file

I am trying to run test case for testing entry point of my web service jest
I am facing one issue while running the unit test.
Cannot spy the async function, because it is a property not a function.
I am trying to test if the run function is called in the server.js file
The entry file is somewhat like below.
import config from 'config';
export default async function run() {
try {
/*
some code
*/
} catch (err) {
process.exit(1);
}
}
run();
And the test file is like below
import run from '../server';
describe('server-test', () => {
it('run', async () => {
const start = require('../server');
const spy = jest.spyOn(start, run);
await run();
expect(spy).toBeCalled();
});
});
The test should run properly,
but I am getting below error on running this test
Cannot spy the async function run() {
try {
/*
some code.
*/
} catch (err) {
process.exit(1);
}
} property because it is not a function; undefined given instead
I researched for quite a long for this error and ended on the following post
How to spy on a default exported function with Jest?
So, without ditching the default keyword (i.e required for ES 6 lint), the only solution is to use 'default' word in place of 'run'.
Use somewhat like this.
const spy = jest.spyOn(start, 'default');
It should work.

jest doesn't wait beforeAll resolution to start tests

What I test: An express server endpoints
My goal: automate API tests in a single script
What I do: I launch the express server in a NodeJS child process and would like to wait for it to be launched before the test suite is run (frisby.js endpoints testing)
What isn't working as expected: Test suite is launched before Promise resolution
I rely on the wait-on package which server polls and resolves once the resource(s) is/are available.
const awaitServer = async () => {
await waitOn({
resources: [`http://localhost:${PORT}`],
interval: 1000,
}).then(() => {
console.log('Server is running, launching test suite now!');
});
};
This function is used in the startServer function:
const startServer = async () => {
console.log(`Launching server http://localhost:${PORT} ...`);
// npmRunScripts is a thin wrapper around child_process.exec to easily access node_modules/.bin like in package.json scripts
await npmRunScripts(
`cross-env PORT=${PORT} node -r ts-node/register -r dotenv/config src/index.ts dotenv_config_path=.env-tests`
);
await awaitServer();
}
And finally, I use this in something like
describe('Endpoints' () => {
beforeAll(startTestServer);
// describes and tests here ...
});
Anyway, when I launch jest the 'Server is running, launching test suite now!' console.log never shows up and the test suite fails (as the server isn't running already). Why does jest starts testing as awaitServer obviously hasn't resolved yet?
The npmRunScripts function works fine as the test server is up and running a short while after the tests have failed. For this question's sake, here's how npmRunScripts resolves:
// From https://humanwhocodes.com/blog/2016/03/mimicking-npm-script-in-node-js/
const { exec } = require('child_process');
const { delimiter, join } = require('path');
const env = { ...process.env };
const binPath = join(__dirname, '../..', 'node_modules', '.bin');
env.PATH = `${binPath}${delimiter}${env.PATH}`;
/**
* Executes a CLI command with `./node_modules/.bin` in the scope like you
* would use in the `scripts` sections of a `package.json`
* #param cmd The actual command
*/
const npmRunScripts = (cmd, resolveProcess = false) =>
new Promise((resolve, reject) => {
if (typeof cmd !== 'string') {
reject(
new TypeError(
`npmRunScripts Error: cmd is a "${typeof cmd}", "string" expected.`
)
);
return;
}
if (cmd === '') {
reject(
new Error(`npmRunScripts Error: No command provided (cmd is empty).`)
);
return;
}
const subProcess = exec(
cmd,
{ cwd: process.cwd(), env }
);
if (resolveProcess) {
resolve(subProcess);
} else {
const cleanUp = () => {
subProcess.stdout.removeAllListeners();
subProcess.stderr.removeAllListeners();
};
subProcess.stdout.on('data', (data) => {
resolve(data);
cleanUp();
});
subProcess.stderr.on('data', (data) => {
reject(data);
cleanUp();
});
}
});
module.exports = npmRunScripts;
I found the solution. After trying almost anything, I didn't realize jest had a timeout setup which defaults at 5 seconds. So I increased this timeout and the tests now wait for the server promise to resolve.
I simply added jest.setTimeout(3 * 60 * 1000); before the test suite.
In my case, it caused by the flaw of the beforeAll part. Make sure the beforeAll doesn't contain any uncaught exceptions, otherwise it will behaves that the testing started without waiting for beforeAll resolves.
After much digging I found a reason for why my beforeAll didn't seem to be running before my tests. This might be obvious to some, but it wasn't to me.
If you have code in your describe outside an it or other beforeX or afterY, and that code is dependent on any beforeX, you'll run into this problem.
The problem is that code in your describe is run before any beforeX. Therefore, that code won't have access to the dependencies that are resolved in any beforeX.
For example:
describe('Outer describe', () => {
let server;
beforeAll(async () => {
// Set up the server before all tests...
server = await setupServer();
});
describe('Inner describe', () => {
// The below line is run before the above beforeAll, so server doesn't exist here yet!
const queue = server.getQueue(); // Error! server.getQueue is not a function
it('Should use the queue', () => {
queue.getMessage(); // Test fails due to error above
});
});
});
To me this seems unexpected, considering that code is run in the describe callback, so my impression was that that callback would be run after all beforeX outside the current describe.
It also seems this behavior won't be changed any time soon: https://github.com/facebook/jest/issues/4097
In newer versions of jest (at least >1.3.1) you can pass a done function to your beforeAll function and call it after everything is done:
beforeAll(async (done) => {
await myAsyncFunc();
done();
})
it("Some test", async () => {
// Runs after beforeAll
})
More discussions here: https://github.com/facebook/jest/issues/1256

Sinon stub method calling from another file

I'm trying to set up unit tests in my project. For that, I use mocha chai and sinon librairies. I'm using a NodeJs server version 8.
Versions :
Sinon : "7.1.0"
Mocha: "5.1.0"
Chai: "4.2.0"
I'd like to stub a method which is declared in another file.
Here's an example :
- a.js
exports.FnA(return FnB())
- b.js
exports.FnB()
I want to stub method FnB() from b.js file so I can test FnA() regardless FnB() return.
Here's what I've tried :
beforeEach(() => {
this.FnBStub = sinon.stub(b, 'FnB').returns('mocked');
});
afterEach(() => this.FnBStub.restore());
it('should mocked FnB function', () => {
try {
console.log(b.FnB()); //returns 'mocked'
console.log(a.FnA()); //return error from FnB() execution ...
} catch (e) {
console.log(e);
}
});
It does stub the method FnB() but only when I called it from an instance of b file. So when I called FnA() the stub seems to go away ...
What am I missing ?
Some help would be really appreciated, thanks :)
EDIT :
a.js example :
const FnB = require('./FnB)
exports.FnA = data => {
const limit = data.releases.update ? 60 : 20;
return FnB(data.ref, limit)
};
b.js example :
exports.FnB = (ref, page, query) => {
//API call
}
testFile.js example :
const a = require('../a')
const b = require('../b')
beforeEach(() => {
this.FnBStub = sinon.stub(b, 'FnB').returns('mocked');
});
afterEach(() => this.FnBStub.restore());
it('should mocked FnB function', () => {
try {
console.log(b.FnB()); //returns 'mocked'
console.log(a.FnA()); //return error from FnB() execution ...
} catch (e) {
console.log(e);
}
});
So as I said I'd like to stub this FnB calling method and just check if this method is called with right parameters.
If the module being exported is a function itself and not a part of an object, you can't stub it directly.
You need to use something like proxyquire. Your test code will look something like this:
const FnBstub = sinon.stub();
const proxyquire = require('proxyquire');
const a = proxyquire('../a', {
FnB: FnBstub
});
const b = require('../b');
For more info, look here: https://github.com/sinonjs/sinon/issues/664

Resources