Light API 0.4.0 is a public beta: a minor release such as 0.5.0 may still break. What that means for your module
Light
Developer guide

Testing

The guards, checks and tests that keep Light and your module honest, and how to run them.

The checks that keep Light and the modules on it honest, and how to run them. Every merge request runs the contract checks; run npm run verify before you push.

The zero-core-edit guard

The guard proves that a bridge, an app or a brand package was added without editing Light core. It compares app/code/Mrx, the 14 core modules and the -hyva modules, between a base commit and your working tree, untracked files included:

tests/guard/zero-core-edit.sh
core='app/code/Mrx'
npm run guard:zero-core-edit                              # base from tests/guard/base.sha against the working tree
sh tests/guard/zero-core-edit.sh <base commit> <head commit>
  • The base is the commit in tests/guard/base.sha: the contract candidate, and from the 0.1.0 beta launch the launch commit. When a core fix lands, the base moves in its own commit, whose message names the reason.
  • Outside the guard: MageRex_Branding and MageRex_DemoData live in app/code/MageRex, and the packs (Mrx_CountryNl, Mrx_PaymentsMollie, Mrx_PaymentsPaynl) in packages/. They are not Light core, and each must land without a core edit.
  • Inside the guard: the -hyva modules, so their storefront changes follow the storefront rule.
  • The storefront rule. A storefront commit in a module under app/code/Mrx (a core or a -hyva module) may land between two bases when it touches nothing under any of those modules' etc/adminhtml/, view/adminhtml/, Api/ or Controller/Adminhtml/, nor Light/Test/Unit/Api/_files/, and keeps the Light/Test/Unit/Api tests green. It is followed by its own commit chore(guard): move base after storefront <topic>, which updates base.sha.

The white-label guard

Light core shows no brand of its own. Two checks prove it:

  • npm run guard:white-label runs tests/guard/white-label.sh, which greps Light core's templates, layout, acl.xml, email_templates.xml, system.xml and i18n for MageRex branding.
  • tests/playwright/white-label.spec.ts disables MageRex_Branding, opens the sign-in page, Home, Orders, a product, Settings, Apps, the kit page and a stock grid, removes the shop's own host names from each page, fails on any "magerex", and enables the module again.

The country-neutral guard

