# Testing signals — immich-app/immich

> Canonical page: https://codevetter.com/unpack/immich/testing-signals

# Testing signals — immich-app/immich

Scanned commit d6d094738366aaf4d2fcefdfe2702f50c72ba5b0 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Testing is layered: Vitest unit tests co-located as *.spec.ts in server/src and web/src, a 'medium' tier in server/test/medium that runs against a real Postgres via testcontainers, API-level e2e specs in e2e/ (Vitest + supertest-style SDK calls against a docker-compose stack), and Playwright browser/UI/maintenance projects. CI (.github/workflows/test.yml) shards jobs per changed directory. Coverage is configured but explicitly excludes some files, and several infra-heavy areas (storage.core is covered, but websocket/adapter and plugin internals have thin coverage).
- Server unit tests run with vitest config test/vitest.config.mjs: name 'server:unit', globals on, include 'src/**/*.spec.ts', swc transform, v8 coverage scoped to src/cores, src/services, src/utils, src/sql-tools. — [server/test/vitest.config.mjs](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/server/test/vitest.config.mjs) [server/package.json#L27-29](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/server/package.json#L27-L29)
- A separate medium tier (test/vitest.config.medium.mjs, 'pnpm test:medium') runs integration-style specs in server/test/medium/specs (exif, repositories, services, sync, workflow) with a globalSetup.ts, using testcontainers (devDependency) for real Postgres. — [server/test/vitest.config.medium.mjs](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/server/test/vitest.config.medium.mjs) [server/test/medium/globalSetup.ts](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/server/test/medium/globalSetup.ts) [server/package.json#L168](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/server/package.json#L168)
- Tests use a factory/stub pattern: server/test/factories/*.factory.ts (asset, auth, user, session, shared-link, person, etc.) plus server/test/fixtures/*.stub.ts and small.factory.ts/medium.factory.ts builders. — [server/test/factories/asset.factory.ts](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/server/test/factories/asset.factory.ts) [server/test/fixtures/auth.stub.ts](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/server/test/fixtures/auth.stub.ts) [server/test/small.factory.ts](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/server/test/small.factory.ts)
- Most controllers and services have co-located .spec.ts files (e.g., asset-media.controller.spec.ts, auth.service.spec.ts, queue.service.spec.ts) — the dominant convention is one spec per source file. — [server/src/controllers/asset-media.controller.spec.ts](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/server/src/controllers/asset-media.controller.spec.ts) [server/src/services/auth.service.spec.ts](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/server/src/services/auth.service.spec.ts) [server/src/controllers/index.spec.ts](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/server/src/controllers/index.spec.ts)
- e2e/ runs Vitest API specs (src/specs/{server,web,maintenance} covering api, cli, immich-admin) and three Playwright projects (web, ui, maintenance) driven by playwright.config.ts against a docker-compose stack (e2e/docker-compose.yml). — [e2e/package.json](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/e2e/package.json) [e2e/playwright.config.ts](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/e2e/playwright.config.ts) [e2e/docker-compose.yml](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/e2e/docker-compose.yml)
- Web unit tests run via vitest inside vite.config.ts: name 'web:unit', happy-dom environment, svelteTesting plugin, setup file src/test-data/setup.ts, TZ=UTC. — [web/vite.config.ts#L58-70](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/web/vite.config.ts#L58-L70) [web/src/lib/utils.spec.ts](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/web/src/lib/utils.spec.ts)
- CI test.yml gates on a pre-job change filter and runs: server unit+lint (mise //server:ci-unit), server medium tests, web lint+unit, cli unit on linux+windows, e2e server-cli and e2e web matrices on ubuntu amd64+arm64 with docker compose up and artifacted docker logs/playwright reports. — [.github/workflows/test.yml#L102-206](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/.github/workflows/test.yml#L102-L206) [.github/workflows/test.yml#L360-578](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/.github/workflows/test.yml#L360-L578)
- check-openapi.yml enforces that the generated spec is in sync with the code and migration-order.yml verifies migration ordering — both are dedicated CI workflows. — [.github/workflows/check-openapi.yml](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/.github/workflows/check-openapi.yml) [.github/workflows/migration-order.yml](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/.github/workflows/migration-order.yml)
- machine-learning has pytest tests (test_main.py, conftest.py) and a locustfile.py for load testing the predict endpoint. — [machine-learning/test_main.py](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/machine-learning/test_main.py) [machine-learning/conftest.py](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/machine-learning/conftest.py) [machine-learning/locustfile.py](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/machine-learning/locustfile.py)
- Mobile has a Flutter test/ tree and integration_test/ directory; mobile CI is exercised through build-mobile.yml rather than the main test workflow. (inferred) — [mobile/pubspec.yaml](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/mobile/pubspec.yaml) [.github/workflows/build-mobile.yml](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/.github/workflows/build-mobile.yml)
- Coverage config explicitly excludes api.service.ts and microservices.service.ts from instrumentation, and files like websocket.adapter.ts, plugin.service.ts, and several controllers have no co-located spec — thin spots in otherwise high coverage. — [server/test/vitest.config.mjs#L17-26](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/server/test/vitest.config.mjs#L17-L26) [server/src/services/plugin.service.ts](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/server/src/services/plugin.service.ts) [server/src/middleware/websocket.adapter.ts](https://github.com/immich-app/immich/blob/d6d094738366aaf4d2fcefdfe2702f50c72ba5b0/server/src/middleware/websocket.adapter.ts)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
