Integration Test with TypeORM - node.js

I'm doing an integration test by making requests to my dev server by Supertest. But I have trouble with how to put data into the database. For example, before run GET test, I want to insert data to the database. But I even can't get a connection from TypeORM:
ConnectionNotFoundError: Connection "default" was not found.
If I even get the connection from TypeORM, how I wrap a test within transaction and rollback transaction after finish the test to make sure the integration test doesn't effect to a real database.
Basically, Is there any package that similar with factory_bot of Rails ?
describe("Templates", (): void => {
describe("GET /api/v1/templates/{templateHash}", (): void => {
let template: Template;
beforeEach(
async (): Promise<void> => {
let templateService: TemplateService = new TemplateService();
let connection: Connection = getConnection("default");
template = new Template(Buffer.from(faker.random.words()), faker.random.uuid(), faker.system.fileName());
await templateService.create(connection, template);
},
);
it("should return a template", (done): void => {
request(config.devEnvEndpoint)
.get(`api/v1/templates/${template.templateHash}`)
.set("Accept", "application/json")
.expect(200)
.end((err, response): void => {
console.log(response);
done();
});
});
});
});

It looks like typeorm is not picking up your config. I recommend using the ormconfig.json file and have two database configs - one for your development and one for testing.
By having two databases, you won't need to worry about transactions and can drop the database between tests. I suppose transactions would be faster but it really depends on your usecase (I noticed tests were much slower when making lots of connection.synchronize() calls).
Then you could use an environment variable to determine which connection to instantiate:
// db.ts
import { Connection, createConnection } from 'typeorm'
let connection: Connection | null = null
export async function getConnection() {
if (connection) {
return connection;
}
// DATABASE_CONFIG can be 'development' or 'test'
// and should correspond to the connection names
// in the ormconfig.json file
connection = await createConnection(process.env.DATABASE_CONFIG);
return connection;
}
export async function closeConnection() {
await connection?.close();
}
Then you can set the environment variable and run your tests:
// DATABASE_CONFIG=test yarn test
import { getConnection, closeConnection } from './db'
let connection: Connection;
beforeAll(async () => {
connection = await getConnection();
});
beforeEach(async () => {
// Drop everything and recreate db
await connection.synchronize(true);
});
afterAll(async () => {
await closeConnection();
});
it('should create a connection', () => {
expect(connection).toBeDefined();
})

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?

How do you test Postgres with Node.js / Jest without mocking the pg import

I have 2 SQL queries I want to test, an INSERT and a SELECT. I want to run a test that calls the insert, and then calls the select, which should return the data from the insert.
I found a stackoverflow post about mocking postgres, but I want to actually run a test instance of postgres instead of mocking the actual queries.
An integration test with postgres could look like this:
const { Pool } = require('pg');
describe('testing postgres', () => {
let pgPool;
beforeAll(() => {
pgPool = new Pool({
connectionString: process.env.TEST_DATABASE_URL
});
});
afterAll(async () => {
await pgPool.end();
});
it('should test', async () => {
const client = await pgPool.connect();
try {
await client.query('BEGIN');
const { rows } = await client.query('SELECT 1 AS "result"');
expect(rows[0]["result"]).toBe(1);
await client.query('ROLLBACK');
} catch(err) {
throw err;
} finally {
client.release();
}
})
});
You would call this test with:
TEST_DATABASE_URL=postgresql://sth:sth#someserver/testdb jest
Testing an insert and select can be done by using RETURNING *.
const { rows } = await client.query('INSERT INTO ... RETURNING *');
Using BEGIN and ROLLBACK is necessary - so you do not alter the database and have side effects for the next test to come.

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?

Jestjs - database connection created in beforeEach block becomes undefined in test block

I have setup my project so that once a database connection is made an event is emitted. The app starts after this.
When unit testing I setup a local variable, create the database connection inside beforeEach and save the connection to the local variable.
Within this beforeEach block I can see that the database is connected. However, if I check inside a test block the local variable returns undefined. What is the correct approach for this?
- db.config.ts -
export async function connectToDatabase(mediator: EventEmitter) {
const connectionOptions = await getConnectionOptions();
const dbConnection = await createConnection(connectionOptions);
mediator.emit('db.ready', dbConnection);
}
- index.ts -
const mediator = new EventEmitter();
connectToDatabase(mediator);
mediator.on('db.ready', (db: Connection) => {
app.listen(3000);
console.log('app started');
});
Test
describe('Jest Tests', () => {
const mediator = new EventEmitter();
let dbConnection: Connection;
beforeEach(async () => {
connectToDatabase(mediator);
mediator.on('db.ready', (db: Connection) => {
dbConnection = db;
console.log(dbConnection.isConnected); // **returns TRUE**
}
}
test('Testing db connection', () => {
console.log(dbConnection.isConnected); // **dbConnection undefined**
}
}
I also tried placing the local variables outside the describe block.
beforeEach hook callback returns immediately, although it is async. You need to explicitly return a Promise from it, and fulfill it only when the db.ready event is emitted (or reject it on a certain timeout).
In pseudo code, it should look like this:
beforeEach(async () => {
return new Promise(async (fulfill, reject) => {
await connectToDatabase(mediator);
mediator.on('db.ready', db => {
dbConnection = db;
fulfill();
})
// reject on timeout
})
})
Just to add a bit more clarity to my comment, the following piece of code worked;
beforeEach(async (done) => {
connectToDatabase(mediator);
mediator.on('db.ready', (db: Connection) => {
dbConnection = db;
done();
});
});

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