Karma & QUnit Testing in Inputmask
This skill guides testing workflows in the Inputmask repository using Karma and QUnit.
Critical Rules & Pitfalls
ALWAYS Use
ChromeHeadlessfor Automated Runs:karma.conf.jsadds a GUI Chrome launcher whenCIis not set. Runningnpx karma startorgrunt karmavia a CLI tool (Bash, PowerShell, etc.) without--browsers ChromeHeadlessopens a visible Chrome window that never exits cleanly, causing the command to hang indefinitely.ALWAYS Redirect Output to a File — Do Not Pipe Inline: Karma emits progress lines with ANSI escape codes that cause PowerShell
Select-Stringand similar pipe commands to buffer indefinitely. Redirect stdout/stderr to a temp file, then read the file separately:npx karma start karma.conf.js --browsers ChromeHeadless --single-run --reporters progress > $env:TEMP\karma_results.log 2>&1Then read the file with the
ReadorSelect-Stringtool in a separate step.ALWAYS Rebuild the Test Bundle After Any Changes: Tests run from
qunit/qunit.js, which is compiled by webpack fromqunit/index.jsandlib/. Any edit inlib/,qunit/tests_*.js, orqunit/index.jsrequires rebuilding the test bundle (npx webpack --config-name test) before running Karma, or running webpack in watch mode.
Workflows
1. Running Tests (Recommended Pattern)
Always use this exact pattern for reliable, non-hanging test runs:
# 1. Rebuild test bundle (if source changed)
npx webpack --config-name test
# 2. Run karma with ChromeHeadless, output to file
npx karma start karma.conf.js --browsers ChromeHeadless --single-run --reporters progress > $env:TEMP\karma_results.log 2>&1
# 3. Read results (separate step)
Select-String -Path $env:TEMP\karma_results.log -Pattern "TOTAL|FAILED" | Select-Object -Last 5
2. Running a Single Test Suite or Selected Test Suites
To isolate specific test files (e.g., only qunit/tests_numeric.js or qunit/tests_date.js):
Edit
qunit/index.jsto import and register only the desired test module(s):import testsNumeric from "./tests_numeric"; import testsDate from "./tests_date"; // ... if (qunit) { testsNumeric(qunit, Inputmask); testsDate(qunit, Inputmask); qunit.load(); }Rebuild the test bundle:
npx webpack --config-name testRun Karma:
npx karma start karma.conf.js --browsers ChromeHeadless --single-run --reporters progress > $env:TEMP\karma_results.log 2>&1Check results:
Select-String -Path $env:TEMP\karma_results.log -Pattern "TOTAL" | ForEach-Object { $_.Line }
3. Fast Interactive & Live Debugging
To keep the browser open and re-run tests instantly on changes:
In one terminal, run the webpack test bundle watcher:
npm run qunitIn another terminal, run Karma in watch mode:
npx karma start --browsers Chrome --no-single-run --auto-watchIn the opened Chrome window, click the DEBUG button in the top right to open the standalone test page, then press F12 to open Chrome DevTools for breakpoints and console logs.
4. Alternative: Direct Browser HTML Runner (No Karma)
You can run and debug QUnit tests directly in any browser without Karma:
- Rebuild the test bundle:
npx webpack --config-name test(or keepnpm run qunitrunning). - Open
qunit/qunit.htmlin your browser. - Use the QUnit web interface dropdown to filter by module or re-run individual tests.
5. Running Specific Tests via CLI Filter
You can filter tests by name or module via Karma client arguments without modifying qunit/index.js:
# Filter by test name
npx karma start karma.conf.js --browsers ChromeHeadless --single-run -- --filter="masked" > $env:TEMP\karma_results.log 2>&1
# Filter by module name
npx karma start karma.conf.js --browsers ChromeHeadless --single-run -- --module="Simple masking" > $env:TEMP\karma_results.log 2>&1
6. Cross-Platform / Cross-Browser Testing (BrowserStack)
Use BrowserStack ONLY when reproducing or verifying browser-specific or OS-specific issues (e.g., Safari/iOS or Android mobile events):
- Ensure credentials are set:
$env:BROWSERSTACK_USERNAME="<username>" $env:BROWSERSTACK_ACCESS_KEY="<access_key>" - Run Karma specifying the target custom launcher from
karma.conf.js:npx karma start karma.conf.js --browsers bs_safari_mac_Sonoma --single-run > $env:TEMP\karma_results.log 2>&1 # Or for mobile: npx karma start karma.conf.js --browsers bs_iPhone14 --single-run > $env:TEMP\karma_results.log 2>&1
Quick Reference Commands
| Task | Command |
|---|---|
| Build test bundle once | npx webpack --config-name test |
| Watch test bundle | npm run qunit |
| Run all tests (headless, non-hanging) | npx karma start karma.conf.js --browsers ChromeHeadless --single-run --reporters progress > $env:TEMP\karma_results.log 2>&1 |
| Run tests with live auto-watch | npx karma start --browsers Chrome --no-single-run --auto-watch |
| Full validation pipeline | npm test (runs grunt validate) |
Known Pre-existing Failures
The following numeric test is known to fail in the current HEAD (a WIP refactor regression — it passes at 9dfeac29f, "fix clearing value leaves sticky minus or lone radix on currency/numeric #2890"). It is NOT something to chase while working on unrelated numeric issues unless asked:
- negationSymbol parentheses + clearIncomplete —
numeric + (negationSymbol = parentheses) + (clearIncomplete = true) + type -123. then blur: expected"(123.000)", actual"(123,000)"(radix renders as group separator after.val()+ blur).
Note:
Currency digits and delete #1351,highlighting values with negative numbers #2714, andcurrency type 1234.56 + backspace x4were previously on this list but are now FIXED on HEAD via therevalidateMaskreplay fix inlib/validation.jsand a fractional-delete realignment branch in the numericonBeforeWritekeydown handler (lib/extensions/numeric.js, thecaret.end > radixNdxelsebranch): it guards one.key === Delete && numericInput && _radixDance && buffer[caret.begin-1]is a digit, then splices the reversed buffer,alignDigitsre-pads toopts.digits, and returnsrefreshFromBuffer+ corrected internal-order buffer sowriteBufferfully re-validates validPositions (orphaned radix gets rebuilt).