feat(administration): introduce admin:test-extensions command by gweiermann · Pull Request #21822 · shopware/shopware · GitHub
Skip to content

feat(administration): introduce admin:test-extensions command - #21822

Open
Gerrit Weiermann (gweiermann) wants to merge 13 commits into
feat/admin-extension-jest-composer-installfrom
feat/admin-extension-test-command
Open

Gerrit Weiermann (gweiermann) wants to merge 13 commits into
feat/admin-extension-jest-composer-installfrom
feat/admin-extension-test-command

Conversation

@gweiermann

@gweiermann Gerrit Weiermann (gweiermann) commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

1. Why is this change necessary?

Running specs for a plugin using the shared Jest harness is still fidely and not very convenient:

node <administration>/node_modules/jest/bin/jest.js --config jest.config.mjs

Instead there should be a new command that abstracts that away.

2. How?

Showcase of the new command:

Help

www-data@docker /var/www/html $ bin/console administration:test-extensions -- --help

Run the specs of Administration extensions with the Administration's own Jest and test harness. Options for Jest go after a second "--", e.g. -- --only=MyPlugin -- --watch.

Usage (note the "--" — composer swallows options placed before it):
  composer admin:test-extensions -- [options]

Options:
  --only=<name[,name]>          Test only the named extensions (skips the interactive picker).
  --all                         Test every extension that has a Jest config (skips the interactive picker).
  --no-vendors                  Leave out extensions installed under vendor/, in --all and in the picker.
  --project-root=<path>         Shop root (defaults to the PROJECT_ROOT env).
  --administration-root=<path>  Administration app root (defaults to the installed one running this script).
  -h, --help                    This help.

Example: composer admin:test-extensions -- --only=<name[,name]>

Run a single plugin

www-data@docker /var/www/html $ bin/console administration:test-extensions -- --only UrCatalog

▶ UrCatalog · custom/plugins/UrCatalog/src/Resources/app/administration/jest.config.mjs
 PASS  src/catalog.spec.js
 PASS  src/own-dependency.spec.js

Test Suites: 2 passed, 2 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        3.839 s
Ran all test suites.

✓ UrCatalog · custom/plugins/UrCatalog/src/Resources/app/administration/jest.config.mjs

Run all

www-data@docker /var/www/html $ bin/console administration:test-extensions -- --all

▶ UrCatalog · custom/plugins/UrCatalog/src/Resources/app/administration/jest.config.mjs
 PASS  src/catalog.spec.js
 PASS  src/own-dependency.spec.js

Test Suites: 2 passed, 2 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        3.67 s, estimated 8 s
Ran all test suites.

