Skip to content

Feature request: official support for a testcontainers image (NPM) #2176

@mtmacdonald

Description

@mtmacdonald

Hi! In my project we sometimes use testcontainers for "disposable" databases in automated tests.

For example, using the @testcontainers/postgresql NPM package:

import {
  PostgreSqlContainer,
  StartedPostgreSqlContainer,
} from '@testcontainers/postgresql';
import path from 'node:path';
import { migrator } from '@oliasoft-open-source/node-postgresql-migrator';
import { database } from 'src/server/db/database';

let container: StartedPostgreSqlContainer;

export const createTestDatabase = async () => {
  container = await new PostgreSqlContainer('postgres')
    .withDatabase('testdb')
    .withUsername('test')
    .withPassword('test')
    .start();

  const connectionString = container.getConnectionUri();

  const { db } = database.getDB(connectionString);

  await db.any(`
    CREATE TABLE IF NOT EXISTS migrations (
      file_hash TEXT NOT NULL PRIMARY KEY,
      file_name TEXT NOT NULL,
      created_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
    )
  `);

  await migrator({
    dbInstance: db,
    dir: path.resolve('./src/server/db/migrations'),
    force: true,
    autoInitializeTable: false,
  });

  return { db, container, connectionString };
};

Then in test files, something like:

import test, { describe } from 'node:test';
import assert from 'node:assert/strict';
import request from 'supertest';
import http from 'node:http';
import {
  createTestDatabase,
  stopTestDatabase,
} from './testcontainers-test-database.ts';

let server: http.Server;
let BASE_URL: string;

test.before(async () => {
  const { connectionString } = await createTestDatabase();
  process.env.CONNECTION_STRING = connectionString;
  // Dynamically import createApp after setting the environment variable (to ensure connection to test db)
  const { createApp } = await import('server/app.ts');
  const app = createApp();
  server = http.createServer(app);
  await new Promise<void>((resolve) => {
    server.listen(0, () => {
      const { port } = server.address() as any;
      BASE_URL = `http://localhost:${port}`;
      console.log(`Server listening on ${BASE_URL}`);
      resolve();
    });
  });
});

test.after(async () => {
  await new Promise<void>((resolve, reject) =>
    server.close((err) => (err ? reject(err) : resolve())),
  );
  await stopTestDatabase();
});

describe('API integration tests with testcontainers and supertest', () => {
  test('GET /api/tasks', async () => {
    const response = await request(BASE_URL).get('/api/tasks');
    assert.strictEqual(response.status, 200);
    assert.strictEqual(response.body.length, 1);
    const { id, created_at, parent_id, ...rest } = response.body[0];
    assert.deepStrictEqual(rest, {
      title: 'Implement task migration',
      priority: 5,
      description: 'Initial task for the task list application',
    });
  });
});

Would you consider supporting an "official" Doltgres testcontainer image that I could use in a similar way?

I found golang.testcontainers.org/modules/dolt, but that's for GO not NPM, I think it's for the MySQL flavour not Doltgres, and I'm not sure if it's "official".

This is more of a "nice-to-have" for me, but great if you could consider it on your roadmap.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions