Testing Inside a DevContainer in CI
If CI runs tests on the raw runner instead of inside the devcontainer, it isn't testing the environment developers use. This page runs the suite inside the container with devcontainer exec, so the test toolchain, services, and dependencies exactly match local development.
Prerequisites
You need a devcontainer that builds in CI and a test command.
- A committed devcontainer config that builds in CI.
- A test command that runs inside the container.
- Any services the tests need declared in the config/compose.
Step-by-Step Implementation
- Build the environment.
devcontainer up --workspace-folder .
- Run the suite inside the container.
devcontainer exec --workspace-folder . -- npm test
- Bring up dependent services if the tests need them (Compose devcontainer).
devcontainer up --workspace-folder . # runServices starts db, cache, etc.
- Fail the job on a non-zero exit —
execpropagates it automatically.
Common Pitfalls
Test parity fails when tests run on the host or services aren't started.
| Symptom | Root Cause | Remediation |
|---|---|---|
| Tests pass in CI, fail locally | CI tested the host, not the container | Run tests via devcontainer exec |
| Tests can't reach the database | Services not started | Start them via the Compose devcontainer |
| Job stays green on failing tests | Exit code not propagated | Let exec return the test exit code |
| Different results each run | Unpinned deps/runtime | Pin runtime + commit the lockfile |
Conclusion
Run the suite where the code runs: inside the devcontainer, via devcontainer exec, against the same services and pinned toolchain developers use. Then a passing CI run is a real statement about the developer environment, not the runner's incidental setup.
FAQ
Why not just run tests on the CI runner?
Because the runner's toolchain, services, and dependencies differ from the devcontainer developers use, so a green run says nothing about their environment. Running inside the container via devcontainer exec makes CI test the exact environment, so failures reproduce locally on the first try.
How do the tests reach a database in CI?
Use a Compose-backed devcontainer so the database and other services start alongside the workspace, and run tests via exec inside the workspace container. The tests reach services by name on the shared network, exactly as they do locally.
Does a failing test fail the job?
Yes, as long as you run via devcontainer exec, which propagates the command's exit code. A non-zero test exit becomes a non-zero job, so CI correctly fails. Avoid swallowing the exit code in a wrapper script.
Related
- Up to CI/CD Integration with DevContainers — the overview of CI integration.
- Running the devcontainer CLI in GitHub Actions — the workflow around the tests.
- Caching DevContainer Builds in CI — keeping the test pipeline fast.