[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6BY7GYC5STYS0CANRNCXEYV":3,"skill-same:01M6BY7GYC5STYS0CANRNCXEYV":68},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":40,"linkOnly":41,"markdownContent":42,"markdownBody":43,"frontMatter":44,"refName":45,"commitSha":46,"skillDirectory":47,"forksCount":48,"repositoryHtmlUrl":49,"repositoryHomepageUrl":6,"ownerHtmlUrl":50,"ownerBlogUrl":51,"ownerDescription":52,"updatedAt":53,"install":54,"resources":67},"01M6BY7GYC5STYS0CANRNCXEYV","acceptance-test-suite",null,"Write and run Playwright acceptance and accessibility tests in a Shopware project that consumes the Shopware Acceptance Test Suite (@shopware-ag\u002Facceptance-test-suite) as an npm package. Use when setting up the test workspace, writing or debugging specs, creating test data, working with actors and tasks, or checking accessibility with the bundled axe integration, including when the request just mentions ATS or acceptance tests. Not for contributing to the shopware\u002Facceptance-test-suite repository itself.","shopware\u002Facceptance-test-suite","shopware","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F612628?v=4","01M6BY7A3ZCJ7Z009TPK94GXVP","Shopware","01M6BY7A7WNR741EKSDFHYGVRG",30,"MIT","https:\u002F\u002Fgithub.com\u002Fshopware\u002Facceptance-test-suite\u002Fblob\u002Ftrunk\u002Fskills\u002Facceptance-test-suite\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39],"test","acceptance test suite","acceptance","playwright","contributing","run","workspace","repository","integration","accessibility","data","npm","package","writing","debugging","tasks","2026-11-10 10:12:30",false,"---\nname: acceptance-test-suite\ndescription: Write and run Playwright acceptance and accessibility tests in a Shopware project that consumes the Shopware Acceptance Test Suite (@shopware-ag\u002Facceptance-test-suite) as an npm package. Use when setting up the test workspace, writing or debugging specs, creating test data, working with actors and tasks, or checking accessibility with the bundled axe integration, including when the request just mentions ATS or acceptance tests. Not for contributing to the shopware\u002Facceptance-test-suite repository itself.\n---\n\n# Shopware Acceptance Test Suite (consumer guide)\n\nUse this skill in a project that consumes `@shopware-ag\u002Facceptance-test-suite` (ATS) as an npm package to test its own Shopware instance.\n\nDo not use this skill for work inside the `shopware\u002Facceptance-test-suite` repository itself. That repository ships its own contributor skill with different rules about which internal layer a change belongs in.\n\nOfficial consumer guide, for prose walkthroughs beyond this skill: https:\u002F\u002Fdeveloper.shopware.com\u002Fdocs\u002Fguides\u002Fdevelopment\u002Ftesting\u002Fe2e-playwright\u002F\n\n## Determine the installed version first\n\nATS moves quickly and its API changes between majors. Read the version from files before giving version specific advice. Never run a package manager to find out.\n\nCheck the project root **and** `tests\u002Facceptance\u002F`, because a separate test workspace is the common layout and is usually where the real dependency lives. Run these from the project root:\n\n```bash\n# 1. Installed truth. Works for npm, pnpm, and Yarn's node-modules linker.\nfor dir in . tests\u002Facceptance; do\n  f=\"$dir\u002Fnode_modules\u002F@shopware-ag\u002Facceptance-test-suite\u002Fpackage.json\"\n  [ -f \"$f\" ] && printf '%s -> ' \"$f\" && grep -m1 '\"version\"' \"$f\"\ndone\n\n# 2. Lock file resolution, when node_modules is absent.\n#    Keep context lines: pnpm splits specifier and resolved version, and a\n#    workspace nests entries under `importers:` per directory.\ngrep -rn -A3 'acceptance-test-suite' \\\n  package-lock.json pnpm-lock.yaml yarn.lock \\\n  tests\u002Facceptance\u002Fpackage-lock.json tests\u002Facceptance\u002Fpnpm-lock.yaml tests\u002Facceptance\u002Fyarn.lock 2>\u002Fdev\u002Fnull\n\n# 3. Requested range only. This is an intention, not proof of what is installed.\ngrep -rn 'acceptance-test-suite' package.json tests\u002Facceptance\u002Fpackage.json 2>\u002Fdev\u002Fnull\n```\n\nSay which of the three sources the version came from. If none yields a version and there is no test workspace yet, this is a fresh setup: continue with the workspace setup below. Otherwise state that the ATS version could not be determined, ask the user, and avoid version specific claims until it is known.\n\nFor the version of the **shop under test** (a different thing), use the `InstanceMeta` fixture. `InstanceMeta.version` is the right way to guard a test against older Shopware releases.\n\n## Environment and constraints\n\nThese are strict and are the usual cause of a broken setup:\n\n- **Package**: `@shopware-ag\u002Facceptance-test-suite`, published on npm, MIT licensed.\n- **ESM only**: the package sets `\"type\": \"module\"`. The test workspace must set it too.\n- **Playwright peer is a caret range** (e.g. `^1.62.1`). Any compatible 1.x release satisfying the range works; a major mismatch of `@playwright\u002Ftest` is the usual cause of fixture type errors. `playwright-core` is declared as an optional peer at the same range.\n- **Node**: only the majors in the package's `engines.node` field. Read that field rather than assuming.\n- **Single import path**: the `exports` map exposes only the package root. Deep imports such as `@shopware-ag\u002Facceptance-test-suite\u002Fdist\u002F...` are unsupported.\n- **axe is bundled**: `@axe-core\u002Fplaywright` and `axe-html-reporter` are runtime dependencies of ATS. Do not install them separately.\n- **Only `dist\u002F` is published.** The suite's own `playwright.config.ts`, its docker compose setup, and its `src\u002F` tree are not in the npm tarball. Nothing in the installed package starts a server or a container.\n\nThe environment variables a typical project needs (the shipped code reads a few more for SaaS and seeded-ID setups, not listed here):\n\n| Variable | Required | Purpose |\n|---|---|---|\n| `APP_URL` | yes | Storefront base URL of the shop under test, with trailing slash |\n| `ADMIN_URL` | no | Administration URL, defaults to `${APP_URL}admin\u002F` |\n| `ADMIN_API_URL` | no | Admin API base URL when it is not on `APP_URL`, trailing slash required |\n| `SHOPWARE_ACCESS_KEY_ID`, `SHOPWARE_SECRET_ACCESS_KEY` | preferred | Admin API integration credentials |\n| `SHOPWARE_ADMIN_USERNAME`, `SHOPWARE_ADMIN_PASSWORD` | alternative | Admin user login, used when no integration credentials are set |\n| `LANG` | no | Locale, read as `LANG`, `LANGUAGE`, or `lang`, default `en-GB`. Set it explicitly: a non English shell locale runs the whole suite in another language and breaks text based locators |\n| `MAILPIT_BASE_URL` | for mail tests | Mailpit base URL, no default |\n| `ATS_SKIP_CLEANUP` | no | Set to `1` to keep test data after a run, for debugging only |\n\nIntegration credentials are preferred over an admin user: they are faster and unaffected by admin session behavior.\n\n## Testing an existing storefront\n\nFor deployed-shop smoke coverage, configure the exported worker option in the consumer project's `use`: `storefrontTarget: { mode: 'existing', url: process.env.SHOPWARE_STOREFRONT_URL! }`. Setting that environment variable alone does not change the npm package's generated-channel default. Select compatible storefront specs with the project's `testMatch` or `grep`; ATS does not rewrite their explicit product\u002Forder\u002Fcustomer setup.\n\nUse `SHOPWARE_STOREFRONT_CUSTOMER_EMAIL` and `SHOPWARE_STOREFRONT_CUSTOMER_PASSWORD` (legacy `SMOKE_CUSTOMER_*` aliases remain supported), or explicitly configure `storefrontCustomer: { email, password }`. A supplied account is resolved and verified through a Store API login, and is never deleted by the fixture. Without credentials, ATS creates and deletes one owned customer per worker. Override the worker `StorefrontCustomer` fixture for anonymous browsing or a project-owned account. Only one configured credential fails; it never triggers fallback creation.\n\nExisting mode uses the resolved channel\u002Fdomain and its locale, skips theme assignment and routes both browser and Store API requests to the domain host\u002Fpath. Browser setup rejects unsupported translation languages with guidance to supply `CustomTranslationResources`. Project-level `use.httpCredentials` and `use.userAgent` are forwarded to Store API requests too; test-level overrides cannot reconfigure an existing worker API context.\n\nKeep `AdminSession`, `AdminPage`, ATS `page` and `context` in generated projects: they provision Admin sessions and throw in existing mode. Set `workers: 1` for tests that mutate shared channel state or share customer carts\u002Forders, and avoid concurrent conflicting projects. Independent read-only cases can use deliberate parallelism.\n\nExisting mode is not read-only: customer creation, credential-verification logins, explicit `TestDataService.create*` calls and test actions still happen. Borrowed-channel `setSystemConfig`, analytics overwrites and field-reset cleanup registration fail rather than discard existing values; cleanup cannot delete the borrowed channel. Cleaning explicitly created records can flush delayed caches. Generated mode retains its original browser-option handling; existing mode also forwards `contextOptions`.\n\nRead [Test an existing storefront](https:\u002F\u002Fdeveloper.shopware.com\u002Fdocs\u002Fguides\u002Fdevelopment\u002Ftesting\u002Fe2e-playwright\u002Fexisting-storefront.html) for the typed project example, authentication and customer lifecycle, selection guidance, remaining writes and CI checks.\n\n## Set up the test workspace\n\nInstall ATS first, then read its peer range from disk. Do not guess the Playwright version.\n\n```bash\nmkdir -p tests\u002Facceptance && cd tests\u002Facceptance\nnpm init -y\nnpm install --save-dev @shopware-ag\u002Facceptance-test-suite\n\n# Read the peer range ATS declares, then install a version satisfying it.\ngrep -A4 '\"peerDependencies\"' node_modules\u002F@shopware-ag\u002Facceptance-test-suite\u002Fpackage.json\n\nnpm install --save-dev @playwright\u002Ftest@^1.62.1\nnpm install --save-dev dotenv\n\n# Add --with-deps only on a fresh CI image: it installs OS packages as root and\n# fails where sudo needs a password.\nnpx playwright install chromium\n```\n\nTarget layout. **Run every command in this skill from `tests\u002Facceptance\u002F`**, except the version detection commands above, which run from the project root.\n\n```text\ntests\u002Facceptance\u002F\n├── .env                  # never commit\n├── package.json          # \"type\": \"module\"\n├── playwright.config.ts\n├── fixtures\u002F\n│   └── AcceptanceTest.ts\n└── tests\u002F\n    ├── checkout.spec.ts\n    └── accessibility.spec.ts\n```\n\n**Edit** the generated `package.json`, do not replace it: it already holds the `devDependencies` from the installs above, and overwriting it breaks every import. Add `\"type\": \"module\"` and the scripts:\n\n```json\n{\n  \"type\": \"module\",\n  \"scripts\": {\n    \"test\": \"playwright test\",\n    \"test:a11y\": \"playwright test --grep @Accessibility\",\n    \"report\": \"playwright show-report\"\n  }\n}\n```\n\n`.env` holds the shop under test. Playwright does not read `.env` by itself, which is why the config below loads it. `APP_URL` needs the trailing slash: ATS composes the admin URL as `${APP_URL}admin\u002F`, and a project's own `.env` usually stores it without one.\n\n```bash\nAPP_URL=\"https:\u002F\u002Fshop.example.test\u002F\"\nLANG=\"en-GB\"\n\n# Preferred: an Admin API integration. Create one in Settings, System, Integrations,\n# or run `bin\u002Fconsole integration:create AcceptanceTest --admin` on the shop:\n# it prints both lines below ready to paste.\nSHOPWARE_ACCESS_KEY_ID=\"...\"\nSHOPWARE_SECRET_ACCESS_KEY=\"...\"\n\n# Alternative, and what a freshly installed shop already has:\n# SHOPWARE_ADMIN_USERNAME=\"admin\"\n# SHOPWARE_ADMIN_PASSWORD=\"shopware\"\n```\n\n`playwright.config.ts`. No `webServer` block: this configuration tests an instance that is already running.\n\n```ts\nimport { defineConfig, devices } from '@playwright\u002Ftest';\nimport dotenv from 'dotenv';\n\ndotenv.config({ quiet: true });\n\nexport default defineConfig({\n  testDir: '.\u002Ftests',\n  timeout: 60_000,\n  expect: { timeout: 10_000 },\n  fullyParallel: true,\n  forbidOnly: !!process.env.CI,\n  retries: process.env.CI ? 1 : 0,\n  reporter: process.env.CI ? [['github'], ['html']] : [['list'], ['html']],\n  use: {\n    baseURL: process.env.APP_URL,\n    trace: 'retain-on-failure',\n    screenshot: 'only-on-failure',\n  },\n  projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],\n});\n```\n\nCreate one base test file and import from it everywhere. This is what makes project fixtures and tasks available alongside the suite's own:\n\n```ts\n\u002F\u002F fixtures\u002FAcceptanceTest.ts\nimport { test as base } from '@shopware-ag\u002Facceptance-test-suite';\nimport type { FixtureTypes } from '@shopware-ag\u002Facceptance-test-suite';\n\nexport * from '@shopware-ag\u002Facceptance-test-suite';\n\nexport const test = base.extend\u003CFixtureTypes>({\n  \u002F\u002F project specific fixtures go here\n});\n```\n\nWhen the project has its own task collections, merge instead of extending:\n\n```ts\nimport { mergeTests, test as ShopwareTestSuite } from '@shopware-ag\u002Facceptance-test-suite';\nimport { test as projectTasks } from '.\u002FProjectTasks';\n\nexport * from '@shopware-ag\u002Facceptance-test-suite';\n\nexport const test = mergeTests(ShopwareTestSuite, projectTasks);\n```\n\n### Typecheck the tests\n\nPlaywright transpiles without typechecking, so type errors run silently and surface as wrong behavior instead of a failure. Add a `tsconfig.json` and run `tsc` in CI alongside the tests.\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"strict\": true,\n    \"noEmit\": true,\n    \"skipLibCheck\": true,\n    \"types\": [\"node\"]\n  },\n  \"include\": [\"fixtures\u002F**\u002F*.ts\", \"tests\u002F**\u002F*.ts\", \"playwright.config.ts\"]\n}\n```\n\n```bash\nnpm install --save-dev typescript @types\u002Fnode\nnpx tsc --noEmit\n```\n\nThis is how the `attemptsTo(ValidateAccessibility(...))` mistake described under Accessibility gets caught.\n\n## Write a spec\n\nEverything the suite offers arrives as Playwright fixtures destructured in the test callback: actors, tasks, page objects, and services. There is no separate setup call.\n\n```ts\n\u002F\u002F tests\u002Fcheckout.spec.ts\nimport { test } from '..\u002Ffixtures\u002FAcceptanceTest';\n\ntest('Customer can add a product to the cart.', { tag: '@Checkout' }, async ({\n  ShopCustomer,\n  TestDataService,\n  AddProductToCart,\n  StorefrontProductDetail,\n  StorefrontCheckoutCart,\n}) => {\n  const product = await TestDataService.createBasicProduct();\n\n  await ShopCustomer.goesTo(StorefrontProductDetail.url(product));\n  await ShopCustomer.attemptsTo(AddProductToCart(product, '5'));\n\n  await ShopCustomer.goesTo(StorefrontCheckoutCart.url());\n  await ShopCustomer.expects(StorefrontCheckoutCart.grandTotalPrice).toBeVisible();\n});\n```\n\nRules that keep specs working:\n\n- **Create the data the test needs.** Never rely on demo data or on data another test created.\n- **One browser surface per test.** `ShopCustomer` for storefront coverage, `ShopAdmin` for administration coverage. Do not model flows that hop from administration to storefront and back in one test.\n- **Use page objects for URLs and elements**, so a routing or markup change is fixed in one place.\n- **`expects` is Playwright's `expect`**, reachable through the actor for readability.\n\n### Actors\n\n| Actor | Surface |\n|---|---|\n| `ShopCustomer` | storefront |\n| `ShopAdmin` | administration |\n\nMethods: `goesTo(url, forceReload?)`, `attemptsTo(task)`, `expects(locator)`, `presses(locator, key?)`, `fillsIn(locator, input)`, `selectsRadioButton(group, label)`, `a11y_checks(locator)`.\n\n`a11y_checks` scrolls the locator into view and asserts it is enabled, focused, and shows a visible focus indicator. `presses`, `fillsIn`, and `selectsRadioButton` call it internally, so keyboard operability and a visible focus ring are asserted as a side effect of using them.\n\n**For storefront interactions, use the actor methods by default** — `presses`\u002F`fillsIn` rather than `click`\u002F`fill`, in ordinary functional tests too, not only accessibility specs. Each interaction then also asserts keyboard operability and a visible focus indicator. This is the suite's convention for storefront flows.\n\n```ts\n\u002F\u002F Preferred\nawait ShopCustomer.fillsIn(StorefrontAccountLogin.emailInput, customer.email);\nawait ShopCustomer.presses(StorefrontAccountLogin.loginButton);\n```\n\nTwo things to know when using them:\n\n- They drive the keyboard instead of clicking, so they skip some of Playwright's click actionability checks. Assert state first where a control may be hidden or disabled:\n\n  ```ts\n  await ShopCustomer.expects(submitButton).toBeVisible();\n  await ShopCustomer.expects(submitButton).toBeEnabled();\n  await ShopCustomer.presses(submitButton);\n  ```\n\n- When converting an existing suite, a control that was never keyboard operable now fails: triage the finding, don't revert to `click` to hide it.```\n\n**Administration flows are the documented exception.** The suite's own guidance prefers the keyboard first methods for storefront flows and says not to generalize that rule to the Administration, so use plain Playwright there unless the test is specifically about keyboard operability. The methods exist on `ShopAdmin` and work, but the Administration is not covered by the storefront convention and has no accessibility task equivalent.\n\n### Tasks\n\nA task is a reusable, named interaction exposed as a fixture, read as a sentence: `Login()`, `AddProductToCart(product, '5')`, `SubmitOrder()`. Destructure it and pass it to `attemptsTo`.\n\nAuthor a project task the same way the suite does, as a fixture returning a function that returns the closure:\n\n```ts\nimport { test as base } from '@playwright\u002Ftest';\nimport type { FixtureTypes, Task } from '@shopware-ag\u002Facceptance-test-suite';\n\nexport const AcceptCookieBanner = base.extend\u003C{ AcceptCookieBanner: Task }, FixtureTypes>({\n  AcceptCookieBanner: async ({ ShopCustomer, StorefrontHome }, use) => {\n    const task = () => {\n      return async function AcceptCookieBanner() {\n        await ShopCustomer.presses(StorefrontHome.consentAcceptAllCookiesButton);\n      };\n    };\n    await use(task);\n  },\n});\n```\n\nName the returned function: `attemptsTo` derives the test step title from it. Keep assertions about the thing under test in the spec, not in the task.\n\n### Test data\n\n`TestDataService` creates entities through the admin API and cleans them up after each test. Method names follow a pattern: `createBasic*`, `create*With*`, `assign*`, `get*`.\n\n```ts\nconst product = await TestDataService.createBasicProduct({ name: 'Test product' });\nconst category = await TestDataService.createCategory();\nawait TestDataService.assignProductCategory(product.id, category.id);\n```\n\n- Cleanup respects entity dependencies, so create through the service where possible.\n- An entity created outside the service can be registered for cleanup; prefer that over leaving data behind.\n- `ATS_SKIP_CLEANUP=1` keeps data for inspection. Never leave it set in CI.\n- For anything the service does not model, use `AdminApiContext` or `StoreApiContext`.\n\n### Locators\n\nStandard Playwright locator priority applies (`getByRole` first, avoid XPath and CSS coupled to styling). One ATS-specific point:\n\n- Text and placeholder locators are unreliable here: the Shopware storefront is multilingual and runs under `LANG`, so visible text changes across locales and placeholder text is often absent from accessible markup. Prefer a role or label; a field with no accessible label is usually an accessibility defect worth fixing rather than working around. Keep locators in page object properties (see the spec rules above).\n\n## Accessibility\n\nThe suite ships exactly one accessibility task, `ValidateAccessibility`, built on the bundled `@axe-core\u002Fplaywright`. It is bound to the shop customer's page: there is no administration equivalent, so do not promise administration accessibility coverage through it.\n\n```ts\n\u002F\u002F tests\u002Faccessibility.spec.ts\nimport { test } from '..\u002Ffixtures\u002FAcceptanceTest';\n\ntest('The storefront implements accessibility best practices.', { tag: '@Accessibility' }, async ({\n  ShopCustomer,\n  TestDataService,\n  ValidateAccessibility,\n  StorefrontAccountLogin,\n  StorefrontCategory,\n}) => {\n  test.slow();\n\n  const category = await TestDataService.createCategory();\n\n  await test.step('Login page', async () => {\n    await ShopCustomer.goesTo(StorefrontAccountLogin.url());\n    await ValidateAccessibility('Login', true)();\n  });\n\n  await test.step('Category page', async () => {\n    await ShopCustomer.goesTo(StorefrontCategory.url(category.name));\n    \u002F\u002F Known violation: the first level headline is CMS configurable.\n    await ValidateAccessibility('Category', 1)();\n  });\n});\n```\n\nCall the closure directly, as shown — do not wrap it in `attemptsTo`. The closure returns the axe results array, not `() => Promise\u003Cvoid>`, so `tsc` rejects it. Examples elsewhere use `attemptsTo(ValidateAccessibility(...))`; it runs (Playwright transpiles without typechecking) but fails typecheck and discards the results.\n\nSignature and behavior:\n\n```\nValidateAccessibility(pageName, assertViolations?, createReport?, ruleTags?, outputDir?)\n```\n\n- `pageName` labels the report. The filename strips every non alphabetic character, so `'Page Not Found'` becomes `PageNotFound.html`.\n- `assertViolations` is polymorphic:\n  - `true` (default) requires zero violations.\n  - a **number** allows at most that many violations. This is a budget, not a targeted waiver: any new violation of any rule hides under the budget.\n  - `false` asserts nothing and only returns results.\n- `createReport` defaults to true and writes `test-results\u002FAccessibilityReports\u002F\u003CPageName>.html`.\n- `ruleTags` defaults to `['wcag2a', 'wcag2aa', 'wcag2aaa', 'wcag21a', 'wcag21aa', 'best-practice']`. That is broader than most projects' stated target: it enforces AAA rules and axe best practice rules, neither of which is a WCAG 2.1 AA requirement, so a default run can fail on issues that are not conformance failures. Pass an explicit list matching the project's target, for example `['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa']`, and keep it consistent across specs.\n- `outputDir` overrides the report directory.\n- The closure returns the violations array, so a spec can inspect or attach it: `const violations = await ValidateAccessibility('Home', false)();`\n\nGuidance:\n\n- One page per `test.step`, so a failure names the page.\n- Use `test.slow()`: axe analysis across several pages exceeds the default timeout.\n- When a violation is accepted for now, put the reason in a comment beside the call and link a tracking issue. Prefer a tighter rule set over a numeric budget, because a budget hides regressions.\n- Automated checks are a floor, not proof of accessibility. Keyboard traversal, focus management in modals and off canvas panels, and screen reader behavior still need explicit tests or manual review.\n\n## Run tests\n\nFrom `tests\u002Facceptance\u002F`:\n\n```bash\nnpx playwright test                                  # everything\nnpx playwright test tests\u002Fcheckout.spec.ts           # one file\nnpx playwright test --grep @Accessibility            # by tag\nnpx playwright test --headed --project=chromium      # watch it run\nnpx playwright show-report                           # last HTML report\n```\n\nDebugging:\n\n- `--debug` opens the inspector; `--trace on` records a trace for `npx playwright show-trace`.\n- `ATS_SKIP_CLEANUP=1` preserves created data so the shop can be inspected after a failure.\n- Accessibility reports land in `test-results\u002FAccessibilityReports\u002F`.\n\n## Troubleshooting\n\n| Symptom | Cause and fix |\n|---|---|\n| Fixture types missing, or `test.extend` type errors | `@playwright\u002Ftest` does not satisfy ATS's peer range. Align it. |\n| `ERR_REQUIRE_ESM` or import failures | The test workspace is not ESM. Set `\"type\": \"module\"`. |\n| Unresolved deep import | Only the package root is exported. Import from `@shopware-ag\u002Facceptance-test-suite`. |\n| `APP_URL` or credentials appear unset | Nothing loads `.env` by itself. Load it in `playwright.config.ts`. |\n| Admin API calls fail with 401 | Credentials missing or wrong, or the API is not on `APP_URL`. Prefer integration credentials; set `ADMIN_API_URL` when the API lives elsewhere. |\n| Tests act on the wrong surface | The bare Playwright `page` fixture is not the storefront page. Use the actors, or the explicit `StorefrontPage` and `AdminPage` fixtures. |\n| Text based locators fail in another language | `LANG` is inherited from the shell. Set it explicitly. |\n| Data from previous runs pollutes tests | `ATS_SKIP_CLEANUP` is set in the environment. |\n| Playwright waits forever, or tries to start a server | Your own config's `webServer` block, not ATS: the published package ships only `dist\u002F` and starts nothing. Omit `webServer` when testing a running instance, or use it purely as a readiness gate. |\n| Accessibility spec times out | Add `test.slow()` and split page audits into steps. |\n| `attemptsTo(ValidateAccessibility(...))` fails to typecheck | Expected. Call the closure directly: `await ValidateAccessibility('Name', true)();` |\n\n## When guidance and reality disagree\n\nThe installed package is the authority. Verify against it rather than against this skill or older documentation:\n\n```bash\ncat node_modules\u002F@shopware-ag\u002Facceptance-test-suite\u002Fpackage.json\ncat node_modules\u002F@shopware-ag\u002Facceptance-test-suite\u002Fdist\u002Findex.d.ts | grep -E 'export|declare' | head -50\n```\n\nThe type definitions list the real exports, fixtures, and task names for the installed version. Task argument shapes are not there: `Task` is typed `(...args: any[]) => () => Promise\u003Cvoid>`, so read a task's real parameters in `dist\u002Findex.mjs`, and do not expect `tsc` to catch wrong task arguments. Published examples elsewhere sometimes use fixture names from older majors; prefer what the installed types show. If this skill and the installed package disagree, follow the package and tell the user exactly what differed: the skill's claim, the installed version, and what you did instead. If the skill looks genuinely stale rather than locally patched, suggest the user report it upstream (an issue or PR against shopware\u002Facceptance-test-suite).\n","# Shopware Acceptance Test Suite (consumer guide)\n\nUse this skill in a project that consumes `@shopware-ag\u002Facceptance-test-suite` (ATS) as an npm package to test its own Shopware instance.\n\nDo not use this skill for work inside the `shopware\u002Facceptance-test-suite` repository itself. That repository ships its own contributor skill with different rules about which internal layer a change belongs in.\n\nOfficial consumer guide, for prose walkthroughs beyond this skill: https:\u002F\u002Fdeveloper.shopware.com\u002Fdocs\u002Fguides\u002Fdevelopment\u002Ftesting\u002Fe2e-playwright\u002F\n\n## Determine the installed version first\n\nATS moves quickly and its API changes between majors. Read the version from files before giving version specific advice. Never run a package manager to find out.\n\nCheck the project root **and** `tests\u002Facceptance\u002F`, because a separate test workspace is the common layout and is usually where the real dependency lives. Run these from the project root:\n\n```bash\n# 1. Installed truth. Works for npm, pnpm, and Yarn's node-modules linker.\nfor dir in . tests\u002Facceptance; do\n  f=\"$dir\u002Fnode_modules\u002F@shopware-ag\u002Facceptance-test-suite\u002Fpackage.json\"\n  [ -f \"$f\" ] && printf '%s -> ' \"$f\" && grep -m1 '\"version\"' \"$f\"\ndone\n\n# 2. Lock file resolution, when node_modules is absent.\n#    Keep context lines: pnpm splits specifier and resolved version, and a\n#    workspace nests entries under `importers:` per directory.\ngrep -rn -A3 'acceptance-test-suite' \\\n  package-lock.json pnpm-lock.yaml yarn.lock \\\n  tests\u002Facceptance\u002Fpackage-lock.json tests\u002Facceptance\u002Fpnpm-lock.yaml tests\u002Facceptance\u002Fyarn.lock 2>\u002Fdev\u002Fnull\n\n# 3. Requested range only. This is an intention, not proof of what is installed.\ngrep -rn 'acceptance-test-suite' package.json tests\u002Facceptance\u002Fpackage.json 2>\u002Fdev\u002Fnull\n```\n\nSay which of the three sources the version came from. If none yields a version and there is no test workspace yet, this is a fresh setup: continue with the workspace setup below. Otherwise state that the ATS version could not be determined, ask the user, and avoid version specific claims until it is known.\n\nFor the version of the **shop under test** (a different thing), use the `InstanceMeta` fixture. `InstanceMeta.version` is the right way to guard a test against older Shopware releases.\n\n## Environment and constraints\n\nThese are strict and are the usual cause of a broken setup:\n\n- **Package**: `@shopware-ag\u002Facceptance-test-suite`, published on npm, MIT licensed.\n- **ESM only**: the package sets `\"type\": \"module\"`. The test workspace must set it too.\n- **Playwright peer is a caret range** (e.g. `^1.62.1`). Any compatible 1.x release satisfying the range works; a major mismatch of `@playwright\u002Ftest` is the usual cause of fixture type errors. `playwright-core` is declared as an optional peer at the same range.\n- **Node**: only the majors in the package's `engines.node` field. Read that field rather than assuming.\n- **Single import path**: the `exports` map exposes only the package root. Deep imports such as `@shopware-ag\u002Facceptance-test-suite\u002Fdist\u002F...` are unsupported.\n- **axe is bundled**: `@axe-core\u002Fplaywright` and `axe-html-reporter` are runtime dependencies of ATS. Do not install them separately.\n- **Only `dist\u002F` is published.** The suite's own `playwright.config.ts`, its docker compose setup, and its `src\u002F` tree are not in the npm tarball. Nothing in the installed package starts a server or a container.\n\nThe environment variables a typical project needs (the shipped code reads a few more for SaaS and seeded-ID setups, not listed here):\n\n| Variable | Required | Purpose |\n|---|---|---|\n| `APP_URL` | yes | Storefront base URL of the shop under test, with trailing slash |\n| `ADMIN_URL` | no | Administration URL, defaults to `${APP_URL}admin\u002F` |\n| `ADMIN_API_URL` | no | Admin API base URL when it is not on `APP_URL`, trailing slash required |\n| `SHOPWARE_ACCESS_KEY_ID`, `SHOPWARE_SECRET_ACCESS_KEY` | preferred | Admin API integration credentials |\n| `SHOPWARE_ADMIN_USERNAME`, `SHOPWARE_ADMIN_PASSWORD` | alternative | Admin user login, used when no integration credentials are set |\n| `LANG` | no | Locale, read as `LANG`, `LANGUAGE`, or `lang`, default `en-GB`. Set it explicitly: a non English shell locale runs the whole suite in another language and breaks text based locators |\n| `MAILPIT_BASE_URL` | for mail tests | Mailpit base URL, no default |\n| `ATS_SKIP_CLEANUP` | no | Set to `1` to keep test data after a run, for debugging only |\n\nIntegration credentials are preferred over an admin user: they are faster and unaffected by admin session behavior.\n\n## Testing an existing storefront\n\nFor deployed-shop smoke coverage, configure the exported worker option in the consumer project's `use`: `storefrontTarget: { mode: 'existing', url: process.env.SHOPWARE_STOREFRONT_URL! }`. Setting that environment variable alone does not change the npm package's generated-channel default. Select compatible storefront specs with the project's `testMatch` or `grep`; ATS does not rewrite their explicit product\u002Forder\u002Fcustomer setup.\n\nUse `SHOPWARE_STOREFRONT_CUSTOMER_EMAIL` and `SHOPWARE_STOREFRONT_CUSTOMER_PASSWORD` (legacy `SMOKE_CUSTOMER_*` aliases remain supported), or explicitly configure `storefrontCustomer: { email, password }`. A supplied account is resolved and verified through a Store API login, and is never deleted by the fixture. Without credentials, ATS creates and deletes one owned customer per worker. Override the worker `StorefrontCustomer` fixture for anonymous browsing or a project-owned account. Only one configured credential fails; it never triggers fallback creation.\n\nExisting mode uses the resolved channel\u002Fdomain and its locale, skips theme assignment and routes both browser and Store API requests to the domain host\u002Fpath. Browser setup rejects unsupported translation languages with guidance to supply `CustomTranslationResources`. Project-level `use.httpCredentials` and `use.userAgent` are forwarded to Store API requests too; test-level overrides cannot reconfigure an existing worker API context.\n\nKeep `AdminSession`, `AdminPage`, ATS `page` and `context` in generated projects: they provision Admin sessions and throw in existing mode. Set `workers: 1` for tests that mutate shared channel state or share customer carts\u002Forders, and avoid concurrent conflicting projects. Independent read-only cases can use deliberate parallelism.\n\nExisting mode is not read-only: customer creation, credential-verification logins, explicit `TestDataService.create*` calls and test actions still happen. Borrowed-channel `setSystemConfig`, analytics overwrites and field-reset cleanup registration fail rather than discard existing values; cleanup cannot delete the borrowed channel. Cleaning explicitly created records can flush delayed caches. Generated mode retains its original browser-option handling; existing mode also forwards `contextOptions`.\n\nRead [Test an existing storefront](https:\u002F\u002Fdeveloper.shopware.com\u002Fdocs\u002Fguides\u002Fdevelopment\u002Ftesting\u002Fe2e-playwright\u002Fexisting-storefront.html) for the typed project example, authentication and customer lifecycle, selection guidance, remaining writes and CI checks.\n\n## Set up the test workspace\n\nInstall ATS first, then read its peer range from disk. Do not guess the Playwright version.\n\n```bash\nmkdir -p tests\u002Facceptance && cd tests\u002Facceptance\nnpm init -y\nnpm install --save-dev @shopware-ag\u002Facceptance-test-suite\n\n# Read the peer range ATS declares, then install a version satisfying it.\ngrep -A4 '\"peerDependencies\"' node_modules\u002F@shopware-ag\u002Facceptance-test-suite\u002Fpackage.json\n\nnpm install --save-dev @playwright\u002Ftest@^1.62.1\nnpm install --save-dev dotenv\n\n# Add --with-deps only on a fresh CI image: it installs OS packages as root and\n# fails where sudo needs a password.\nnpx playwright install chromium\n```\n\nTarget layout. **Run every command in this skill from `tests\u002Facceptance\u002F`**, except the version detection commands above, which run from the project root.\n\n```text\ntests\u002Facceptance\u002F\n├── .env                  # never commit\n├── package.json          # \"type\": \"module\"\n├── playwright.config.ts\n├── fixtures\u002F\n│   └── AcceptanceTest.ts\n└── tests\u002F\n    ├── checkout.spec.ts\n    └── accessibility.spec.ts\n```\n\n**Edit** the generated `package.json`, do not replace it: it already holds the `devDependencies` from the installs above, and overwriting it breaks every import. Add `\"type\": \"module\"` and the scripts:\n\n```json\n{\n  \"type\": \"module\",\n  \"scripts\": {\n    \"test\": \"playwright test\",\n    \"test:a11y\": \"playwright test --grep @Accessibility\",\n    \"report\": \"playwright show-report\"\n  }\n}\n```\n\n`.env` holds the shop under test. Playwright does not read `.env` by itself, which is why the config below loads it. `APP_URL` needs the trailing slash: ATS composes the admin URL as `${APP_URL}admin\u002F`, and a project's own `.env` usually stores it without one.\n\n```bash\nAPP_URL=\"https:\u002F\u002Fshop.example.test\u002F\"\nLANG=\"en-GB\"\n\n# Preferred: an Admin API integration. Create one in Settings, System, Integrations,\n# or run `bin\u002Fconsole integration:create AcceptanceTest --admin` on the shop:\n# it prints both lines below ready to paste.\nSHOPWARE_ACCESS_KEY_ID=\"...\"\nSHOPWARE_SECRET_ACCESS_KEY=\"...\"\n\n# Alternative, and what a freshly installed shop already has:\n# SHOPWARE_ADMIN_USERNAME=\"admin\"\n# SHOPWARE_ADMIN_PASSWORD=\"shopware\"\n```\n\n`playwright.config.ts`. No `webServer` block: this configuration tests an instance that is already running.\n\n```ts\nimport { defineConfig, devices } from '@playwright\u002Ftest';\nimport dotenv from 'dotenv';\n\ndotenv.config({ quiet: true });\n\nexport default defineConfig({\n  testDir: '.\u002Ftests',\n  timeout: 60_000,\n  expect: { timeout: 10_000 },\n  fullyParallel: true,\n  forbidOnly: !!process.env.CI,\n  retries: process.env.CI ? 1 : 0,\n  reporter: process.env.CI ? [['github'], ['html']] : [['list'], ['html']],\n  use: {\n    baseURL: process.env.APP_URL,\n    trace: 'retain-on-failure',\n    screenshot: 'only-on-failure',\n  },\n  projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],\n});\n```\n\nCreate one base test file and import from it everywhere. This is what makes project fixtures and tasks available alongside the suite's own:\n\n```ts\n\u002F\u002F fixtures\u002FAcceptanceTest.ts\nimport { test as base } from '@shopware-ag\u002Facceptance-test-suite';\nimport type { FixtureTypes } from '@shopware-ag\u002Facceptance-test-suite';\n\nexport * from '@shopware-ag\u002Facceptance-test-suite';\n\nexport const test = base.extend\u003CFixtureTypes>({\n  \u002F\u002F project specific fixtures go here\n});\n```\n\nWhen the project has its own task collections, merge instead of extending:\n\n```ts\nimport { mergeTests, test as ShopwareTestSuite } from '@shopware-ag\u002Facceptance-test-suite';\nimport { test as projectTasks } from '.\u002FProjectTasks';\n\nexport * from '@shopware-ag\u002Facceptance-test-suite';\n\nexport const test = mergeTests(ShopwareTestSuite, projectTasks);\n```\n\n### Typecheck the tests\n\nPlaywright transpiles without typechecking, so type errors run silently and surface as wrong behavior instead of a failure. Add a `tsconfig.json` and run `tsc` in CI alongside the tests.\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"strict\": true,\n    \"noEmit\": true,\n    \"skipLibCheck\": true,\n    \"types\": [\"node\"]\n  },\n  \"include\": [\"fixtures\u002F**\u002F*.ts\", \"tests\u002F**\u002F*.ts\", \"playwright.config.ts\"]\n}\n```\n\n```bash\nnpm install --save-dev typescript @types\u002Fnode\nnpx tsc --noEmit\n```\n\nThis is how the `attemptsTo(ValidateAccessibility(...))` mistake described under Accessibility gets caught.\n\n## Write a spec\n\nEverything the suite offers arrives as Playwright fixtures destructured in the test callback: actors, tasks, page objects, and services. There is no separate setup call.\n\n```ts\n\u002F\u002F tests\u002Fcheckout.spec.ts\nimport { test } from '..\u002Ffixtures\u002FAcceptanceTest';\n\ntest('Customer can add a product to the cart.', { tag: '@Checkout' }, async ({\n  ShopCustomer,\n  TestDataService,\n  AddProductToCart,\n  StorefrontProductDetail,\n  StorefrontCheckoutCart,\n}) => {\n  const product = await TestDataService.createBasicProduct();\n\n  await ShopCustomer.goesTo(StorefrontProductDetail.url(product));\n  await ShopCustomer.attemptsTo(AddProductToCart(product, '5'));\n\n  await ShopCustomer.goesTo(StorefrontCheckoutCart.url());\n  await ShopCustomer.expects(StorefrontCheckoutCart.grandTotalPrice).toBeVisible();\n});\n```\n\nRules that keep specs working:\n\n- **Create the data the test needs.** Never rely on demo data or on data another test created.\n- **One browser surface per test.** `ShopCustomer` for storefront coverage, `ShopAdmin` for administration coverage. Do not model flows that hop from administration to storefront and back in one test.\n- **Use page objects for URLs and elements**, so a routing or markup change is fixed in one place.\n- **`expects` is Playwright's `expect`**, reachable through the actor for readability.\n\n### Actors\n\n| Actor | Surface |\n|---|---|\n| `ShopCustomer` | storefront |\n| `ShopAdmin` | administration |\n\nMethods: `goesTo(url, forceReload?)`, `attemptsTo(task)`, `expects(locator)`, `presses(locator, key?)`, `fillsIn(locator, input)`, `selectsRadioButton(group, label)`, `a11y_checks(locator)`.\n\n`a11y_checks` scrolls the locator into view and asserts it is enabled, focused, and shows a visible focus indicator. `presses`, `fillsIn`, and `selectsRadioButton` call it internally, so keyboard operability and a visible focus ring are asserted as a side effect of using them.\n\n**For storefront interactions, use the actor methods by default** — `presses`\u002F`fillsIn` rather than `click`\u002F`fill`, in ordinary functional tests too, not only accessibility specs. Each interaction then also asserts keyboard operability and a visible focus indicator. This is the suite's convention for storefront flows.\n\n```ts\n\u002F\u002F Preferred\nawait ShopCustomer.fillsIn(StorefrontAccountLogin.emailInput, customer.email);\nawait ShopCustomer.presses(StorefrontAccountLogin.loginButton);\n```\n\nTwo things to know when using them:\n\n- They drive the keyboard instead of clicking, so they skip some of Playwright's click actionability checks. Assert state first where a control may be hidden or disabled:\n\n  ```ts\n  await ShopCustomer.expects(submitButton).toBeVisible();\n  await ShopCustomer.expects(submitButton).toBeEnabled();\n  await ShopCustomer.presses(submitButton);\n  ```\n\n- When converting an existing suite, a control that was never keyboard operable now fails: triage the finding, don't revert to `click` to hide it.```\n\n**Administration flows are the documented exception.** The suite's own guidance prefers the keyboard first methods for storefront flows and says not to generalize that rule to the Administration, so use plain Playwright there unless the test is specifically about keyboard operability. The methods exist on `ShopAdmin` and work, but the Administration is not covered by the storefront convention and has no accessibility task equivalent.\n\n### Tasks\n\nA task is a reusable, named interaction exposed as a fixture, read as a sentence: `Login()`, `AddProductToCart(product, '5')`, `SubmitOrder()`. Destructure it and pass it to `attemptsTo`.\n\nAuthor a project task the same way the suite does, as a fixture returning a function that returns the closure:\n\n```ts\nimport { test as base } from '@playwright\u002Ftest';\nimport type { FixtureTypes, Task } from '@shopware-ag\u002Facceptance-test-suite';\n\nexport const AcceptCookieBanner = base.extend\u003C{ AcceptCookieBanner: Task }, FixtureTypes>({\n  AcceptCookieBanner: async ({ ShopCustomer, StorefrontHome }, use) => {\n    const task = () => {\n      return async function AcceptCookieBanner() {\n        await ShopCustomer.presses(StorefrontHome.consentAcceptAllCookiesButton);\n      };\n    };\n    await use(task);\n  },\n});\n```\n\nName the returned function: `attemptsTo` derives the test step title from it. Keep assertions about the thing under test in the spec, not in the task.\n\n### Test data\n\n`TestDataService` creates entities through the admin API and cleans them up after each test. Method names follow a pattern: `createBasic*`, `create*With*`, `assign*`, `get*`.\n\n```ts\nconst product = await TestDataService.createBasicProduct({ name: 'Test product' });\nconst category = await TestDataService.createCategory();\nawait TestDataService.assignProductCategory(product.id, category.id);\n```\n\n- Cleanup respects entity dependencies, so create through the service where possible.\n- An entity created outside the service can be registered for cleanup; prefer that over leaving data behind.\n- `ATS_SKIP_CLEANUP=1` keeps data for inspection. Never leave it set in CI.\n- For anything the service does not model, use `AdminApiContext` or `StoreApiContext`.\n\n### Locators\n\nStandard Playwright locator priority applies (`getByRole` first, avoid XPath and CSS coupled to styling). One ATS-specific point:\n\n- Text and placeholder locators are unreliable here: the Shopware storefront is multilingual and runs under `LANG`, so visible text changes across locales and placeholder text is often absent from accessible markup. Prefer a role or label; a field with no accessible label is usually an accessibility defect worth fixing rather than working around. Keep locators in page object properties (see the spec rules above).\n\n## Accessibility\n\nThe suite ships exactly one accessibility task, `ValidateAccessibility`, built on the bundled `@axe-core\u002Fplaywright`. It is bound to the shop customer's page: there is no administration equivalent, so do not promise administration accessibility coverage through it.\n\n```ts\n\u002F\u002F tests\u002Faccessibility.spec.ts\nimport { test } from '..\u002Ffixtures\u002FAcceptanceTest';\n\ntest('The storefront implements accessibility best practices.', { tag: '@Accessibility' }, async ({\n  ShopCustomer,\n  TestDataService,\n  ValidateAccessibility,\n  StorefrontAccountLogin,\n  StorefrontCategory,\n}) => {\n  test.slow();\n\n  const category = await TestDataService.createCategory();\n\n  await test.step('Login page', async () => {\n    await ShopCustomer.goesTo(StorefrontAccountLogin.url());\n    await ValidateAccessibility('Login', true)();\n  });\n\n  await test.step('Category page', async () => {\n    await ShopCustomer.goesTo(StorefrontCategory.url(category.name));\n    \u002F\u002F Known violation: the first level headline is CMS configurable.\n    await ValidateAccessibility('Category', 1)();\n  });\n});\n```\n\nCall the closure directly, as shown — do not wrap it in `attemptsTo`. The closure returns the axe results array, not `() => Promise\u003Cvoid>`, so `tsc` rejects it. Examples elsewhere use `attemptsTo(ValidateAccessibility(...))`; it runs (Playwright transpiles without typechecking) but fails typecheck and discards the results.\n\nSignature and behavior:\n\n```\nValidateAccessibility(pageName, assertViolations?, createReport?, ruleTags?, outputDir?)\n```\n\n- `pageName` labels the report. The filename strips every non alphabetic character, so `'Page Not Found'` becomes `PageNotFound.html`.\n- `assertViolations` is polymorphic:\n  - `true` (default) requires zero violations.\n  - a **number** allows at most that many violations. This is a budget, not a targeted waiver: any new violation of any rule hides under the budget.\n  - `false` asserts nothing and only returns results.\n- `createReport` defaults to true and writes `test-results\u002FAccessibilityReports\u002F\u003CPageName>.html`.\n- `ruleTags` defaults to `['wcag2a', 'wcag2aa', 'wcag2aaa', 'wcag21a', 'wcag21aa', 'best-practice']`. That is broader than most projects' stated target: it enforces AAA rules and axe best practice rules, neither of which is a WCAG 2.1 AA requirement, so a default run can fail on issues that are not conformance failures. Pass an explicit list matching the project's target, for example `['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa']`, and keep it consistent across specs.\n- `outputDir` overrides the report directory.\n- The closure returns the violations array, so a spec can inspect or attach it: `const violations = await ValidateAccessibility('Home', false)();`\n\nGuidance:\n\n- One page per `test.step`, so a failure names the page.\n- Use `test.slow()`: axe analysis across several pages exceeds the default timeout.\n- When a violation is accepted for now, put the reason in a comment beside the call and link a tracking issue. Prefer a tighter rule set over a numeric budget, because a budget hides regressions.\n- Automated checks are a floor, not proof of accessibility. Keyboard traversal, focus management in modals and off canvas panels, and screen reader behavior still need explicit tests or manual review.\n\n## Run tests\n\nFrom `tests\u002Facceptance\u002F`:\n\n```bash\nnpx playwright test                                  # everything\nnpx playwright test tests\u002Fcheckout.spec.ts           # one file\nnpx playwright test --grep @Accessibility            # by tag\nnpx playwright test --headed --project=chromium      # watch it run\nnpx playwright show-report                           # last HTML report\n```\n\nDebugging:\n\n- `--debug` opens the inspector; `--trace on` records a trace for `npx playwright show-trace`.\n- `ATS_SKIP_CLEANUP=1` preserves created data so the shop can be inspected after a failure.\n- Accessibility reports land in `test-results\u002FAccessibilityReports\u002F`.\n\n## Troubleshooting\n\n| Symptom | Cause and fix |\n|---|---|\n| Fixture types missing, or `test.extend` type errors | `@playwright\u002Ftest` does not satisfy ATS's peer range. Align it. |\n| `ERR_REQUIRE_ESM` or import failures | The test workspace is not ESM. Set `\"type\": \"module\"`. |\n| Unresolved deep import | Only the package root is exported. Import from `@shopware-ag\u002Facceptance-test-suite`. |\n| `APP_URL` or credentials appear unset | Nothing loads `.env` by itself. Load it in `playwright.config.ts`. |\n| Admin API calls fail with 401 | Credentials missing or wrong, or the API is not on `APP_URL`. Prefer integration credentials; set `ADMIN_API_URL` when the API lives elsewhere. |\n| Tests act on the wrong surface | The bare Playwright `page` fixture is not the storefront page. Use the actors, or the explicit `StorefrontPage` and `AdminPage` fixtures. |\n| Text based locators fail in another language | `LANG` is inherited from the shell. Set it explicitly. |\n| Data from previous runs pollutes tests | `ATS_SKIP_CLEANUP` is set in the environment. |\n| Playwright waits forever, or tries to start a server | Your own config's `webServer` block, not ATS: the published package ships only `dist\u002F` and starts nothing. Omit `webServer` when testing a running instance, or use it purely as a readiness gate. |\n| Accessibility spec times out | Add `test.slow()` and split page audits into steps. |\n| `attemptsTo(ValidateAccessibility(...))` fails to typecheck | Expected. Call the closure directly: `await ValidateAccessibility('Name', true)();` |\n\n## When guidance and reality disagree\n\nThe installed package is the authority. Verify against it rather than against this skill or older documentation:\n\n```bash\ncat node_modules\u002F@shopware-ag\u002Facceptance-test-suite\u002Fpackage.json\ncat node_modules\u002F@shopware-ag\u002Facceptance-test-suite\u002Fdist\u002Findex.d.ts | grep -E 'export|declare' | head -50\n```\n\nThe type definitions list the real exports, fixtures, and task names for the installed version. Task argument shapes are not there: `Task` is typed `(...args: any[]) => () => Promise\u003Cvoid>`, so read a task's real parameters in `dist\u002Findex.mjs`, and do not expect `tsc` to catch wrong task arguments. Published examples elsewhere sometimes use fixture names from older majors; prefer what the installed types show. If this skill and the installed package disagree, follow the package and tell the user exactly what differed: the skill's claim, the installed version, and what you did instead. If the skill looks genuinely stale rather than locally patched, suggest the user report it upstream (an issue or PR against shopware\u002Facceptance-test-suite).\n",{"name":5,"description":7},"trunk","7dda09197978a1aebb0b8fb8ca624b776bd90377","skills\u002Facceptance-test-suite",9,"https:\u002F\u002Fgithub.com\u002Fshopware\u002Facceptance-test-suite","https:\u002F\u002Fgithub.com\u002Fshopware","https:\u002F\u002Fwww.shopware.com","Shopware 6 is an open commerce platform based on Symfony Framework and Vue and supported by a worldwide community and more than 2.500 community extensions","2026-11-12 18:53:38",{"source":8,"skillName":5,"commands":55,"prompt":65,"zipAvailable":66},[56,59,62],{"tool":57,"command":58},"npx","npx skills add shopware\u002Facceptance-test-suite --skill acceptance-test-suite",{"tool":60,"command":61},"bunx","bunx skills add shopware\u002Facceptance-test-suite --skill acceptance-test-suite",{"tool":63,"command":64},"pnpm","pnpm dlx skills add shopware\u002Facceptance-test-suite --skill acceptance-test-suite","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fshopware\u002Facceptance-test-suite\u002Fblob\u002Ftrunk\u002Fskills\u002Facceptance-test-suite\u002FSKILL.md",true,[],[69,88],{"skillNo":70,"name":71,"nameZh":6,"description":72,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":73,"categories":74,"keywords":76,"publishedAt":40},"01M6BY7DTT65562SZZ74DVVAK0","shopware-ats","Work effectively in the Shopware Acceptance Test Suite repository: inspect or modify Playwright specs, merged fixtures, page objects, tasks, service helpers, shared types, and locale-backed assertions. Use when you need to debug a failing ATS test, add or refactor Shopware end-to-end coverage, trace how exported fixtures are wired together, or choose the right file to update in `tests\u002F`, `src\u002Ffixtures\u002F`, `src\u002Fpage-objects\u002F`, `src\u002Ftasks\u002F`, `src\u002Fservices\u002F`, or `src\u002Ftypes\u002F`.","https:\u002F\u002Fgithub.com\u002Fshopware\u002Facceptance-test-suite\u002Fblob\u002Ftrunk\u002F.codex\u002Fskills\u002Fshopware-ats\u002FSKILL.md",[75],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[77,31,78,79,80,81,82,83,84,85,26,86,39,87,24,27],"shopware ats","choose","trace","page","src","how","refactor","services","file","update","debug",{"skillNo":89,"name":71,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":90,"categories":91,"keywords":92,"publishedAt":40},"01M6BY7CHT7479PM7R3E74BTE1","https:\u002F\u002Fgithub.com\u002Fshopware\u002Facceptance-test-suite\u002Fblob\u002Ftrunk\u002F.claude\u002Fskills\u002Fshopware-ats\u002FSKILL.md",[],[77]]