Skip to content

Build and test

TargetDescription
make buildFull build: UI + Go binary into bin/simpledeploy
make build-goGo only. Requires cmd/simpledeploy/ui_dist/ to exist
make ui-buildBuild Svelte UI and copy dist/ into cmd/simpledeploy/ui_dist/
make testAll Go unit/integration tests (go test ./...)
make e2eBuild binary, start a real server, run Playwright suite headless
make e2e-headedSame, with a visible browser window
make e2e-reportOpen the HTML report from the last E2E run
make devHot-reload: Air for Go API + Vite for UI
make apiAPI only with hot-reload (Air)
make uiVite dev server only
make api-non-hmrBuild + run with config.dev.yaml, no reloader
make cleanRemove bin/ and cmd/simpledeploy/ui_dist/
make hooks-installEnable git hooks from .githooks/ (pre-push: vet + lint + build + short tests + vitest)

After cloning, run make hooks-install once. This points core.hooksPath at .githooks/ and enables:

  • pre-push: go vet ./..., golangci-lint run ./..., go build ./..., go test -short ./..., and ui vitest if ui/node_modules exists.

golangci-lint is required (mirrors CI). Install: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.4. Skip just the lint step with SIMPLEDEPLOY_SKIP_LINT=1 git push.

Bypass all hooks with git push --no-verify or SIMPLEDEPLOY_SKIP_HOOKS=1 git push.

Terminal window
go test ./... # everything
go test ./internal/api/ -v # one package
go test ./internal/store/ -run TestUpsert # one test
go test -race -count=1 ./internal/... # race detector, no cache

Conventions:

  • Docker tests skip cleanly when the daemon is unavailable.
  • Store tests use a temp DB file per test.
  • API tests use httptest + a real store.
  • Mock Docker client in internal/docker/mock.go.
  • Mock command runner in internal/deployer/runner.go.

Fast Svelte + JS tests covering pure helpers, stores, components, and routes. Run in ~4 seconds and gate every push via the pre-push hook.

Terminal window
cd ui
npm test # run once
npm run test:watch # watch mode

Tests live in ui/src/**/__tests__/*.test.js and use @testing-library/svelte + jsdom. src/test-mocks/api.js exposes makeApiMock() for stubbing the API module, and src/routes/__tests__/LayoutStub.svelte passes through Layout children so route-level tests stay focused.

Any UI change that adds new behavior, fixes a bug, or modifies component logic must include or update a vitest. See UI Test Coverage Rule for the full policy.

Skip only for pure visual tweaks, docblock-only edits, or behavior fully covered by E2E where a vitest would duplicate without adding signal.

Terminal window
make e2e # full suite, headless, ~2.5 min
make e2e-headed # with browser window
make e2e-report # open last HTML report

Requires Docker running, Go, Node.js. The harness builds the binary, starts a real server on a random port with TLS off, and deploys real fixture apps. See E2E tests for adding cases.

Prefer a vitest over a new E2E spec when the logic can be exercised with mocks. Vitests run in seconds; the full E2E suite takes ~20 minutes.

Where to add tests for each kind of change

Section titled “Where to add tests for each kind of change”
ChangeAdd tests in
New store methodinternal/store/<feature>_test.go
New API endpointinternal/api/<handler>_test.go plus E2E flow
New backup strategyinternal/backup/<name>_test.go
New backup targetinternal/backup/<name>_test.go
New Caddy moduleinternal/proxy/<module>_test.go
New UI componentui/src/components/__tests__/<Name>.test.js
New UI lib/helperui/src/lib/__tests__/<name>.test.js
New UI routeui/src/routes/__tests__/<Name>.test.js (smoke + key interaction)
UI flow (full-stack)New or extended file in e2e/tests/
CLI commandcmd/simpledeploy/*_test.go if behavior is non-trivial
JobTriggerWhat it does
lintpush + PRgolangci-lint
testpush + PRgo test ./... and cd ui && npm test
buildpush + PRfull make build
e2epush to mainPlaywright against a real server

All jobs except E2E must pass before a PR can merge.