Best Practice: CSS-Selektoren in Cypress für verschiedene Environments verwalten

Von Roland Golla
0 Kommentar
Cypress.io Logo verbindet drei Umgebungen mit verschiedenen CSS-Selektoren

Wer kennt es nicht? Die Cypress-Tests laufen lokal einwandfrei, aber auf Testing oder Live knallt es. Der Übeltäter: Unterschiedliche CSS-Selektoren zwischen den Umgebungen. Ein Login-Button heißt mal #user, mal .tx-felogin-input-username. Wir zeigen euch eine Best Practice, die dieses Problem elegant löst und eure Tests deutlich wartbarer macht.

Das Problem mit Environment-spezifischen Selektoren

In der Realität sieht die HTML-Struktur auf verschiedenen Umgebungen oft unterschiedlich aus. Vielleicht nutzt ihr auf Testing noch ein älteres CMS-Plugin, während Live schon die neue Version hat. Oder die Preview-Umgebung hat andere CSS-Klassen als Production.

Hardcodierte Selektoren in euren Page Objects bedeuten: Eure Tests brechen, sobald ihr die Umgebung wechselt. Das frustriert nicht nur, es kostet auch wertvolle Entwicklungszeit.

Die Lösung: Ein zentrales Selektor-Management

Wir haben bei Never Code Alone ein System entwickelt, das automatisch die richtigen CSS-Selektoren basierend auf der aktuellen Umgebung auswählt. Das Prinzip: Zentrale Verwaltung statt verteiltes Chaos.

Schritt 1: Zentrale Selektor-Konfiguration

Erstellt eine zentrale Datei für alle eure Selektoren:

// cypress/support/selectors.ts
export const defaultSelectors = {
  login: {
    username: '#user',
    password: '#pass',
    submit: '#kc-login'
  },
  navigation: {
    menu: '.main-menu',
    search: '#search-box'
  }
};

export const selectorOverrides = {
  testing1: {
    login: {
      username: '.tx-felogin-input-username'
      // password und submit bleiben default
    }
  },
  preview: {
    navigation: {
      menu: '.nav-primary'
    }
  }
};

Schritt 2: Intelligente Selektor-Funktion

Das Herzstück ist eine smarte Funktion, die Environment-spezifische Overrides prüft und auf Defaults zurückfällt:

export function getSelector(path: string): string {
  const env = Cypress.env('configFile') || 'live';

  // Pfad in Objekt-Navigation aufteilen (z.B. 'login.username')
  const keys = path.split('.');

  // Erst in Overrides suchen
  let selector = getNestedValue(selectorOverrides[env], keys);

  // Falls nicht gefunden, Default verwenden
  if (!selector) {
    selector = getNestedValue(defaultSelectors, keys);
  }

  return selector;
}

function getNestedValue(obj: any, keys: string[]): string | null {
  return keys.reduce((current, key) => current?.[key], obj);
}

Schritt 3: Saubere Page Objects

Eure Page Objects bleiben sauber und müssen nichts über Environments wissen:

// cypress/support/pageObjects/LoginPage.ts
class LoginPage {
  fillUsername(username: string) {
    cy.get(getSelector('login.username'))
      .clear()
      .type(username);
  }

  fillPassword(password: string) {
    cy.get(getSelector('login.password'))
      .clear()
      .type(password);
  }

  submit() {
    cy.get(getSelector('login.submit')).click();
  }
}

Schritt 4: Tests ausführen

Die Umgebung steuert ihr einfach über die Command Line:

# Verwendet default Selektoren (#user)
npx cypress open

# Verwendet testing1 Overrides (.tx-felogin-input-username)
npx cypress open --env configFile=testing1

# Verwendet preview Overrides
npx cypress open --env configFile=preview

Best Practices für nachhaltiges Selektor-Management

1. Semantische Struktur verwenden

Organisiert eure Selektoren nach Features, nicht nach Seiten:

{
  authentication: { ... },
  navigation: { ... },
  userProfile: { ... }
}

2. Data-Attributes für Stabilität

Wenn ihr Einfluss auf die Entwicklung habt, nutzt data-cy Attribute:

<button data-cy="login-submit">Login</button>

3. Fallback-Strategien implementieren

export function getSelectorWithFallback(primary: string, fallback: string): string {
  const primarySelector = getSelector(primary);
  return cy.get(primarySelector).should('exist').then($el => {
    return $el.length > 0 ? primarySelector : getSelector(fallback);
  });
}

4. Dokumentation ist Pflicht

export const defaultSelectors = {
  login: {
    // Verwendet auf: Live, Staging
    // CMS: TYPO3 v11
    username: '#user',

    // Fallback für ältere Versionen
    // Siehe: selectorOverrides.testing1
    usernameAlt: '.tx-felogin-input-username'
  }
};

Die Vorteile auf einen Blick

Keine Code-Duplikation: Selektoren werden nur einmal definiert
Einfache Wartung: Alle Selektoren an einem Ort
Flexibilität: Neue Environments ohne Test-Änderungen
Übersichtlichkeit: Klar erkennbar, was pro Environment anders ist
Minimaler Refactoring-Aufwand: Bestehende Tests brauchen nur kleine Anpassungen

Troubleshooting-Tipps

Problem: Selektor wird nicht gefunden
Lösung: Debug-Modus aktivieren

export function getSelector(path: string, debug = false): string {
  if (debug) {
    console.log(`Searching selector for: ${path} in env: ${env}`);
  }
  // ...
}

Problem: Performance-Probleme bei vielen Selektoren
Lösung: Caching implementieren

const selectorCache = new Map<string, string>();

Fazit: Investition, die sich lohnt

Die initiale Einrichtung kostet vielleicht eine Stunde, spart aber unzählige Stunden Debugging-Frust. Bei uns im Team sind die „Test läuft nur lokal“-Tickets praktisch verschwunden.

Das System hat sich besonders bewährt bei:

  • Multi-Stage Deployments
  • Legacy-System-Migrationen
  • Teams mit verschiedenen Testing-Umgebungen
  • Projekten mit häufigen Frontend-Änderungen

Nächste Schritte

Wollt ihr das System in eurem Projekt implementieren? Hier unsere Empfehlung:

  1. Analysiert eure Umgebungen und dokumentiert Selektor-Unterschiede
  2. Erstellt die zentrale selectors.ts mit Defaults
  3. Fügt Environment-spezifische Overrides nur wo nötig hinzu
  4. Refactored einen Test als Proof of Concept
  5. Rollt das System schrittweise aus

Kontakt und Support

Habt ihr Fragen zur Implementierung oder braucht Unterstützung bei euren Cypress-Tests? Bei Never Code Alone bieten wir Workshops und Consulting zu Test-Automatisierung an. Cypress, Playwright, oder andere Frameworks – wir helfen euch, eure Tests auf das nächste Level zu bringen.

Schreibt uns einfach oder kommt zu einem unserer Community-Events. Gemeinsam machen wir eure Tests stabiler und eure Entwicklung effizienter!


Dieser Artikel ist Teil unserer Best Practice Serie zu Software-Qualität und Test-Automatisierung. Bei Never Code Alone setzen wir uns für nachhaltige Entwicklung und stabile Tests ein. Folgt uns für mehr praktische Tipps aus dem Entwickler-Alltag!

0 Kommentar

Tutorials und Top Posts

Gib uns Feedback

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