error MongoNotConnectedError when running yield file from unit test nodeJs - node.js

I have a file that containt yield and co logic in node JS, the code look like below
module.export = {
moduleName(payload, callback){
//first logic
// second logic
co(function*(){
yield user.findById(somerandomid)
//error when find user by id
})
}
}
and this is my unit test code
beforeAll(async () => {
await dbHandler.connect();
//this part to connecto to mongodb
});
afterAll(async () => {
await dbHandler.disconnect();
});
afterEach(async () => {
jest.clearAllMocks();
});
it("test",()=>{
moduleName(somepayload)
})
so when i run my test case i got error :
MongoNotConnectedError: Client must be connected before running operations
i know this error because not connected to mongodb but i already create connection in beforeAll function, i have tried to wrap my connection in test case to yield like below
it('ts',async()=>{
co(function*(){
yield dbHandler.connect()
yield moduleName(somepayload)
}
})
but it did not work, any ideas?

Related

Best way to setup files for jest and mongodb

Hihi.
I'm having a problem where jest it's sometimes failing a couple of tests randomly, most of the time because of this error "mongodb memory server cannot perform operation: a background operation is currently running for collection".
In another post I read something about building differents mongo instance for each block of tests.
What I have so far is a globalsetup file where I start the mongo replica set like this:
// global.ts
import { MongoMemoryReplSet } from "mongodb-memory-server";
const replSet = new MongoMemoryReplSet({
replSet: { storageEngine: "wiredTiger" },
});
module.exports = async () => {
await replSet.waitUntilRunning();
const uri = await replSet.getUri();
process.env.MONGODB_URI = uri;
};
and my db.ts is like this
// db.ts
export const connect = async () => {
mongoose.set("useFindAndModify", false);
const conn = mongoose.connect(
process.env.MONGODB_URI || config.connectionString, connectionSettings
);
When trying to call it from a test file I do something like this
// test.spec.ts
import db from "./db";
beforeAll(async () => {
await db.connect();
});
afterAll(async (done) => {
await db.dropCollections();
await db.disconnect(done);
});
beforeEach(async () => {
await seed();
});
describe('Some test', () => {
it('Should not fail and get the seeders', () => {
// some random tests using the seeds values
})
})
What I read in that post is instead of using globalSetup use a setupFile that will run for every test instead of one globally and then I MIGHT be able to solve the concurrency issue I have with my tests.
So, to conclude, does anyone knows if there is a proper way to configure the mongodb in memory or if I am doing something THAT BAD that is allowing this to happend or if is there any kind of improvement I can do that will prevent "mongodb memory server cannot perform operation: a background operation is currently running for collection" this to happen?

mocha unit test not working within callback

I am trying to define my mocha tests in json and then parse them and run my tests. However, I find that I am having difficulty running the tests in the callback functions
function addTwoNumbers(a,b){
return a+b;
}
function testAddNumbers(){
describe("testing the addition of 2 numbers",() => {
it('should return the addition',(done) => {
addTwoNumbers(2,2).should.be.equal(4)
done()
})
})
}
//Obtain all the test jsons
glob(__dirname +'/../**/*.doc.json', {} , (err,fileNames) => {
fileNames.forEach(fileName => {
let file = fs.readFileSync(fileName)
let tests = JSON.parse(file)
tests.forEach(test => {
testAddNumbers()
})
})
})
Which returns:
Backend listening on port 3000
0 passing (1ms)
Moving testAddNumbers() outside the glob block works, so I am not too sure of the problem. Eg:
function addTwoNumbers(a,b){
return a+b;
}
function testAddNumbers(){
describe("testing the addition of 2 numbers",() => {
it('should return the addition',(done) => {
addTwoNumbers(2,2).should.be.equal(4)
done()
})
})
}
//Obtain all the test jsons
glob(__dirname +'/../**/*.doc.json', {} , (err,fileNames) => {
fileNames.forEach(fileName => {
let file = fs.readFileSync(fileName)
let tests = JSON.parse(file)
tests.forEach(test => {
})
})
})
testAddNumbers()
returns
Backend listening on port 3000
testing the addition of 2 numbers
√ should return the addition
1 passing (238ms)
Thanks for the help!
I have fixed it in a way that I find rather disgraceful, but if you can do better do enlighten me
Problem:
Mocha was exiting when it reached the end of the file
Solution:
Loop and wait till file has completed running. This must be done within a mocha test or mocha will blatantly ignore you as if you were its mom
describe('Wait for dynamically added tests to complete', function () {
this.timeout(999999999)
it('Waiting...', function (done) {
completed = (function wait() {
// console.log(completed)
// console.log('boomdiyadah')
if (!completed) {
setTimeout(wait, 1000)
} else {
done()
}
})();
})
})
Probably this could be implemented with promises but my life needs to move forward

Possible collisions of asynchronous unit tests against a test database in Mocha

I am new to the javascript ecosystem, and I am trying to wrap my head around a decent way to do some basic unit testing against the REST API using a stored set of fixtures, i.e. .json files.
My entry point sets up a testing environment by connecting to a test database and emits a ready state.
if (!process.env.TESTING) {
/* Connect to MongoDB */
connect(process.env.DEV_DB_HOST, process.env.DEV_DB, () => app.emit(ready));
app.on(ready, () => {
app.listen(port, () => console.log(`Listening on port ${port}!`));
});
} else {
connect(process.env.TEST_DB_HOST, process.env.TEST_DB, () => app.emit(ready));
}
export default app;
Once the connection is established, the collection recreated in the test database using fixtures and the tests are executed.
import Paper from '../models/paper.js';
describe('Home Page', () => {
before(async() => {
await new Promise((resolve, reject) => {
app.on(ready, () => resolve());
}).then(async() => {
try {
await Paper.collection.drop();
} catch(error) {
/* Mongo throws an exception if the collection in question does not exist */
}
await Paper.create(fixtures);
});
});
after(async() => {
await Paper.collection.drop();
});
it('Returns a list of items ordered by date in descending order', async() => {
const response = await chai.request(app).get('/');
expect(response.body).to.have.lengthOf(2);
expect(response.body).to.be.sortedBy("date", { descending: true });
});
});
If I replace the before and after hooks with beforeEach and afterEach, since the tests are async, is it possible that the hook gets executed for a test and dumps out the collection before another test, which is using the collection, finishes executing? If so, what is a good way to go about populating a test database with fixtures for each test case?

Mocha tests with async initialization code

I am writing tests for a REST client library which has to "login" against the service using the OAuth exchange. In order to prevent logging in for every endpoint I am going to test I'd like to write some sort of "test setup" but I am not sure how I am supposed to do this.
My test project structure:
test
endpoint-category1.spec.ts
endpoint-category2.spec.ts
If I had only one "endpoint category" I had something like this:
describe('Endpoint category 1', () => {
let api: Client = null;
before(() => {
api = new Client(credentials);
});
it('should successfully login using the test credentials', async () => {
await api.login();
});
it('should return xyz\'s profile', async () => {
const r: Lookup = await api.lookup('xyz');
expect(r).to.be.an('object');
});
});
My Question:
Since the login() method is the first test there, it would work and the client instance is available for all the following tests as well. However, how can I do some sort of setup where I make the "logged in api instance" available to my other test files?
Common code should be moved to beforeEach:
beforeEach(async () => {
await api.login();
});
At this point should successfully login using the test credentials doesn't make much sense because it doesn't assert anything.
describe('Endpoint category 1', () => {
let api: Client = null;
beforeEach(() => {
api = new Client(credentials);
});
afterEach(() => {
// You should make every single test to be ran in a clean environment.
// So do some jobs here, to clean all data created by previous tests.
});
it('should successfully login using the test credentials', async () => {
const ret = await api.login();
// Do some assert for `ret`.
});
context('the other tests', () => {
beforeEach(() => api.login());
it('should return xyz\'s profile', async () => {
const r: Lookup = await api.lookup('xyz');
expect(r).to.be.an('object');
});
});
});
Have you had a look at https://mochajs.org/#asynchronous-code ?
You can put in a done-parameter in your test functions and you will get a callback with this you have to call.
done() or done(error/exception)
This done would be also available in before and after.
When calling done() mocha knows your async-code has finished.
Ah. And if you want to test for login, you shouldn't provide this connection to other tests, because there is no guarantee of test order in default configuration.
Just test for login and logout afterwards.
If you need more tests with "login-session", describe a new one with befores.

How do I test this async method call in reactjs using mocha

// Balance.jsx
...
updateToken () {
const parseResponse = (response) => {
if (response.ok) {
return response.json()
} else {
throw new Error('Could not retrieve access token.')
}
}
const update = (data) => {
if (data.token) {
this.data.accessTokenData = data
} else {
throw new Error('Invalid response from token api')
}
}
if (this.props.balanceEndpoint !== null) {
return fetch(this.props.accessTokenEndpoint, {
method: 'get',
credentials: 'include'
})
.then(parseResponse)
.then(update)
.catch((err) => Promise.reject(err))
}
}
componentDidMount () {
this.updateToken()
.then(() => this.updateBalance())
}
}
// Test
it('updates the balance', () => {
subject = mount(<Balance {...props} />)
expect(fetchMock.called('balance.json')).to.be.true
})
I can't figure out how to test the above using Mocha. The code is does work the method updateBalance is called and the fetch api call actually does happen, but the test still fails. If I call updateBalance() synchronously it passes... How do I tell the test to wait for the promise to resolve?
You don't really say what you want to test that the
method does, but if all you want to test is that the method resolves on a network call, then there is no need for Sinon or any of that, as this is all you need:
describe("BalanceComponent", () => {
it("should resolve the promise on a successful network call", () => {
const component = new BalanceComponent({any: 'props', foo: 'bar'});
// assumes you call a network service that returns a
// successful response of course ...
return component.updateToken();
});
});
This will test that the method actually works, but it is slow and is not a true unit test, as it relies on the network being there and that you run the tests in a browser that can supply you with a working implementation of fetch. It will fail as soon as you run it in Node or if the service is down.
If you want to test that the method actually does something specific, then you would need to to that in a function passed to then in your test:
it("should change the token on a successful network call", () => {
const component = new BalanceComponent({any: 'props', foo: 'bar'});
const oldToken = component.data.accessTokenData;
return component.updateToken().then( ()=> {
assert(oldToken !== component.data.accessTokenData);
});
});
If you want to learn how to test code like this without being reliant on there being a functioning link to the networked service you are calling, you can check out the three different techniques described in this answer.

Resources