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:
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) inpackages/. They are not Light core, and each must land without a core edit. - Inside the guard: the
-hyvamodules, 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-hyvamodule) may land between two bases when it touches nothing under any of those modules'etc/adminhtml/,view/adminhtml/,Api/orController/Adminhtml/, norLight/Test/Unit/Api/_files/, and keeps theLight/Test/Unit/Apitests green. It is followed by its own commitchore(guard): move base after storefront <topic>, which updatesbase.sha.
The white-label guard
Light core shows no brand of its own. Two checks prove it:
npm run guard:white-labelrunstests/guard/white-label.sh, which greps Light core's templates, layout,acl.xml,email_templates.xml,system.xmlandi18nfor MageRex branding.tests/playwright/white-label.spec.tsdisables 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.allowlists 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
FACTSin the script. tests/guard/country-neutral.test.shproves the guard on a throwaway tree, and runs innpm 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:scanloads every class of the pattern-B example'ssrc/with an autoloader that refusesMrx\classes, the way the compiler would on a shop without Light. It printsOK: <n> classes, or each file that needs Light. Run it on your own base module withdocker exec -w /var/www/html magerexlight-php-fpm-1 php tests/compat/scan-without-light.php <path>.- The CI job
compat:pattern-brunstests/compat/pattern-b.shin a throwaway container: without Light,setup:di:compilepasses and the compat module stays unregistered; with Light, the compat module is enabled, compiles and passes the doctor.PLATFORM_VERSIONpicks the Mage-OS release, and the script ends withLight 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:compilein the development container: that would replace its generated code, which the environment rules forbid.pattern-b.shneeds its own container,COMPOSER_AUTHand a longcomposer 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=jsonprivate_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.testand writes each run to its own folder (MRX_PW_RUN_ID,MRX_PW_OUTPUT_DIR). - The
setupproject,tests/playwright/global.setup.ts, signs in once aslighttest, switches to simple mode and stores the session intests/playwright/.auth/lighttest.json. Another user comes fromMRX_ADMIN_USERandMRX_ADMIN_PASSWORD:
export const ADMIN_USER = process.env.MRX_ADMIN_USER ?? 'lighttest';- Import
testandexpectfrom./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,waitForTableandremoveOrders. - 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 inbeforeAllwithbin/magento config:set dev/mrx_light/kit_fixtures 1, and off again inafterAll. - A spec for a module skips itself when the module is disabled, and
tests/playwright/users-and-permissions.spec.tsmust 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\ModuleGateto test a class with and without its module, asapp/code/Mrx/Home/Test/Unit/Model/Todo/TodoListGateTest.phpdoes, andMagento\Framework\AuthorizationInterfaceto test with and without an ACL resource, asapp/code/Mrx/Apps/Test/Unit/Model/AdvancedView/BackToAppsTest.phpdoes. - A bridge keeps its vendor boundary with a unit test, as the pilot's
Test/Unit/BoundaryTest.phpdoes: every reference to the bridged module sits underModel/Backend/. The scaffold writesTest/Unit/LightBoundaryTest.phpinto a pattern-B base module. - The golden examples:
ExampleGoldenTestandPatternBGoldenTestcompare the scaffold's output withdocs/magerex-light/examples/. After a scaffold change, regenerate the examples with the commands indocs/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 testsIt 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:
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 builddocs:site:checkfails 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.txtand/llms-full.txt(Build with an AI assistant). - Screenshots live in
docs/site/public/screenshots, anddocs/site/screenshots.jsonsays how to take each one again.
Last updated on