Problems getting Mocha tests to wait for db to be built - javascript

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

Related

Creating single knex connection pool for all tests in jest

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?

SQL query does not execute in afterAll() function while writing test cases

I am writing unit test cases using Protractor, Jasmine.
I have a code written in beforeAll() functions which sets up data by fetching from database using sql queries
Similarly, there is an afterAll() function whose task is to reset the data in database as it was before the test cases executed
beforeAll(() => {
//get database connection
// setup database data
});
it('should .....', () => {
//code
});
afterAll(() => {
// we can cleanup the database after we're done running our tests
cleanup.clearAlerts(connection)
.then(data => {
//code
});
});
Here the beforeAll() functions executes sql queries correctly
However, the afterAll() function just doesn't execute any cleanup sql queries.
Do some browser action in afterall to overcome the problem.
like
afterAll(async function () {
//your sql query here
await browser.waitForAngularEnabled(false);
await browser.get(browser.baseUrl);
});
Hope it help you.

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);
});
});

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)

Assert not working in mocha when using child_process exec

I have some troubles with unit testing code that uses a module that uses child_process exec. Mocha does not work properly when I create an unit test that uses asserts inside or after an exec call. When an assert is triggered, Mocha just will keep running until the given timeout is reached. When the assert is not triggered, everything will work properly.
For example, in this test case Mocha will run until the timeout is reached:
it('someTest', function (done) {
var exec = require('child_process').exec;
exec('ping 8.8.8.8', () => {
assert.deepEqual(1, 2, 'test');
done();
});
});
Then same problem still accrues when the assert is outside the exec:
it('someTest2', function (done) {
var exec = require('child_process').exec;
var promise = new Promise((promiseDone) => {
exec('ping 8.8.8.8', () => {
var success = 1 === 2;
promiseDone(success, '1 has to be 2');
});
});
promise.then((success, message) => {
assert.deepEqual(success, true, message); // Assert stops the test but Mocha does not stop
done();
});
});
A workaround for this problem is to create a before statement where you execute the method that uses exec and save the results, then you create a it(); block that checks those results with asserts.
This does not feel like a proper solution. With this approach, you are doing the unit tests in a before statement and check the results later in an it(); block. That cannot be right.
An example:
var success = true;
before(function (done) {
this.timeout(10000);
var exec = require('child_process').exec;
exec('ping 8.8.8.8', () => {
success = 1 === 2;
done();
});
});
it('someTest1', function (done) {
assert.deepEqual(success, true, 'test');
done();
});
Your ping command takes longer than 2 seconds. I'm not all that familiar with Windows but the attempts that ping makes by default take longer than 2 seconds. So increasing the timeout is one solution.
On a *nix system ping will typically run until you hit Ctrl-C. According to the man on my Debian system, if you want ping to end earlier, you can use -c [count] to set the number of packets to send. Or -w [deadline] to set a deadline by which it must end. For instance, ping -w 1 8.8.8.8 will work just fine with your code. (There's also -W [timeout] which tells ping how long to wait before giving up if there is no response, see the manual for details.)
If you were just using ping as some placeholder command just to test the structure of your Mocha tests, you could use echo foo instead (or whatever the equivalent is on Windows), or something as simple that ends right away.

Categories

Resources