Multi-Store-Testing-Strategie für Magento-Shops
PASS
expect()
E2E-Testing · Multi-Store · Cypress · Playwright
Multi-Store-Testing-Strategie für Magento-Shops
Store-Kontext parametrisieren statt Suiten duplizieren

Wer für jede Sprache und jeden Store eine eigene Testkopie pflegt, verliert Übersicht und Laufzeit gleichzeitig. Ein Store-Kontext-Parameter in Cypress oder Playwright reicht aus, um Sprachen, Währungen und Katalogunterschiede gezielt zu prüfen und typische Store-Scope-Konfigurationsfehler zuverlässig vor dem Go-Live abzufangen.

16 Min. Lesezeit Store View · Website · Store Group · CI Magento 2.4.8 · Cypress · Playwright

1. Warum Multi-Store-Testing ein eigenes Problem ist

Magento-Shops mit mehreren Store Views laufen selten mit identischer Konfiguration: unterschiedliche Sprachen, Währungen, Steuerausweise und teilweise sogar unterschiedliche Kataloge pro Website sind der Normalfall, nicht die Ausnahme. Der naive Reflex vieler Teams ist, die bestehende E2E-Suite einmal pro Store zu kopieren und anzupassen. Das funktioniert für zwei Stores noch akzeptabel, wird aber bei fünf oder zehn Stores zur Wartungslast: Jede Änderung am Checkout-Flow muss in jeder Kopie nachgezogen werden, und Testdrift zwischen den Kopien bleibt oft unbemerkt, bis ein Store-spezifischer Bug live geht.

Das eigentliche Ziel von Multi-Store-Testing ist nicht, jede Kombination aus Store, Sprache und Gerät vollständig abzudecken, sondern gezielt die Stellen zu prüfen, an denen Store-Scope-Konfiguration tatsächlich Verhalten verändert: Preisanzeige, Übersetzungen, Steuerlogik, Zahlungs- und Versandmethoden. Eine funktionierende Checkout-Logik muss nicht zehnmal bewiesen werden, aber eine falsch konfigurierte Währung auf einem einzelnen Store View muss zuverlässig auffallen. Diese Verschiebung von vollständiger Duplikation zu gezielter, parametrisierter Abdeckung ist der Kern einer tragfähigen Multi-Store-Teststrategie.

2. Store View, Website und Store Group: die Testarchitektur verstehen

Magento kennt drei Scope-Ebenen: Website (eigene Domain, eigener Checkout, oft eigener Katalog und eigene Preise), Store Group (bündelt Store Views unter einer Website, teilt sich meist einen Root-Katalog) und Store View (Sprache, Locale, teils Währung innerhalb einer Store Group). Für Testautomatisierung ist entscheidend, auf welcher Scope-Ebene ein Konfigurationswert liegt, denn davon hängt ab, welche Kombinationen aus Store und Sprache überhaupt getestet werden müssen. Ein Wert auf Website-Scope wie der Produktkatalog muss nur einmal pro Website geprüft werden, ein Wert auf Store-View-Scope wie eine Übersetzung braucht einen eigenen Testlauf pro Store View.

In der Praxis bewährt sich eine zentrale Store-Konfigurationsdatei, die diese Hierarchie explizit abbildet, statt sie implizit in Testnamen oder Kommentaren zu verstecken. Jeder Eintrag trägt Store-Code, Locale, Währung, Basis-URL und die Website-Zugehörigkeit. Diese Datei wird zur einzigen Quelle der Wahrheit für alle Tests, die store-abhängiges Verhalten prüfen, und ersetzt verstreute, hartcodierte URLs und Sprachstrings in einzelnen Spec-Dateien.


{
  "stores": [
    {
      "code": "default",
      "website": "base",
      "locale": "de_DE",
      "currency": "EUR",
      "baseUrl": "https://shop.example.com/",
      "taxDisplay": "including_tax"
    },
    {
      "code": "austria",
      "website": "base",
      "locale": "de_AT",
      "currency": "EUR",
      "baseUrl": "https://shop.example.com/at/",
      "taxDisplay": "including_tax"
    },
    {
      "code": "uk",
      "website": "uk_website",
      "locale": "en_GB",
      "currency": "GBP",
      "baseUrl": "https://uk.example.com/",
      "taxDisplay": "excluding_tax"
    },
    {
      "code": "us",
      "website": "us_website",
      "locale": "en_US",
      "currency": "USD",
      "baseUrl": "https://us.example.com/",
      "taxDisplay": "excluding_tax"
    }
  ]
}

