Skip to content

About

Vitest bridge for Shopware 6 Administration extensions

Resources

Stars

1 star

Watchers

1 watching

Forks

Repository files navigation

Vitest Shopware Admin Bridge

@friendsofshopware/vitest-shopware-admin-bridge provides a Vitest and Vue Test Utils environment for Shopware 6 Administration extensions. It boots the real installed Administration runtime while keeping version-sensitive setup out of each extension.

The bridge currently supports Shopware 6.6 and 6.7. It also detects and uses the native Shopware setup-SFC transform when a newer Administration source tree ships it.

Documentation

  • Set up a new Shopware plugin covers the local file layout, first tests, npm lockfiles, a Shopware-version CI matrix and an optional release-artifact job.
  • Testing best practices explains which level of test to choose, how to isolate Shopware state and which helpers belong in an extension rather than the bridge.
  • Shopware testing inventory records the upstream testing patterns and the bridge's compatibility boundary.

Requirements

  • Shopware 6.6 or 6.7 Administration source and installed npm dependencies
  • Node.js 22.12+, 24, or 26+
  • npm 10+
  • Vitest 5 and Vite 6.4+

The bridge discovers an Administration in a Shopware monorepo, a Composer installation, or an npm administration link. SHOPWARE_ADMINISTRATION_PATH and the legacy ADMIN_PATH can override discovery. Discovery is read-only: the bridge never downloads or modifies Shopware.

Quick start

Install the published package and commit the resulting npm lockfile. See the complete plugin setup guide for Administration dependency installation and CI:

npm install --save-dev vitest@5 @friendsofshopware/vitest-shopware-admin-bridge
// vitest.config.ts
import { defineShopwareConfig } from '@friendsofshopware/vitest-shopware-admin-bridge';

export default defineShopwareConfig();
{
    "scripts": {
        "test:unit": "vitest run",
        "test:unit:watch": "vitest"
    }
}

Tests are discovered under src/ and test/ using .spec.* or .test.*. Consumer options are merged without allowing the mandatory jsdom bootstrap to be replaced:

export default defineShopwareConfig({
    administrationPath: process.env.SHOPWARE_ADMINISTRATION_PATH,
    runtime: {
        strictConsole: true,
    },
    vitest: {
        test: {
            include: ['tests/unit/**/*.spec.ts'],
        },
    },
});

The configuration installs:

  • the correct 6.6 Vue compatibility or 6.7 native Vue runtime;
  • Vue SFC compilation and the Administration-native setup transform when present;
  • Twig, SCSS/CSS/Less and SVG handling;
  • real Shopware component, mixin, directive, filter, state and service registries;
  • the Administration Pinia store initializer plus context and a safe no-op notification store on 6.7, and legacy Vuex state on 6.6;
  • fresh Pinia and legacy Vuex state for every test;
  • Vue Test Utils plugins, dependency injection, synchronized locales/i18n and standard Administration mocks.

The full runtime also installs slot-preserving stubs for common layout components (sw-page, sw-card-view, mt-card, mt-banner, mt-empty-state, mt-link and sw-search-bar) plus lightweight icon stubs. Named sw-page content and smart-bar slots therefore remain visible without a local page-stub map.

Component tests

Import the extension entry point so it registers its components, then mount by Shopware component name:

import { expect, it } from 'vitest';
import { mountShopwareComponent } from '@friendsofshopware/vitest-shopware-admin-bridge/test-utils';
import '../src/main';

it('renders the widget', async () => {
    const wrapper = await mountShopwareComponent('acme-widget', {
        props: { title: 'Orders' },
    });

    expect(wrapper.text()).toContain('Orders');
});

loadShopwareComponent() scans the installed Administration source without writing Shopware's private generated component map. This allows extensions to test overrides and extended core components even when their base component was not registered yet. Dependencies are loaded recursively before Shopware.Component.build() applies the override chain.

The resulting import map is cached in the operating system's temporary directory per Administration Git revision. Disable the cache while editing the selected Administration source without changing its revision:

export default defineShopwareConfig({
    runtime: { componentScanCache: false },
});

VITEST_SHOPWARE_ADMIN_BRIDGE_CACHE_DIR can place the cache below a different base directory. Cache read and write failures fall back to a fresh scan.

Shopware.Component.override('sw-button', overrideConfig);
await loadShopwareComponent('sw-button');
const component = await buildShopwareComponent('sw-button');

Available component utilities:

  • loadShopwareComponent(name)
  • buildShopwareComponent(name)
  • mountShopwareComponent(name, options)
  • shallowMountShopwareComponent(name, options)
  • direct Vue Test Utils exports: mount, shallowMount, flushPromises, config

