Skip to content

Repository files navigation

Pago, the paguro mascot, carrying a Docker container on his shell

testcontainer_compose

Hex PackageHex DocsCILicense: MITMade with Gleam

Spin up docker-compose.yml stacks from your Gleam tests. Pago hands you typed services; the lifecycle (up + body + down) runs automatically.

Companion to testcontainer: use it when you have an existing compose file and want it as the source of truth at test time, with typed access to parsed services.

letcfg=testcontainer_compose.from_file("./docker-compose.yml")|>testcontainer_compose.with_project_name("test_42")|>testcontainer_compose.with_env_override("PG_PASS","secret")usestack<-testcontainer_compose.with_compose(cfg)// Inspect typed service infocasetestcontainer_compose.service_by_name(stack,"postgres"){option.Some(svc)->{let_image=testcontainer_compose.service_image(svc)let_ports=testcontainer_compose.service_ports(svc)Ok(Nil)}option.None->Ok(Nil)}

with_compose/2 runs docker compose up -d --wait, calls your body, then always tears the stack down with docker compose down --volumes --remove-orphans, even if the body returns an error. If the body succeeds but teardown fails, the teardown error is surfaced so leaked stacks are never silent.

Why use it

  • 🐚 Native multi-container: uses Docker's own dependency resolution and health-wait
  • 🔒 Type-safe services: parsed into Service records with name, image, ports
  • 🩺 Reliable YAML handling: delegates parsing to docker compose config --format json, so anchors, includes and extends: all work
  • Hard-cleanup guarantee: down --volumes --remove-orphans runs even on body failure
  • 🔐 Secret-safe overrides: with_env_override wraps values in cowl.Secret

Install

gleam add testcontainer_compose@1

API

Builder

  • from_file(path)ComposeConfig
  • with_project_name(cfg, name) → unique project per test run
  • with_env_override(cfg, key, value) → values wrapped in cowl.Secret (no leak via string.inspect)

Lifecycle

  • with_compose(cfg, body) — up + body + down (always). Teardown failure surfaced when body succeeds.
  • formula(cfg) — returns a StandaloneFormula(ComposeServices, Error). Pass it to testcontainer.with_standalone_formula/2 to get the same up + body + down guarantee with a typed output:
letassertOk(f)=testcontainer_compose.from_file("./docker-compose.yml")|>testcontainer_compose.with_project_name("test_42")|>testcontainer_compose.formula()usestack<-testcontainer.with_standalone_formula(f)

Service inspection

  • services(stack)List(Service)
  • service_by_name(stack, name)Option(Service)
  • service_name(svc) / service_image(svc) / service_ports(svc)

Parser (testable without Docker)

  • parse_services_json(path, json_str): feed it the output of docker compose config --format json and validate parsing.

Errors (testcontainer_compose/error)

pubtypeError{ComposeFileNotFound(path:String)InvalidYaml(path:String,reason:String)ComposeFailed(path:String,reason:String)}

ComposeFailed.reason carries the exit-code prefix (e.g. "docker daemon error: ...") plus full stderr/stdout, so diagnostics never get silently swallowed.

How it works

testcontainer_compose shells out to the Docker CLI for two reasons:

  1. docker compose config --format json lets Docker handle YAML parsing, anchors, env-var interpolation, includes, and extends: inheritance. More reliable than re-implementing the spec.
  2. docker compose up/down reuses Docker's own dependency resolution and health-wait logic.

The Erlang FFI uses erlang:open_port with a 60-second timeout and explicit exit-code mapping (125 = daemon error, 126 = no permissions, 127 = not found).

When to use this vs alternatives

ScenarioTool
Pre-built public image, single containertestcontainer core, container.new
Multi-service Gleam-defined stacktestcontainer.with_network + multiple with_container
Existing docker-compose.yml, source of truththis package
Compose file rarely changesFormula Builder → codegen native
Custom image built inlinetestcontainer_dockerfile

Development

gleam run -m testcontainer_compose_dev # Dev runner (needs Docker)
gleam test# Unit tests (no Docker)
TESTCONTAINERS_INTEGRATION=true gleam test# Integration tests (Docker required)

See also

Full API docs: https://hexdocs.pm/testcontainer_compose

License

MIT.

About

Companion to testcontainer: use it when you have an existing compose file

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages