Jest, 2 describe make timeOut in test with 2 beforeEach mockClear() - jestjs

I have a test file like this:
const axios = require('axios')
const Vacations = require('../../soap/vacationsSoap')
jest.mock('axios')
describe('describe a', () => {
beforeEach(() => { axios.default.post.mockClear() })
it('some it a.1', () => {
expect(Vacations.getReadXML()).toBe('something')
})
})
describe('describe b', () => {
beforeEach(() => { axios.default.post.mockClear() })
it('some it b.1', async () => {
axios.default.post.mockResolvedValueOnce({ data: 'sth' })
const client = new Vacations()
await expect(client.save()).rejects.toThrow('some error')
})
})
When I run the test, it gets hangout until I get a timeOut error.
But, if I remove the:
beforeEach(() => { axios.default.post.mockClear() })
from the second "describe" it works ok.
I copy pasted the while body from the describe 1 into 2, that's why I thought that it would works with the beforeEach. Why is happening that?

Related

Jest await not working/returning anything test is frozen

I am trying to use await in my test and when I run the test runner the test becomes stuck and no test result is returned. Here is my code
describe("retrieveCandidate", () => {
describe("when settings are found", () => {
beforeEach(() => {
configurationApi = new ConfigurationApi(BaseUrl);
});
afterEach(() => {
configurationApi = undefined;
});
it("should return set of configuration values", () => {
const configurationValueSet: IConfigurationValueSet | undefined =
await configurationApi?.retrieveCandidate(controlConfigurationValueSet.specializationKey);
expect(true).toEqual(true);
});
});
So in my testsetup file I had
jest.useFakeTimers();
This caused my async functions to never return anything and caused my test to be in a frozen state

How to optimize tests from multiple "act"?

My tests are already working fine. But I'm a bit worried because I have still remaining 5 tests to make and it already consumed 5 seconds. There are five working testing, and one only using async
The code below shows that act is running on each tests. Even though I already mocked the api, I don't seem to see the difference because I think its consuming 1 second on each test.
I would like to ask advice or ask on how we could optimize it, so we could lessen the time execution? I already tried beforeAll but it will cause and error to other test.
describe('when using filter functions', () => {
describe('when using search function', () => {
beforeEach(async () => {
providerApi.getUsers.mockImplementationOnce(() => {
return Promise.resolve().then(() => {
return { data: testData.token }
})
})
await act(async () => {
render(
<Main>
<Home />
</Main>
)
})
})
afterEach(() => {
providerApi.getUsers.mockReset()
jest.clearAllMocks()
})
it('test #1', async () => {
const pagination = await screen.getByTestId('project-list')
...
});
it('test #2', () => { ... })
it('test #3', () => { ... })
it('test #4', () => { ... })
it('test #5', () => { ... })
});
});

Change jest mock on class for single test

I have an issue where I want to change what a class method returns for a single test while testing a different module. I have the following:
testingModule.test.js
const { testingModuleMethod } = require('../testingModule')
jest.mock('../helperClass', () =>
jest.fn().mockImplementation(() => ({
helperClassMethod: jest.fn()
}))
);
describe('testingModule.js', () => {
describe('testingModuleMethod', () => {
describe('when errors', () => {
const consoleSpy = jest.spyOn(console, 'error');
// SOMETHING NEEDS TO GO HERE TO CHANGE THE jest.mock ON LINE 3
await expect(testingModuleMethod(data)).rejects.toThrow('Error');
expect(consoleSpy).toHaveBeenCalled();
consoleSpy.mockRestore();
});
});
});
testingModule.js
const HelperClass = require('./helperClass');
const testingModuleMethod = async (data, callback) => {
try {
const objectToEvaluate = data.object;
const helperClassInstance = new HelperClass();
await helperClassInstance.helperClassMethod(objectToEvaluate);
log('info', "Success!");
callback(null, {});
} catch(error) {
log('error', 'Something went wrong')
}
};
No matter what I put in there I either get an error with the code (undefined) or it just ignores it and resolves due to the mock at the start. I have tried adding a spy as well as importing the class and using the prototype override.
I'm using node and "jest": "^27.0.6"
I have managed to answer this by doing the following:
Firstly I discovered that to mock a class like that I have to add a jest function into the mock like so:
describe('testingModuleMethod', () => {
describe('when errors', () => {
const consoleSpy = jest.spyOn(console, 'error');
HelperClass.mockImplementation(() => ({
helperClassMethod: jest.fn(() => { throw new Error('Error') })
}));
await expect(testingModuleMethod(data)).rejects.toThrow('Error');
expect(consoleSpy).toHaveBeenCalled();
consoleSpy.mockRestore();
});
});
This also had a knock on effect to the rest of the tests though so I added a beforeEach at the start that looks like:
HelperClass.mockImplementation(
jest.fn().mockImplementation(() => ({
helperClassMethod: jest.fn()
}))
);
Finally I needed to require the class. The overall test looks like this now and works:
const { testingModuleMethod } = require('../testingModule');
const HelperClass = require('./helperClass');
jest.mock('../helperClass', () =>
jest.fn().mockImplementation(() => ({
helperClassMethod: jest.fn()
}))
);
describe('testingModule.js', () => {
beforeEach(() => {
HelperClass.mockImplementation(
jest.fn().mockImplementation(() => ({
helperClassMethod: jest.fn()
}))
);
});
describe('testingModuleMethod', () => {
describe('when errors', () => {
const consoleSpy = jest.spyOn(console, 'error');
HelperClass.mockImplementation(() => ({
helperClassMethod: jest.fn(() => { throw new Error('Error') })
}));
await expect(testingModuleMethod(data)).rejects.toThrow('Error');
expect(consoleSpy).toHaveBeenCalled();
consoleSpy.mockRestore();
});
});
});

Open handles while testing Koa.js with Jest

Here's a trivial trivial koa server implementation:
const Koa = require('koa')
const api = require('./resources')
const createServer = () => {
const app = new Koa()
app.use(api.routes())
app.use(api.allowedMethods())
return app
}
module.exports = createServer
And a simple test:
const request = require('supertest')
const createServer = require('../src/server')
const { knex } = require('../src/config/db')
let server
beforeAll(() => {
server = createServer().listen(8081)
return server
})
beforeEach(() => {
return () => {
knex.migrate.latest()
knex.seed.run()
}
})
afterEach(() => {
return () => {
knex.migrate.rollback()
}
})
afterAll(() => {
server.close()
})
describe('routes: /api/users', () => {
describe('GET /users', () => {
test('should return json', async () => {
const response = await request(server).get('/api/users')
expect(response.status).toEqual(200)
expect(response.type).toEqual('application/json')
expect(response.body).toHaveLength(3)
})
})
})
I will skip the example route for brevity sake as the test passes successfully. But then it hangs, and running jest --detectOpenHandles produces:
Jest has detected the following 1 open handle potentially keeping Jest from exiting:
● TCPSERVERWRAP
6 |
7 | beforeAll(() => {
> 8 | server = createServer().listen(8081)
| ^
9 | return server
10 | })
11 |
at Application.listen (node_modules/koa/lib/application.js:82:19)
at Object.<anonymous> (__tests__/routes.test.js:8:27)
Why does this occur and how can I fix it?
There are several problems.
return server doesn't affect anything, it can be removed. But beforeAll doesn't wait for the server to start, it should be:
beforeAll(done => {
server = createServer().listen(8081, done)
})
beforeEach and afterEach return functions that are not executed, promises from Knex aren't chained, it should be:
beforeEach(async () => {
await knex.migrate.latest()
await knex.seed.run()
})
afterEach(async () => {
await knex.migrate.rollback()
})
afterAll doesn't wait for server connection to be closed, which is likely the cause for this error, it should be:
afterAll(done => {
server.close(done)
});

Fail mocha test in catch block of rejected promise

How to fail the test in catch block of promise rejection when making http call using axios?
Adding expectations, asserts, should expressions in catch block doesn't help.
The test is passing.
I's run using .\node_modules\.bin\mocha
let chai = require('chai');
var expect = chai.expect;
var axios = require('axios')
var instance = axios.create({})
describe('test', () => {
context('test', () => {
it('should succeed', () => {
let url = 'url'
instance.get(url)
.then(function(response) {
expect(response.data).not.to.be.null
} )
.catch(function(err) {
console.error(err.data)
// should fail the test
})
})
})
})
If You want to verify my suggestions, replace url value with valid url (ex: https://google.com)
You can try several ways:
1) Using assert.fail()
const axios = require('axios');
const { assert, expect } = require('chai');
const instance = axios.create({})
describe('test', () => {
context('test', () => {
it('should succeed', () => {
let url = 'abc'
return instance.get(url)
.then((res) => {
expect(res.data).not.to.be.null;
})
.catch((err) => {
assert.fail('expected', 'actual', err);
});
});
});
});
2) Using done() with error object
const axios = require('axios');
const { expect } = require('chai');
const instance = axios.create({})
describe('test', () => {
context('test', () => {
it('should succeed', (done) => {
let url = 'abc'
instance.get(url)
.then((res) => {
expect(res.data).not.to.be.null;
done();
})
.catch((err) => {
done(err);
});
});
});
});
3) Simply just throw an error :)
const axios = require('axios');
const { expect } = require('chai');
const instance = axios.create({})
describe('test', () => {
context('test', () => {
it('should succeed', () => {
let url = 'abc'
return instance.get(url)
.then((res) => {
expect(res.data).not.to.be.null;
})
.catch((err) => {
throw err;
});
});
});
})
If You want to check if that method fails at all and You expect this, go that way (it requires chai-as-promised package):
const axios = require('axios');
const chai = require('chai');
chai.use(require('chai-as-promised'));
const instance = axios.create({})
describe('test', () => {
context('test', () => {
it('should succeed', () => {
let url = 'abc'
return chai.expect(instance.get(url)).to.be.rejected;
});
});
});

Resources