Failing expect() inside subscribe() does not mark test as invalid - jestjs

We recently upgraded to Angular 6.0.3, RxJs 6.2.0 and jest 23.1.0 (upgrading from RxJS 5 & Angular 4).
There seems to be a problem with Jest & RxJs as failing expect-statements inside a subscribe-Block do not mark the test as failed. Here's a minimal example:
it("should fail", () => {
const obs = Observable.create((observer) => {
observer.next(false);
});
obs.subscribe((value) => {
console.log(value); // => false
expect(value).toBeTruthy();
});
});
The expect-Statement gets executed, but the test still passes. We didn't observe this behaviour with the previous RxJs version and Jest.

Try to use done.
it("should fail", (done) => {
const obs = Observable.create((observer) => {
observer.next(false);
});
obs.subscribe((value) => {
console.log(value); // => false
expect(value).toBeTruthy();
done();
});
});
more info

Related

Jest: setSystemTime is not available when not using modern timers

Here is the code. I'm getting error TypeError: setSystemTime is not available when not using modern timers when I run the test. I have "#jest/fake-timers": "^27.4.2" in my package.json since I thought there could be a conflict on the package in some dependencies, but issue remains
beforeAll(() => {
jest.useFakeTimers('modern');
jest.setSystemTime(new Date());
});
afterAll(() => {
jest.useRealTimers();
});
Any idea how to resolve this?
As mentioned in this issue, it can be solved by checking the version of jest and it's related packages. For example, I had jest on version 26.6.0 and babel-jest and ts-jest on 27.x. Setting them to 26.x solved the problem.
Facing the same issue here, this patch from #stereodenis is working (copying it here):
let dateNowSpy: jest.SpyInstance;
const today = new Date('2000-01-01').getTime();
describe('...', () => {
beforeEach(() => {
dateNowSpy = jest.spyOn(Date, 'now').mockImplementation(() => today);
});
afterEach(() => {
dateNowSpy.mockRestore();
});
test('...', () => {
/* Date.now() -> 2000-01-01 */
});

isVueInstance is deprecated and will be removed in future releases

I am new with JEST and have received the above warning. I want to know which is the alternative since is being deprecated.
Here is the test that I am making:
it('is instantiated', () => {
expect(wrapper.isVueInstance()).toBeTruthy();
});
Here's how to rigorously check VueInstance
https://github.com/vuejs/vue-test-utils/blob/2d6b49780c7e1d663b877ddf5d6492ed7b510379/packages/test-utils/src/wrapper.js#L400
it('is instantiated', () => {
expect(wrapper.vm).toBeTruthy();
});
I have checked https://vue-test-utils.vuejs.org/api/wrapper/#isvisible and they say:
Assert Wrapper is Vue instance.
So the final thing would be:
it('is instantiated', () => {
expect(wrapper).toBeTruthy();
});
The right answer should be the following:
it('is instantiated', () => {
expect(wrapper.exists()).toBeTruthy();
});
From test/specs/wrapper/find.spec.js in vue-test-utils repository,
you can see that when wrapper doesnt exists they assert Wrapper object with exists().
it('returns empty Wrapper with error if no nodes are found', () => {
const wrapper = mountingMethod(Component)
const selector = 'pre'
const error = wrapper.find(selector)
expect(error.exists()).toEqual(false)
expect(error.selector).toEqual(selector)
})

Nodejs Jest mocking is not working in multiple describe block in a single file, it works in first describe block only

I am using jest for unit testing in my node express application,please excuse , because i am new to all this
in my abc.test.js
const s3Helper = require('../../../../../lib/s3_helper');
beforeEach(async () => {
s3Helper.uploadBufferToS3 = jest.fn(() => true);
});
describe('test1', () => {
it('test1', async () => {
expect(s3Helper.uploadBufferToS3)
.toHaveBeenCalled();
});
});
describe('test2', () => {
it('test2', async () => {
expect(s3Helper.uploadBufferToS3)
.toHaveBeenCalled();
});
});
so when i run this test file in test1 it returns that test is passed, however in test2 it returns expected >=1 returned 0.
since i am mocking it beforeEach i expect it should return 1 for each describe block

How to close Express server inside Jest afterAll hook

I am trying to write integration tests for my Express server using Jest. Since Jest runs tests in parallel (and I would like to avoid running tests in sequence using --runInBand), I am using the get-port library to find a random available port so that different test suites don't have port collisions.
My tests all run successfully, the only problem is that the server is failing to close down properly inside the afterAll hook. This causes Jest to print the following in the console...
Jest did not exit one second after the test run has completed.
This usually means that there are asynchronous operations that weren't stopped in your tests.
Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.
When I use the --detectOpenHandles flag, Jest just hangs after tests complete. Nothing gets printed to the console.
Here is my test code...
let axios = require('axios')
const getPort = require('get-port')
const { app } = require('../../index')
const { Todo } = require('../../models')
// set reference to server to access
// from within afterAll hook
let server
beforeAll(async () => {
const port = await getPort()
axios = axios.create({ baseURL: `http://localhost:${port}` })
server = app.listen(port)
})
afterAll(() => {
server.close()
})
describe('GET /todos', () => {
it('returns a list of todos', async () => {
const { data: todos } = await axios.get('/todos')
todos.forEach(todo => {
expect(Todo.validate(todo)).toEqual(true)
})
})
})
I am on that github thread on this issue. Here is exactly the configuration that works for me. In package.json
"test": "jest --no-cache --detectOpenHandles --runInBand --forceExit",
Here is the configuration in test file
afterEach(async () => {
await server.close();
});
afterAll(async () => {
await new Promise(resolve => setTimeout(() => resolve(), 10000)); // avoid jest open handle error
});
beforeEach(() => {
// eslint-disable-next-line global-require
server = require('../index');
jest.setTimeout(30000);
});
OR you have only afterAll to set timeout and settimeout for each test in the test body individually.That's example below
afterEach(async () => {
await server.close();
});
afterAll(async () => {
await new Promise(resolve => setTimeout(() => resolve(), 10000)); // avoid jest open handle error
});
beforeEach(() => {
// eslint-disable-next-line global-require
server = require('../index');
});
describe('POST /customers', () => {
jest.setTimeout(30000);
test('It creates a customer', async () => {
const r = Math.random()
.toString(36)
.substring(7);
const response = await request(server)
.post('/customers')
.query({
name: r,
email: `${r}#${r}.com`,
password: 'beautiful',
});
// console.log(response.body);
expect(response.body).toHaveProperty('customer');
expect(response.body).toHaveProperty('accessToken');
expect(response.statusCode).toBe(200);
});
});
The root cause is that the express app server is still running after the tests complete. So the solution is to close the server.
In the main server file:
export const server = app.listen(...)
In the test file:
import { server } from './main-server-file'
afterAll(() => {
server.close();
});
Using nodejs 17.4.0, jest 27.5.1, supertest 6.2.2. Running test with
cross-env NODE_OPTIONS=--experimental-vm-modules NODE_ENV=test jest

Node.js: Jest + redis.quit() but open handle warning persists

I'm trying to run an integration test with redis and jest.
It always throws the "Jest has detected the following 1 open handle potentially keeping Jest from exiting:" error when running with --detectOpenHandles.
It doesn't hang so the socket is closing, but how do I write it so it doesn't throw that warning?
My code
import redis from 'redis';
let red: redis.RedisClient;
beforeAll(() => {
red = redis.createClient();
});
afterAll((done) => {
red.quit(() => {
done();
});
});
test('redis', (done) => {
red.set('a', 'b', (err, data) => {
console.log(err);
red.get('a', (err, data) => {
console.log(data);
done();
});
});
});
Warning
Jest has detected the following 1 open handle potentially keeping Jest from exiting:
● TCPWRAP
3 |
4 | beforeAll(() => {
> 5 | red = redis.createClient();
| ^
6 | });
7 |
8 | afterAll((done) => {
at RedisClient.Object.<anonymous>.RedisClient.create_stream (node_modules/redis/index.js:251:31)
at new RedisClient (node_modules/redis/index.js:159:10)
at Object.<anonymous>.exports.createClient (node_modules/redis/index.js:1089:12)
at Object.<anonymous>.beforeAll (src/sockets/redis.integration.test.ts:5:17)
Running the compiled code with regular jest throws the same warning. The compiled code looks nearly identical.
Figured it out after posting. I forgot to post the answer here.
It has to do with how redis.quit() handles its callback.
It creates a new thread so we need to wait for the entire eventloop stack to cycle again. See below for the workaround.
async function shutdown() {
await new Promise((resolve) => {
redis.quit(() => {
resolve();
});
});
// redis.quit() creates a thread to close the connection.
// We wait until all threads have been run once to ensure the connection closes.
await new Promise(resolve => setImmediate(resolve));
}
I have the same issue. I haven't figured it out to fix this but I have a workaround.
You can add jest --forceExit.
For info about forceExit: https://jestjs.io/docs/en/cli.html#forceexit
Fixed for me doing
const redis = require("redis");
const { promisify } = require("util");
const createRedisHelper = () => {
const client = redis.createClient(`redis://${process.env.REDIS_URI}`);
client.on("error", function (error) {
console.error(error);
});
const setAsync = promisify(client.set).bind(client);
const setCallValidateData = async (key, data) => {
return setAsync(key, JSON.stringify(data));
};
return {
setCallValidateData,
cleanCallValidateData: promisify(client.flushdb).bind(client),
end: promisify(client.end).bind(client),
};
};
module.exports = createRedisHelper;
Versions:
redis 3.0.2
node 12.6.1
The problem is that you are creating the redis client but not connecting, so calling later redis.quit will not work, since you have no connection.
try:
beforeAll(async () => {
red = redis.createClient();
await red.connect();
});

Resources