Testing
DXPR Builder has four kinds of automated checks: a Puppeteer test of
the editor, Bash end-to-end tests for the Drush commands, a Selenium
visual regression suite in the separate dxpr_maven repository, and
linters. This page lists each one, how to run it locally and how CI
runs it.
What exists
| Check | Where it lives | Runs on |
|---|---|---|
| Editor console and layout test | test/test-editor.js |
Pull requests that touch JavaScript, HTML or test/ (.github/workflows/fe-test.yaml) |
| Drush end-to-end tests | scripts/drush-e2e/ |
Pull requests that touch PHP, YAML or Markdown (.github/workflows/review.yaml) |
| Selenium visual regression suite | dxpr_maven repository |
PR comment commands (.github/workflows/e2e-command.yaml, e2e-bs3-command.yml, e2eV2-command.yaml) |
| PHP coding standards (phpcs) | scripts/linters/run-drupal-lint.sh, phpcs.xml.dist |
Pull requests that touch PHP, YAML or Markdown; every push to 3.x |
| PHPStan | scripts/linters/run-drupal-check.sh |
Pull requests that touch PHP, YAML or Markdown; every push to 3.x |
| ESLint, Stylelint, Rust Clippy | scripts/linters/ |
Pull requests, filtered by changed paths |
| Deprecation detectors | .github/workflows/deprecations.yml |
Pull requests that touch js/ or dxpr_builder/build/ |
Docs checks (markdownlint, check_docs.py, Vale) |
.markdownlint-cli2.yaml, docs/lint/, .vale.ini |
Pull requests that touch docs/ (review.yaml) |
The only PHPUnit test in the repository is
modules/dxpr_builder_media/tests/src/FunctionalJavascript/MediaEntityBrowserTest.php
for the legacy media submodule. No GitHub workflow runs it; the
drupal.org GitLab pipeline (.gitlab-ci.yml) uses the standard
DrupalCI templates, whose PHPUnit job is not switched off there.
Editor console test
test/test-editor.js starts a static server on port 3000
(test/start-standalone-server.js) and opens four standalone pages
from test/standalone-editor/ in headless Chrome:
test-bs5-anon.html, test-bs5-cms-block.html,
test-bs5-editor.html and test-bs5-clean-html.html. It fails
when:
- a page throws a JavaScript error;
- the full editor is not ready within 2000 ms, or no off-screen controls are left deferred after load (the performance gate);
- element controls overlap in Power user mode (the baseline is zero overlapping pairs);
- the saved HTML of the full editor page is larger than the reference of 32,094 characters;
- a page-specific check fails, for example the parsing of clean Bootstrap HTML, the breadcrumb, the Panel types, the local video Muted setting or the CMS block preview.
The pages load the built files from dxpr_builder/, so build first.
- Install dependencies:
bash
npm install
- Build the editor bundle. The CI script runs these tasks in this
order (
test/scripts/run-fe-tests.sh):
bash
npx grunt concat
npx grunt exec:gen
npx grunt babel
npx grunt terser
npx grunt sass
npx grunt postcss
- Run the test:
bash
npm run fe-test
Use npm run fe-test:headed to watch the browser, and
npm run fe-test:dev to serve the standalone pages without
running assertions.
In CI, .github/workflows/fe-test.yaml runs the same test through
Docker:
docker compose --profile fe-test run --rm fe-test
Drush end-to-end tests
scripts/drush-e2e/run-e2e-tests.sh installs a fresh Drupal 11 site with
SQLite inside a Composer container, symlinks the module into it,
enables it, creates a Basic page content type with the
dxpr_builder_text formatter, a page template and a user template,
then runs every scripts/drush-e2e/test-*.sh file:
| File | Commands under test |
|---|---|
test-cleartext-key-update.sh |
Update 9026 clears a clear-text product key left under Key module storage, and keeps it when the chosen Key is gone (cleartext-key-update.php) |
test-cms-cache-tags.sh |
Cache invalidation of block and view listings (cms-cache-tags.php) |
test-elements.sh |
drush dxb:element:list |
test-migration-summary.sh |
Singular and plural wording of the migration column summary (migration-summary.php) |
test-migrations.sh |
drush dxb:migrate and content migration regressions (migration-regressions.php) |
test-page-controller.sh |
The page controller builds for its routes (page-controller.php) |
test-page-create.sh |
drush dxb:page:create |
test-page-get-update.sh |
drush dxb:page:get, drush dxb:page:update |
test-page-module.sh |
The Drag and Drop Page module ships every configuration it lists (page-module.php) |
test-profile-buttons.sh |
Text editor buttons of builder profiles (profile-buttons.php) |
test-profile-order.sh |
Which profile applies by weight, and the order of the profile list (profile-order.php) |
test-settings-form.sh |
Saving and validating the product key on General Settings, and the licence sync it triggers (settings-form.php) |
test-setup-ai.sh |
drush dxb:setup-ai |
test-templates.sh |
drush dxb:template:list |
test-user-licenses-page.sh |
The licence card shows once on User Licenses and still shows on People (user-licenses-page.php) |
test-user-settings.sh |
Each editor's own editor settings (user-settings.php) |
test-user-templates.sh |
drush dxb:user-template:list, drush dxb:user-template:create |
Run all of them:
docker compose --profile drush-e2e run --rm e2e-test
Run one file by passing part of its name; the script matches
scripts/drush-e2e/test-*<filter>*.sh:
docker compose --profile drush-e2e run --rm e2e-test page-create
To add a test, create scripts/drush-e2e/test-<name>.sh, call
section "<Title>", and use the helpers from
scripts/drush-e2e/_helpers.sh: assert_success, assert_fail,
assert_eq, assert_has, assert_not_empty, assert_runs and
assert_dry_run. Each helper takes a description and a command
string.
In CI this suite is the "Run Drush E2E tests" job in
.github/workflows/review.yaml. It runs when a pull request changes
.php, .module, .inc, .install, .yml, .md, composer.json
or composer.lock files.
Selenium visual regression suite
The browser tests are Java TestNG suites in the dxpr_maven
repository. They run against a Docker stack defined in
docker-compose.test.yml (Selenium hub, Chrome nodes and a Maven
container) on a site installed from this repository. You do not run
them from a local checkout; you trigger them from a pull request
comment. .github/workflows/command-dispatcher.yml turns the comment
into a workflow run.
| Command | Suite | Workflow |
|---|---|---|
/e2e |
chrome.editor.bs5.parallel.xml plus the anonymous BS5 suite |
e2e-command.yaml |
/e2e-bs3 |
chrome.editor.bs3.parallel.xml |
e2e-bs3-command.yml |
/e2eV2 |
BS5 editor and anonymous suites on the DXPR CMS stack | e2eV2-command.yaml |
/qa-demo-2x-dxpr_theme6x-tests |
QA demo with DXPR Theme 6.x | qa-demo-2x-dxpr_theme6x-tests-command.yaml |
Options, as documented in CONTRIBUTING.md:
groups=row-element-test,icon-element-testruns the named<test name="...">groups from the suite XML.tests=RowColumnLayoutVisualTestruns the named test classes.maven_ref=branch-nameuses adxpr_mavenbranch, which is how a builder change and its test update are reviewed together.
The workflow uploads target/reports/** and the screenshots as a
build artifact and posts the result as a comment on the pull
request, listing failures or tests that only passed on retry. Each
suite job has a 90-minute timeout.
Linters and static analysis
Each linter is a Docker Compose service, so no local toolchain is required beyond Docker.
| Service | Command | What it checks |
|---|---|---|
drupal-lint |
docker compose run --rm drupal-lint |
phpcs with PHPCompatibility (PHP 8.3 and up), Drupal and DrupalPractice standards |
drupal-check-D11 |
docker compose run --rm drupal-check-D11 |
PHPStan level 5 with mglaman/phpstan-drupal inside a fresh drupal/recommended-project |
eslint |
docker compose run --rm eslint |
ESLint on js/ and dxpr_builder/build/, plus a spellcheck of dxpr_builder/extracted_t_functions.js |
stylelint |
docker compose run --rm stylelint |
Stylelint on dxpr_builder/sass/ and sass/ |
rust-lint |
docker compose run --rm rust-lint |
Clippy on the Rust sources in rust/ |
no-jquery, no-underscore, html-in-js |
docker compose run --rm <service> |
Deprecation detectors from .github/workflows/deprecations.yml |
Auto-fix variants exist for phpcs, ESLint and Stylelint
(drupal-lint-auto-fix, eslint-auto-fix, stylelint-auto-fix).
The same checks are available without Docker through npm run
lint:scss, npm run lint:no-jquery, npm run lint:no-underscore
and npm run lint:html-in-js.
npm install also installs a Husky pre-commit hook
(.husky/pre-commit). It runs the matching auto-fix and lint
services on the staged JavaScript, PHP and SCSS files and the Rust
sources, and docs/video-tools/bin/lint-videos.mjs when files under
docs/ are staged.
.github/workflows/review.yaml runs the linters that match the
changed paths on every pull request. .github/workflows/main.yaml
runs drupal-lint, eslint, drupal-check-D11 and rust-lint on
every push to 3.x. Both fail the build when a check fails and
write a summary with the offending files.
What's next?
- Contributing for the pull request process and
the
maven_refworkflow for test updates. - Drush commands for the commands the Bash suite exercises.