Gutenberg’s JavaScript Unit and Integration Tests Now Use Vitest ![rw-book-cover](https://s.w.org/images/home/wordpress-default-ogimage.png) 🔗 **Source:** [Gutenberg’s JavaScript Unit and Integration Tests Now Use Vitest](https://make.wordpress.org/core/2026/09/23/gutenbergs-javascript-unit-and-integration-tests-now-use-vitest/) > [!note]+ Document Notes > tags: [vitest, jest-migration, gutenberg-testing, wordpress-scripts, browser-mode-testing, block-plugin-tooling] > author: Marco Ciampini > source: Make WordPress Core > reference: https://make.wordpress.org/core/2026/09/23/gutenbergs-javascript-unit-and-integration-tests-now-use-vitest/ > date created: 2026-09-23 19:03 > > > [!info] Generated analysis — not the author's words. Sections below are machine-written > > from the captured source. Only text inside `> [!quote]` blocks is verbatim from the author. > > Do not quote or attribute any other line to the named author. > > # 🏷️ Title: Gutenberg's JavaScript unit and integration tests now use Vitest > <!-- deep-read:sections start --> ## 🧭 Table of contents - [📝 Summary](#-summary) - [📖 Main content](#-main-content) - [🗒️ Notes](#️-notes) - [📚 References](#-references) - [🗣️ Paraphrase](#️-paraphrase) - [📰 Newsletter](#-newsletter) - [✅ Action items](#-action-items) - [🧪 Hypotheses](#-hypotheses) - [📊 Methodology](#-methodology) - [❓ Questions](#-questions) - [🔮 Future research](#-future-research) - [💡 Implications](#-implications) - [🧠 Learning styles assessment](#-learning-styles-assessment) - [📊 Accessibility assessment](#-accessibility-assessment) - [🌍 DEIB assessment](#-deib-assessment) - [✅ Logical validity](#-logical-validity) - [🛡️ DARVO analysis](#️-darvo-analysis) - [🎯 Conclusion](#-conclusion) - [🔄 Refactor appendix](#-refactor-appendix--gutenbergs-javascript-unit-and-integration-tests-now-use-vitest) ## 📝 Summary - **What happened.** Marco Ciampini published an 893-word announcement on Make WordPress Core on 2026-09-23: Gutenberg has finished moving its JavaScript unit and integration tests from Jest to Vitest. The Slack permalink for the "initial announcement in #core-editor" decodes to 2026-08-28, 26 days earlier. Six contributors are credited with the work; the decisions live in Gutenberg issue #80855. - **The claim.** Two benefits justify the switch: native ECMAScript module support, which removes the Babel transform allowlist in `test/unit/jest.config.js`, and Browser Mode, which runs component tests in a real browser instead of jsdom. A softer third argument is maintainability: Jest's maintainers acknowledged a slow period (the linked Jest 30 post), and Vitest shares the Vite toolchain Storybook already uses in the repo. - **What changes for consumers.** Starting with `@wordpress/scripts` 36.0.0, `wp-scripts test-unit-js` runs the project's own installed Vitest. The package no longer ships Jest, its environment, the WordPress Jest configuration, or the transformer. `@wordpress/eslint-plugin` 27.0.0 moves its default unit-test lint rules to Vitest. `@wordpress/jest-preset-default` and `@wordpress/jest-console` are deprecated with published versions left in place; no `@wordpress/vitest-*` packages replace them. - **Why it matters.** Every block plugin that runs `wp-scripts test-unit-js` and bumps past 36.0.0 has work to do either way. Keeping Jest means installing what the wrapper used to supply and renaming the command to `test-unit-jest`, which is maintenance-only with no removal date. Moving to Vitest means owning a config, choosing an environment, and rewriting whatever mocks and CLI flags differ. - **Key stakeholders.** Gutenberg contributors; block plugin authors on `@wordpress/scripts`; Block Editor Handbook maintainers; the Jest and Vitest projects. - **Risks and tradeoffs.** The benchmark claim is scoped to "that measured configuration," but the numbers are in issue #80855, not the post. Two structural blocks (the filename-to-environment list after ¶9 and the two-options list after ¶14) did not survive text capture. Dropping the preset packages pushes configuration onto every consuming project, and ¶20 concedes console-failure behavior now needs explicit setup. - **Bottom line.** For Gutenberg, a completed change with a clear rationale. For plugin authors, a breaking `@wordpress/scripts` release dressed as an announcement: read the `test-unit-js` docs before upgrading. ## 📖 Main content **The rationale, in order of weight.** First, ESM. As dependencies moved to ECMAScript modules, Gutenberg's CommonJS-based Jest setup needed an explicit list of packages for Babel to transform (linked to lines 25 to 35 of `test/unit/jest.config.js` at commit `d0fb944`). Bumping a dependency could mean touching test config. Vitest reads ESM natively, so the list goes away. Second, environment fidelity. Vitest runs in Node by default and only supplies a DOM or a browser when a test asks, which the post frames as not "supplying simulated browser behavior to tests that don't need it." Browser Mode then lets component tests check computed styles, element sizes, scrolling, focus, and keyboard interaction against a real rendering engine. Third, maintainability: Jest's release cadence slowed (linked to the Jest 30 post of 2025-06-04; Jest 29 shipped in August 2022, a 34-month gap the article doesn't state), Vitest's Jest-compatible API allowed incremental migration, and Storybook already runs on Vite in the repo. **The performance claim, exactly as stated.** Paragraph 7 says the migration adds real-browser coverage while keeping execution parallel. Browser Mode tests run alongside the Node and jsdom suites, and in Gutenberg's benchmarks the browser group finished before the longest Node/jsdom group, so browser testing did not determine completion time in that configuration. Two things to keep straight. The post publishes no durations, worker counts, or CI hardware; those live in issue #80855. And the claim is about the critical path, not total compute: a parallel browser shard can leave wall-clock unchanged while raising CPU minutes. The post also says workers and shared setup were optimized during the migration, so the framework swap and the tuning are confounded. **What changes for Gutenberg contributors.** Imports become explicit: `describe`, `test`, `expect`, and `vi` come from `vitest`. Some mocking APIs, assertions, and CLI options differ, so existing examples may need more than new imports. Test filenames select the environment; the post introduces a list here (¶9 ends with a colon) that the capture did not preserve, so the exact conventions must be read from the Testing Overview. Browser Mode requires a browser installation and uses different React rendering and interaction APIs from jsdom tests (likely Vitest's browser-specific React helpers rather than Testing Library's; that's inference, not something the post says). `npm test` and `npm run test:unit` are unchanged. **What changes for consumers of the published packages.** With `@wordpress/scripts` 36.0.0, `wp-scripts test-unit-js` uses whatever Vitest the project has installed, and the release carries breaking changes to configuration, dependencies, APIs, and CLI options. New projects start from the `test-unit-js` documentation, which links to Node, jsdom, and Browser Mode examples; projects own their config. Existing projects get "two options," and the list after ¶14 is another capture casualty. Reconstructed from ¶15 to ¶17: migrate to Vitest, or keep Jest by switching to `test-unit-jest` and installing what the wrapper no longer bundles. The lint side moves too: `@wordpress/eslint-plugin` 27.0.0's `test-unit` config and the default `wp-scripts lint-js` unit-test rules target Vitest, so Jest holdouts need explicit Jest rules. **The fate of the Jest packages.** `test-unit-jest` stays as a maintenance-only command with no scheduled removal; new features go to Vitest. `@wordpress/jest-preset-default` and `@wordpress/jest-console` are deprecated with no further updates, but published versions remain installable. The stated reason for not publishing Vitest equivalents is that Vitest's built-in features cover most of what motivated the separate packages. Paragraph 20 tempers that: Vitest's spies can assert expected console calls, but making a test fail on unexpected console output (the core job of `@wordpress/jest-console`) needs additional setup. **Uncertainties in this source.** The two uncaptured lists are the largest gap; the benchmark figures are external. The post doesn't say which Vitest major 36.0.0 expects, which browser provider Gutenberg uses, or whether the consumer upgrade guidance was tested on a plugin outside the monorepo. ## 🗒️ Notes #### Opening: what was announced - Gutenberg's Jest-to-Vitest migration for JS unit and integration tests is complete (¶0). The #core-editor announcement is dated 2026-08-28 by its Slack permalink. - Scope: both Gutenberg's setup and the published tooling change (¶1); two headline benefits, module support and real-browser testing (¶2). #### Why Vitest? - ESM pressure: the CommonJS Jest setup needed a hand-maintained Babel transform list, linked to `test/unit/jest.config.js` lines 25 to 35 (¶3). > [!quote] [¶4] > Tests run in Node by default, with DOM or browser environments selected explicitly when needed. - Browser Mode covers computed styles, element sizes, scrolling, focus, and keyboard interactions; jsdom stays available for DOM tests that don't need rendering (¶5). - Maintainability (¶6): Jest's maintainers acknowledged slower progress (linked Jest 30 post); Vitest shares Vite tooling with Storybook. > [!quote] [¶6] > Its Jest-compatible APIs also made an incremental migration possible. - Performance (¶7): parallel execution preserved; browser tests finished before the longest Node/jsdom group; workers and shared setup also optimized. Figures are in issue #80855. #### What changes for Gutenberg contributors? - Explicit imports of `describe`, `test`, `expect`, `vi` from `vitest` (¶8). > [!quote] [¶8] > Some mocking APIs, assertions, and command-line options differ from Jest, so existing examples may need more than a change of imports. - "Test filenames select the environment:" (¶9). The list that followed was not captured. - Browser Mode needs a browser installed and different React rendering APIs (¶10). `npm test` and `npm run test:unit` remain (¶11). #### What changes for consumers of WordPress test tooling? - `@wordpress/scripts` 36.0.0: `wp-scripts test-unit-js` uses the project's installed Vitest; breaking changes to configuration, dependencies, APIs, CLI options (¶12). - New setups start at the `test-unit-js` docs with Node, jsdom, and Browser Mode examples; projects own their configuration (¶13). - "Existing projects have two options:" (¶14). List not captured. From ¶15 to ¶17: migrate to Vitest, or keep Jest via `test-unit-jest`. > [!quote] [¶15] > The package no longer supplies Jest, its environment, or the WordPress Jest configuration and transformer. - Lint: `@wordpress/eslint-plugin` 27.0.0's `test-unit` config and default `wp-scripts lint-js` unit-test rules switch to Vitest (¶16). > [!quote] [¶17] > test-unit-jest remains a maintenance-only command with no scheduled removal. New testing features target Vitest. #### What happens to the WordPress Jest packages? - `@wordpress/jest-preset-default` and `@wordpress/jest-console` deprecated; published versions remain (¶18). No Vitest counterparts because built-ins cover most of the motivation (¶19). > [!quote] [¶20] > Vitest’s spies can check expected console calls, but automatically failing tests on unexpected console output requires additional setup. #### Questions and feedback - Feedback: post comments, #core-editor, or issue #80855 (¶21). - Props: @manzoorwanijk, @aduth, @0mirka00, @jonsurrell, @tyxla, @mamaduka for the work; @aduth, @manzoorwanijk, @simison, @tyxla for reviewing the post (¶22). ## 📚 References The article contains 22 outbound anchors, grouped by what they support. **Decision record and discussion** - [Gutenberg issue #80855, migration tracking](https://github.com/WordPress/gutenberg/issues/80855). Linked twice: as "migration benchmarks" (¶7) and as the tracking issue (¶21). The only source for the timing figures. - [#core-editor announcement, 2026-08-28](https://wordpress.slack.com/archives/C02QB2JS7/p1787919476655399). Supports ¶0. Requires a Making WordPress Slack account. - [#core-editor channel](https://wordpress.slack.com/archives/C02QB2JS7). **Evidence for the rationale** - [Gutenberg `test/unit/jest.config.js` lines 25 to 35 at commit d0fb944](https://github.com/WordPress/gutenberg/blob/d0fb944025b1a4b88e383e2aa890c1d163c2e570/test/unit/jest.config.js#L25-L35). The Babel transform allowlist of ¶3, pinned to a commit so it stays readable after deletion. - [Vitest](https://vitest.dev/). The framework (¶0). - [Vitest Browser Mode: why](https://vitest.dev/guide/browser/why). Supports ¶5. - [Jest 30 blog post, 2025-06-04](https://jestjs.io/blog/2025/06/04/jest-30). Supports ¶6's "acknowledged a period of slower progress and fewer releases." **Documentation the post points consumers to** - [Testing Overview, Block Editor Handbook](https://developer.wordpress.org/block-editor/contributors/code/testing-overview/). Setup, environment selection, writing and running tests (¶10). - [`test-unit-js`, `@wordpress/scripts` reference](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/#test-unit-js). Installation, configuration, and the Node, jsdom, and Browser Mode examples (¶13). The "documented upgrade steps" for keeping Jest (¶15, ¶16) have no separate anchor; this is the nearest link given. **Deprecated packages** - [`@wordpress/jest-preset-default` on npm](https://www.npmjs.com/package/@wordpress/jest-preset-default) and [`@wordpress/jest-console` on npm](https://www.npmjs.com/package/@wordpress/jest-console). Linked in ¶0, deprecated per ¶18. **Contributor profiles (¶22)** - [@manzoorwanijk](https://profiles.wordpress.org/manzoorwanijk/), [@aduth](https://profiles.wordpress.org/aduth/), [@0mirka00](https://profiles.wordpress.org/0mirka00/), [@jonsurrell](https://profiles.wordpress.org/jonsurrell/), [@tyxla](https://profiles.wordpress.org/tyxla/), [@mamaduka](https://profiles.wordpress.org/mamaduka/), [@simison](https://profiles.wordpress.org/simison/). ## 🗣️ Paraphrase - Gutenberg's JavaScript tests now run on Vitest instead of Jest, and the switch reaches the published `@wordpress/scripts` tooling, not only the monorepo. Test shapes stay familiar, but each test says more explicitly what environment it needs. - Two technical facts and one organizational one drove the move. Dependencies went ESM and Jest's CommonJS setup needed a hand-kept transform list; Vitest reads ESM natively. Focus, scrolling, and computed styles test better in a real browser than through jsdom mocks, and Browser Mode provides that. Jest's release pace slowed while Vite was already in the repo through Storybook. - Plugin authors on `@wordpress/scripts` 36.0.0 either adopt Vitest with their own config or keep Jest by installing it themselves and switching to `test-unit-jest`, which is frozen but staying. Lint defaults move to Vitest as well. - The two WordPress Jest helper packages are deprecated with no Vitest counterparts; Vitest's built-ins cover most of the ground, and the rest is manual configuration. ## 📰 Newsletter **Gutenberg swapped test runners, and your plugin's `npm test` is about to notice.** Marco Ciampini's Make/Core post confirms the JavaScript suite now runs on Vitest. The reasons: native ESM (goodbye to the Babel transform allowlist), a real browser for component tests through Browser Mode, and a toolchain Storybook was already using. Browser tests slot in parallel and didn't stretch the run. Here's the part to read twice. `@wordpress/scripts` 36.0.0 makes `wp-scripts test-unit-js` a Vitest command that uses *your* installed Vitest, and stops bundling Jest, its environment, and the WordPress preset. `@wordpress/eslint-plugin` 27.0.0 moves the default unit-test lint rules to Vitest too. Prefer Jest? `test-unit-jest` is frozen but staying, and `@wordpress/jest-preset-default` plus `@wordpress/jest-console` remain on npm as deprecated packages you now install yourself. Either path is real work; neither is a one-line rename. The post sends you elsewhere for the filename conventions ([Testing Overview](https://developer.wordpress.org/block-editor/contributors/code/testing-overview/)) and the benchmark numbers ([issue #80855](https://github.com/WordPress/gutenberg/issues/80855)). Start at the [`test-unit-js` docs](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/#test-unit-js), and read the [post](https://make.wordpress.org/core/2026/09/23/gutenbergs-javascript-unit-and-integration-tests-now-use-vitest/) before your next `npm update`. ## ✅ Action items #### DevRel - Developer advocacy: record a 10-minute screencast migrating one real block plugin from Jest to Vitest, showing the full diff (imports, config, package.json, lint) and before/after `npm test` durations. - Education: run one office-hours session, "Your `wp-scripts test-unit-js` changed," within two weeks of 36.0.0 reaching `@wordpress/create-block` scaffolds, built around a one-page migrate-versus-keep decision table. - Developer experience: file a docs issue asking that the `test-unit-js` reference gain a "Keeping Jest" subsection with the exact install line (`jest`, `jest-environment-jsdom`, `@wordpress/jest-preset-default`, `@wordpress/jest-console`) and the ESLint override, since the post says the steps exist but doesn't link them. - Developer marketing: don't repeat "browser tests didn't slow the suite" as a general Vitest benefit. It's a Gutenberg-specific critical-path result from #80855. Cite the mechanism (parallel shards) and link the issue. - Community management: pin the post and the `test-unit-js` docs in #core-js and #core-editor for 30 days; collect breakage reports into one FAQ. - Internal/external/cross-project: ask the Gutenberg team which Vitest major 36.0.0 was tested against and whether `@wordpress/create-block` now emits a `vitest.config.js`; publish the answer. #### OSPO - Policy and governance: record the retirement pattern used here (deprecate packages, freeze the command, leave published versions) as the precedent for retiring WordPress dev tooling. - License compliance: Vitest and its browser providers are MIT; pin and scan whichever provider enters CI. - Security management: Browser Mode downloads a browser binary in CI. Pin the version and verify the source. - Software inventory: add `vitest` and the provider to the SBOM; remove `jest`, `babel-jest`, and the deprecated presets once gone. - Developer support: warn teams on `@wordpress/scripts` about the 36.0.0 break before the dependency bot opens the PR. - Community engagement: Browser Mode stability for React component testing is where upstream funding would pay back. - Strategic alignment: track test-suite wall-clock per repo before and after migration. #### Community - Maintainers: schedule the `@wordpress/scripts` bump as a deliberate release, not a routine dependency update. - Contributors: converting one plugin's Jest mocks to `vi` equivalents is a bounded, reviewable "first issue." - Sponsors: if funding plugin test migration, require the diff and runtime numbers as the deliverable. - Ecosystem: coordinate with boilerplate maintainers so generated `package.json` files match 36.0.0. #### WordPress - Core: no PHP-side change. When Gutenberg packages next sync into core, check any core `jest.config.js` that depends on `@wordpress/jest-preset-default` and decide whether core's JS tests follow the migration. - Core Performance: none; the runtime claim is about the test suite, not the editor. - Core AI: none from this source. - **Core Program Team:** put the `@wordpress/scripts` 36.0.0 and `@wordpress/eslint-plugin` 27.0.0 breaks in the next release's dev notes so plugin authors see them alongside the core release, not only on Make/Core. - Mobile: confirm whether the React Native test setup used the shared Jest preset; the post is silent on native tests. - Playground: none. - Community: none from this source. - Training: one Learn WordPress lesson, "Testing a block plugin with Vitest," would replace Jest-based material now pointing at deprecated packages. - Marketing: none. - Support: watch forum threads for `wp-scripts test-unit-js` errors after 36.0.0; route to the `test-unit-js` docs and DevRel's FAQ. - Design: none. - Documentation: three gaps. (1) The Testing Overview must carry the filename-to-environment table the post relies on. (2) The `test-unit-js` reference needs the "two options" as commands, not prose. (3) Every DevHub page or example that imports `@wordpress/jest-console` or references `@wordpress/jest-preset-default` needs a deprecation banner pointing to the Vitest equivalent or the manual console setup of ¶20. - Photos: none. - TV: none. - Polyglots: ¶3 expands ESM inline; carry the expansion in translated dev notes. - Accessibility: Browser Mode makes focus and keyboard tests real rather than mocked (¶5). Propose that Gutenberg's focus-management and keyboard-navigation component tests move to Browser Mode first, and count how many jsdom-passing tests fail in a real browser. - Meta: none. - CLI: `wp scaffold plugin` and `wp scaffold block` generate PHPUnit scaffolding, not `wp-scripts` tests, so direct impact is nil. Update WP-CLI docs that recommend `@wordpress/scripts` for JS tests to reference 36.0.0, and add a smoke test that a freshly scaffolded block plugin's `npm test` runs green on 36.0.0. - Hosting: none. - Tide: flag the deprecated `@wordpress/jest-*` packages if any rule inspects test config. - Openverse: none. - Themes: block themes rarely ship JS unit tests; where they do, the same break applies. - Plugins: review criteria don't change. For plugin authors, the checklist is: read the `test-unit-js` docs; pick migrate or keep. Migrate: `npm i -D vitest` plus `jsdom` or a browser provider as needed, write `vitest.config.js`, change imports to `from 'vitest'`, rewrite differing mocks and CLI flags, configure console-failure behavior if you relied on `@wordpress/jest-console`, confirm `wp-scripts lint-js` passes under 27.0.0 defaults. Keep: rename to `test-unit-jest`, install `jest`, its environment, `@wordpress/jest-preset-default`, `@wordpress/jest-console`, and add explicit Jest ESLint rules. #### The WPOCC - Programs: none directly. If The WP Open Community Collective funds maintainer stipends, plugin test-suite migration is bounded, verifiable work a stipend could cover. - Projects: a one-day documentation sprint on the three Documentation gaps above has a measurable output. - Funding experiments: none from this source. ### FAIR - Technical independence: the tooling is npm-distributed; nothing to do. - Policies and covenants: the soft-sunset pattern (deprecate packages, freeze the command, keep published versions) is a usable model for retiring FAIR-adjacent tooling. - Productized governance artifacts: none from this source. ## 🧪 Hypotheses 1. A majority of block plugin repositories that run `wp-scripts test-unit-js` and bump `@wordpress/scripts` from 35.x to 36.0.0 without other changes see `npm test` fail on first run, because Jest is no longer bundled and no Vitest config exists. 2. In a plugin repo with under 50 test files, converting from Jest to Vitest touches more than imports in at least 20% of files, concentrated in module mocking (`jest.mock` hoisting and `requireActual`), fake timers, and snapshot serializers. 3. A parallel Browser Mode shard leaves CI wall-clock within 5% of baseline whenever the longest jsdom shard exceeds the browser shard, matching Gutenberg's #80855 result, and fails to hold when the browser shard is longest. 4. A measurable share of Gutenberg's focus- and keyboard-related component tests that pass under jsdom produce different results in Browser Mode, because jsdom computes neither layout nor real focus order. 5. Without a `@wordpress/vitest-preset-default`, `vitest.config.js` files across the 100 most-downloaded block plugins with JS tests diverge into at least five distinct shapes within six months of 36.0.0. ## 📊 Methodology - **H1.** Sample 100 public repositories whose `package.json` contains `wp-scripts test-unit-js` and an `@wordpress/scripts` 35.x dependency. Bump each to 36.0.0, run `npm ci && npm test` in a clean container, record pass/fail and the first error line. Report the failure rate with a 95% confidence interval. - **H2.** Take 10 of those repos with 10 to 50 test files and complete the migration by hand. Per file, record whether changes beyond the import line were needed and classify them (mocking, timers, snapshots, assertions, CLI). - **H3.** In three plugin repos, add a Browser Mode shard of 10 to 30 component tests. Run 10 CI runs before and after; compare p50 and p95 wall-clock and CPU minutes, recording the longest shard. - **H4.** Pull Gutenberg's component tests that assert on focus or keyboard behavior. Run each under jsdom and Browser Mode on the same commit. Classify divergences as jsdom false-pass, browser flake, or real bug. Check #80855 first; part of this data may exist. - **H5.** At release plus 180 days, collect `vitest.config.*` from the top 100 block plugins with JS tests; cluster by environment, setup files, and coverage settings. - **Controls.** Pin Node and npm; fresh containers; pre-register failure and divergence definitions. ## ❓ Questions - Which Vitest major does `@wordpress/scripts` 36.0.0 expect, and is it a peer dependency or only documented? - What are the actual filename suffixes that select Node, jsdom, and Browser Mode? The post defers to a list this capture lost. - Which browser provider does Gutenberg's Browser Mode use, and does `@wordpress/scripts` ship a default? - How much of the runtime result in #80855 came from the framework swap versus the worker and shared-setup tuning done at the same time? - Does `@wordpress/create-block` already emit a Vitest config, or will new scaffolds fail `npm test` until it does? - What does the replacement for `@wordpress/jest-console`'s fail-on-unexpected-console behavior look like in `vitest.config.js`: a snippet or a package? - Were the "documented upgrade steps" for keeping Jest tested on a plugin outside the monorepo before publication? ## 🔮 Future research - **jsdom false-pass rate.** No published figure exists for how often a React component test passes under jsdom and fails in a real browser. Gutenberg's suite, with both environments on one commit, is the best dataset for producing one. - **Config divergence after preset removal.** Declining to publish Vitest presets is a natural experiment in whether shared presets reduce drift or only reduce onboarding time. - **Soft-sunset outcomes.** Track how long `test-unit-jest` persists and how many projects stay on it, as evidence for or against "maintenance-only, no scheduled removal" as a retirement pattern. ## 💡 Implications - **Practice.** A build wrapper's bundled defaults are a dependency you don't see until they're removed. List what `wp-scripts` supplies on your behalf and decide, per item, whether you'd rather own it. - **Policy.** WordPress now has a worked example of retiring published dev tooling: deprecate the packages, freeze the command, point new features elsewhere. Writing that down would make the next retirement predictable. - **Security.** Browser Mode brings a browser binary download into unit-test CI. The pinning and provenance checks already applied to Playwright in e2e suites now apply here. - **Education.** Any tutorial teaching block-plugin testing with `@wordpress/jest-preset-default` now teaches a deprecated path. Learn WordPress and DevHub gain at least one rewrite. - **Funding models.** Migration work is bounded and verifiable, which fits microgrants that require a diff and a runtime number as deliverables. ## 🧠 Learning styles assessment - **Reading level estimate.** Flesch-Kincaid Grade Level on the captured paragraphs computes to about 13.3 (686 alphabetic tokens, 47 sentences, syllable heuristic), Flesch Reading Ease near 26. College-level by the formula, driven by package names rather than sentence length (14.6 words per sentence). For contributors and plugin authors it reads as plain. #### 👀 Visual learners - Present: none in the captured text. The live page likely has a filename-to-environment table after ¶9; it didn't survive capture. - Improve: a one-row-per-environment table (suffix, runtime, when to use) and a before/after pipeline diagram (Jest plus Babel transforms versus Vitest with Node, jsdom, and browser shards). #### 🔊 Aural learners - Present: none. Make/Core posts have no audio. - Improve: a 3-minute read-aloud in a WordPress dev-news podcast segment, narrating the two-path decision for plugin authors. #### 🗣️ Verbal learners - Present: "ECMAScript modules, or ESM" (¶3) expands the acronym; jsdom and Browser Mode are explained by what they do (¶5). - Improve: "transformer" (¶15) and "environment" (¶4, ¶15) mean specific things in Jest configuration and go undefined. One clause each. #### 🧩 Kinesthetic learners - Present: links to the `test-unit-js` docs with Node, jsdom, and Browser Mode examples (¶13). - Improve: no inline commands. One fenced block with the migrate and keep-Jest paths as shell lines. #### 🧠 Logical learners - Present: causal, ordered rationale (ESM adoption causes transform-list churn; native ESM removes it); the benchmark claim is scoped to its configuration (¶7). - Improve: two figures in the post (longest jsdom shard, browser shard) would let a reader verify the critical-path argument without leaving the page. #### 🧑‍🤝‍🧑 Social learners - Present: three feedback channels and 7 contributors credited by handle (¶21 to ¶22). - Improve: a pointer to where plugin authors, as distinct from contributors, should ask; #core-editor is a contributor channel. #### 🧘‍♀️ Solitary learners - Present: self-contained, 4-minute read, docs links for follow-up. - Improve: a self-check ("Does your `package.json` contain `test-unit-js`? Read the next section.") would route each reader to the paragraphs that apply. #### 🌿 Naturalistic learners - Present: nothing explicit. - Improve: the maintainability argument (¶6) is about a slowing upstream. Framing it as a lifecycle, with the 34-month Jest 29 to 30 gap as the data point, would land here. ## 📊 Accessibility assessment #### Screen reader semantics - Present: five H2 headings give a navigable outline. Package names and commands are likely `<code>` elements on the live page. - Improve: the two blocks lost in capture (after ¶9 and ¶14) are probably a table and a list. A filename table without a header row is a WCAG 2.2 AA 1.3.1 (Info and Relationships) gap. Verify on the live page. #### Keyboard navigation - Present: Make/Core runs on a standard WordPress theme with keyboard-operable links and comment form. - Improve: nothing in the content adds barriers; 2.1.1 and 2.4.7 depend on the theme. #### Contrast and readability - Present: unverifiable from text. - Improve: confirm 4.5:1 for inline code text against the Make theme's tinted code background (1.4.3). #### Text resizing and reflow - Present: responsive theme; text reflows. - Improve: a wide filename table can force horizontal scroll at 320px (1.4.10 Reflow). Check the missing block at mobile width. #### Media and captions - Present: no media in the captured text. - Improve: if the live page includes screenshots, each needs alt text (1.1.1). #### Forms and interactions - Present: the comment form is the only interaction. - Improve: theme-level; no content-specific issue. #### Standards reference - Candidate gaps, pending a live-page check: **1.3.1** (table header association), **1.4.10** (table reflow), **1.4.3** (inline code contrast). No confirmed failures from the captured text. ## 🌍 DEIB assessment #### Cultural breadth - Present: written for a global contributor base; links to documentation, not region-specific resources. - Improve: translate the consumer-facing section; plugin authors outside English-first communities hit the same break. #### Inclusive language - Present: plain "we" voice; jargon expanded at first use (ESM, ¶3); no idioms. - Improve: "Props" is WordPress shorthand; a translated dev note should render it as "credit." #### Neurodiversity support - Present: five headings over 893 words, each section under 200 words, predictable order (why, contributors, consumers, packages, feedback). - Improve: the consumer section carries the most consequential information and, in this capture, the least structure. A numbered two-option list and a checklist would cut working-memory load. #### Representation - Present: seven contributors credited by handle, with separate credit for code and post review. - Improve: handles over names is the Make convention; no change. #### Psychological safety - Present: the Jest maintainers get credit for recent improvements in the same sentence that notes their slow period (¶6). Feedback is invited through three channels. - Improve: a one-line acknowledgment that either consumer path is work would set expectations honestly. ## ✅ Logical validity #### Strong reasoning - **Causal chain, ¶3 to ¶4.** Dependencies adopt ESM; Jest's CommonJS setup needs a transform allowlist; dependency updates then require config edits; Vitest reads ESM natively, so the allowlist is unnecessary. Each link is stated, and the allowlist is pinned to a commit and line range. Clarify by stating how many entries the list had at its peak. - **Scoped empirical claim, ¶7.** The browser shard finished before the longest Node/jsdom shard, therefore browser testing did not set completion time "in that measured configuration." The conclusion is exactly as wide as the evidence. Strengthen by including the two durations in the post. - **Concession against interest, ¶6.** The maintainability argument credits Jest's recent improvements alongside its slow period, which raises the credibility of the surrounding rationale. - **Honest limitation, ¶20.** After stating that built-in features cover most of the preset's motivation (¶19), the post names a case that doesn't: failing on unexpected console output. #### Fallacies - None found. Checked for: unsupported quantification (the performance claim is qualitative and scoped; numbers are linked, not asserted), appeal to popularity (Vitest's adoption elsewhere is never used as an argument), false dilemma (the "two options" framing omits pinning `@wordpress/scripts` below 36, but doesn't exclude it), and burying the lede (the consumer break has its own headed section). One weakness short of a fallacy: ¶7 credits the runtime result to the migration while noting worker and setup tuning in the same pass, so the two are confounded. *Fix:* report them separately in #80855. #### Tone of voice - Institutional and even. First-person plural where Gutenberg acts ("we maintained an explicit list," ¶3; "We also optimized test workers," ¶7), impersonal elsewhere. No superlatives; the strongest evaluative word is "major" in ¶2. Breaking changes are stated as facts ("This release includes breaking changes," ¶12), not minimized. The register is a changelog with reasons attached, which makes the post quotable in dev notes without editing. ## 🛡️ DARVO analysis Not applicable to this source. DARVO (Deny, Attack, Reverse Victim and Offender) describes a defensive response to accusation, and this is an infrastructure announcement with no accuser. For completeness across the three prongs: **Deny**: nothing is denied or minimized; the breaking changes in `@wordpress/scripts` 36.0.0 and `@wordpress/eslint-plugin` 27.0.0 are stated outright (¶12, ¶16), and the gap in Vitest's console handling is conceded (¶20). **Attack**: the one party that could have been disparaged, the Jest project, is credited for recent improvements (¶6). **Reverse victim/offender**: no such move; Gutenberg is framed as having longer-term needs, not as burdened by Jest. ## 🎯 Conclusion Gutenberg's move to Vitest is a completed, well-reasoned infrastructure change, and the post explains it in the right order: the ESM transform list was a maintenance cost that native ESM removes (¶3 to ¶4), Browser Mode gives component tests a real rendering engine (¶5), and adding browser coverage cost nothing on the critical path in Gutenberg's measured configuration (¶7). Each claim is linked to a commit, a Vitest doc, or issue #80855. The consequential part for anyone outside the monorepo is `@wordpress/scripts` 36.0.0. `wp-scripts test-unit-js` is now a Vitest command that uses the project's own install, and the package no longer bundles Jest, its environment, or the WordPress preset and transformer (¶12, ¶15). `@wordpress/eslint-plugin` 27.0.0 follows. The two Jest helper packages are deprecated with no Vitest replacements, and `test-unit-jest` is frozen but not scheduled for removal (¶17 to ¶19). Either path costs time. **Next steps for readers:** before the next `@wordpress/scripts` bump, grep `package.json` for `test-unit-js`. If it's there, read the `test-unit-js` reference and the Testing Overview, because the filename conventions and the two-option list live there rather than in this capture. Decide migrate or keep, and follow the checklist in the Plugins action item. If you write developer docs, the three Documentation gaps above are the highest-value fixes this post creates. ## 🔄 Refactor Appendix — Gutenberg's JavaScript unit and integration tests now use Vitest > Density: 2–5 Literature atoms (H3 pad), 0–3 Permanent candidates (H4 pad). > Emitted: 3 Literature, 1 Permanent. Resonance filter applied: the Storybook/Vite > consistency point and the Jest 30 maintainability point were folded into context > rather than promoted, since neither is reusable outside this decision. > > Konik claim-header rules: present tense, declarative, ≤10 words, searchable, unique. > > Atomicity: one declarative sentence per atom. "and"/"also" → split. > > Tag pool: #bmf · #addendum · #xref · #articleseed · #storystem · #share · #aphorisms ### 📚 Literature Split Pad #### [H1] wp-scripts 36 runs the project's own Vitest > [!quote] [¶12] > Starting with @wordpress/scripts 36.0.0, wp-scripts test-unit-js uses the project’s installed Vitest. **Context & use**: - ¶12, the first sentence of "What changes for consumers of WordPress test tooling?" - The most operational sentence in the post. "The project's installed Vitest" means the consumer installs and versions the runner; the wrapper only invokes it. Every migration checklist starts here. **Tags**: #xref #share <!-- atomicity: 1 idea ✓ --> #### [H2] Keeping Jest means installing what the wrapper dropped > [!quote] [¶15] > The package no longer supplies Jest, its environment, or the WordPress Jest configuration and transformer. **Context & use**: - ¶15, right after "Existing projects have two options" and before the lint changes in ¶16. - Four bundled dependencies (runner, environment, preset, transformer) become the consumer's responsibility at once. This sentence turns "rename the command" into a real migration, and it's the one plugin authors are most likely to skip. **Tags**: #xref #share #articleseed <!-- atomicity: 1 idea ✓ --> #### [H3] Parallel browser shard leaves the critical path unchanged > [!quote] [¶7] > Browser testing therefore did not determine the overall test completion time in that measured configuration. **Context & use**: - ¶7, the performance paragraph; the figures behind it are in Gutenberg issue #80855, not the post. - A model of how to state a benchmark result: the conclusion is about the critical path and the scope is pinned to the measured configuration. Carry the caveat that worker and setup tuning happened in the same pass. **Tags**: #xref <!-- atomicity: 1 idea ✓ --> ### 🧠 Atomic Split Pad #### [P1] Bundled defaults are hidden dependencies **Claim** (one sentence, Courtney's voice): Anything a build wrapper installs on your behalf is a dependency you own the day the wrapper stops installing it. **Evidence pointer**: [[#H1]] · [[#H2]] **Scope & conditions**: Holds for any convenience wrapper (`wp-scripts`, `react-scripts`, framework CLIs) that bundles a runner, environment, or preset. Breaks when the wrapper commits to a stable, versioned contract for its defaults. The mitigation is to list the wrapper's transitive supply and decide per item whether to pin it yourself. **Links**: - [[Dependency management for WordPress block plugins]] — because extends - [[Zero-config tooling tradeoffs]] — because contrasts on where configuration ownership sits - [[Plugin release checklist]] — because applies-in pre-upgrade review of `@wordpress/scripts` majors <!-- atomicity: 1 idea ✓ --> ### ✏️ Fleeting Queue - [F1] Fetch the live page and recover the two blocks the capture lost: the filename-to-environment list after ¶9 and the two-options list after ¶14 — https://make.wordpress.org/core/2026/09/23/gutenbergs-javascript-unit-and-integration-tests-now-use-vitest/ #fleeting #inbox - [F2] Read Gutenberg issue #80855 for the shard durations and worker counts behind the ¶7 claim, and note whether the framework swap and the tuning were measured separately — https://github.com/WordPress/gutenberg/issues/80855 #fleeting #inbox - [F3] Open question: which Vitest major does `@wordpress/scripts` 36.0.0 expect, and is it a peer dependency? Check the package's `package.json` and changelog #fleeting #inbox - [F4] Article seed: "What your build wrapper installs for you," a walkthrough of listing a wrapper's transitive supply before a major bump, using the 36.0.0 break as the worked example #fleeting #inbox #articleseed ### → Things 3 (max 2 actions) - [ ] Audit each maintained block plugin for `wp-scripts test-unit-js` and `@wordpress/jest-*` usage and record migrate-or-keep per repo — before bumping `@wordpress/scripts` to 36.0.0, 30 min #things - [ ] Read the `test-unit-js` reference and Gutenberg issue #80855, then draft the "Keeping Jest" and filename-conventions docs fixes as a Block Editor Handbook issue — developer docs, 45 min #things <!-- deep-read:sections end --> 📄 **Full text:** [[Full Document Contents/Articles/Gutenberg’s JavaScript Unit and Integration Tests Now Use Vitest.md|Gutenberg’s JavaScript Unit and Integration Tests Now Use Vitest by Marco Ciampini]] ## Highlights - The migration adds real-browser coverage while keeping test execution parallel. Browser Mode tests run alongside the Node and jsdom suites and, in our migration benchmarks, finished before the longest-running Node/jsdom group. Browser testing therefore did not determine the overall test completion time in that measured configuration. We also optimized test workers and shared setup to reduce runtime during the migration. ([View Highlight](https://read.readwise.io/read/01m388vj59582eesxvnnrck59p)) - Note: [H3] Parallel browser shard leaves the critical path unchanged - Tags: atom/literature/h3 - Starting with @wordpress/scripts 36.0.0, wp-scripts test-unit-js uses the project’s installed Vitest. This release includes breaking changes to test configuration, dependencies, APIs, and command-line options. ([View Highlight](https://read.readwise.io/read/01m388vdpd84k9gjgwgn0qcynv)) - Note: [H1] wp-scripts 36 runs the project's own Vitest - Tags: atom/literature/h1 - Keeping Jest requires more than renaming the command if your project relied on the defaults previously bundled with @wordpress/scripts. The package no longer supplies Jest, its environment, or the WordPress Jest configuration and transformer. The documented upgrade steps cover how to retain that setup using the published packages. ([View Highlight](https://read.readwise.io/read/01m388vfwjp9fye86qn8egvw8r)) - Note: [H2] Keeping Jest means installing what the wrapper dropped - Tags: atom/literature/h2