Skip to content

Testing

PHPUnit

Unit tests mirror the src/ directory structure under tests/. Tests use SQLite (configured in .env.test), so no running database container is needed.

bin/phpunit
make test

Vitest

Vitest with jsdom is used to unit-test Stimulus controllers and JavaScript/TypeScript utilities. Test files live in tests/js/ and mirror the assets/ structure.

yarn test              # Single run
yarn test:watch        # Watch mode during development
yarn test:coverage     # Run with coverage report
make jstest

Behat

Behat feature files are in features/. They test user-facing functionality through a browser simulation.

bin/behat --format progress
make integration

Dovecot integration

Dovecot authenticates users and looks up mailbox info via Userli's HTTP API (/api/dovecot/). A Lua adapter (contrib/userli-dovecot-adapter.lua) sends requests with a Bearer token to Userli's DovecotController.

Behat tests

The Dovecot API is tested automatically as part of the Behat suite in features/api_dovecot.feature. These tests run in CI without a real Dovecot instance -- they simulate the HTTP requests that Dovecot would make.

The scenarios cover:

  • Status -- API health check with valid and invalid tokens
  • Passdb -- password verification for valid users, wrong passwords, nonexistent users, and blocked (spam) users
  • Userdb -- mailbox lookup for existing users, nonexistent users, and spam users

To run only the Dovecot-related tests:

bin/behat --tags=@dovecot --format progress

Mailcrypt integration test

A dedicated GitHub Actions workflow (.github/workflows/mailcrypt.yml) tests the Dovecot mailcrypt integration end-to-end. It uses a separate compose file (docker-compose.mailcrypt-test.yml) that starts a real Dovecot instance with a Python mock of the Userli API (tests/dovecot-api-mock.py).

The test (tests/mailcrypt_integration.sh) uploads emails via IMAP to two users:

  • A user with mailcrypt enabled -- verifies that the email content is not readable on disk (encrypted)
  • A user without mailcrypt -- verifies that the email content is readable on disk (plaintext)

This ensures that the Lua adapter, Dovecot's mail_crypt plugin, and the API contract work correctly together.

To run the mailcrypt tests locally:

COMPOSE_FILE=docker-compose.mailcrypt-test.yml podman compose up -d
bash tests/mailcrypt_integration.sh
COMPOSE_FILE=docker-compose.mailcrypt-test.yml podman compose down -v
COMPOSE_FILE=docker-compose.mailcrypt-test.yml docker compose up -d
bash tests/mailcrypt_integration.sh
COMPOSE_FILE=docker-compose.mailcrypt-test.yml docker compose down -v

Manual testing with containers

The development containers are pre-configured to connect Dovecot to Userli's API. After loading the fixtures (see Getting started), you can test authentication from inside the Dovecot container:

podman compose exec dovecot doveadm auth test user@example.org password
docker compose exec dovecot doveadm auth test user@example.org password

You can also test the full flow by connecting an IMAP client to localhost:1143 or by using Roundcube at http://localhost:8001.

See the Dovecot documentation for more context.