Vite Test Timeouts endlich im Griff: Von 30 Sekunden Chaos zu stabilen CI/CD Pipelines

Von Roland Golla
0 Kommentar
Surreale Darstellung: Chaos der Test-Timeouts wird zur stabilen CI/CD Pipeline

Ihr kennt das: Die AI-Service Tests brauchen plötzlich 45 Sekunden statt 5. Die CI Pipeline bricht mit „Test timeout of 5000ms exceeded“ ab. Und dann diese endlosen }, 30000) Callbacks in jedem einzelnen Test. Nach über 15 Jahren Erfahrung in der Softwarequalität haben wir bei Never Code Alone genau diese Timeout-Hölle unzählige Male gemeistert. Heute zeigen wir euch, wie ihr das Problem ein für alle Mal löst.

Die moderne JavaScript-Entwicklung mit Vite und Vitest bietet mächtige Möglichkeiten – wenn ihr wisst, wie ihr sie richtig konfiguriert. Lasst uns direkt in die häufigsten Fragen einsteigen, die uns in unseren Remote Consulting Sessions immer wieder begegnen.

FAQ 1: Wie setze ich globale Timeout-Werte für alle Tests?

Die Herausforderung: Jeder Test hat individuelle Timeout-Callbacks mit }, 30000) am Ende. Das ist wartungstechnisch ein Albtraum und führt zu inkonsistenten Werten.

Die Lösung: Zentrale Konfiguration in der vite.config.ts:

import { defineConfig } from 'vite';

export default defineConfig({
  test: {
    testTimeout: 25000, // 25 Sekunden für AI/API-Tests
    hookTimeout: 10000, // 10 Sekunden für Setup/Teardown
  }
});

Diese eine Zeile ersetzt hunderte individuelle Timeout-Definitionen. Bei der Eye-Able Datary konnten wir damit die Wartungszeit um 60% reduzieren und die Test-Stabilität von flackernden 70% auf solide 98% steigern.

FAQ 2: Wie konfiguriere ich unterschiedliche Timeouts für CI und lokale Entwicklung?

Die Herausforderung: CI-Server sind langsamer, lokale Entwicklung soll schnell bleiben.

Die Lösung: Dynamische Konfiguration basierend auf der Umgebung:

const getTestTimeout = () => {
  if (process.env.CI === 'true') return 60000; // CI braucht mehr Zeit
  if (process.env.TEST_MODE === 'integration') return 30000;
  return 10000; // Standard Unit-Tests
};

export default defineConfig({
  test: {
    testTimeout: getTestTimeout(),
    threads: process.env.CI === 'true' ? 1 : 4,
  }
});

FAQ 3: Wie nutze ich Umgebungsvariablen in Vitest richtig?

Die Herausforderung: process.env.MEINE_VARIABLE funktioniert nicht wie erwartet in Tests.

Die Lösung: Vitest lädt standardmäßig nur VITE_ prefixed Variablen. Für alle anderen:

import { loadEnv } from 'vite';
import { defineConfig } from 'vitest/config';

export default defineConfig(({ mode }) => ({
  test: {
    env: loadEnv(mode, process.cwd(), ''),
    // Oder explizit eigene Variablen
    env: {
      NODE_ENV: 'test',
      VITEST: 'true',
      API_KEY: process.env.API_KEY
    }
  }
}));

FAQ 4: Wie vermeide ich Timeout-Probleme bei API-Tests?

Die Herausforderung: Externe API-Calls dauern unvorhersagbar lange (500ms bis 30+ Sekunden).

Die Lösung: Intelligentes Mocking statt echter API-Calls:

// Mock für deterministische Tests
vi.mock('../services/AI/OpenAIService.ts', () => ({
  openAIService: {
    generateResponse: vi.fn().mockResolvedValue({
      text: 'Mocked response',
      tokens: 42
    })
  }
}));

// Resultat: Von 20+ Sekunden auf konstante 8ms

Bei einem aktuellen Kundenprojekt reduzierten wir die Testlaufzeit von durchschnittlich 12 Minuten auf 45 Sekunden – bei gleichbleibender Testabdeckung.

FAQ 5: Was ist der Unterschied zwischen testTimeout und hookTimeout?

Die Herausforderung: Tests schlagen fehl, obwohl der testTimeout hoch genug ist.

Die Lösung: Separate Timeouts für verschiedene Phasen:

export default defineConfig({
  test: {
    testTimeout: 25000,  // Für einzelne Tests
    hookTimeout: 10000,  // Für beforeEach, afterEach, etc.
    teardownTimeout: 5000 // Für Cleanup-Operationen
  }
});

FAQ 6: Wie konfiguriere ich Timeouts pro Test-Suite?

Die Herausforderung: Unit-Tests brauchen 500ms, Integration-Tests 30 Sekunden.

Die Lösung: Nutzt Test-Projekte mit eigenen Konfigurationen:

// vitest.config.ts
export default defineConfig({
  projects: [
    {
      name: 'unit',
      include: ['**/*.unit.test.ts'],
      test: { testTimeout: 5000 }
    },
    {
      name: 'integration',
      include: ['**/*.integration.test.ts'],
      test: { testTimeout: 30000 }
    }
  ]
});

FAQ 7: Wie debugge ich Timeout-Probleme effektiv?

Die Herausforderung: „Test timeout exceeded“ – aber wo genau hängt es?

