Thank you for contributing to css-minify-tests -- a correctness test suite
for CSS minifiers.
This project is governed by the Contributor Covenant Code of Conduct. By participating you agree to abide by its terms.
The suite compares minifier output against canonical expected results across many CSS features. Each test isolates one minification technique to make failures easy to diagnose.
tests/
<category>/
<NNNN>/
source.css # Unminified input (formatted, 2-space indent)
expected.css # Canonical minified output (single line + newline)
README.md # 2-4 line description of the transformation
validate.html # For difficult to reason about tests, this can provide
# an test example to run in browsers, showcasing this.
If you'd like to add a test, please consider the following a guide for doing so:
Each test covers ONE transformation. Do not combine multiple optimisations in a single test. It's likely whitespace will be compressed, but for example try to avoid combining declarations what will be minified for a test not focusing on that.
Before writing the test, confirm the minification is safe -- the minified output must be semantically identical to the source. Pay attention to known unsafe transformations:
0%->0is sometimes unsafe (percentage context matters)0s->0is unsafe (unitless zero is invalid for<time>)0deg->0is often unsafe (unitless zero is invalid for<angle>in some contexts)0fr->0is unsafe (unitless zero is invalid for<flex>)background: none->background: 0 0is unsafe (different initial values)- Merging nested
@mediacan change cascade behaviour - Stripping
/*!comments removes licence text - Removing quotes from
url()with special chars breaks parsing calc(100% - 20px)spaces around-are required- Reordering shorthand values can change meaning
content: ""quotes are required
Unsafe tests are also useful! Often minifiers can be overly aggressive and accidentally make unsafe transforms. Adding tests that confirm CSS shouldn't be minified in certain cases can help highlight this.
Read every existing source.css and expected.css in the target category. If
an existing test already covers the same transformation, do not add a redundant
test. Only proceed if the new test covers a meaningfully different edge case.
List existing directories in tests/<category>/. The new test number is the
next sequential 4-digit number (e.g. if 0007 exists, use 0008).
The unminified CSS. Keep it minimal -- one rule, one transformation, focus on the value being tested. Use standard formatting (2-space indent, spaces after colons). Some tips:
- Simple selectors like
aandbkeep things short. - Avoid empty rules -- most minifiers remove them entirely, confounding the test.
- If you're not testing declarations a good "filler" declaration is
color:red, which is already compact enough to not be minified any further.
The shortest correct representation that is semantically identical to the source. Must be a single line terminated by a newline.
Short description (2-4 lines):
# Short title
Brief explanation of what transformation is being tested and why it matters or
could go wrong.npm test
DEBUG=1 npm run test:debugInterpret results:
- All pass -- test is valid and all minifiers handle it. Is this test too simple? Is it well covered?
- Some fail -- check if the minifier produces a different-but-equivalent output (test may be too opinionated) or simply doesn't implement this optimisation (that's fine -- the test is still valid). Maybe one minifier produces a surprisingly better result, if so it's worth checking how valid that result is.
- All fail -- verify the transformation against the spec and check that the source and expected CSS render identically. If valid but no tool implements it yet, keep the test -- congratulations you found a new opportunity for all minifiers!
To add a new CSS minifier to the suite:
npm install --save-dev <package-name>If the minifier needs a peer dependency (like postcss for cssnano), install
that too.
Add lib/minifiers/<name>.js. The file must export a default function that
takes a CSS source string and returns the minified CSS string. The function can
be sync or async.
Sync example (like csso):
import { minify as theirMinify } from "some-minifier";
export default function minify(source) {
return theirMinify(source).css;
}Async example (like esbuild):
import { transform } from "some-minifier";
export default async function minify(source) {
const { code } = await transform(source, { minify: true });
return code;
}If the minifier is a CLI binary rather than a JS API, see
lib/minifiers/csskit.js for an example that calls execSync and returns
null when the binary is unavailable (shown as N/A in results).
In lib/minify.js:
- Import the adapter at the top of the file.
- Add an entry to the
registryMap. The key is the npm package name (used for version lookups and display).
import myMinifier from "./minifiers/my-minifier.js";
const registry = new Map([
// ... existing entries ...
["my-minifier", myMinifier],
]);npm testAll existing tests should still run. Your minifier will appear as a new column in the results table. Failures are expected -- they just mean that minifier doesn't implement a particular optimisation yet.
Clean up the code by running prettier.
Include the minifier name, a link to its repository or npm page, and a brief note on why it's a good addition.
No specific linter. Keep things simple and consistent with existing files.
Open a pull request. Describe what transformation the test covers and reference the relevant CSS spec section if applicable.