Services, ACL and feature flags

Default service mocks reset before every test. ACL allows access by default, feature flags are inactive, user configuration is empty, and repository calls return empty results.

import {
    getShopwareTestServices,
    mockShopwareService,
    setAclRoles,
    setFeatureFlags,
    withShopwareService,
} from '@friendsofshopware/vitest-shopware-admin-bridge/test-utils';

setAclRoles(['order.viewer']);
setFeatureFlags(['FEATURE_NEXT']);

const restore = mockShopwareService('myService', { load: vi.fn() });
restore();

await withShopwareService('myService', replacement, async () => {
    // Shopware.Service('myService') and inject('myService') use replacement.
});

getShopwareTestServices().userConfigService.search.mockResolvedValue({ data: {} });

Scoped service helpers update both Shopware's Bottle container and Vue dependency injection, then restore the exact previous instance. Any un-restored scope is cleaned up automatically after the test.

Repository doubles

The bridge provides small DAL-shaped doubles rather than Shopware's private HTTP/entity-schema test infrastructure:

const products = createRepositoryMock({
    search: vi.fn().mockResolvedValue({
        data: [{ id: 'product-1' }],
        total: 1,
    }),
});

setRepositoryMocks({ product: products });

An unconfigured entity name throws immediately instead of silently returning the wrong fixture.

Context and state

setShopwareContext() updates Shopware.Context.api and the real context/session/system stores. The bridge boots the Pinia stores used by Shopware 6.7 and keeps the legacy Vuex stores working on 6.6:

setShopwareContext({
    api: { languageId: 'language-id' },
    session: { locale: 'de-DE', locales: ['de-DE'], languageId: 'language-id' },
});

The standard en-GB and de-DE locales are registered before extension code runs. Locale messages added through Shopware's locale factory are synchronized to the Vue i18n instance before mountShopwareComponent() and shallowMountShopwareComponent() mount a component.

State is reset automatically. resetShopwareTestState() is available when a single test needs to return to the default API context, locale state, services and a fresh Pinia explicitly.

Lite runtime

Class, API-client and other non-component tests can use a lighter runtime that keeps Shopware context, state and service helpers but skips Administration component discovery, mixins, directives, filters and component-helper registration:

export default defineShopwareConfig({
    runtime: { mode: 'lite' },
    vitest: {
        test: { include: ['test/core/**/*.spec.ts'] },
    },
});

Use a separate Vitest config when one package needs both modes. Tests that mount registered Shopware components must continue to use the default mode: 'full' runtime.

Vue wrapper queries and Meteor interaction

The bridge installs these methods on every Vue wrapper and also exports them as standalone functions:

  • findByText(selector, text)
  • findByAriaLabel(selector, text)
  • findByLabel(text)
  • findByPlaceholder(text)

selectMtSelectOptionByText(wrapper, text) covers the recurring Meteor select interaction while accepting either the legacy popover or role-based option markup.

Strict console mode

Enable runtime.strictConsole to fail tests that emit unexpected console.warn or console.error. Permit deliberate output in the test that owns it:

allowConsoleMessage('expected deprecation', 'warn');

Strict mode starts after the Shopware bootstrap, so it reports test behavior rather than initialization noise.

Compatibility contract

The bridge deliberately separates stable test adapters from Shopware runtime behavior.

Bridge-owned adapters behave identically for every supported Administration:

  • Twig and imported HTML become ESM strings; HTML and Twig comments are removed while all other bytes are preserved;
  • SVG imports contain the exact UTF-8 file contents;
  • CSS, SCSS and Less imports resolve to an empty module in unit tests;
  • jsdom polyfills, repository doubles, queries and console enforcement use the bridge's own versioned contracts.

The selected Administration remains authoritative for Vue or Vue compat, Shopware's component and Twig runtime factories, state, services, mixins, directives, filters, core components and native setup-SFC transformation. This keeps the test-facing API stable without making a Shopware 6.6 test silently run copied 6.7 runtime behavior. The bridge does not import Shopware's private Twig, SVG or style Vite plugins.

Diagnostics

npx vitest-shopware-admin-bridge doctor
npx vitest-shopware-admin-bridge doctor --json
npx vitest-shopware-admin-bridge doctor --admin-path /path/to/administration

If dependencies are missing, the command prints the exact npm ci --prefix ... command. It does not run the command automatically.

Design boundary and compatibility evidence

See docs/testing-inventory.md for the Shopware test pattern inventory, helper ownership decisions, gap-closure table and executable proof for each compatibility behavior.

About

Vitest bridge for Shopware 6 Administration extensions

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages