A polished, security-first reimagination of zodern/mtest, created to eliminate the maintenance burden and dependency vulnerabilities that have accumulated around the original Node.js CLI.
- Why a Reimagining?
- Feature Highlights
- Quick Start
- CLI Reference
- Workflow Deep Dive
- Parity with the Original Project
- Migration Tips
- Roadmap
- Contributing
- License
Important
The primary motivation behind this Go rewrite is to remedy the vulnerable, end-of-life dependencies that power the legacy @zodern/mtest npm package. By leaning on modern Go tooling and actively maintained libraries, the attack surface shrinks while day-to-day DX improves.
- Security posture: No more transitive npm chain; Go modules (Rod, Logrus, pflag) are actively patched.
- Portability: Ships as a single static binary, making CI/CD distribution trivial.
- Stability: System signal handling, process groups, and deterministic logging are first-class citizens.
| Area | What’s New | Why It Matters |
|---|---|---|
| CLI ergonomics | pflag-powered parsing, verbose levels (-vvv) |
Familiar UX with precise logging control |
| Browser automation | Rod + Chromium headless launch | Mirrors Puppeteer behaviour without npm baggage |
| Output fidelity | Streams Meteor + browser console verbatim, skips sentinel lines | All the insights, none of the noise |
| Graceful shutdown | Cross-platform process group teardown | Prevents orphaned Meteor or Chrome processes |
| Observability | Structured, timestamped logrus output | Parse-friendly logs for CI pipelines |
# 1. Validate code style + unit tests via the Makefile helpers
make ci
# 2. Build the CLI (outputs ./bin/mtest)
make build
# 3. Execute the test runner
./bin/mtest --package <package-path-or-name> --onceNeed a quick smoke test? A tiny Meteor package lives at test/dummy. Point the CLI at it to validate your setup after building:
make integrationor run directly:
./bin/mtest --package ./test/dummy --oncenpm install --save-dev @illusionfield/mtest
npx mtest --package <package-path-or-name> --onceor globally:
npm install --global @illusionfield/mtest
mtest --package <package-path-or-name> --onceThe installer pulls the latest GitHub release from illusionfield/mtest, inspects the published assets, and picks the bundle that best matches your OS/arch (e.g. mtest-{tag}-{GOOS}-{GOARCH}.zip). Pin a specific release with either npm install --save-dev @illusionfield/mtest --mtest-version=v1.2.3 or MTEST_DIST_VERSION=v1.2.3 npm install. Further controls:
MTEST_DIST_BASE_URL– point at a custom artefact host (supports{tag}/{version}placeholders).MTEST_DIST_ASSET_PREFIX– override the asset basename (same placeholders supported).MTEST_DIST_ASSET– fetch a single explicit filename.MTEST_DIST_REPO– target another GitHub repository for releases.MTEST_DIST_GITHUB_TOKEN– provide a token if the GitHub API rate-limit is hit.
When developing locally you can bypass downloads entirely via MTEST_SKIP_BINARY_INSTALL=true.
| Target | What it does |
|---|---|
make ci |
Runs fmt-check, go vet, and unit tests to mirror the default CI suite. |
make build |
Compiles the CLI into ./bin/mtest (respects BIN_DIR/BIN_NAME). |
make integration |
Executes the dummy Meteor package smoke test (INTEGRATION_PACKAGE/INTEGRATION_FLAGS configurable). |
make fmt / make fmt-check |
Formats Go sources in place or verifies formatting without writing. |
make lint |
Runs formatting verification plus go vet static analysis. |
make coverage |
Produces coverage.out via go test -coverprofile. |
make tidy / make deps |
Keeps module metadata tidy or prefetches dependencies. |
make clean |
Drops build artefacts, coverage data, and Go build caches. |
make install |
Installs the CLI into $(go env GOPATH)/bin for use in your PATH. |
Common options:
--once– exit after the first run (perfect for CI)--release <version>– pin a specific Meteor release--test-app-path <path>– point at a custom test harness-v,-vv– step logging to debug/trace (or use--verbose=<0-5|info|debug|trace>)
| Flag | Alias | Type | Description |
|---|---|---|---|
--package |
string | Required. Meteor package name to execute under meteor test-packages. |
|
--release |
string | Target Meteor release (for reproducible environments). | |
--test-app-path |
string | Relative/absolute path to an app folder used as the test harness. | |
--once |
bool | Stop after the first test cycle completes. | |
--inspect |
bool | Passes --inspect to Meteor for live debugging. |
|
--inspect-brk |
bool | Passes --inspect-brk to Meteor (breaks on first line). |
|
--port |
int | Force a specific port (defaults to an auto-picked free port 10000-11999). | |
--verbose |
-v |
string | Increase logging level (-v→debug, -vv→trace, --verbose=info or --verbose=3, etc.). |
--version |
-V |
bool | Print semantic version/commit info and exit. |
-
Port discovery By default
mtestshuffles ports in the 10000-11999 range and selects a free one, matching the behaviour of the Node CLI’sget-portdependency. -
Meteor orchestration The tool spawns
meteor test-packageswith your CLI flags, mirroring stdout/stderr exactly, and listens for readiness markers (10015,test-in-console listening). -
Headless verification Once ready, Rod launches Chromium in headless mode with the same sandbox overrides Puppeteer used. Console output (minus the magic sentinel) is streamed straight back to your terminal.
-
Status polling Every 500 ms the page is evaluated to determine TinyTest completion and failure counts. Results are piped back as exit codes, so CI can fail fast.
-
Graceful teardown SIGINT/SIGTERM handlers fan out to Meteor and Chromium process groups, protecting local dev cycles and shared CI runners from orphaned processes.
| Capability | @zodern/mtest (Node) |
mtest (Go) |
|---|---|---|
| CLI flags | ✔ identical flag set | ✔ (see cmd/mtest) |
| Auto port selection | via get-port |
via native TCP probing |
| Puppeteer driven | ✔ | ➜ Rod-powered |
| Stream test console | ✔ | ✔ (sentinel filtered) |
| Process cleanup | basic tree-kill |
cross-platform process groups |
| Dependency health | multiple unmaintained npm deps | lean Go module graph |
If you relied on custom Node scripts around the original CLI, drop-in replacement is as simple as swapping the executable call — arguments and behaviour line up 1:1.
Tip
To ensure reproducibility, bake the compiled binary into your project’s toolchain (e.g., commit to an internal bucket or wrap it in a Makefile target).
- Replace
npx mtestinvocations with the compiled Go binary. - Use the new verbosity levels to mirror any logging you previously captured with
DEBUG=*. - Validate that your CI environment still has Chromium/Chrome available; Rod auto-downloads when necessary, but caching the binary speeds things up.
- JSON output mode for machine parsing
- Native HTML/JUnit report generation
- Plug-in hooks before/after Meteor spawn
- Homebrew/Scoop/Tap packages for one-command installs
Have ideas? Open an issue and join the discussion.
- Fork and clone this repository.
- Run
make fmt(ormake fmt-check) andmake cibefore proposing changes. - Describe behavioural impacts clearly in your PR — backwards compatibility is a priority.
MIT © The mtest Contributors. See LICENSE for details.