phpunit-integration-test-generation
Use this skill when the user asks to generate, write, or create integration tests for a Shopware 6 source class whose contract requires wired-up code — phrases like "generate integration tests for X", "write an integration test for this controller", "test this indexer", "create an integration test for the message handler". Detects supported integration patterns (controller/route, scheduled-task, message-handler, indexer, DAL-persistence flow, multi-service coordinator) and applies a template producing an INTEGRATION-001..008-compliant test using IntegrationTestBehaviour against the real DAL, container, and HTTP/messaging. When the source class is unit-shape (no persistence, no kernel state, no wiring under test), returns SKIPPED and points at phpunit-unit-test-writing. Do NOT activate for unit tests or migration tests (use phpunit-migration-test-generation).
What this skill does
# PHPUnit Integration Test Generation
Generate Shopware-compliant PHPUnit integration tests that exercise wired-up code through `IntegrationTestBehaviour`, produce integration-shape assertions, and pass PHPStan and PHPUnit validation.
## File Write Restrictions
Write ONLY to:
- `tests/integration/**` — Integration test files
NEVER write to:
- `src/**` — Source code (read-only)
- `tests/unit/**` — Out of scope (use `phpunit-unit-test-generation`)
- `tests/migration/**` — Out of scope (use `phpunit-migration-test-generation`)
- Any other directory
## Workflow
```dot
digraph integration_test_generation {
"User invocation" [shape=doublecircle];
"Validate input" [shape=box];
"Source is PHP class in src/?" [shape=diamond];
"Analyze source" [shape=box];
"Integration pattern detected?" [shape=diamond];
"Select template + apply" [shape=box];
"Write test file" [shape=box];
"Validate (PHPStan, PHPUnit, ECS)" [shape=box];
"All green?" [shape=diamond];
"Fix iteration (max 3)" [shape=box];
"Iterations exhausted?" [shape=diamond];
"Report SUCCESS" [shape=doublecircle];
"Report PARTIAL" [shape=doublecircle];
"Report SKIPPED (defer to unit gen)" [shape=doublecircle];
"Report FAILED" [shape=doublecircle];
"User invocation" -> "Validate input";
"Validate input" -> "Source is PHP class in src/?";
"Source is PHP class in src/?" -> "Report FAILED" [label="no"];
"Source is PHP class in src/?" -> "Analyze source" [label="yes"];
"Analyze source" -> "Integration pattern detected?";
"Integration pattern detected?" -> "Report SKIPPED (defer to unit gen)" [label="no — unit-shape SUT"];
"Integration pattern detected?" -> "Select template + apply" [label="yes"];
"Select template + apply" -> "Write test file";
"Write test file" -> "Validate (PHPStan, PHPUnit, ECS)";
"Validate (PHPStan, PHPUnit, ECS)" -> "All green?";
"All green?" -> "Report SUCCESS" [label="yes"];
"All green?" -> "Iterations exhausted?" [label="no"];
"Iterations exhausted?" -> "Report PARTIAL" [label="yes"];
"Iterations exhausted?" -> "Fix iteration (max 3)" [label="no"];
"Fix iteration (max 3)" -> "Validate (PHPStan, PHPUnit, ECS)";
}
```
## Phase 1: Validate Input
1. Verify single file provided
2. Verify file exists and is a PHP class (not interface/trait/abstract)
3. Verify path starts with `src/`
If validation fails, return FAILED with reason.
## Phase 2: Analyze Source
Read the source class and detect which integration pattern applies. See references/source-analysis.md for the full detection logic.
### Step 1: Extract Metadata
- Class name, full namespace
- `#[Package('...')]` attribute value (default to `'framework'` if absent)
- Constructor dependencies (FQCN list)
- Area from namespace (`Core`, `Administration`, `Storefront`, `Elasticsearch`)
- Public methods and their return types
### Step 2: Detect Pattern
Walk the decision table in references/source-analysis.md. Patterns are evaluated top to bottom; the first match wins.
| Pattern | Indicator |
|---------|-----------|
| `controller` | Extends `AbstractController` or `AbstractRoute` / `Abstract*Route`, or methods carry `#[Route]` |
| `scheduled-task` | Extends `ScheduledTaskHandler`, OR has `#[AsMessageHandler]` and the `__invoke()` parameter is a `ScheduledTask` subclass |
| `message-handler` | Has `#[AsMessageHandler]` on `__invoke()` AND the parameter is a domain message (not a `ScheduledTask`) |
| `indexer` | Extends `EntityIndexer` (Shopware) |
| `dal-flow` | Constructor takes `EntityRepository` AND public methods write through it (`create`, `update`, `upsert`) AND the SUT contract is "the data was persisted" or "the indexer/event was triggered" |
| `multi-service` | Constructor takes ≥ 3 non-boundary dependencies (boundary set defined in `INTEGRATION-002`), and at least 2 are stateful (DAL, indexer, event dispatcher, system config) |
### Step 3: Decide
- **Pattern detected** → Continue to Phase 3
- **No pattern detected** → The SUT is unit-shape. Return SKIPPED with `skip_type: unit_test_more_appropriate` and reason: "Source class fits a unit-shape pattern (no persistence, no wiring, no multi-service coordination under test). Use `phpunit-unit-test-generation` instead." Reference the relevant refactoring pattern in `phpunit-integration-to-unit-migrating/references/refactoring-patterns.md` when the SUT looks like a factory, compiler pass, single subscriber, parser, constraint-only validator, or DAL materializer.
## Phase 3: Generate Test
### Step 1: Determine Test Path
Mirror source path with `src/` → `tests/integration/`:
- `src/Core/Content/Product/ProductIndexer.php` → `tests/integration/Core/Content/Product/ProductIndexerTest.php`
- `src/Core/Checkout/Cart/SalesChannel/CartLoadRoute.php` → `tests/integration/Core/Checkout/Cart/SalesChannel/CartLoadRouteTest.php`
Namespace mirrors the path: `Shopware\Tests\Integration\Core\Content\Product`.
### Step 2: Apply Template
Use the integration test template at templates/integration-test.md. The template has a base block plus one conditional section per pattern. Include exactly one pattern section based on Phase 2 detection. The base block defers all behavior trait `use` statements to the conditional section, because the trait choice varies by pattern:
- **Always (base block)**: namespace, `#[CoversClass]`, `#[Package]`, `@internal`, empty class shell
- **`controller`**: `IntegrationTestBehaviour + SalesChannelApiTestBehaviour` (or admin/storefront equivalent), `IdsCollection`, `KernelBrowser` built via `createCustomSalesChannelBrowser([...])`, `#[Group('store-api')]`, request invocation, response assertions
- **`scheduled-task`**: `DatabaseTransactionBehaviour + KernelTestBehaviour` (lighter than `IntegrationTestBehaviour`), `parent::setUp()`, direct `$handler->run()` invocation, raw SQL `Connection::fetchOne(...)` assertions
- **`message-handler`**: `IntegrationTestBehaviour`, direct `($this->handler)($message)` invocation, DAL read-back assertion (bus dispatch only when transport routing is part of the SUT contract)
- **`indexer`**: `DatabaseTransactionBehaviour + KernelTestBehaviour`, `parent::setUp()`, realtime flow — write via DAL captures `$event`, `$indexer->update($event)` returns `?EntityIndexingMessage`, assert on the returned message's data
- **`dal-flow`**: `IntegrationTestBehaviour`, arrange prerequisite state via DAL, invoke SUT, assert persisted result via separate DAL read
- **`multi-service`**: `IntegrationTestBehaviour` composed with domain behaviours per dependency (`AppSystemTestBehaviour`, `GuzzleTestClientBehaviour`, `MailTemplateTestBehaviour`), configure inputs through `SystemConfigService` / DAL, invoke SUT, assert effects across multiple collaborators
Fill placeholders using Phase 2 metadata. Use `IdsCollection` (`Shopware\Core\Test\Stub\Framework\IdsCollection`) for any test that manages more than one entity ID, and type all repository properties with the generic PHPDoc `@var EntityRepository<XxxCollection>`. Leave `TODO:` markers where the behavior-specific arrange or assertion is genuinely SUT-dependent and not derivable from class structure — these are the spots a human or follow-up step must complete.
### Step 3: Rule Compliance Checklist
The generated test must satisfy all `INTEGRATION-001..008` rules at write time. Self-check before validation:
- INTEGRATION-001: `use IntegrationTestBehaviour;` present
- INTEGRATION-002: SUT and primary collaborators retrieved from container (not mocked); only boundary types may be mocked (HTTP client, mailer, clock, randomness)
- INTEGRATION-003: any DDL, filesystem write, or cache write has a matching teardown (or is wrapped in try/finally)
- INTEGRATION-004: assertions don't depend on wall-clock time or unsourced randomness — assertions on UUIDs go through referential lookups, not literal-value equality
- INTEGRATION-005: no `#[Depends]` between test methods
- INTEGRATION-006: never `mRelated in Productivity
gitea-workflow
IncludedOrchestrate agile development workflows for Gitea repositories using the tea CLI. Use when working with Gitea-hosted repos and asking to 'run the workflow', 'continue working', 'what's next', 'complete the task cycle', 'start my day', 'end the sprint', 'implement the next task', or wanting guided step-by-step development assistance. Keywords: workflow, orchestrate, agile, task cycle, sprint, daily, implement, review, PR, standup, retrospective, gitea, tea.
microsoft-graph-gateway
IncludedRoute Microsoft Graph work in this workspace. Use when users want to read or write Outlook mail, calendar events, contacts, OneDrive or SharePoint files, Teams, Planner, To Do, users, groups, directory data, or arbitrary Microsoft Graph endpoints from VS Code. Prefer WorkIQ for common read scenarios. Use Microsoft Graph for write actions and gap-read scenarios that need exact Graph properties, filters, permissions, or endpoints.
copilotkit
IncludedUse when building with CopilotKit — setup, development, integrations, debugging, upgrading, or contributing. Routes to the appropriate specialized skill based on the task.
wordly-wisdom
IncludedProvides calibrated decision analysis using Charlie Munger-style multiple mental models, inversion, incentive mapping, circle-of-competence checks, misjudgment audits, second-order effects, and forecast updates. Use when the user asks for an oracle take, a hard call, a decision memo, a premortem, an outside view, a red-team, a sanity-check, what am I missing, think this through, or wants a strategy, hire, investment, plan, product, partnership, or major life choice analysed. Avoid for simple factual lookups or time-sensitive legal, medical, or market questions without fresh evidence.
swain-session
IncludedSession management and project status dashboard. Owns the full session lifecycle (start/work/close/resume), focus lane, bookmarks, worktree detection, and tab naming. Also serves as the project status dashboard — shows active epics, progress, actionable next steps, blocked items, tasks, GitHub issues, and recommendations. Worktree creation is deferred to swain-do task dispatch (SPEC-195). Triggers on: 'session', 'status', 'what's next', 'dashboard', 'overview', 'where are we', 'what should I work on', 'show me priorities', 'bookmark', 'focus on', 'session info'.
gandi
IncludedComprehensive Gandi domain registrar integration for domain and DNS management. Register and manage domains, create/update/delete DNS records (A, AAAA, CNAME, MX, TXT, SRV, and more), configure email forwarding and aliases, check SSL certificate status, create DNS snapshots for safe rollback, bulk update zone files, and monitor domain expiration. Supports multi-domain management, zone file import/export, and automated DNS backups. Includes both read-only and destructive operations with safety controls.