Run unit tests

Reference of commands and testing strategy for gitrust.

Existing infrastructure

Rust Unit Testing

cargo test --workspace          # Tous les tests
cargo test -p gitrust-core      # Un crate spécifique
cargo test -p gitrust-git       # Tests Git (tempdir)

Unit tests are integrated into each crate via #[cfg(test)].

e2e Playwright tests

17 specs covering: auth, admin, repos, issues, labels, teams, tokens, settings, navigation.

# Pré-requis (première fois)
npm install
./scripts/e2e-setup-db.sh       # Crée la DB gitrust_test

# Lancer les tests
npm run test:e2e                 # Mode headless
npm run test:e2e:ui              # Mode interactif (navigateur visible)
npm run test:e2e:debug           # Mode debug
npm run test:e2e:report          # Voir le rapport HTML

Configuration: playwright.config.ts (port 4001, DB gitrust_test, locale fr-FR).

Directory structure

tests/
  e2e/                    # Specs Playwright (TypeScript)
    global-setup.ts       # Setup : lancer l'app, créer admin
    global-teardown.ts    # Teardown : arrêter l'app
    fixtures.ts           # Fixtures Playwright partagées
    auth.spec.ts          # Tests authentification
    admin.spec.ts         # Tests administration
    issues.spec.ts        # Tests issues
    ...
  integration/            # Tests d'intégration Rust (DB réelle) [à créer]
  fixtures/               # Fichiers de test (repos, configs) [à créer]
  seeds/                  # Seeds Rust pour initialiser la DB de test
    mod.rs
    seed.rs

Tests to add

1. REST API functional testing (Rust integration)

Tests with a real PostgreSQL DB to verify API endpoints.

Location: tests/integration/ or crates/gitrust-web/tests/

Recommended approach: use reqwest + a test server:

// tests/integration/api_test.rs
use reqwest::Client;

#[tokio::test]
#[ignore] // Nécessite une DB + serveur running
async fn test_api_login() {
    let client = Client::new();
    let res = client.post("http://localhost:4001/api/v1/auth/login")
        .json(&serde_json::json!({
            "login": "admin",
            "password": "test_password"
        }))
        .send()
        .await
        .unwrap();
    assert_eq!(res.status(), 200);
}

Alternative: axum::test to test handlers without an HTTP server:

use axum::body::Body;
use axum::http::Request;
use tower::ServiceExt;

#[tokio::test]
async fn test_health_check() {
    let app = create_test_app().await; // Build router with test DB
    let response = app
        .oneshot(Request::builder().uri("/api/hello").body(Body::empty()).unwrap())
        .await
        .unwrap();
    assert_eq!(response.status(), 200);
}

2. CI functional testing

Test Description Priorité
CI detection Repo avec .gitrust-ci.yml -> Easy, .dagger/ -> Power, rien -> None Haute
Pipeline CRUD Créer, lister, mettre à jour, annuler un pipeline Haute
Config CI Activer/désactiver CI, modifier triggers, vérifier effet Haute
Variables héritage Team var + repo var -> merge correct Moyenne
Auto-cancel Nouveau push annule les pipelines en cours Moyenne
Logs streaming Append logs + lecture paginée Moyenne
Notifications CI Pipeline échoue -> notification créée Moyenne

For CI tests: mock dagger with a shell script that simulates success/failure:

#!/bin/bash
# tests/fixtures/mock-dagger.sh
echo "Step 1: Building..."
echo "Step 2: Testing..."
if [ "$MOCK_FAIL" = "true" ]; then
    echo "FAILED" >&2
    exit 1
fi
echo "All checks passed"
exit 0

Configure CI_DAGGER_BIN=tests/fixtures/mock-dagger.sh in tests.

3. e2e Playwright tests to add

New specs for CI and notifications features:

Spec Couverture
ci-pipelines.spec.ts Liste pipelines, détail, status badges
ci-config.spec.ts Config CI (enable/disable, triggers, timeout)
ci-variables.spec.ts CRUD variables CI, masquage secrets
notifications.spec.ts Liste notifications, marquer lu, préférences
api-docs.spec.ts Swagger UI accessible, spec chargée
i18n.spec.ts Changement de langue, textes traduits
docker-smoke.spec.ts docker compose up + smoke test

CI spec example:

// tests/e2e/ci-pipelines.spec.ts
import { test, expect } from './fixtures';

test.describe('CI Pipelines', () => {
  test('affiche la page CI vide', async ({ authenticatedPage }) => {
    await authenticatedPage.goto('/admin/mon-repo/ci');
    await expect(authenticatedPage.locator('text=Aucun pipeline')).toBeVisible();
  });

  test('bouton trigger CI visible pour le maintainer', async ({ authenticatedPage }) => {
    await authenticatedPage.goto('/admin/mon-repo/ci');
    await expect(authenticatedPage.locator('text=Lancer CI')).toBeVisible();
  });
});

4. Test settings ↔ behavior

The most critical tests verify that changing a setting modifies the observable behavior:

Setting Action Vérification
PAT révoqué Appel API 401 immédiatement
ci_enabled = false Push Pas de pipeline créé
trigger_on_push = false Push Pas de pipeline
auto_cancel = true 2 pushes rapides 1er pipeline annulé
email_on_pipeline_failure = false Pipeline échoue Pas d'email, notif in-app ok
DEFAULT_LOCALE = en Charger page Texte en anglais

Test commands

# Tests unitaires Rust
cargo test --workspace

# Tests avec filtrage
cargo test -p gitrust-core -- ci_service
cargo test -p gitrust-core -- notification

# Tests e2e Playwright
npm run test:e2e

# Tests e2e spécifiques
npx playwright test tests/e2e/ci-pipelines.spec.ts
npx playwright test --grep "notifications"

# Lint
cargo clippy --workspace -- -D warnings

# Format check
cargo fmt --all -- --check

Local CI (execute before a push)

# Script rapide de vérification pré-push
cargo fmt --all -- --check && \
cargo clippy --workspace -- -D warnings && \
cargo test --workspace && \
echo "All checks passed"