▶ UrGreetings · custom/plugins/UrGreetings/src/Resources/app/administration/jest.config.mjs
 PASS  src/greetings.spec.js
  UrGreetings
    ✓ resolves shopware:utils (2 ms)
    ✓ renders a template (8 ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        1.902 s, estimated 4 s
Ran all test suites.

▶ vendor-widgets · vendor/ur/vendor-widgets/src/Resources/app/administration/jest.config.mjs
 PASS  src/widgets.spec.js
  UrVendorWidgets
    ✓ runs (1 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.183 s, estimated 5 s
Ran all test suites.

✓ UrCatalog · custom/plugins/UrCatalog/src/Resources/app/administration/jest.config.mjs
✓ UrGreetings · custom/plugins/UrGreetings/src/Resources/app/administration/jest.config.mjs
✓ vendor-widgets · vendor/ur/vendor-widgets/src/Resources/app/administration/jest.config.mjs
⊘ SwagCmsExtensions · custom/plugins/SwagCmsExtensions/src/Resources/app/administration/jest.config.js (not run)
  It does not use the Administration's test harness, so it runs on its own Jest, which is not installed.
  Fix: run `npm ci` in custom/plugins/SwagCmsExtensions/src/Resources/app/administration,
  or build the config on the harness with `shopwareAdminJestConfig` from `.shopware/jest.mjs`.

3. Decisions

  • Adds command composer admin:test-extensions (bin/console administration:test-extensions in a Composer install)
  • Interactive picker exists
  • Plugins that don't use .shopware/jest.config.mjs are excluded (+ a hint how to make it work)
  • generates the component import map when it is missing, for example after a Shopware update.

to be followed up

  • --config=<path> for configs outside the discovered folders, e.g. SwagCommercial's tests/jest/administration

4. Repro

With a plugin set up as in #21797, whose jest.config.mjs imports .shopware/jest.mjs:

composer admin:test-extensions -- --only=MyPlugin              # ▶ MyPlugin · …/jest.config.mjs, Jest's output, ✓ MyPlugin · …
composer admin:test-extensions -- --only=MyPlugin -- --watch   # Jest's watch mode; q quits and prints the report
composer admin:test-extensions -- --only=NoSuchPlugin          # ✗ --only names unknown extension(s): NoSuchPlugin. …
composer admin:test-extensions                                 # interactive picker

The plugin needs no Jest of its own.
In a Composer install, run npm ci once in vendor/shopware/administration/Resources/app/administration, then use bin/console administration:test-extensions with the same options.

A plugin with its own Jest setup, for example SwagCmsExtensions (Jest 29 with @shopware-ag/jest-preset-sw6-admin), before its npm ci:

$ composer admin:test-extensions -- --all
…
⊘ SwagCmsExtensions · custom/plugins/SwagCmsExtensions/src/Resources/app/administration/jest.config.js (not run)
  It does not use the Administration's test harness, so it runs on its own Jest, which is not installed.
  Fix: run `npm ci` in custom/plugins/SwagCmsExtensions/src/Resources/app/administration,
  or build the config on the harness with `shopwareAdminJestConfig` from `.shopware/jest.mjs`.

After that npm ci, the run prints ✓ SwagCmsExtensions · …/jest.config.js (own Jest).

5. Please link to the relevant issues (if any).

6. Checklist

  • I have written tests and verified that they fail without my change
  • I have updated developer-facing release notes if this change is relevant for external developers:
    • Add a short entry to RELEASE_INFO-6.<current major line>.md in the upcoming version section for informational changes: what changed, who is affected, and how to adapt.
    • Add an entry to UPGRADE-6.<next major>.md for breaking changes and deprecations: what changed, who is affected, and how to adapt.
    • See the Documenting a Release Process for details.
  • I have written or adjusted the documentation and agent skills according to my changes
  • This change has comments for package types, values, functions, and non-obvious lines of code
  • I have read the contribution requirements and fulfilled them

@gweiermann Gerrit Weiermann (gweiermann) added component/administration domain/framework Responsible for the framework-level code includes core, administration, storefront, and frontends labels Oct 21, 2026
@github-actions github-actions Bot added the waiting-on/nobody The PR is a draft or parked. Set daily by the waiting-on-report workflow. label Oct 21, 2026
@explore-openapi

explore-openapi Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

@codecov

codecov Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 71.81%. Comparing base (ee27b44) to head (d2fa100).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@                              Coverage Diff                               @@
##           feat/admin-extension-jest-composer-install   #21822      +/-   ##
==============================================================================
- Coverage                                       71.81%   71.81%   -0.01%     
==============================================================================
  Files                                            5983     5985       +2     
  Lines                                          219740   219735       -5     
  Branches                                        12115    12115              
==============================================================================
- Hits                                           157812   157805       -7     
- Misses                                          58101    58103       +2     
  Partials                                         3827     3827              
Flag Coverage Δ
jest-admin 68.82% <ø> (-0.01%) ⬇️
jest-storefront 72.53% <ø> (ø)
phpunit-migration 95.04% <ø> (ø)
phpunit-unit 69.66% <100.00%> (-0.01%) ⬇️
vitest-storefront-components 62.47% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

An extension that composes the Administration's Jest config still had to
call the Administration's Jest binary by path, or install a Jest of the
matching major itself.

admin:test-extensions (bin/console administration:test-extensions in a
Composer install) runs every selected extension's jest.config.* with the
Administration's Jest. Selection works like check-extensions, options
after a second "--" go to Jest, and a missing component import map is
generated first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
admin:test-extensions now skips extensions installed under vendor/ unless
--only (or the interactive picker) names them, and lists the skipped ones
in its report. A run in which no Jest config ran exits 1, so a CI job
cannot pass without running a spec.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…al extensions

Jest's --watch and --watchAll never return, so every config after the
first would never run. admin:test-extensions now exits 2 with a usage
error when watch mode meets no or several Jest configs, and asks to name
one extension via --only.

A spec path or name filter usually matches in one extension only. When
Jest options go to more than one Jest config, the command adds
--passWithNoTests unless it is already given, so the run fails only on a
failing spec.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…:test-extensions

- The report starts with the setup warnings of the selected extensions,
  as they may explain a failed run.
- The interactive picker shows each extension's location and number of
  Jest configs.
- Watch mode on one extension with several Jest configs names those
  configs instead of asking for --only.
- A ts-node that cannot start fails the component import generation with
  its error.
- Composer's process timeout no longer stops admin:test-extensions.
- README and RELEASE_INFO keep the regenerate-after-update guidance and
  say when test-extensions generates the component import map itself.
- The specs are split by concern and cover generator failures, the
  precedence of a fatal diagnostic over watch mode, the picker, the config
  lookup, the report lines and the CLI help and usage paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d run

testExtensions mixed deciding which Jest configs run, deciding whether the
selection is fatal and running Jest, guarded by repeated
fatalDiagnostics.length === 0 checks. planTestRun and selectionDiagnostic
now take the first two steps, and every fatal case returns early.
The behaviour does not change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gweiermann
Gerrit Weiermann (gweiermann) force-pushed the feat/admin-extension-test-command branch from 7a29c23 to 64c626f Compare October 21, 2026 14:48
…ensions

isWatchRun treated any --watch or --watchAll option as watch mode, so
`--watchAll=false` over several extensions failed with the watch usage
error. It now follows Jest's parser: the last occurrence of each flag
wins, and `--no-<flag>` or a `false` value turns it off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gweiermann
Gerrit Weiermann (gweiermann) marked this pull request as ready for review October 21, 2026 14:57
@github-actions github-actions Bot added waiting-on/shopware The PR is waiting on shopware. Set daily by the waiting-on-report workflow. and removed waiting-on/nobody The PR is a draft or parked. Set daily by the waiting-on-report workflow. labels Oct 21, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review ✅ Completed 2026-10-27T16:47:10.024406Z d2fa100 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@shopwareBot

shopwareBot commented Oct 21, 2026 •

Copy link
Copy Markdown

@gweiermann
Gerrit Weiermann (gweiermann) marked this pull request as draft October 22, 2026 08:13
@github-actions github-actions Bot added waiting-on/nobody The PR is a draft or parked. Set daily by the waiting-on-report workflow. and removed waiting-on/shopware The PR is waiting on shopware. Set daily by the waiting-on-report workflow. labels Oct 22, 2026
…ithout a spec

- Count the tests of each Jest run through a --json results file and fail
  the run when no Jest config ran a spec, also when --passWithNoTests was
  added for several configs; mark an empty config with "–"
- Print "▶ <extension> · <config>" before each Jest run
- --all and the non-interactive default now test vendor/ extensions too;
  --no-vendors leaves them out
- Leave type-check and lint warnings, and extensions without a Jest
  config, out of the report

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…epts

test-extensions decides watch mode, --passWithNoTests and its own --json
results file from the forwarded Jest options. It now reads kebab-case
spellings (--watch-all, --pass-with-no-tests, --output-file), --no-<option>
and a separate true/false value (--watch false), and builds the Jest
options once per run instead of once per config.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…le line

The runner counted the specs of each Jest run with --json --outputFile, and
Jest then printed "Test results written to: <temp path>" after every run, for a
file that was deleted right after. A results processor now writes the counts,
so the output shows only what Jest prints for the specs. A caller's own --json
or --outputFile no longer turns the counting off; only their own
--testResultsProcessor does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ension's own Jest

admin:test-extensions ran every Jest config it found on the Administration's
Jest. A config that brings its own Jest setup, such as a preset from the
extension's node_modules, failed there and turned --all red for a plugin the
developer may not maintain.

A config on the harness keeps running on the Administration's Jest. Any other
config runs on the Jest the extension installs between the config and the
extension root. When a package.json there declares Jest that is not installed,
the config does not run: the report marks it with ⊘ and names the npm ci or
npm install that installs it, and fails the run only when the extension was
named via --only or the picker. The picker marks such an extension too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gweiermann
Gerrit Weiermann (gweiermann) marked this pull request as ready for review October 27, 2026 16:38
@github-actions github-actions Bot added waiting-on/shopware The PR is waiting on shopware. Set daily by the waiting-on-report workflow. and removed waiting-on/nobody The PR is a draft or parked. Set daily by the waiting-on-report workflow. labels Oct 27, 2026
@gweiermann Gerrit Weiermann (gweiermann) changed the title feat(administration): run extension specs with the Administration's Jest feat(administration): introduce admin:test-extensions command Oct 27, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component/administration domain/framework Responsible for the framework-level code includes core, administration, storefront, and frontends waiting-on/shopware The PR is waiting on shopware. Set daily by the waiting-on-report workflow.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants