testcontainers_gleam
Gleam wrapper around Elixir TestContainers for managing Docker containers in tests.
Installation
gleam add --dev testcontainers_gleam
Mind that elixir is required to use this library, as it wraps an Elixir dependency. You can install Elixir from the official website.
Quick start
import testcontainers_gleam
import testcontainers_gleam/container
pub fn demo_test() {
// Build a container definition
let c =
container.new("redis:7.4-alpine")
|> container.with_exposed_port(6379)
|> container.with_environment("REDIS_PASSWORD", "secret")
// Start the container (GenServer is started automatically)
let assert Ok(running) = testcontainers_gleam.start_container(c)
// Query the running container
let id = container.container_id(running)
let assert Ok(host_port) = container.mapped_port(running, 6379)
// ... use host_port to connect to Redis ...
// Stop the container
let assert Ok(Nil) = testcontainers_gleam.stop_container(id)
}
Container configuration
The container module exposes a builder API for configuring containers:
import testcontainers_gleam/container
import testcontainers_gleam/wait_strategy
container.new("postgres:16-alpine")
|> container.with_exposed_port(5432)
|> container.with_environment("POSTGRES_PASSWORD", "test")
|> container.with_cmd(["postgres", "-c", "log_statement=all"])
|> container.with_label("project", "my_app")
|> container.with_waiting_strategy(
wait_strategy.log("database system is ready to accept connections", 30_000, 1000),
)
|> container.with_auto_remove(True)
Available builder functions
| Function | Description |
|---|---|
with_exposed_port | Expose a single port (mapped to a random host port) |
with_exposed_ports | Expose multiple ports at once |
with_fixed_port | Bind a container port to a specific host port |
with_environment | Set an environment variable |
with_cmd | Set the container command |
with_bind_mount | Mount a host path into the container |
with_bind_volume | Mount a named Docker volume |
with_label | Add a container label |
with_waiting_strategy | Add a readiness wait strategy |
with_auto_remove | Auto-remove the container on exit |
with_reuse | Reuse containers across test runs |
with_network_mode | Set the network mode ("bridge", "host", etc.) |
with_auth | Set registry credentials for private images |
with_check_image | Set an image name validation pattern |
with_pull_policy | Set the pull policy (AlwaysPull or NeverPull) |
Wait strategies
Wait strategies control how testcontainers detects that a container is ready:
import testcontainers_gleam/wait_strategy
// Wait for a TCP port to accept connections
wait_strategy.port("0.0.0.0", 5432, 5000, 500)
// Wait for a log line matching a regex pattern
wait_strategy.log("Ready to accept connections", 10_000, 1000)
// Wait for a command to exit with status 0
wait_strategy.command(["pg_isready"], 10_000, 1000)
All strategies take timeout (max wait in ms) and retry_delay (polling interval in ms) parameters.
Requirements
- Docker must be running
- Erlang/OTP and Elixir (this library wraps an Elixir dependency)
Further documentation can be found at https://hexdocs.pm/testcontainers_gleam.
Troubleshooting integration tests on CI
This doesn’t seem to be always necessary, but in case you are experiencing issues such as:
An unexpected error occurred:
[Id([1]), Reason(Undefined), Desc(Undefined), Spawn(Undefined), Order(Undefined)]
gleeunit.main
An unexpected error occurred:
[Id([]), Reason(Blame([1, 1])), Desc(Undefined), Spawn(Undefined), Order(Undefined)]
it may required to run the tests as follows.
testcontainers-gleam provides a test runner and guard function for integration tests that start Docker containers.
Test runner
Replace gleeunit.main() with integration.main() in your test entry point.
This gives each test a 600-second timeout instead of gleeunit’s default 5 seconds,
which is too short for container startup. It also automatically disables the Ryuk
sidecar container, which fails in most CI environments:
// test/my_project_test.gleam
import testcontainers_gleam/integration
pub fn main() {
integration.main()
}
Gating integration tests
Use integration.guard() to skip individual tests when the
TESTCONTAINERS_INTEGRATION_TESTS environment variable is not set:
pub fn redis_test() {
use <- integration.guard()
let assert Ok(running) = testcontainers_gleam.start_container(container)
// ...
}
CI configuration
Add these to your CI workflow:
- run: gleam test
env:
TESTCONTAINERS_INTEGRATION_TESTS: 1
inotify-toolsis required on Linux for the filesystem watcher dependency- Ryuk is automatically disabled by the test runner
Development
gleam deps download # Download dependencies
TESTCONTAINERS_INTEGRATION_TESTS=1 gleam test # Run the tests (requires Docker)
gleam format src test # Format code
License
testcontainers-gleam is licensed under the MIT license. See full license HERE