TESTING_DOCS.md
This document explains the structure of the test/ directory in the Webpack project using Jest. The directory is organized into multiple folders and files, each serving a specific purpose in testing various aspects of Webpack’s functionality.
__snapshots__/benchmarkCases/many-modules-esm/) — a webpack.config.mjs plus an entry; measures one build per scenario (mode-development, mode-development-rebuild, mode-production).*-unit (e.g. js-parser-unit/) — an index.bench.mjs exporting default (bench) => {…}; measures a piece of lib/ directly, with no scenarios.*-runtime (e.g. many-modules-interop-runtime/) — measures the emitted bundle, not the build. The case is compiled once per scenario outside any measured region; the exec task then instantiates the output (runtime bootstrap plus every module factory that runs at import time) and calls the entry's exported run on it. The rebuild scenario is skipped, since it emits the same output.*-runtime case: the entry must export run(seed), do its work with that opaque seed, and return the result — otherwise the compiler folds the workload away and the bench measures nothing (both are checked and fail the run). The harness forces target: "node" and a commonjs2 library so the output can be instantiated in-process; generate large fixtures from options.mjs (setup()), as the build cases do.exec is reported per scenario, so a development/production pair shows what scope hoisting and minification are worth at runtime.
cases/configCases/fixtures/helpers/hotCases/hotPlayground/memoryLimitCases/jsonstatsCases/typesCases/test262-cases/git submodule update --init test/test262-cases. Test runner: test/test262.spectest.js.html5lib-tests/lib/html/syntax.git submodule update --init test/html5lib-tests. Test runner: test/html5lib-webpack.spectest.js (yarn test:html5lib) compiles every input as a webpack HTML entry to confirm the full pipeline handles it without crashing.wpt/html/syntax/parsing/resources/*.dat is the HTML tree-construction conformance corpus for parseHtml (html5lib-tests dropped its copy in 224991e). The .html documents under html/, conformance-checkers/ and dom/nodes, plus the declarations the css/**/parsing/ tests state a verdict for, are the printers' corpus: minifying must not change the DOM webpack's parser builds, the DOM Chrome builds, or the style Chrome computes.git submodule update --init --depth 1 test/wpt (the repository is ~161k files, so keep it shallow). Test runners: test/html5lib.spectest.js (yarn test:html5lib), which also reads test/html5lib-tests — initialize both to run the whole suite — and test/syntaxEquivalence.spectest.js (yarn test:syntax-equivalence), whose browser tiers need a Chrome (PUPPETEER_EXECUTABLE_PATH picks a binary other than the installed channel). A document that is not UTF-8 is skipped: the encoding fixtures are UTF-16, which no string API can read as source.css-parsing-tests/lib/css/syntax.git submodule update --init test/css-parsing-tests. Test runner: test/cssParsing-webpack.spectest.js (yarn test:css-parsing) compiles every input as a webpack CSS entry to confirm the full pipeline handles it without crashing.watchCases/*.unittest.jsCodeSizeTestCases.size.jslib/ that grows (or shrinks) every bundle is visible.yarn test:size builds every configCases/ case — one plain Node.js process, outside jest, no worker pool — and writes a JSON report of what each case emitted: the raw, gzip, brotli and zstd size of every asset, plus a per-runtime-module breakdown (total bytes over the suite, how many cases emit it, the biggest single instance) — which is what shows which runtime grew, which is no longer emitted at all, and which one is simply large. The CI job (.github/workflows/code-size.yml) compares the report against the one main last uploaded, posts it as a pull request comment (updated in place on every push) and repeats it in the job summary.--output <file> (report path), --baseline <file> (report to compare against), --summary <file> (append the markdown comparison, e.g. $GITHUB_STEP_SUMMARY), --filter / --negative-filter (regexps matched against <category>/<case>, also read from FILTER / NEGATIVE_FILTER).output.pathinfo — not with the ConfigTestCases ones. Needs Node.js >= 22.15 for zstd.BannerPlugin.test.jsBannerPlugin functionality.Many Webpack tests simulate small projects that are compiled during the test run.
For example, a configuration test may look like:
test/configCases/entry/simple/ index.js webpack.config.js expected.txt
Explanation:
During the test run, webpack compiles this project and compares the result with the expected output to ensure behavior remains consistent.
ProfilingPlugin.unittest.js, syntaxEquivalence.spectest.js and
WebpackDevServer.longtest.js launch Chrome through test/helpers/launchChrome.js.
A browser that will not launch fails the suite — it is never skipped, so no
environment can report these checks as passing without having run them. The
helper uses the installed Chrome channel; set PUPPETEER_EXECUTABLE_PATH to
point at another binary.
They are excluded from test:bun / test:deno (see the --testPathIgnorePatterns
in those scripts): under Jest on Bun, loading the ESM-only puppeteer-core fails
outright with "Provided module is not an instance of Module", and Jest's
require(ESM) fallback needs Node >= 24.9. Drop the exclusion once those
runtimes can load it.
output.environmentNo old browser runs in CI, so test/helpers/ecmaConformance.js asks the two
questions one would answer, over every configCases case in ConfigTestCases
and ConfigCacheTestCases. See that file for how it reads an environment.
restrictEnvironment: true in test.config.js removes from
the bundle's realm what the target lacks, so webpack's guards are taken
rather than stepped over. Web targets only.Two more test.config.js fields: ecmaConformance: true widens the parse check
to every emitted asset, so the case's own sources are held to its
output.environment too, and
ecmaConformanceExpected declares findings deliberate as regexps, each with its
reason — one that stops matching fails the case.
Under ecmaVersion/, the es5-* cases cover one runtime-emitting feature each
(jsonp, importScripts, require and read-file chunk loading, workers and
asset urls, css, hot updates, wasm, the library wrappers, Module Federation,
the neutral platform);
es-versions sweeps every rung of the esX ladder; environment-flags turns
each flag off on its own against an otherwise current target, which a version
sweep cannot do; and esm-environment repeats both over ESM output.
To execute all tests:
yarn test
Choose test command based on modified directory:
| Modified directory/file | Command |
|---|---|
test/*.unittest.js | yarn test:base --testPathPatterns="<filename>" |
test/cases/ | yarn test:basic |
test/configCases/ | yarn test:basic --testPathPatterns="ConfigTestCases" |
test/statsCases/ | yarn test:basic --testPathPatterns="StatsTestCases" |
test/watchCases/ | yarn test:base --testPathPatterns="WatchTestCases" |
test/hotCases/ | yarn test:base --testPathPatterns="HotTestCases" |
test/benchmarkCases/ | FILTER="<case-name>" yarn benchmark |
lib/runtime/ | yarn test:size (size of the generated code; --filter "<category>/" narrows it) |
test/test262-cases/ | yarn test:test262 (requires git submodule update --init test/test262-cases first) |
test/html5lib-tests/ | yarn test:html5lib (requires git submodule update --init test/html5lib-tests first) |
test/wpt/ | yarn test:html5lib + yarn test:syntax-equivalence (require git submodule update --init --depth 1 test/html5lib-tests test/wpt first) |
test/css-parsing-tests/ | yarn test:css-parsing (requires git submodule update --init test/css-parsing-tests first) |
Running a single test case with --testNamePattern. The test name format is <category> <case-name> (e.g., css basic, asset url):
yarn test:basic --testPathPatterns="ConfigTestCases" --testNamePattern="css basic"
Multiple patterns can be combined with |:
yarn test:basic --testPathPatterns="ConfigTestCases" --testNamePattern="css basic|css url"
yarn test before pushing changes to validate functionality.