algoritma / shopware-test-utils
A collection of helpers for Shopware 6 integration/functional tests.
Installs: 13
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/algoritma/shopware-test-utils
Requires
- php: >=8.2
- fakerphp/faker: ^1.24
- shopware/core: ^6.7
Requires (Dev)
- algoritma/php-coding-standards: ^3.0
- frosh/shopware-rector: ^0.5.8
- phpstan/phpstan-phpunit: ^2.0
- phpunit/phpunit: ^12.5
- symfony/browser-kit: ^8.0
Suggests
- store.shopware.com/swagcommercial: Enables the B2B extension for functional tests.
This package is auto-updated.
Last update: 2025-12-23 16:40:43 UTC
README
A comprehensive collection of helpers, factories, and utilities for Shopware 6 integration and functional tests.
๐ฆ Installation
composer require --dev algoritma/shopware-test-utils
๐ฏ Overview
This library provides a structured, clean, and maintainable approach to writing tests for Shopware 6 projects. It follows strict Single Responsibility Principle (SRP) and the Factory/Helper/Trait pattern to ensure separation of concerns.
Core Philosophy
"Factory CREATES, Helper ACTS, Trait ASSERTS"
- Factories โ Create and configure entities (Products, Orders, Customers, etc.)
- Helpers โ Execute actions on existing entities (place order, cancel, transition states, configuration, time travel)
- Traits โ Provide test assertions (database checks, event verification, mail assertions)
๐ Quick Start
Basic Integration Test
<?php use Algoritma\ShopwareTestUtils\Core\AbstractIntegrationTestCase; use Algoritma\ShopwareTestUtils\Factory\ProductFactory; use Algoritma\ShopwareTestUtils\Factory\CustomerFactory; class OrderPlacementTest extends AbstractIntegrationTestCase { public function testUserCanPlaceOrder(): void { // Create test entities using Factories $customer = (new CustomerFactory($this->getContainer())) ->withEmail('test@example.com') ->withFirstName('John') ->withLastName('Doe') ->create(); $product = (new ProductFactory($this->getContainer())) ->withName('Test Product') ->withPrice(19.99) ->withStock(100) ->create(); $context = $this->createAuthenticatedContext($customer); // Create cart and add product $cart = $this->createCart($context) ->withProduct($product->getId()) ->create(); // Place order using Helper $order = $this->placeOrder($cart, $context); // Assert order was created $this->assertOrderState($order, 'open'); $this->assertDatabaseHas('order', ['id' => $order->getId()]); } }
Functional/Storefront Test
<?php use Algoritma\ShopwareTestUtils\Core\AbstractFunctionalTestCase; class StorefrontCheckoutTest extends AbstractFunctionalTestCase { public function testCheckoutFlow(): void { // Create storefront request helper $storefront = $this->createStorefrontHelper(); // Simulate user actions $storefront->addProductToCart($productId); $storefront->goToCheckout(); $response = $storefront->submitOrder(); $this->assertResponseIsSuccessful($response); $this->assertMailSent('order_confirmation'); } }
๐ Available Components
๐ญ Factories (Create Entities)
Factories use the Builder pattern to create and configure entities with a fluent API.
| Factory | Description |
|---|---|
ProductFactory |
Create products with variants, prices, and stock |
CustomerFactory |
Create customers with addresses and groups |
OrderFactory |
Create orders with line items and states |
CategoryFactory |
Create category trees |
CartFactory |
Build carts with products and promotions |
MediaFactory |
Create media files (images, documents) |
PromotionFactory |
Create promotions and discounts |
RuleFactory |
Create business rules |
SalesChannelFactory |
Create sales channels |
ShippingMethodFactory |
Create shipping methods |
PaymentMethodFactory |
Create payment methods |
TaxFactory |
Create tax configurations |
Example:
$product = (new ProductFactory($container)) ->withName('Gaming Laptop') ->withPrice(1499.99) ->withStock(50) ->withTax(19.0) ->active() ->create();
๐ง Helpers (Execute Actions)
Helpers perform operations on existing entities. Use the HelperAccessor trait for easy access in tests.
| Helper | Description |
|---|---|
OrderHelper |
Cancel orders, mark as paid/shipped, get order details |
CartHelper |
Clear cart, remove items, recalculate |
MediaHelper |
Assign media to products, delete media |
StateManager |
Transition state machine states |
CheckoutRunner |
Execute complete checkout flows |
StorefrontRequestHelper |
Simulate storefront HTTP requests |
MigrationDataTester |
Test data integrity in migrations |
ConfigHelper |
Manage system configuration and feature flags |
TimeHelper |
Time travel and date manipulation |
ProductHelper |
Create and manage products |
CustomerHelper |
Create and manage customers |
SalesChannelHelper |
Create and manage sales channels |
MailHelper |
Send and verify emails |
Example:
use Algoritma\ShopwareTestUtils\Traits\HelperAccessor; class MyTest extends AbstractIntegrationTestCase { use HelperAccessor; public function testOrderFlow(): void { // Access helpers easily via trait methods $this->orderHelper()->markOrderAsPaid($orderId); $this->orderHelper()->markOrderAsShipped($orderId); // Set configuration $this->configHelper()->set('core.cart.maxQuantity', 100); // Time travel $this->timeHelper()->travelForward('30 days'); } }
โจ Traits (Assertion Helpers)
Traits provide assertion methods for test verification. Note: Actions have been moved to Helper classes.
| Trait | Description |
|---|---|
HelperAccessor |
Provides easy access to all Helper classes |
DatabaseHelpers |
Database assertions (table exists, row count, etc.) |
CacheHelpers |
Cache assertions (key exists, cache cleared) |
TimeHelpers |
Time-related assertions (date in future/past, timestamp validity) |
LogHelpers |
Log assertions (error logged, warning count, log contains) |
MailHelpers |
Mail assertions (email sent, recipient correct) |
EventHelpers |
Event assertions (event dispatched, payload validation) |
QueueHelpers |
Queue assertions (job queued, queue empty) |
MigrationHelpers |
Migration assertions (idempotency, schema changes) |
Example:
use Algoritma\ShopwareTestUtils\Traits\HelperAccessor; use Algoritma\ShopwareTestUtils\Traits\TimeHelpers; use Algoritma\ShopwareTestUtils\Traits\MailHelpers; class SubscriptionTest extends AbstractIntegrationTestCase { use HelperAccessor; // Access to all helpers use TimeHelpers; // Time assertions use MailHelpers; // Mail assertions public function testSubscriptionRenewal(): void { // Use TimeHelper for actions $this->timeHelper()->freezeTime(new \DateTime('2025-01-01 00:00:00')); // ... create subscription ... // Travel forward 30 days $this->timeHelper()->travelForward('30 days'); // Run renewal process $this->runScheduledTask(RenewalTask::class); // Use MailHelpers trait for assertions $this->assertMailSent(1); $this->assertMailWasSent(); } }
๐งช Test Base Classes
AbstractIntegrationTestCase
Base class for integration tests (database, repositories, services).
Features:
- Database transaction rollback after each test
- Access to Shopware container and services
- Event capturing
- Mail capturing
- Queue testing support
- Custom assertions
- Fixture Loading: Load fixtures with automatic dependency resolution and container injection.
AbstractFunctionalTestCase
Base class for functional/storefront tests (HTTP requests, controllers).
Extends: AbstractIntegrationTestCase
Additional Features:
- Storefront browser simulation
- HTTP request/response testing
- Session management
MigrationTestCase
Base class for migration tests.
Features:
- Test migration up/down
- Assert table creation/modification
- Test data integrity
- Assert migration idempotency
๐จ Custom Assertions
The ShopwareAssertions trait provides Shopware-specific assertions:
// Entity assertions $this->assertEntityExists('product', $productId); // Price assertions $this->assertPriceEquals(19.99, $product); // Customer assertions $this->assertCustomerHasRole($customer, 'B2B'); // Database assertions $this->assertDatabaseHas('product', ['id' => $productId, 'active' => 1]); $this->assertDatabaseMissing('order', ['id' => $deletedOrderId]); // Order assertions $this->assertOrderState($order, 'completed'); // Rule assertions $this->assertRuleMatches($ruleId, $salesChannelContext); // State machine assertions $this->assertStateMachineState($orderId, 'order_state', 'completed'); // Table structure assertions $this->assertTableExists('custom_table'); $this->assertColumnExists('product', 'custom_field'); $this->assertIndexExists('product', 'idx_custom'); $this->assertForeignKeyExists('order_line_item', 'fk_order_id'); // Mail Template assertions $this->assertMailTemplateExists('order_confirmation'); $this->assertMailTemplateSubjectContains('order_confirmation', 'en-GB', 'Order confirmation'); $this->assertMailTemplateContentContains('order_confirmation', 'en-GB', 'Thank you for your order', true);
๐๏ธ Directory Structure
src/
โโโ Assert/
โ โโโ ShopwareAssertions.php # Custom assertions
โโโ Core/
โ โโโ AbstractIntegrationTestCase.php # Integration test base
โ โโโ AbstractFunctionalTestCase.php # Functional test base
โ โโโ MigrationTestCase.php # Migration test base
โโโ Factory/ # Entity factories
โ โโโ ProductFactory.php
โ โโโ CustomerFactory.php
โ โโโ OrderFactory.php
โ โโโ CartFactory.php
โ โโโ ...
โโโ Helper/ # Action helpers
โ โโโ OrderHelper.php
โ โโโ CartHelper.php
โ โโโ MediaHelper.php
โ โโโ StateManager.php
โ โโโ ...
โโโ Traits/ # Reusable behaviors
โ โโโ DatabaseHelpers.php
โ โโโ CacheHelpers.php
โ โโโ TimeHelpers.php
โ โโโ EventHelpers.php
โ โโโ ...
โโโ Fixture/
โโโ FixtureInterface.php
โโโ FixtureManager.php
โโโ AbstractFixture.php
โโโ ReferenceRepository.php
๐ Advanced Examples
Testing with Fixtures
use Algoritma\ShopwareTestUtils\Fixture\AbstractFixture; use Algoritma\ShopwareTestUtils\Fixture\ReferenceRepository; class MyFixture extends AbstractFixture { public function load(ReferenceRepository $references): void { // Access container $repo = $this->getContainer()->get('product.repository'); // Create data... } } class MyTest extends AbstractIntegrationTestCase { public function testWithFixture(): void { $this->loadFixtures(new MyFixture()); // ... } }
Testing with Time Travel
use Algoritma\ShopwareTestUtils\Traits\TimeHelpers; class CouponExpirationTest extends AbstractIntegrationTestCase { use TimeHelpers; public function testCouponExpires(): void { $coupon = $this->createCoupon(['validUntil' => '2025-12-31']); // Test before expiration $this->freezeTime(new \DateTime('2025-06-01')); $this->assertTrue($coupon->isValid()); // Test after expiration $this->travelTo(new \DateTime('2026-01-01')); $this->assertFalse($coupon->isValid()); } }
Testing with Event Capture
use Algoritma\ShopwareTestUtils\Traits\EventHelpers; class ProductEventTest extends AbstractIntegrationTestCase { use EventHelpers; public function testProductCreationDispatchesEvent(): void { $this->startCapturingEvents(); $product = (new ProductFactory($this->getContainer())) ->create(); $this->assertEventWasDispatched(ProductCreatedEvent::class); $event = $this->getDispatchedEvent(ProductCreatedEvent::class); $this->assertEquals($product->getId(), $event->getProductId()); } }
Testing Migrations
use Algoritma\ShopwareTestUtils\Core\MigrationTestCase; use Algoritma\ShopwareTestUtils\Traits\MigrationHelpers; class Migration1234567890Test extends MigrationTestCase { use MigrationHelpers; public function testMigrationCreatesTable(): void { // Test idempotency (can run multiple times) $this->assertMigrationIsIdempotent(Migration1234567890::class); // Test table creation $this->assertMigrationAddsTable(Migration1234567890::class, 'custom_entity'); // Test column exists $this->assertColumnExists('custom_entity', 'custom_field'); } public function testDataIntegrity(): void { // Seed old data $this->seedTable('old_table', [ ['id' => 1, 'name' => 'Test'] ]); // Run migration $this->runMigration(Migration1234567890::class); // Test data was migrated correctly $this->assertDatabaseHas('new_table', ['id' => 1, 'name' => 'Test']); } }
Testing with Database Snapshots
use Algoritma\ShopwareTestUtils\Traits\DatabaseHelpers; class BulkOperationTest extends AbstractIntegrationTestCase { use DatabaseHelpers; public function testBulkImport(): void { // Create snapshot before bulk operation $snapshotId = $this->snapshotTable('product'); // Perform bulk import $this->importProducts($csvFile); // Test the import $this->assertDatabaseHas('product', ['sku' => 'NEW-SKU-001']); // Restore original state for other tests $this->restoreTableSnapshot($snapshotId); } }
๐ ๏ธ Configuration
PHPUnit Configuration
<?xml version="1.0" encoding="UTF-8"?> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/12.0/phpunit.xsd" bootstrap="vendor/autoload.php" colors="true"> <testsuites> <testsuite name="Integration"> <directory>tests/Integration</directory> </testsuite> <testsuite name="Functional"> <directory>tests/Functional</directory> </testsuite> </testsuites> </phpunit>
Running Tests
# Run all tests vendor/bin/phpunit # Run only integration tests vendor/bin/phpunit --testsuite Integration # Run with coverage vendor/bin/phpunit --coverage-html coverage/
๐ Documentation
For detailed architecture documentation, see ARCHITECTURE.md.
๐ค Contributing
Contributions are welcome! Please follow these guidelines:
- Factories should only create entities
- Helpers should only perform actions
- Traits should provide reusable behaviors
- All code must follow PSR-12 coding standards
- Add tests for new features
Code Quality Tools
# Check code style composer cs-check # Fix code style composer cs-fix # Run static analysis composer phpstan # Run rector composer rector-check
๐ License
This project is licensed under the MIT License.
๐ Credits
Developed by Algoritma for the Shopware community.
๐ก Support
For issues, questions, or feature requests, please open an issue on GitHub.