Skip to content
6 changes: 2 additions & 4 deletions docs/modules/selenium.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@ These examples use the following libraries:

Choose an image from the container registry and substitute `IMAGE`:

- [AMD Standalone Chrome](https://hub.docker.com/r/selenium/standalone-chrome)
- [AMD Standalone Firefox](https://hub.docker.com/r/selenium/standalone-firefox)
- [ARM Standalone Chromium](https://hub.docker.com/r/seleniarm/standalone-chromium)
- [ARM Standalone Firefox](https://hub.docker.com/r/seleniarm/standalone-firefox)
- [Standalone Chrome](https://hub.docker.com/r/selenium/standalone-chrome)
- [Standalone Firefox](https://hub.docker.com/r/selenium/standalone-firefox)

### Navigate to a page

Expand Down
18 changes: 9 additions & 9 deletions packages/modules/cassandra/src/cassandra-container.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { ImageName } from "testcontainers";
import { getImage } from "../../../testcontainers/src/utils/test-helper";
import { CassandraContainer } from "./cassandra-container";

const IMAGE = getImage(__dirname);
const IMAGES = ["cassandra:4.1.12", getImage(__dirname)];

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

const client = new Client({
contactPoints: [container.getContactPoint()],
Expand All @@ -18,7 +18,7 @@ describe("CassandraContainer", { concurrent: false, timeout: 240_000 }, () => {
await client.connect();

const result = await client.execute("SELECT release_version FROM system.local");
expect(result.rows[0].release_version).toBe(ImageName.fromString(IMAGE).tag);
expect(result.rows[0].release_version).toBe(ImageName.fromString(image).tag);

await client.shutdown();
// }
Expand All @@ -29,7 +29,7 @@ describe("CassandraContainer", { concurrent: false, timeout: 240_000 }, () => {
const username = "testUser";
const password = "testPassword";

await using container = await new CassandraContainer(IMAGE).withUsername(username).withPassword(password).start();
await using container = await new CassandraContainer(image).withUsername(username).withPassword(password).start();

const client = new Client({
contactPoints: [container.getContactPoint()],
Expand All @@ -52,7 +52,7 @@ describe("CassandraContainer", { concurrent: false, timeout: 240_000 }, () => {
const customDataCenter = "customDC";
const customRack = "customRack";

await using container = await new CassandraContainer(IMAGE)
await using container = await new CassandraContainer(image)
.withDatacenter(customDataCenter)
.withRack(customRack)
.start();
Expand All @@ -73,7 +73,7 @@ describe("CassandraContainer", { concurrent: false, timeout: 240_000 }, () => {

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

const client = new Client({
contactPoints: [container.getContactPoint()],
Expand Down Expand Up @@ -112,7 +112,7 @@ describe("CassandraContainer", { concurrent: false, timeout: 240_000 }, () => {
// }

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

const client = new Client({
Expand All @@ -124,7 +124,7 @@ describe("CassandraContainer", { concurrent: false, timeout: 240_000 }, () => {
await client.connect();

const result = await client.execute("SELECT release_version FROM system.local");
expect(result.rows[0].release_version).toBe(ImageName.fromString(IMAGE).tag);
expect(result.rows[0].release_version).toBe(ImageName.fromString(image).tag);

await client.shutdown();
});
Expand Down
186 changes: 94 additions & 92 deletions packages/modules/couchbase/src/couchbase-container.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,76 +6,17 @@ import { CouchbaseContainer } from "./couchbase-container";
import { CouchbaseService } from "./couchbase-service";
import PORTS from "./ports";

const ENTERPRISE_IMAGE = getImage(__dirname, 0);
const COMMUNITY_IMAGE = getImage(__dirname, 1);

describe("CouchbaseContainer", { timeout: 180_000 }, () => {
const flushBucketAndCheckExists = async (
cluster: Cluster,
bucket: Bucket,
key: string
): Promise<couchbase.ExistsResult> => {
const coll = bucket.defaultCollection();

await cluster.buckets().flushBucket(bucket.name);
return coll.exists(key);
};

it.each([ENTERPRISE_IMAGE, COMMUNITY_IMAGE])("should connect and query using %s image", async (image) => {
// connectAndQuery {
const bucketDefinition = new BucketDefinition("mybucket");
await using container = await new CouchbaseContainer(image).withBucket(bucketDefinition).start();

const cluster = await couchbase.Cluster.connect(container.getConnectionString(), {
username: container.getUsername(),
password: container.getPassword(),
});

const bucket = cluster.bucket(bucketDefinition.getName());
await bucket.waitUntilReady(10_000, {
serviceTypes: [couchbase.ServiceType.KeyValue],
});

const coll = bucket.defaultCollection();
await coll.upsert("testdoc", { foo: "bar" });
const result = await coll.get("testdoc");
const COMMUNITY_IMAGES = ["couchbase/server:community-7.6.2", getImage(__dirname, 1)];
const ENTERPRISE_IMAGES = ["couchbase/server:enterprise-7.6.12", getImage(__dirname, 0)];

expect(result.content).toEqual({ foo: "bar" });
describe.each(COMMUNITY_IMAGES)("CouchbaseContainer (%s)", { concurrent: false, timeout: 180_000 }, (image) => {
it.concurrent("should connect and query", () => expectStoredDocument(image));

await cluster.close();
// }
});

it.each([ENTERPRISE_IMAGE, COMMUNITY_IMAGE])(
"should flush bucket if flushEnabled and check any document exists with %s image",
async (image) => {
const bucketDefinition = new BucketDefinition("mybucket").withFlushEnabled(true);
const container = new CouchbaseContainer(image).withBucket(bucketDefinition);

await using startedTestContainer = await container.start();
const cluster = await couchbase.Cluster.connect(startedTestContainer.getConnectionString(), {
username: startedTestContainer.getUsername(),
password: startedTestContainer.getPassword(),
});

const bucket = cluster.bucket(bucketDefinition.getName());
await bucket.waitUntilReady(10_000, {
serviceTypes: [couchbase.ServiceType.KeyValue],
});

const coll = bucket.defaultCollection();

await coll.upsert("testdoc", { foo: "bar" });

const existResult = await flushBucketAndCheckExists(cluster, bucket, "testdoc");
it.concurrent("should flush bucket if flushEnabled and check any document exists", () =>
expectFlushRemovesDocument(image));

expect(existResult.exists).toBe(false);
await cluster.close();
}
);

it("should throw error if analytics service enabled with community version", async () => {
const container = new CouchbaseContainer(COMMUNITY_IMAGE).withEnabledServices(
it.concurrent("should throw error if analytics service enabled with community version", async () => {
const container = new CouchbaseContainer(image).withEnabledServices(
CouchbaseService.KV,
CouchbaseService.ANALYTICS
);
Expand All @@ -85,28 +26,17 @@ describe("CouchbaseContainer", { timeout: 180_000 }, () => {
);
});

it("should throw error if eventing service enabled with community version", async () => {
const container = new CouchbaseContainer(COMMUNITY_IMAGE).withEnabledServices(
CouchbaseService.KV,
CouchbaseService.EVENTING
);
it.concurrent("should throw error if eventing service enabled with community version", async () => {
const container = new CouchbaseContainer(image).withEnabledServices(CouchbaseService.KV, CouchbaseService.EVENTING);

await expect(() => container.start()).rejects.toThrowError(
"The Eventing Service is only supported with the Enterprise version"
);
});

it("should start with analytics service enabled", async () => {
await using container = await new CouchbaseContainer(ENTERPRISE_IMAGE)
.withEnabledServices(CouchbaseService.KV, CouchbaseService.ANALYTICS)
.start();

expect(container.getConnectionString()).toContain("couchbase://");
});

it("should create and use a bucket with KV service only", async () => {
it.concurrent("should create and use a bucket with KV service only", async () => {
const bucketDefinition = new BucketDefinition("kvbucket").withPrimaryIndex(false);
await using container = await new CouchbaseContainer(COMMUNITY_IMAGE)
await using container = await new CouchbaseContainer(image)
.withEnabledServices(CouchbaseService.KV)
.withBucket(bucketDefinition)
.start();
Expand All @@ -128,10 +58,8 @@ describe("CouchbaseContainer", { timeout: 180_000 }, () => {
await cluster.close();
});

it("should connect without a bucket", async () => {
await using container = await new CouchbaseContainer(COMMUNITY_IMAGE)
.withEnabledServices(CouchbaseService.KV)
.start();
it.concurrent("should connect without a bucket", async () => {
await using container = await new CouchbaseContainer(image).withEnabledServices(CouchbaseService.KV).start();

const cluster = await couchbase.Cluster.connect(container.getConnectionString(), {
username: container.getUsername(),
Expand All @@ -145,21 +73,95 @@ describe("CouchbaseContainer", { timeout: 180_000 }, () => {
await cluster.close();
});

it("should fail when setup exceeds the startup timeout", async () => {
const container = new CouchbaseContainer(COMMUNITY_IMAGE)
.withEnabledServices(CouchbaseService.KV)
.withStartupTimeout(2_000);
it.concurrent("should fail when setup exceeds the startup timeout", async () => {
const container = new CouchbaseContainer(image).withEnabledServices(CouchbaseService.KV).withStartupTimeout(2_000);

await expect(() => container.start()).rejects.toThrowError(/URL \/pools not accessible after \d+ms/);
});

it("should preserve fixed host port binding", async () => {
it.concurrent("should preserve fixed host port binding", async () => {
const hostPort = await getPort();
await using container = await new CouchbaseContainer(COMMUNITY_IMAGE)
await using container = await new CouchbaseContainer(image)
.withEnabledServices(CouchbaseService.KV)
.withExposedPorts({ container: PORTS.MGMT_PORT, host: hostPort })
.start();

expect(container.getMappedPort(PORTS.MGMT_PORT)).toBe(hostPort);
});
});

describe.each(ENTERPRISE_IMAGES)("CouchbaseContainer (%s)", { concurrent: false, timeout: 180_000 }, (image) => {
it.concurrent("should connect and query", () => expectStoredDocument(image));

it.concurrent("should flush bucket if flushEnabled and check any document exists", () =>
expectFlushRemovesDocument(image));

it.concurrent("should start with analytics service enabled", async () => {
await using container = await new CouchbaseContainer(image)
.withEnabledServices(CouchbaseService.KV, CouchbaseService.ANALYTICS)
.start();

expect(container.getConnectionString()).toContain("couchbase://");
});
});

async function expectStoredDocument(image: string): Promise<void> {
// connectAndQuery {
const bucketDefinition = new BucketDefinition("mybucket");
await using container = await new CouchbaseContainer(image).withBucket(bucketDefinition).start();

const cluster = await couchbase.Cluster.connect(container.getConnectionString(), {
username: container.getUsername(),
password: container.getPassword(),
});

const bucket = cluster.bucket(bucketDefinition.getName());
await bucket.waitUntilReady(10_000, {
serviceTypes: [couchbase.ServiceType.KeyValue],
});

const coll = bucket.defaultCollection();
await coll.upsert("testdoc", { foo: "bar" });
const result = await coll.get("testdoc");

expect(result.content).toEqual({ foo: "bar" });

await cluster.close();
// }
}

async function expectFlushRemovesDocument(image: string): Promise<void> {
const bucketDefinition = new BucketDefinition("mybucket").withFlushEnabled(true);
const container = new CouchbaseContainer(image).withBucket(bucketDefinition);

await using startedTestContainer = await container.start();
const cluster = await couchbase.Cluster.connect(startedTestContainer.getConnectionString(), {
username: startedTestContainer.getUsername(),
password: startedTestContainer.getPassword(),
});

const bucket = cluster.bucket(bucketDefinition.getName());
await bucket.waitUntilReady(10_000, {
serviceTypes: [couchbase.ServiceType.KeyValue],
});

const coll = bucket.defaultCollection();

await coll.upsert("testdoc", { foo: "bar" });

const existResult = await flushBucketAndCheckExists(cluster, bucket, "testdoc");

expect(existResult.exists).toBe(false);
await cluster.close();
}

async function flushBucketAndCheckExists(
cluster: Cluster,
bucket: Bucket,
key: string
): Promise<couchbase.ExistsResult> {
const coll = bucket.defaultCollection();

await cluster.buckets().flushBucket(bucket.name);
return coll.exists(key);
}
8 changes: 4 additions & 4 deletions packages/modules/kurrentdb/src/kurrentdb-container.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { KurrentDBClient, type StreamSubscription } from "@kurrent/kurrentdb-cli
import { getImage } from "../../../testcontainers/src/utils/test-helper";
import { KurrentDbContainer } from "./kurrentdb-container";

const IMAGE = getImage(__dirname);
const IMAGES = ["kurrentplatform/kurrentdb:25.0.1", getImage(__dirname)];

describe("KurrentDbContainer", { concurrent: false, timeout: 240_000 }, () => {
describe.each(IMAGES)("KurrentDbContainer (%s)", { concurrent: false, timeout: 240_000 }, (image) => {
it("should execute write and read", async () => {
// startContainer {
await using container = await new KurrentDbContainer(IMAGE).start();
await using container = await new KurrentDbContainer(image).start();

const client = KurrentDBClient.connectionString(container.getConnectionString());

Expand Down Expand Up @@ -49,7 +49,7 @@ describe("KurrentDbContainer", { concurrent: false, timeout: 240_000 }, () => {

it("should use built-in projections", async () => {
// usingStandardProjections {
await using container = await new KurrentDbContainer(IMAGE).start();
await using container = await new KurrentDbContainer(image).start();
const client = KurrentDBClient.connectionString(container.getConnectionString());

await client.appendToStream("Todo-1", [
Expand Down
2 changes: 0 additions & 2 deletions packages/modules/selenium/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
FROM selenium/standalone-chrome:153.0
FROM seleniarm/standalone-chromium:124.0
FROM selenium/standalone-firefox:156.0
FROM seleniarm/standalone-firefox:125.0
4 changes: 2 additions & 2 deletions packages/modules/selenium/src/selenium-container.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { getImage } from "../../../testcontainers/src/utils/test-helper";
import { SELENIUM_VIDEO_IMAGE, SeleniumContainer } from "./selenium-container";

const browsers = [
["CHROME", process.arch === "arm64" ? getImage(__dirname, 1) : getImage(__dirname, 0)],
["FIREFOX", process.arch === "arm64" ? getImage(__dirname, 3) : getImage(__dirname, 2)],
["CHROME", getImage(__dirname, 0)],
["FIREFOX", getImage(__dirname, 1)],
] as const;

describe.for(browsers)("SeleniumContainer", { timeout: 240_000 }, ([browser, image]) => {
Expand Down
Loading