Die Lösung: Performance-Tracking einbauen:

// test-setup.ts
let testStartTime: number;

beforeEach(() => {
  testStartTime = performance.now();
});

afterEach(() => {
  const duration = performance.now() - testStartTime;
  if (duration > 5000) {
    console.warn(`⚠️ Slow test detected: ${duration}ms`);
  }
});

FAQ 8: Wie setze ich Retry-Strategien für flaky Tests?

Die Herausforderung: Tests schlagen sporadisch wegen Netzwerk-Timeouts fehl.

Die Lösung: Automatische Wiederholungen konfigurieren:

export default defineConfig({
  test: {
    retry: process.env.CI === 'true' ? 2 : 0,
    bail: 5, // Stop nach 5 Fehlern
    testTimeout: 15000
  }
});

FAQ 9: Wie optimiere ich Memory und Performance bei großen Test-Suites?

Die Herausforderung: Tests werden mit der Zeit immer langsamer.

Die Lösung: Ressourcen-Management aktivieren:

export default defineConfig({
  test: {
    pool: 'threads',
    poolOptions: {
      threads: {
        singleThread: process.env.DEBUG === 'true',
        minThreads: 1,
        maxThreads: 4
      }
    },
    // Memory-Limit für Worker
    workerIdleMemoryLimit: '512MB'
  }
});

FAQ 10: Wie integriere ich Coverage ohne Performance-Verlust?

Die Herausforderung: Coverage-Reports verdoppeln die Testlaufzeit.

Die Lösung: Intelligente Coverage-Konfiguration:

export default defineConfig({
  test: {
    coverage: {
      provider: 'v8', // Schneller als istanbul
      reporter: process.env.CI ? ['json'] : ['text'],
      exclude: [
        'node_modules/',
        '**/*.test.ts',
        '**/__mocks__/**'
      ],
      // Coverage nur in CI erzwingen
      enabled: process.env.CI === 'true'
    }
  }
});

Praxis-Beispiel: Von Chaos zu Stabilität

Ein konkretes Beispiel aus unserer Beratungspraxis: Ein SaaS-Startup kam zu uns mit einer Test-Suite, die regelmäßig nach 45 Minuten mit Timeouts abbrach. Das Problem:

  • Über 200 individuelle Timeout-Definitionen
  • Keine Unterscheidung zwischen Test-Typen
  • Echte API-Calls in Unit-Tests
  • Keine Parallelisierung

Unsere Lösung in 3 Schritten:

  1. Zentrale Konfiguration: Eine einzige vite.config.ts mit intelligenten Defaults
  2. Test-Kategorisierung: Unit, Integration und E2E mit eigenen Timeout-Strategien
  3. Mock-First-Ansatz: Externe Dependencies nur in dedizierten Integration-Tests

Das Ergebnis:

  • Testlaufzeit: Von 45 auf 3 Minuten
  • Erfolgsrate: Von 60% auf 99.5%
  • Wartungsaufwand: -80% durch zentrale Konfiguration

Best Practices aus über 15 Jahren Erfahrung

Nach unzähligen Projekten und Workshops haben wir folgende Kern-Prinzipien entwickelt:

1. Start Simple, Scale Smart
Beginnt mit einer Basis-Konfiguration und erweitert nur bei Bedarf.

2. Mock Early, Test Fast
Externe Dependencies gehören gemockt, außer ihr testet explizit die Integration.

3. Monitor Everything
Slow-Test-Detection sollte vom ersten Tag an aktiv sein.

4. Environment Matters
CI, Staging und lokale Entwicklung brauchen unterschiedliche Strategien.

Der Never Code Alone Weg

Bei Never Code Alone setzen wir auf nachhaltige Lösungen statt Quick-Fixes. Unsere Expertise in Softwarequalität und Remote Consulting hilft Teams, ihre Test-Infrastruktur grundlegend zu verbessern.

Ihr habt konkrete Herausforderungen mit eurer Test-Konfiguration? Ihr wollt eure CI/CD Pipeline endlich stabil bekommen? Meldet euch direkt bei uns: roland@nevercodealone.de

Wir bieten:

  • Remote Code Reviews eurer Test-Konfiguration
  • Hands-on Workshops mit der bewährten Funktastatur-Methode
  • Langfristige Begleitung bei der Test-Automation

Fazit: Investiert in eure Test-Infrastruktur

Eine durchdachte Vite-Test-Konfiguration ist kein Nice-to-have, sondern die Basis für stabile Software. Die Zeit, die ihr heute in eine saubere Konfiguration investiert, spart ihr morgen hundertfach bei der Fehlersuche.

Die wichtigsten Takeaways:

  • Zentrale Timeout-Konfiguration eliminiert Inkonsistenzen
  • Umgebungsspezifische Settings machen Tests robust
  • Intelligentes Mocking beschleunigt Test-Suites dramatisch
  • Performance-Monitoring identifiziert Bottlenecks früh

Implementiert diese Strategien schrittweise. Startet mit zentralen Timeouts, fügt dann Mocking hinzu und optimiert kontinuierlich. Eure CI/CD Pipeline wird es euch danken – und euer Team auch.

0 Kommentar

Tutorials und Top Posts

Gib uns Feedback

Diese Seite benutzt Cookies. Ein Akzeptieren hilft uns die Seite zu verbessern. Ok Mehr dazu