Light core names no country and no payment provider. npm run guard:country-neutral runs tests/guard/country-neutral.sh, which greps the PHP, templates, view files, etc/*.xml and translations of app/code/Mrx for the names Belastingdienst, KvK, PostNL, Mollie, iDEAL, Kamer van Koophandel and Autoriteit Persoonsgegevens, the country code NL and a literal euro sign. It also fails on the names of two other admin products, so copy and code don't borrow their words. Tests, docs, READMEs and comment lines don't count.

  • tests/guard/country-neutral.allow lists the hits that stay on purpose, one line each: path, word and reason, separated by tabs. An entry that matches nothing fails the guard, so the list only shrinks.
  • A pack for another country adds its own words to FACTS in the script.
  • tests/guard/country-neutral.test.sh proves the guard on a throwaway tree, and runs in npm run guard:self-test.

The distribution check

npm run guard:distribution runs tests/guard/distribution.mjs over packages/. Each module-* folder needs one autoload.psr-4 entry and one autoload.files entry in the root composer.json, and the range in its registration.php guard must equal extra.mrx-light-api in its own composer.json. An autoload entry that names a folder that doesn't exist fails too.

Pattern-B checks

A pattern-B module must keep compiling and working on a shop without Light.

  • npm run compat:scan loads every class of the pattern-B example's src/ with an autoloader that refuses Mrx\ classes, the way the compiler would on a shop without Light. It prints OK: <n> classes, or each file that needs Light. Run it on your own base module with docker exec -w /var/www/html magerexlight-php-fpm-1 php tests/compat/scan-without-light.php <path>.
  • The CI job compat:pattern-b runs tests/compat/pattern-b.sh in a throwaway container: without Light, setup:di:compile passes and the compat module stays unregistered; with Light, the compat module is enabled, compiles and passes the doctor. PLATFORM_VERSION picks the Mage-OS release, and the script ends with Light compiled on Mage-OS <version>.
  • CompatGuardTest (app/code/Mrx/Apps/Test/Unit/Model/Scaffold/CompatGuardTest.php) proves that the range guard leaves a module out of range unregistered.
  • Neither runs setup:di:compile in the development container: that would replace its generated code, which the environment rules forbid. pattern-b.sh needs its own container, COMPOSER_AUTH and a long composer install, so run it before a release and after a platform upgrade, and trust the latest green CI run in between.

The doctor's API checks

bin/magento mrx:light:doctor --module=<your module> --format=json

private_api reports a use of a Light class that isn't @api (an error when your module declares extra.mrx-light-api), and deprecated_use a use of a deprecated one. That replaces an API-only unit test copied from core: the doctor builds the surface from the running code. Which modules the doctor counts, and what happens to findings about the others, is in Doctor rules.

How the doctor reaches its findings:

npm run verify

One entry point for the contract checks every merge request runs: the unit tests of the API surface, the catalogue and the scaffold, the white-label guard, the country-neutral guard, the distribution check, compat:scan, the docs check's own tests, the docs check without Docker, the guards' self-test (guard:self-test) and the zero-core-edit guard. The guard runs last: while a core fix is in progress it is expected to fail, and every check before it still runs. verify needs the RollDev environment for the unit tests.

The same checks run in CI on every merge request:

Browser tests (Playwright)

npx playwright test --config=tests/playwright/playwright.config.ts tests/playwright/<feature>.spec.ts
  • The config runs one worker against https://app.magerexlight.test and writes each run to its own folder (MRX_PW_RUN_ID, MRX_PW_OUTPUT_DIR).
  • The setup project, tests/playwright/global.setup.ts, signs in once as lighttest, switches to simple mode and stores the session in tests/playwright/.auth/lighttest.json. Another user comes from MRX_ADMIN_USER and MRX_ADMIN_PASSWORD:
tests/playwright/helpers/admin.ts
export const ADMIN_USER = process.env.MRX_ADMIN_USER ?? 'lighttest';
  • Import test and expect from ./helpers/test, which blocks RollDev's auto-login script.
  • The helpers in tests/playwright/helpers/admin.ts: login, adminUrl, openAdmin (resolves the secret key of an admin URL), setMode, collectErrors (assert it is empty), waitForShell, waitForTable and removeOrders.
  • Browser tests of form cards and critical badges use the kit fixtures, which only exist in developer mode with the flag dev/mrx_light/kit_fixtures. Switch it on in beforeAll with bin/magento config:set dev/mrx_light/kit_fixtures 1, and off again in afterAll.
  • A spec for a module skips itself when the module is disabled, and tests/playwright/users-and-permissions.spec.ts must still pass.
  • Design system, section 15 has the conventions: cleanup, prefixes, storefront forms and other users.

Unit tests

docker exec -w /var/www/html magerexlight-php-fpm-1 php vendor/bin/phpunit -c dev/tests/unit/phpunit.xml.dist --no-extensions <path>
  • PHPUnit 12.5, with attributes such as #[DataProvider].
  • Mock Mrx\Light\Model\ModuleGate to test a class with and without its module, as app/code/Mrx/Home/Test/Unit/Model/Todo/TodoListGateTest.php does, and Magento\Framework\AuthorizationInterface to test with and without an ACL resource, as app/code/Mrx/Apps/Test/Unit/Model/AdvancedView/BackToAppsTest.php does.
  • A bridge keeps its vendor boundary with a unit test, as the pilot's Test/Unit/BoundaryTest.php does: every reference to the bridged module sits under Model/Backend/. The scaffold writes Test/Unit/LightBoundaryTest.php into a pattern-B base module.
  • The golden examples: ExampleGoldenTest and PatternBGoldenTest compare the scaffold's output with docs/magerex-light/examples/. After a scaffold change, regenerate the examples with the commands in docs/magerex-light/examples/README.md.

The docs check

npm run docs:check     # every check; needs the RollDev environment to regenerate the reference pages
npm run docs:static    # the checks without Docker, part of npm run verify
npm run docs:test      # the docs check's own tests

It fails when a code block in this guide doesn't appear in the file its title names, when a generated reference page differs from the doctor's output, when a link or anchor is broken, when a page, a pool, an event, a doctor rule or a gate message has no entry, when a page lacks its title or description or is missing from its folder's meta.json, when a screenshot is missing, too heavy or off its page, and on an em dash. Each failure names the page and the line. After a change to the catalogue or the API, regenerate the two reference pages with the command the check prints.

The developer site

The guide is also a website, built with Fumadocs from these pages. It runs locally for now, and the README.md in the project root says how to start it. Its source is docs/site, and it installs and builds in a copy under var/docs-site, which never reaches the PHP container:

Terminal
npm run docs:site:install  # once: the site's packages, in var/docs-site
npm run docs:site:build    # the static site in var/docs-site/out, for any web server
npm run docs:site:serve    # that static site on http://localhost:3000
npm run docs:site:dev      # or the dev server on http://localhost:3000, with each saved edit
npm run docs:site:check    # build, parse every Mermaid diagram, and check every link of the build
  • docs:site:check fails on a diagram that doesn't parse, and on a link, an image or an anchor of the build that goes nowhere.
  • Every page has a Markdown copy at /md/<page>.md, and the site serves /llms.txt and /llms-full.txt (Build with an AI assistant).
  • Screenshots live in docs/site/public/screenshots, and docs/site/screenshots.json says how to take each one again.

Last updated on

On this page