3. Tests parametrisieren statt duplizieren

Playwright bietet mit dem projects-Array in playwright.config.ts genau den Mechanismus, der Multi-Store-Testing ohne Spec-Duplikation ermöglicht: Jedes Projekt bekommt eigene baseURL, locale und beliebige Custom-Properties, während der Testcode selbst store-agnostisch bleibt. Ein einziger Spec wie checkout.spec.ts läuft dann automatisch gegen jeden konfigurierten Store, ohne dass eine Zeile Testlogik dupliziert werden muss. Store-spezifische Erwartungswerte wie Währungssymbol oder Steuerausweis werden zur Laufzeit aus der Store-Konfigurationsdatei gelesen, nicht im Test hartcodiert.

In Cypress erreicht man dasselbe Ziel über Cypress.env() in Kombination mit mehreren cypress.config.js-Umgebungsvarianten oder einem einzigen Config-File, das den Store-Code als Environment-Variable liest. Der entscheidende Architekturgrundsatz bleibt in beiden Frameworks identisch: Der Testcode kennt keine store-spezifischen Werte direkt, sondern fragt sie über eine gemeinsame Fixture oder einen Store-Context-Helper ab. Das reduziert die Wartungsfläche auf eine einzige Konfigurationsquelle statt auf N Kopien der gesamten Suite.


// playwright.config.ts - one project per store, shared spec files
import { defineConfig } from '@playwright/test';
import stores from './fixtures/stores.json';

export default defineConfig({
  testDir: './e2e',
  fullyParallel: true,
  projects: stores.stores.map((store) => ({
    name: store.code,
    use: {
      baseURL: store.baseUrl,
      locale: store.locale,
      extraHTTPHeaders: { 'X-Store-Code': store.code },
    },
    metadata: {
      currency: store.currency,
      taxDisplay: store.taxDisplay,
    },
  })),
});

// e2e/checkout.spec.ts - one spec, runs against every project/store
import { test, expect } from '@playwright/test';

test('shows the store currency on the product price', async ({ page }, testInfo) => {
  const currency = testInfo.project.metadata.currency as string;
  await page.goto('/catalog/product/view/id/42');
  await expect(page.getByTestId('product-price')).toContainText(currency === 'EUR' ? '€' : '$');
});

4. Übersetzungen und Sprachfallbacks testen

Fehlende Übersetzungen sind einer der häufigsten Multi-Store-Bugs, weil sie sich in der Entwicklungsumgebung meist nicht zeigen: Dort liegt in der Regel nur die Standardsprache vor, und ein fehlender i18n-Key fällt erst auf einem sekundären Store View auf, oft erst nach dem Go-Live. Statt Übersetzungen manuell zu prüfen, lohnt sich ein datengetriebener Test, der für jeden Store View die erwarteten Kernstrings aus einer zentralen Fixture lädt und gegen den gerenderten Text prüft. Wichtig ist, gezielt auf Fallback-Verhalten zu testen: Zeigt eine fehlende Übersetzung den Translation-Key im Klartext, den englischen Ausgangsstring oder eine leere Fläche? Jedes dieser Verhalten erfordert eine andere Reaktion im Test.

Ein robuster Ansatz prüft nicht jeden einzelnen String jeder Seite, sondern eine kuratierte Liste kritischer Touchpoints: Produktseite, Warenkorb, Checkout-Schritte und Bestätigungsseite. Diese Stellen haben den größten Business-Impact, wenn eine Übersetzung fehlt oder falsch ist, und die Testkosten bleiben überschaubar, weil nicht der komplette Content-Baum durchlaufen wird. Ergänzend hilft ein einfacher Regex-Check, der rohe Translation-Keys im gerenderten HTML erkennt und den Test unabhängig von der konkreten Zielsprache fehlschlagen lässt.


// e2e/translations.spec.js - data-driven translation check per store view
import { test, expect } from '@playwright/test';
import translations from '../fixtures/translations.json';

test('renders the correct add-to-cart label for this store view', async ({ page }, testInfo) => {
  const storeCode = testInfo.project.name;
  const expectedLabel = translations[storeCode]['add_to_cart'];

  await page.goto('/catalog/product/view/id/42');
  await expect(page.getByRole('button', { name: expectedLabel })).toBeVisible();

  // Guard against raw, untranslated i18n keys leaking into the DOM
  const bodyText = await page.locator('body').innerText();
  expect(bodyText).not.toMatch(/[a-z0-9_]+\.[a-z0-9_]+\s*=\s*/i);
});

5. Währungsformate und Preisanzeige testen

Währungsbugs entstehen selten durch einen falschen Umrechnungskurs, sondern durch Formatierungsdetails: falsches Symbol, falsche Position des Symbols relativ zum Betrag, falsches Dezimaltrennzeichen oder ein fehlender Tausendertrennpunkt. 1.234,56 € und €1,234.56 sind beide korrekt, aber nur für den jeweils passenden Store View. Ein Test, der den Preis als hartcodierten String vergleicht, bricht bei jeder Preisänderung im Katalog. Robuster ist ein Test, der Symbol, Dezimaltrennzeichen und Position anhand der Locale aus der Store-Konfiguration ableitet und nur diese Formateigenschaften prüft, nicht den konkreten Zahlenwert.

Zusätzlich zur reinen Formatierung muss der Steuerausweis pro Store geprüft werden: Manche Store Views zeigen Preise inklusive Mehrwertsteuer, andere exklusive, abhängig von taxDisplay im Store-Scope. Ein B2C-Store in Deutschland zeigt üblicherweise Bruttopreise, ein B2B-orientierter UK-Store oft Nettopreise mit separat ausgewiesener Steuer. Ein E2E-Test, der stur einen einzigen Preisformat-Assert für alle Stores verwendet, produziert entweder False Positives oder übersieht echte Regressionen, je nachdem, welcher Store zufällig zuerst getestet wurde.


// cypress/e2e/pricing.cy.js - currency and tax display assertion driven by store context
import stores from '../fixtures/stores.json';

const storeCode = Cypress.env('STORE_CODE') || 'default';
const store = stores.stores.find((s) => s.code === storeCode);

describe(`Pricing display for store: ${storeCode}`, () => {
  it('renders the price with the correct currency symbol and separators', () => {
    cy.visit(`${store.baseUrl}catalog/product/view/id/42`);

    cy.get('[data-testid="product-price"]').should(($el) => {
      const text = $el.text().trim();

      if (store.currency === 'EUR') {
        expect(text).to.match(/^\d{1,3}(\.\d{3})*,\d{2}\s?€$/);
      } else if (store.currency === 'GBP') {
        expect(text).to.match(/^£\d{1,3}(,\d{3})*\.\d{2}$/);
      } else if (store.currency === 'USD') {
        expect(text).to.match(/^\$\d{1,3}(,\d{3})*\.\d{2}$/);
      }
    });

    // Tax display must match the store scope configuration
    if (store.taxDisplay === 'excluding_tax') {
      cy.get('[data-testid="price-tax-note"]').should('contain.text', 'excl. VAT');
    } else {
      cy.get('[data-testid="price-tax-note"]').should('not.exist');
    }
  });
});

6. Katalogunterschiede zwischen Websites testen

Der Produktkatalog liegt in Magento auf Website-Scope: Ein Produkt kann einer Website zugeordnet sein, aber nicht der anderen, und der Preis eines Produkts kann sich zwischen Websites unterscheiden, selbst wenn beide dieselbe Währung nutzen. Das führt zu einer eigenen Klasse von Bugs, die reine UI-Tests auf einem einzigen Store leicht übersehen: ein Produkt, das im UK-Shop sichtbar sein soll, aber versehentlich nur der Basis-Website zugewiesen wurde, oder ein Sonderpreis, der nur für eine Website gepflegt wurde und auf einer zweiten Website fälschlich den Basispreis zeigt.

Sinnvolle Tests prüfen deshalb nicht nur, ob ein Produkt irgendwo im Shop erscheint, sondern gezielt, ob es auf der erwarteten Website sichtbar ist und ob der Preis dort dem für diese Website gepflegten Wert entspricht. Eine kompakte Stichprobe reicht meist aus: ein bis zwei Referenzprodukte pro Website, die bewusst unterschiedliche Preise oder Sichtbarkeitsregeln zwischen den Websites haben. Diese Referenzprodukte fungieren als Kanarienvögel für Katalog-Synchronisationsfehler, die sonst erst durch Kundenreklamationen auffallen würden.

7. Store-Scope-Konfigurationsfehler gezielt abfangen

Die teuersten Multi-Store-Bugs entstehen nicht im Code, sondern in der Store-Konfiguration selbst: eine falsch gesetzte Standardwährung nach einem config:set-Deployment, eine vergessene Secure-Base-URL für einen neuen Store View, eine Zahlungsmethode, die versehentlich global statt store-spezifisch deaktiviert wurde. Diese Fehler sind besonders tückisch, weil sie den Code überhaupt nicht verändern und deshalb von klassischen Unit- oder Integrationstests nicht erfasst werden. Sie zeigen sich ausschließlich im tatsächlich gerenderten Frontend eines bestimmten Store Views.

Ein gezielter Konfigurations-Smoke-Test, der nach jedem Deployment gegen alle Stores läuft, deckt genau diese Lücke ab: Basis-URL erreichbar, korrekte Währung auf der Startseite sichtbar, mindestens eine Zahlungs- und eine Versandmethode im Checkout verfügbar, korrektes Sprachattribut im <html>-Tag. Dieser Smoke-Test ist bewusst flach und schnell, weil er nicht Geschäftslogik prüft, sondern reine Konfigurationskonsistenz zwischen dem, was im Admin gepflegt wurde, und dem, was tatsächlich im Frontend ankommt.

8. Smart Test Selection: volle Suite versus Smoke-Tests in CI

Mit wachsender Store-Anzahl wird die naheliegende Strategie, die komplette Suite auf jedem Store laufen zu lassen, schnell zum CI-Laufzeitproblem: Zehn Stores mal dreißig Minuten Suite-Laufzeit summieren sich zu fünf Stunden, selbst bei paralleler Ausführung meist zu einem Engpass in der Runner-Kapazität. Die risikobasierte Alternative: Die vollständige Regressionssuite läuft nur gegen den Default-Store, während alle übrigen Stores eine schlanke Smoke-Suite durchlaufen, die sich auf store-spezifische Aspekte konzentriert, Sprache, Währung, Basis-Checkout-Fähigkeit.

Diese Aufteilung basiert auf der Beobachtung, dass die meisten funktionalen Bugs store-unabhängig sind und deshalb auf jedem einzelnen Store dieselbe Regression reproduzieren würden. Store-spezifische Bugs hingegen betreffen fast immer Konfiguration, nicht Anwendungslogik, und werden von einer gezielten Smoke-Suite mit hoher Trefferquote bei niedrigen Kosten gefunden. In der CI-Pipeline lässt sich das sauber als Matrix-Strategie abbilden, bei der ein Job-Typ die volle Suite und ein anderer Job-Typ die Smoke-Suite über alle Stores fährt.


# .gitlab-ci.yml - full suite on default store, smoke suite as a matrix over all stores
stages:
  - test

e2e-full-default:
  stage: test
  image: mcr.microsoft.com/playwright:v1.48.0-jammy
  script:
    - npm ci
    - npx playwright test --project=default
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

e2e-smoke-all-stores:
  stage: test
  image: mcr.microsoft.com/playwright:v1.48.0-jammy
  parallel:
    matrix:
      - STORE_CODE: [austria, uk, us, canada, switzerland]
  script:
    - npm ci
    - npx playwright test --project=$STORE_CODE --grep @smoke
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

9. Multi-Store-Test-Strategien im Vergleich

Die folgende Übersicht stellt die brüchigen, teuren Ansätze den robusten Alternativen gegenüber, die sich in gewachsenen Multi-Store-Setups in der Praxis bewährt haben. Der gemeinsame Nenner der robusten Spalte: Store-Wissen liegt in Konfiguration und Fixtures, nicht im Testcode selbst.

Aufgabe Brüchig / teuer Robust / empfohlen Vorteil
Suite pro Store Komplette Spec-Kopie je Store Parametrisierte Fixtures + eine Spec Eine Änderung wirkt auf alle Stores
Währungsprüfung Hartcodiertes Symbol im Assert Locale-getriebene Format-Assertion Bricht nicht bei Preisänderungen
CI-Laufzeit Volle Suite auf jedem Store Full Suite Default + Smoke-Matrix Laufzeit bleibt planbar
Store-Ziel Hartcodierte Base-URL im Spec Config-driven Store-Matrix Neue Stores ohne Codeänderung
Übersetzungscheck Manuelles Durchklicken pro Sprache Datengetriebener Fixture-Vergleich Fällt fehlende Keys automatisch auf

Mironsoft

E2E-Testautomatisierung, Multi-Store-Setups und CI-Pipelines für Magento-Shops

Multi-Store-Setup zuverlässig testen?

Wir bauen parametrisierte Cypress- und Playwright-Suiten für eure Store-Views, richten risikobasierte Smoke-Tests in der CI-Pipeline ein und decken Sprach-, Währungs- und Katalog-Bugs auf, bevor sie live gehen.

Test-Architektur-Audit

Bestehende Suiten auf Duplikate und Store-Scope-Lücken prüfen

Parametrisierung

Store-Fixtures, Playwright-Projects und Cypress-Config-Setup

CI-Integration

Smoke-Matrix und Full-Suite-Strategie in GitLab CI oder GitHub Actions

10. Zusammenfassung

Eine tragfähige Multi-Store-Testing-Strategie löst ein Kernproblem: Sprachen, Währungen und Kataloge unterscheiden sich zwischen Store Views, aber die Testlogik dahinter bleibt gleich. Statt die gesamte Suite pro Store zu duplizieren, wird der Store-Kontext als Parameter behandelt, über Playwright-Projects, Cypress-Environment-Variablen oder eine zentrale Store-Fixture-Datei mit Store-Code, Locale, Währung und Basis-URL. Übersetzungen und Preisformate werden datengetrieben gegen diese Fixture geprüft statt hartcodiert im Testcode.

Für die CI-Laufzeit gilt: nicht jeder Store braucht die volle Regressionssuite. Die vollständige Suite läuft gegen den Default-Store, alle übrigen Stores durchlaufen eine risikobasierte Smoke-Suite, die gezielt Store-Scope-Konfiguration prüft, Währung, Sprache, Zahlungs- und Versandmethoden. Diese Kombination hält die Laufzeit planbar und erkennt trotzdem die Bugs, die tatsächlich store-spezifisch sind, nämlich Konfigurationsfehler statt Anwendungslogik.

Multi-Store-Testing für Magento-Shops - Das Wichtigste auf einen Blick

Parametrisieren statt duplizieren

Store-Kontext über Playwright-Projects oder Cypress-Env statt Spec-Kopien pro Store.

Zentrale Store-Fixture

Store-Code, Locale, Währung und Basis-URL an einer Stelle pflegen, nicht in einzelnen Specs.

Locale-getriebene Assertions

Währungssymbol, Dezimaltrennzeichen und Steuerausweis aus der Konfiguration ableiten, nicht hartcodieren.

Risikobasierte CI-Strategie

Volle Suite nur auf dem Default-Store, schlanke Smoke-Suite als Matrix über alle übrigen Stores.

11. FAQ: Multi-Store-Testing für Magento-Shops

1Was ist der Unterschied zwischen Store View, Website und Store Group?
Website bündelt Domain, Checkout und oft eigenen Katalog. Store Group fasst Store Views unter einer Website zusammen. Store View steht für Sprache, Locale und teils Währung.
2Warum die Suite nicht pro Store duplizieren?
Änderungen müssten in jeder Kopie manuell nachgezogen werden. Ab mehr als zwei, drei Stores entsteht Testdrift, die oft erst nach dem Go-Live auffällt.
3Wie parametrisiere ich Playwright-Tests?
Über das projects-Array, generiert aus einer Store-Fixture. Jedes Projekt bekommt eigene baseURL, locale und Metadata, der Spec-Code bleibt store-agnostisch.
4Wie parametrisiere ich Cypress-Tests?
Über Cypress.env() plus Store-Konfigurationsdatei. Store-Code, Basis-URL, Locale und Währung werden über einen gemeinsamen Helper abgefragt statt hartcodiert.
5Wie teste ich Übersetzungen zuverlässig?
Datengetrieben gegen eine zentrale Übersetzungs-Fixture prüfen, kombiniert mit einem Regex-Check auf rohe, untranslatete i18n-Keys im gerenderten HTML.
6Wie teste ich Währungsformate und Preisanzeige?
Symbol, Dezimaltrennzeichen und Position locale-getrieben ableiten statt hartcodieren, plus separaten Check des Steuerausweises pro Store.
7Wie fange ich Katalogunterschiede zwischen Websites ab?
Mit Referenzprodukten pro Website, die bewusst unterschiedliche Preise oder Sichtbarkeit haben und als Kanarienvögel für Synchronisationsfehler dienen.
8Was ist Smart Test Selection?
Volle Suite nur auf dem Default-Store, schlanke Smoke-Suite auf allen übrigen Stores. Hält die CI-Laufzeit planbar bei weiterhin hoher Trefferquote.
9Wie strukturiere ich Store-Konfigurationsdaten als Fixtures?
Als zentrale JSON- oder YAML-Datei mit Store-Code, Website, Locale, Währung, Basis-URL und Steuerausweis pro Eintrag, als einzige Quelle der Wahrheit.
10Welche Store-Scope-Fehler sollte ich gezielt testen?
Falsche Standardwährung nach Deployment, fehlende Secure-Base-URL, versehentlich global deaktivierte Zahlungsmethoden, fehlerhaftes Sprachattribut im html-Tag.