Skip to content

Document why NodeJS is needed to run the tests - #347

Open
iarif4u wants to merge 6 commits into
WordPress:masterfrom
iarif4u:docs/why-nodejs
Open

iarif4u wants to merge 6 commits into
WordPress:masterfrom
iarif4u:docs/why-nodejs

Conversation

@iarif4u

@iarif4u iarif4u commented Oct 2, 2026 •

Copy link
Copy Markdown

Fixes #243.

Purpose

Hosts ask why a PHP test suite needs NodeJS. This adds a short "Why NodeJS is needed" section under the NodeJS installation steps in the README.

What it explains

  • prepare.php runs npm install && npm run build. The step the tests need is build:gutenberg. It downloads the pinned Gutenberg artifact from ghcr.io and copies the block editor PHP files, routes, blocks, scripts, styles and theme.json into src/.
  • The tests load WordPress from src/. Those files left version control in changeset 61438, so without the build, WordPress fails to load (example: PHPUnit tests fail: routes.php generated under build/ but tests bootstrap from src/ #292).
  • Hosts must allow outbound connections to ghcr.io. This is new information for firewalled hosts.
  • engine-strict = true in wordpress-develop/.npmrc means that npm install stops on an older Node.js version.
  • The production part of npm run build (copy to build/, minify) is not used by PHPUnit. Core's own PHPUnit workflow uses npm ci and npm run build:dev. Links to Find ways to reduce the need for NodeJS #244 for the follow-up.

Sources (wordpress-develop trunk)

  • Gruntfile.js: the build, build:gutenberg and gutenberg:download tasks, and the comment that references changeset 61438 and ticket 64393
  • tools/gutenberg/utils.js and download.js: version check, auto-download, ghcr.io URLs
  • package.json (gutenberg.sha, engines) and .npmrc (engine-strict)
  • .github/workflows/reusable-phpunit-tests-v3.yml: npm ci and npm run build:dev before PHPUnit
  • wp-tests-config-sample.php: ABSPATH is src/

Contributed at WordCamp Contributor Day.

Explains that the build step downloads the pinned Gutenberg artifact from
ghcr.io and copies the block editor files into src/, which the tests load.
Also notes engine-strict and that the production build is not needed for
PHPUnit.

Fixes WordPress#243.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: iarif4u <iarif4u@git.wordpress.org>
Co-authored-by: dhruvang21 <dhruvang21@git.wordpress.org>
Co-authored-by: mindctrl <mindctrl@git.wordpress.org>
Co-authored-by: ekamran <ekamran@git.wordpress.org>
Co-authored-by: Crixu <crixu@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Comment thread README.md Outdated
Comment on lines +133 to +148
#### Why NodeJS is needed

The PHPUnit tests are PHP, but they do not run on a plain checkout of `wordpress-develop`. Some files that WordPress loads are not in version control. A build step creates them.

`prepare.php` runs `npm install && npm run build` in the checkout. For the tests, the important part is the Gutenberg step (`build:gutenberg` in the [Gruntfile](https://github.com/WordPress/wordpress-develop/blob/trunk/Gruntfile.js)):

1. It downloads the built Gutenberg artifact for the version pinned in `package.json` (`gutenberg.sha`). The download comes from `ghcr.io`, so the server must be able to connect to it.
2. It copies the block editor PHP files, routes, blocks, scripts, styles and `theme.json` into `src/`.

The tests load WordPress from `src/` (`ABSPATH` in `wp-tests-config.php`). These files were removed from version control in [changeset 61438](https://core.trac.wordpress.org/changeset/61438). Without the build, the tests fail when they load WordPress, for example on a missing `src/wp-includes/build/routes.php` ([#292](https://github.com/WordPress/phpunit-test-runner/issues/292)).

Also:

- Use the Node.js and npm versions in the `engines` field of `wordpress-develop/package.json`. Its `.npmrc` sets `engine-strict = true`, so `npm install` stops on older versions.
- `npm run build` also makes the production build: it copies files to `build/` and minifies JavaScript and CSS. The PHPUnit tests do not use these files. WordPress Core runs its own PHPUnit workflow after `npm ci` and `npm run build:dev`. [#244](https://github.com/WordPress/phpunit-test-runner/issues/244) tracks ways to make this step smaller.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why Node.js is needed

The PHPUnit test suite itself is written in PHP, but Node.js is required to prepare the WordPress source code before the tests can run.

The test runner uses prepare.php to set up a WordPress checkout and prepare it for PHPUnit. As part of this process, it runs the WordPress build tasks, including the Gutenberg build step. This is necessary because some files used by WordPress Core are generated or assembled as part of the build process rather than being available directly in the wordpress-develop checkout.

The Gutenberg build step:

  1. Uses the Gutenberg version pinned by WordPress Core.
  2. Downloads the corresponding pre-built Gutenberg artifact from GitHub Container Registry (ghcr.io).
  3. Copies the required Gutenberg files into the WordPress src/ directory.
  4. Makes those files available to the WordPress installation that PHPUnit loads during the test run.

The PHPUnit test suite loads WordPress from the src/ directory. Therefore, these build steps must complete successfully before the tests can run. If the Gutenberg files have not been prepared, the test suite can fail while loading WordPress because required files are missing.

This is why Node.js and npm are requirements for the test runner even though the tests themselves are written in PHP.

The Node.js and npm versions must also be compatible with the versions specified in the engines field of wordpress-develop/package.json. The WordPress development repository enables npm's engine-strict setting, so using an unsupported Node.js or npm version can cause npm install to fail.

It is also worth noting that npm run build performs more work than is required by PHPUnit. The complete WordPress build also creates the production build/ directory and performs tasks such as JavaScript and CSS minification. The PHPUnit tests primarily need the files prepared in src/. The additional build work is currently part of the preparation process.

Make it a standalone ### section, open with why a PHP suite needs Node.js,
list the Gutenberg steps in order, and add a summary sentence (from the
review). Keep the ghcr.io network requirement, the changeset and issue
references, and the build:dev note. Mention that devEngines also enforces
the npm version.
@iarif4u

iarif4u commented Oct 2, 2026

Copy link
Copy Markdown
Author

Thanks @dhruvang21, your version reads better. I reworked the section in 3632464 and used your structure:

  • A standalone ### Why Node.js is needed section, with "Node.js" spelled correctly.
  • It opens with why a PHP suite needs Node.js.
  • The Gutenberg steps are numbered in order, starting with the pinned version.
  • It ends with your summary sentence.

I kept a few things that your text left out, because hosts need them:

I also added that devEngines enforces the npm version, in addition to engine-strict. Could you take another look?

@dhruvang21

Copy link
Copy Markdown
Contributor

@iarif4u The technical details here are useful, but I think the section could be improved for clarity, flow, and grammatical accuracy. Rather than making several small edits, could we replace the current section with the version suggested in the change? It keeps the technical details while making the explanation easier to follow.

Comment thread README.md Outdated
Comment thread README.md Outdated
Base the section on the wording suggested in review, and use real
headings for Versions and Extra work (review suggestions). Keep the
facts hosts need: the build commands, changeset 61438, gutenberg.sha,
the ghcr.io connection, the routes.php example, devEngines with the
EBADDEVENGINES error, and Core's build:dev workflow.
@iarif4u

iarif4u commented Oct 6, 2026

Copy link
Copy Markdown
Author

@dhruvang21 Done in 148566c. The section now uses your version, with your sentences. I only added back the facts that your version left out, each as a short clause in your text:

I also applied @mindctrl's two heading suggestions. Could you take another look?

Comment thread README.md Outdated
The Gutenberg build step:

1. Uses the Gutenberg version pinned by WordPress Core (`gutenberg.sha` in `package.json`).
2. Downloads the corresponding pre-built Gutenberg artifact from GitHub Container Registry (`ghcr.io`), so the server must be able to connect to `ghcr.io`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this domain redirects to pkg-containers.githubusercontent.com when downloading the package.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, confirmed. With the current pinned Gutenberg build, GET https://ghcr.io/v2/WordPress/gutenberg/gutenberg-wp-develop-build/blobs/<digest> returns 307 with Location: https://pkg-containers.githubusercontent.com/..., and download.js uses fetch(), which follows it. Step 2 now names both domains (4814a42).

Note: 4814a42 also deleted other files by mistake, because my local copy was damaged. 3a9c1e6 restores them, and the PR is back to README.md only (+25).

GHCR answers the blob request with a 307 to pkg-containers.githubusercontent.com,
so a host with an outbound allowlist needs both domains.
4814a42 recorded the deletion of 22 files that were missing from my local
working copy. Restore them unchanged. The only change left from that
commit is the ghcr.io redirect sentence in README.md.
Comment thread README.md Outdated
routes.php is in version control again since r62118, so cite WordPress#292 as
something that happened instead of a current example.

@ekamran ekamran left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, looks good.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Document why NodeJS is needed.

4 participants