Creating single knex connection pool for all tests in jest - javascript

I use knex in my project and I try to write tests with it (with jest). I want to execute some scripts before each test and after each test, so each test will run on the same data in db.
I tried to create a global connection pool with knex, and execute the scripts in the tests setup. The problem is when I have tests in different describe scope.
For example, lets say I have 2 tests, each test is in different describe scope
import { connection } from './global-setup.ts'
describe('first', () => {
beforeEach( async () => {
await connection.raw(...)
}
afterEach( async () => {
await connection.raw(...)
}
it('test1', () => {...})
}
and same for the second test. The result is that the scripts in beforeEach is not always run, And as a result the second tests sometimes pass, and sometimes fail.
I did noticed that the connection pool is initalized every time for different describe scope, which I think is the cause of the problem. (and if I put the first and the second test in the same describe scope they always pass)
How can I fix this? or how can I make one connection pool for all the describe tests?

Related

Problems getting Mocha tests to wait for db to be built

I have the following code which is designed to create a test db, upgrade it, seed it with data and then run a bunch of mocha tests:-
await createDatabase().then(async () => {
console.log("upgrading database");
await dbUpgrade().then(async () => {
console.log("seeding database");
await seedTestDatabase().then(() => {
After "seedTestDatabase", I call all my test suites. When I run this code, I get the following in the console:-
Opening database ./db/test.sqlite
listening on port 4001
creating database
upgrading database
starting upgrade
0 passing (1ms)
finished upgrade
seeding database
seeding test database
starting tests
For some reason, Mocha decides in the middle of the db upgrade function that it can't find any tests! If I run the functions createDatabase, dbUpgrade then seedDatabase manually one by one, everything works. What's going on with Mocha?
probably, it can work with mochajs
describe('test database is build', function(){
this.timeout(60 * 1000); // mocha terminates tests after 3 seconds with timeout error
it('creates database', function() {
return createDatabase();
});
it('updates database', function() {
return dbUpgrade();
});
it('seeds database', function() {
return seedTestDatabase();
});
});
if we assume each function depicted in question returns promise, we can call all them as test suit items in promise style approach sequently

Async Mocha done() isn't called in my function

I call this function, console log is called but done() is not called:
import {Database} from "../../code/server/Database";
import 'mocha'
const expect = require('chai').expect
describe('Database save', function() {
it('should save without error', function(done) {
Database.saveSessionData(1, 2, 3, function(err, docs) {
expect(err).to.equal(null)
expect(docs.sessionOpenTime).to.equal(1)
expect(docs.sessionCloseTime).to.equal(2)
expect(docs.sessionLength).to.equal(3)
console.log(2222)
done()
})
})
})
Here is the result, 'Running tests' continues spinning on forever:
But if I change the 'Database' code into this, it works as expected:
setTimeout(function () {
console.log('lol')
done()
}, 1000)
What am I missing here?
Mocha test hangs since you have an opened database connection.
There are two options to solve this problem:
If you do not need a real database connection in your tests:
you can use sinon.stub() (https://www.npmjs.com/package/sinon) to return a predetermined response for async methods you use in your tests or sinon.spy() to make sure a stubbed method called exact number of times.
Here's a good article I just found to illustrate how to use sinon.js: https://semaphoreci.com/community/tutorials/best-practices-for-spies-stubs-and-mocks-in-sinon-js.
you can implement a dependency injection container to be able to replace your implementation of Database class to a Database class that does not perform I/O operations.
Although dependency injection implementations may vary depending on requirements some simple implementations are also available:
https://blog.risingstack.com/dependency-injection-in-node-js/
If you need to perform a real connection in your tests:
Consider adding an after hook to your mocha tests:
let's say mongodb is used as a database (it does not matter, but it would
be an actual working example)
const mongoose = require('mongoose');
const expect = require('chai').expect;
mongoose.connect('mongodb://localhost/test');
after(() => {
mongoose.connection.close();
});
describe('db connection', () => {
it('should make a test', () => {
expect(1).to.equal(1);
});
});

Mocha change timeout for afterEach

I am writing a node application with mocha and chai. Some of the tests call an external API for integration tests, which might take up to 90sec to perform the action.
In order to cleanup properly, I defined an afterEach()-block, which will delete any generated remote resources, in case an expect fails and some resources weren't deleted.
The tests themselves have an increased timeout, while the rest of the tests should retain their default and small timeout:
it('should create remote resource', () => {...}).timeout(120000)
However, I can't do the same with afterEach().timeout(120000), because the function does not exist - nor can I use the function ()-notation due to the unknown resource names:
describe('Resources', function () {
beforeEach(() => {
this._resources = null
})
it('should create resources', async () => {
this._resources = await createResources()
expect(false).to.equal(true) // fail test, so...
await deleteResources() // will never be called
})
afterEach(async() => {
this._resources.map(entry => {
await // ... delete any created resources ...
})
}).timeout(120000)
})
Any hints? Mocha is version 4.0.1, chai is 4.1.2
The rules are same for all Mocha blocks.
timeout can be set for arrow functions in Mocha 1.x with:
afterEach((done) => {
// ...
done();
}).timeout(120000);
And for 2.x and higher it, beforeEach, etc. blocks are expected to be regular functions in order to reach spec context. If suite context (describe this) should be reached, it can be assigned to another variable:
describe('...', function () {
const suite = this;
before(function () {
// common suite timeout that doesn't really need to be placed inside before block
suite.timeout(60000);
});
...
afterEach(function (done) {
this.timeout(120000);
// ...
done();
});
});
Mocha contexts are expected to be used like that, since spec context is useful, and there are virtually no good reasons to access suite context inside specs.
And done parameter or promise return are necessary for asynchronous blocks.
If you need to use dynamic context you have to use normal function.
describe('Resources', function () {
// ...
afterEach(function (){
this.timeout(120000) // this should work
// ... delete any created resources ...
})
})

Javascript Mocha schedule one time test data cleanup

I am writing a mini-framework for executing unit tests for a product I work on. I want test data to be published and managed as seamlessly as possible. With Mocha, it is easy to schedule test data cleanup using the After() hook.
You could wrap an individual test in a describe() block and use that block's Before/After method, but that I'd rather avoid that if possible.
You could pass a cleanup function to afterEach which specifically targets data populated inside a test. Though that would only be necessary for one cleanup and it seems clunky to do that.
Is it possible to generate test data within one test, just for the sake of that test, and also schedule a cleanup for it with Mocha?
Sure, just run your generation and cleanup in the test itself. If it's asynchronous, you can use the done callback to make it wait until it's called.
mocha.setup('bdd');
describe('suite', function() {
function getData() {
// Simulate asynchronous data generation
console.log('grabbing data');
return new Promise((resolve, reject) => {
setTimeout(() => resolve(100), 500);
});
}
function cleanup() {
// Simulate asynchronous cleanup
console.log('cleaning up...');
return new Promise((resolve, reject) => {
setTimeout(resolve, 500);
});
}
it('should do generation and clean up', function(done) {
// Generate some data
getData()
.then(data => {
// Test the data
if (data !== 100) {
throw new Error('How?!');
}
console.log('test passed');
// Cleanup
return cleanup();
})
.then(_ => {
// Use done() after all asynchronous work completes
console.log('done cleaning');
done();
})
.catch(err => {
// Make sure it cleans up no matter what
cleanup().then(_ => console.error(err));
});
});
});
mocha.run();
<script src="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.js"></script>
<div id="mocha"></div>
I think cleanup after test is generally problematic because cleanup consistency guarantees aren't very strong, ie is cleanup function guaranteed to run? probably not. If it's not assured that cleanup will take place then it could very well leave the next tests in an inconsistent state. I think it's good to make an attempt but you can guard against failure by:
cleaning up/establishing db state BEFORE each test
nuking the world so each test has a consistent state (can be accomplished by executing your test in the context of a transaction and rolling back the transaction after each test, and at least not ever committing the transaction)
having test create unique data. By leveraging unique data you can also run your tests in parallel, since it allows for multiple different tests to have an isolated view of the db. If each test writes its own data you only have to worry about provisioning the whole db at the beginning of each test run
Of the above if you're able to wrap your test in a transaction it is lightning fast, (web frameworks like django and rails do this and it is quite fast and makes tests/db state very easy to reason about)

Tests for asynchron functions which depend on the previous one with mochajs

I'm writing a set of tests for a server.
Basically there are pre defined requests and the expected answers for every of them.
The tests are stored in a json file, so I could later extend it as demanded.
A few tests rely on two ID's of foregoing test, so the tests shouldn't be executed in parallel. To archive that I'm using the waterfall function of the async library, so im able to pass arguments to the next function.
The problem is, when I'm iterating through this array of tests, I'm calling it(testname, function(done){...}).In this function I execute the request and compare the response to the expected answer. After that I call the done function so mochajs knows the test is finished.
When I'm starting the tests, the first one get's executed, but no further ones.
For me it looks like that mochajs recognizes that there's currently no other test-task running, so it stops the script.
This is the test:
var testFunctions=[];
predefinedTests.forEach(function(test){
var fn = function(error, id_1, id_2, callback){
it("Test", function(done){
makeAsyncRequest(test.url, function(res){
expect(res).to.have.properties(test.answer);
id_1=res.id1;
id_2=res.id2;
done();
/*check if it's the first test,
if that's the case it needs to use the first argument as callback */
if(callback==undefined) return error(null, id_1, id_2);
callback(null, id_1, id_2);
});
});
}
testFunctions.push(fn);
});
async.waterfall(testFunctions);
so the tests shouldn't be executed in parallel.
Declaring a test to be asynchronous only tells Mocha that is must wait for the test to be complete, not that it is free to run tests in parallel. Mocha does not run tests in parallel, no matter whether they are synchronous or not. So you do not have to use async to prevent Mocha from doing something it does not do in the first place. (There exist packages that you must add to your test setup if you want tests running in parallel. Like this one. Presumably, they patch Mocha to add the parallel capability.)
You should just remove the async stuff, and have your foreEach callback call it directly.
Other than this, you have set up your test suite so that one test depends on the status of a previous test. Generally, you should write your Mocha tests so that they are independent from one another. Mocha is really designed so that the tests are supposed to be run independently. For instance, if you use --grep to select only a subset of tests. Mocha won't know about the dependencies between your tests and you'll get failures if the selected tests depend on tests that were not selected. Generally, you want to put anything a test depends on in a before or beforeEach hook.
If you are in a situation where doing this would be onerous, you could keep state in a higher scope. I would not want to make it global, so I'd put everything inside a describe:
describe("all tests", function () {
// WARNING: The following tests must be run in sequence.
// We have to do this because [explain here what reason requires
// this setup].
var id1;
var id2;
predefinedTests.forEach(function(test){
it("Test", function(done){
makeAsyncRequest(test.url, function(res){
expect(res).to.have.properties(test.answer);
id1=res.id1;
id2=res.id2;
done();
});
});
});
(I don't see in your question how the idX variables are used to make a new request so my code above does not show it. I presume makeAsyncRequest would somehow use them.)

Categories

Resources