Testing Guide
Test Strategy Overview
The CSS & JS Minifier extension uses VS Code’s extension testing framework with Mocha. The current test suite covers 171 tests (2 of them skipped) across six files, spanning activation, main functionality, new-file naming, file prefix validation, workspace capabilities, and internationalization. Both CSS and JS minification are fully local (LightningCSS + oxc-minify) so tests run fast with no network dependency or rate-limiting concerns.
Test Structure
Test Files (src/test/)
| File | Tests | Focus |
|---|---|---|
activation.test.ts | 5 | Regression guard for #168: asserts activationEvents in package.json contains onLanguage:css and onLanguage:javascript, and that the deprecated onCommand:* / invalid onSaveTextDocument entries are not re-added. |
extension.test.ts | 31 | Main functionality: CSS/JS minification (in-place + new file), file-prefix configurations, explorer context menu, empty file / unsupported file type validation, configuration behaviors (autoOpenNewFile, minifyInNewFile, minifiedNewFilePrefix, showSizeReduction), CSS nth-child selectors, and keybinding smoke tests. |
fileService.test.ts | 15 | (18 when run: the end-to-end check is generated for four file names) Regression guard for #255: createMinifiedFileName for .css, .js, .mjs, .cjs, uppercase extensions, Windows paths, no extension, leading dot and already-prefixed names, with every prefix the setting offers; and an extension-host proof that Minify and Save as New File never overwrites the original (temp files in the OS temp folder, read back from disk) and that saveAsNewFile refuses to write when the target URI equals the source URI. |
i18n.test.ts | 23 | Two nested suites: (a) static bundle validation — file existence, JSON validity, key parity across all seven languages, placeholder preservation; and (b) Runtime Localization (vscode.l10n) — regression guard for #169: asserts t() returns real interpolated text (never a raw key), placeholder interpolation is preserved end-to-end, vscode.l10n.bundle matches the shipped bundle.l10n.<locale>.json when running under a non-English locale, and every non-English bundle differs from English for at least one key. |
workspaceCapabilities.test.ts | 7 | Virtual workspace support: registers an in-memory file system under a non-file scheme and checks that Minify and Save as New File writes the sibling file through that provider (same scheme and authority, no local file, query and fragment dropped), and that in-place minification persists through it. Also asserts the capabilities declared in package.json (virtual workspaces supported, untrusted workspaces limited with the write-target settings restricted). |
File Management & Test Isolation
Temporary File Strategy
Configuration tests use temporary files to avoid modifying source fixtures:
const sourceFile = path.join(__dirname, "..", "..", "src", "test", "fixtures", "test.css");
const testFile = path.join(__dirname, "fixtures", "temp-test.css");
fs.copyFileSync(sourceFile, testFile);Comprehensive Cleanup Strategy
Each test suite includes cleanup in beforeAll hooks:
- Reset all configurations to defaults
- Remove generated minified files (
.min,.compressed, etc.) - Restore original fixture files from source
Sinon Spy Management
this.afterEach(function () {
sinon.restore();
});Running Tests
VS Code Tasks (Recommended)
Access via Ctrl/Cmd + Shift + P → “Tasks: Run Task”:
| Task | Focus |
|---|---|
| Test: Run All Tests | Full 73-test suite (compile + lint + all suites) |
| Test: Configuration Suite Only | Configuration Test Suite in extension.test.ts |
| Test: Main Functionality Suite Only | JS & CSS Minifier Test Suite in extension.test.ts |
| Test: CSS nth-child Suite Only | CSS nth-child Test Suite in extension.test.ts |
| Test: Keybinding Suite Only | Keybinding Test Suite in extension.test.ts |
| Test: Internationalization (i18n) Suite Only | Both static + runtime suites in i18n.test.ts |
| Test: Specific Test by Name | Prompts for a --grep pattern and runs matching tests |
| Test: Compile and Build Only | npm run pretest (compile + lint + copy fixtures, no test run) |
| Test: Quick Compile and Test | npm run compile-tests (TS only, no webpack, no lint) |
Command Line
# Complete test suite (compile + lint + all tests)
npm test
# Individual suites (grep-based)
npx vscode-test --grep "Configuration Test Suite"
npx vscode-test --grep "JS & CSS Minifier Test Suite"
npx vscode-test --grep "CSS nth-child Test Suite"
npx vscode-test --grep "Keybinding Test Suite"
npx vscode-test --grep "Virtual Workspace Test Suite"
npx vscode-test --grep "Internationalization"
npx vscode-test --grep "File Service Test Suite"
npx vscode-test --grep "File Prefix Validation"
npx vscode-test --grep "Activation Events"
npx vscode-test --grep "Runtime Localization"
# Specific test
npx vscode-test --grep "autoOpenNewFile setting - enabled"
# Under a specific display locale (VS Code Language Pack must be installed)
VSCODE_LOCALE=es npm test
VSCODE_LOCALE=fr npx vscode-test --grep "Internationalization"
VSCODE_LOCALE=qps-ploc npm test # pseudo-locale, no pack needed
# Build only (no tests)
npm run pretest
# Coverage: per-file summary for src/** plus coverage/lcov.info
npm run test:coverageSee docs/INTERNATIONALIZATION.md#testing-under-a-specific-locale for the runtime localization test wiring.
Test coverage
npm run test:coverage is opt-in. npm test is unchanged and collects nothing.
npm run test:coverageIt runs pretest:coverage (compile tests, rebuild the bundle with webpack --env coverage, lint, copy fixtures), then vscode-test --coverage --coverage-output coverage, then scripts/coverage-report.mjs. The output is a per-file table of lines, functions and branches for src/** (without src/test/**) and coverage/lcov.info with repository-relative paths. There is no threshold: the numbers are for orientation.
How it is wired:
.vscode-test.mjsholds acoverageblock (include,exclude,reporter: ['lcovonly']). It is a sibling oftestsinsidedefineConfig({ tests, coverage }); a flatdefineConfig({ files, version, coverage })ignores it silently. The CLI also ignorescoverage.output, so the folder comes from--coverage-outputin the npm script. Patterns are matched against absolute paths, which is why they start with**/.- The extension under test runs from the webpack bundle
dist/extension.js, not from theout/files thattscemits. Webpack’s default source-map paths (webpack://css-js-minifier/./src/...) point at nothing c8 can read, so it reports every file at a false 100% or 0%.--env coveragemakeswebpack.config.cjssetdevtoolModuleFilenameTemplateto[absolute-resource-path], which maps the bundle back to the realsrc/**files. Regular builds and the shipped source maps never get these absolute paths. - c8 also lists non-source modules of the bundle (
external commonjs "vscode",webpack/bootstrap) as 100% covered.scripts/coverage-report.mjsdrops them, rewriteslcov.infowith onlysrc/**, and prints the table. scripts/coverage-report.mjsexits 1 whensrc/extension.tsis missing from the lcov file. That means the bundle was built without--env coverageand only the few files the tests import fromout/were measured, so the run is refused instead of showing a tiny table that looks complete.- With
includeAll: false, a file nothing loads, such as a type-only module, does not appear.
What it cannot measure: the minification itself runs in the Rust bindings lightningcss and oxc-minify, so the percentages describe the VS Code orchestration around them.
CI: the Ubuntu job of .github/workflows/test-vscode-stable.yml (VS Code Stable) reruns the suite with npm run test:coverage and appends the table to $GITHUB_STEP_SUMMARY. Both steps use continue-on-error, so a coverage problem never changes a required check. The other jobs are unchanged.
Local note: on macOS, VS Code needs the user-data path under 103 characters for its IPC socket. In a deeply nested checkout (for example a git worktree) the run fails with listen EINVAL ... main.sock. Pass a short directory through launchArgs: ['--user-data-dir=/tmp/short'] in a local, uncommitted copy of the config.
Development Workflow
Feature Development:
- Start watch mode: “tasks: watch-tests”
- Run the relevant suite for your change (e.g.
Test: Configuration Suite Only). - Run the full suite before commit:
Test: Run All Tests.
Bug Fixing:
- Identify failing suite via
Test: Run All Tests. - Focus on the specific suite.
- Target a single test via
Test: Specific Test by Name.
Test Data Management
Expected Minification Results
// CSS (LightningCSS output)
const cssMinifiedContent = "p{color:red}";
// JavaScript (oxc-minify output)
const jsMinifiedContent = 'function test(){for(var e=`Hello, World!`,t=``,n=0;n<e.length;n++)t+=String.fromCharCode(e.charCodeAt(n)+1);return t}';Test File Organization
src/test/
├── activation.test.ts # Activation Events regression guard (#168)
├── extension.test.ts # Main test suite (41 tests, 2 skipped)
├── filePrefix.test.ts # minifiedNewFilePrefix validation, command and on-save paths (#259, 77 tests)
├── fileService.test.ts # New-file naming + overwrite guard (#255, 18 tests)
├── i18n.test.ts # Static + runtime i18n suites (23 tests)
├── workspaceCapabilities.test.ts # Virtual workspace + capabilities (7 tests)
└── fixtures/
├── test.css # Basic CSS test file
├── test.js # Basic JS test file
├── test-minified.js # Expected JS minified output
├── nth-child-test.css # CSS nth-child test case
├── starting-style.css # CSS @starting-style test case
├── large.css # Larger CSS file for size-reduction tests
├── empty.css # Empty file test case
├── empty.js # Empty file test case
└── test.txt # Unsupported file typeDebugging Test Failures
Common Issues
-
Configuration Test Failures
- VS Code configuration updates are asynchronous — use small delays after
.update(). - Always use temporary files, never modify source fixtures.
- VS Code configuration updates are asynchronous — use small delays after
-
File Path Issues
- Ensure
npm run copy-fixturesran duringpretest. - Check
out/test/fixtures/directory exists.
- Ensure
-
In-Place Modification Conflicts
- Use unique temporary file names per test.
- Comprehensive cleanup in
beforeAllhooks.
-
Runtime i18n Assertions Silently Pass Under English
Runtime Localizationtests usevscode.env.languageto decide what to assert. Under the default English locale several assertions no-op. Run them under a non-English locale (VSCODE_LOCALE=es npm test) or the pseudo-locale (VSCODE_LOCALE=qps-ploc npm test) to exercise them properly.
Best Practices
- Source Protection: Never modify files in
src/test/fixtures/. - Temporary Files: Use unique prefixes (
temp-test.css). - Complete Cleanup: Remove generated and temporary files after tests.
- Fixture Restoration: Copy fresh content from source when needed.
- Spy Management: Always restore Sinon spies to prevent interference.
- Descriptive Names: Use clear functionality descriptions for test names.
- Content Verification: Assert specific minified output, not just “changed”.
Last Updated: 2026-10-28 Extension Version: 1.3.4 Test Suite: 171 tests across 6 files (activation, main, file service, file prefix, workspace capabilities, i18n)