[node] Testcontainers with github actions
Published: 2024-08-19
I tried running testcontainers on github actions, the trick to running them was increasing the default timeout for your tests. Github has out of the box support for docker, there is a delay with startup though, so you need to account for that. I thought this was a hack, but the official testcontainers repo uses this approach as well.
{
// jest config
"testEnvironment": "node",
"preset": "ts-jest",
"testTimeout": 60000
}
About testcontainers
In case you’re wondering what testcontainers are; it’s a library that provides lightweight containers for your tests. It allows you to easily set up dependencies, so you can run your tests against in a “real” environment. You can E2E test a CRUD backend with a real database, or test against an actual message queue. It adds a lot of reliability since the dependencies are very close to the real deal, and it makes E2E/integration test set up a breeze.
Here’s an example test using nestjs with drizzle as an ORM:
import request from 'supertest';
import { runMigrations } from '@db/migrate';
import { schema } from '@db/schema';
import { DrizzlePostgresModule } from '@knaadh/nestjs-drizzle-postgres';
import { INestApplication } from '@nestjs/common';
import { PostgreSqlContainer } from '@testcontainers/postgresql';
import { StartedPostgreSqlContainer } from '@testcontainers/postgresql/build/postgresql-container';
import { UserModule } from '../src/user/user.module';
describe('users e2e', () => {
let app: INestApplication;
let postgresContainer: StartedPostgreSqlContainer;
beforeAll(async () => {
postgresContainer = await new PostgreSqlContainer().start();
// add DATABASE_URL to env so we can use it for our migrations
process.env.DATABASE_URL = postgresContainer.getConnectionUri();
const moduleFixture = await Test.createTestingModule({
imports: [
DrizzlePostgresModule.registerAsync({
tag: 'DB',
useFactory() {
return {
postgres: {
url: postgresContainer.getConnectionUri(),
},
config: { schema },
};
},
}),
UserModule
],
}).compile();
// this also runs a seed method for testdata in non dev environments
await runMigrations();
app = moduleFixture.createNestApplication();
await app.init();
});
afterAll(async () => {
await app.close();
await postgresContainer.stop();
});
it('Get users', () => {
// Run actual http request against server with postgres database
return request(app.getHttpServer())
.get('/users')
.expect(200)
.expect([
{ id: 1, name: 'Marijn' },
]);
});
});