Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/modules/mssqlserver/Dockerfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
FROM mcr.microsoft.com/mssql/server:2022-CU13-ubuntu-22.04
FROM mcr.microsoft.com/mssql/server:2025-CU9-ubuntu-24.04
54 changes: 24 additions & 30 deletions packages/modules/mssqlserver/src/mssqlserver-container.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import sql, { type config } from "mssql";
import { getImage } from "../../../testcontainers/src/utils/test-helper";
import { MSSQLServerContainer } from "./mssqlserver-container";

const IMAGE = getImage(__dirname);
const IMAGES = ["mcr.microsoft.com/mssql/server:2022-CU27-ubuntu-22.04", getImage(__dirname)];

describe("MSSQLServerContainer", { timeout: 180_000 }, () => {
it("should connect and return a query result", async () => {
describe.each(IMAGES)("MSSQLServerContainer (%s)", { concurrent: false, timeout: 180_000 }, (image) => {
it.concurrent("should connect and return a query result", async () => {
// mssqlConnect {
await using container = await new MSSQLServerContainer(IMAGE).acceptLicense().start();
await using container = await new MSSQLServerContainer(image).acceptLicense().start();

const sqlConfig: config = {
user: container.getUsername(),
Expand All @@ -18,7 +18,7 @@ describe("MSSQLServerContainer", { timeout: 180_000 }, () => {
pool: { max: 1, min: 0, idleTimeoutMillis: 30000 },
options: { trustServerCertificate: true },
};
const connection = await sql.connect(sqlConfig);
const connection = await new sql.ConnectionPool(sqlConfig).connect();

const { recordset } = await connection.query`SELECT 1;`;
expect(recordset).toStrictEqual([{ "": 1 }]);
Expand All @@ -27,12 +27,12 @@ describe("MSSQLServerContainer", { timeout: 180_000 }, () => {
// }
});

it("should connect and return a query result with database URI", async () => {
it.concurrent("should connect and return a query result with database URI", async () => {
// mssqlUriConnect {
await using container = await new MSSQLServerContainer(IMAGE).acceptLicense().start();
await using container = await new MSSQLServerContainer(image).acceptLicense().start();

const connectionString = container.getConnectionUri();
const connection = await sql.connect(connectionString);
const connection = await new sql.ConnectionPool(connectionString).connect();

const { recordset } = await connection.query`SELECT 1;`;
expect(recordset).toStrictEqual([{ "": 1 }]);
Expand All @@ -41,52 +41,46 @@ describe("MSSQLServerContainer", { timeout: 180_000 }, () => {
// }
});

it("should connect and return a query result with valid custom password", async () => {
it.concurrent("should connect and return a query result with valid custom password", async () => {
// mssqlValidPassword {
await using container = await new MSSQLServerContainer(IMAGE).acceptLicense().withPassword("I!@M#$eCur3").start();
await using container = await new MSSQLServerContainer(image).acceptLicense().withPassword("I!@M#$eCur3").start();
// }

const connectionString = container.getConnectionUri();
const connection = await sql.connect(connectionString);
const connection = await new sql.ConnectionPool(connectionString).connect();

const { recordset } = await connection.query`SELECT 1;`;
expect(recordset).toStrictEqual([{ "": 1 }]);

await connection.close();
});

it("should throw error with invalid password", async () => {
const container = new MSSQLServerContainer(IMAGE).acceptLicense().withPassword("password");
it.concurrent("should throw error with invalid password", async () => {
const container = new MSSQLServerContainer(image).acceptLicense().withPassword("password");
await expect(container.start()).rejects.toThrow(
Error('Log stream ended and message "/.*Recovery is complete.*/" was not received')
);
});

it("should start db with express edition", async () => {
it.concurrent("should start db with express edition", async () => {
// mssqlExpressEdition {
await using container = await new MSSQLServerContainer(IMAGE)
await using container = await new MSSQLServerContainer(image)
.acceptLicense()
.withEnvironment({ MSSQL_PID: "Express" })
.withWaitForMessage(/.*Attribute synchronization manager initialized*/)
.withWaitForMessage(/.*SQL Server is now ready for client connections.*/)
.start();
// }

const { output, exitCode } = await container.exec([
"/opt/mssql-tools/bin/sqlcmd",
"-S",
container.getHost(),
"-U",
container.getUsername(),
"-P",
container.getPassword(),
"-Q",
"SELECT @@VERSION;",
]);

expect(exitCode).toBe(0);
expect(output).toContain("Express Edition");
const connection = await new sql.ConnectionPool(container.getConnectionUri()).connect();

const { recordset } = await connection.query`SELECT SERVERPROPERTY('Edition') AS edition;`;
expect(recordset[0].edition).toContain("Express Edition");

await connection.close();
});
});

describe("MSSQLServerContainer", { timeout: 180_000 }, () => {
it("should use custom wait message", async () => {
await using _ = await new MSSQLServerContainer("alpine")
.withCommand(["/bin/sh", "-c", 'echo "custom ready"; sleep 5'])
Expand Down
2 changes: 1 addition & 1 deletion packages/modules/neo4j/Dockerfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
FROM neo4j:5.26.31
FROM neo4j:2026.09.0
20 changes: 10 additions & 10 deletions packages/modules/neo4j/src/neo4j-container.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import neo4j from "neo4j-driver";
import { getImage } from "../../../testcontainers/src/utils/test-helper";
import { Neo4jContainer, Neo4jPlugin } from "./neo4j-container";

const IMAGE = getImage(__dirname);
const IMAGES = ["neo4j:5.26.31", getImage(__dirname)];

describe("Neo4jContainer", { timeout: 180_000 }, () => {
it("should create a person node", async () => {
describe.each(IMAGES)("Neo4jContainer (%s)", { concurrent: false, timeout: 180_000 }, (image) => {
it.concurrent("should create a person node", async () => {
// createNode {
await using container = await new Neo4jContainer(IMAGE).start();
await using container = await new Neo4jContainer(image).start();

const driver = neo4j.driver(
container.getBoltUri(),
Expand All @@ -26,9 +26,9 @@ describe("Neo4jContainer", { timeout: 180_000 }, () => {
// }
});

it("should connect with custom password", async () => {
it.concurrent("should connect with custom password", async () => {
// setPassword {
await using container = await new Neo4jContainer(IMAGE).withPassword("xyz1234@!").start();
await using container = await new Neo4jContainer(image).withPassword("xyz1234@!").start();

const driver = neo4j.driver(
container.getBoltUri(),
Expand All @@ -47,9 +47,9 @@ describe("Neo4jContainer", { timeout: 180_000 }, () => {
await driver.close();
});

it("should have APOC plugin installed", async () => {
it.concurrent("should have APOC plugin installed", async () => {
// apoc {
await using container = await new Neo4jContainer(IMAGE).withApoc().withStartupTimeout(120_000).start();
await using container = await new Neo4jContainer(image).withApoc().withStartupTimeout(120_000).start();

const driver = neo4j.driver(
container.getBoltUri(),
Expand All @@ -66,9 +66,9 @@ describe("Neo4jContainer", { timeout: 180_000 }, () => {
await driver.close();
});

it("should work with plugin list", async () => {
it.concurrent("should work with plugin list", async () => {
// pluginsList {
await using container = await new Neo4jContainer(IMAGE)
await using container = await new Neo4jContainer(image)
.withPlugins([Neo4jPlugin.APOC_EXTENDED, Neo4jPlugin.GRAPH_DATA_SCIENCE])
.withStartupTimeout(120_000)
.start();
Expand Down
2 changes: 1 addition & 1 deletion packages/modules/scylladb/Dockerfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
FROM scylladb/scylla:6.2.3
FROM scylladb/scylla:2026.3.3
18 changes: 9 additions & 9 deletions packages/modules/scylladb/src/scylladb-container.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { Client } from "cassandra-driver"; // Scylla uses Cassandra's driver in
import { getImage } from "../../../testcontainers/src/utils/test-helper";
import { ScyllaContainer } from "./scylladb-container";

const IMAGE = getImage(__dirname);
const IMAGES = ["scylladb/scylla:2025.1.16", getImage(__dirname)];

describe("ScyllaDB", { timeout: 240_000 }, () => {
it("should connect and execute a query", async () => {
describe.each(IMAGES)("ScyllaDB (%s)", { concurrent: false, timeout: 240_000 }, (image) => {
it.concurrent("should connect and execute a query", async () => {
// connectWithDefaultCredentials {
await using container = await new ScyllaContainer(IMAGE).start();
await using container = await new ScyllaContainer(image).start();

const client = new Client({
contactPoints: [container.getContactPoint()],
Expand All @@ -25,8 +25,8 @@ describe("ScyllaDB", { timeout: 240_000 }, () => {
});

// createAndFetchData {
it("should create keyspace, a table, insert data, and retrieve it", async () => {
await using container = await new ScyllaContainer(IMAGE).start();
it.concurrent("should create keyspace, a table, insert data, and retrieve it", async () => {
await using container = await new ScyllaContainer(image).start();

const client = new Client({
contactPoints: [container.getContactPoint()],
Expand All @@ -38,7 +38,7 @@ describe("ScyllaDB", { timeout: 240_000 }, () => {
// Create the keyspace
await client.execute(`
CREATE KEYSPACE IF NOT EXISTS test_keyspace
WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}
WITH replication = {'class': 'NetworkTopologyStrategy', 'replication_factor': '1'}
`);

await client.execute("USE test_keyspace");
Expand All @@ -64,8 +64,8 @@ describe("ScyllaDB", { timeout: 240_000 }, () => {
});
// }

it("should work with restarted container", async () => {
await using container = await new ScyllaContainer(IMAGE).start();
it.concurrent("should work with restarted container", async () => {
await using container = await new ScyllaContainer(image).start();
await container.restart();

const client = new Client({
Expand Down
Loading