Testing

July 30, 2026 · View on GitHub

Running the test suite

# Run all 36 tests (no ONNX model required)
cd precise-onnx-js
node --test test/*.test.js
# or: npm test

Requires Node.js 18+. No npm install is needed. The library has no runtime dependencies beyond an ONNX runtime, which is only needed for load(). Tests mock the session.

Regenerating Python reference vectors

# Requires sonopy and ovos-ww-plugin-precise-onnx in the Python venv
"/home/miro/PycharmProjects/HiveMind Workspace/.venv/bin/python" \
    test/generate_ww_vectors.py

Writes test/ww_vectors.json. Commit the updated file so JS test runs are reproducible without a Python environment.


Test coverage (36 tests)

ThresholdDecoder (6 tests)

TestWhat it checks
Constructor propertiesminOut, maxOut, outRange, center, CDF length all match Python
CDF first 5 valuesFloating-point match to 1e-12 tolerance
CDF last 5 valuesFloating-point match to 1e-12 tolerance
decode on 13 valuesEach decoded value matches Python to 1e-6
Boundary: decode(0)0Exact
Boundary: decode(1)1Exact

TriggerDetector (7 tests)

TestWhat it checks
Seq 1 results match PythonFire pattern: [F,F,F,T,F,F,F,F,F,F,T], firing on the 4th consecutive
Seq 1 activations match PythonInternal counter after each step
Seq 2 (all zeros) never fires10 steps of 0.0 → all false
Seq 3 (boundary 0.5) never firesprob > 1-sensitivity is strict, and 0.5 is not > 0.5
Cooldown value matches Python-floor(8 * 2048 / chunkSize) = -8
Re-fires after cooldown8+ low-prob steps + 4 high → fires again

PreciseOnnxWakeWord properties (5 tests)

TestWhat it checks
windowSamples1600
hopSamples800
bufferSamples24000
nFeatures29
nMfcc13

All values compared against precise_props from ww_vectors.json.

_updateVectors: rolling buffer (5 tests)

TestWhat it checks
Zero-length chunk returns zero matrixNo frames computed
Short chunk (< windowSamples) accumulatesNo frames yet, audio stored
windowSamples chunk → 1 frameExactly one MFCC row produced
After consumption, buffer drains correctlywindowAudio.length === hopSamples after 1 frame
MFCC matrix rolls on second chunkOldest rows drop, new rows appended

mfccSpec equivalence: zeros (4 tests)

TestWhat it checks
Frame count matches Pythonn_frames
frame[0][0] matches PythonLog-energy value (float32 precision)
frame[0][1..12] all zeroDCT of zero log-mels is zero
ATOL for all coefficients ≤ 1e-3All 13 coefficients, all frames

mfccSpec equivalence: 440 Hz sine (4 tests)

TestWhat it checks
Frame count matches Python
frame[0] all coefficients within ATOL1e-3
frame[-1] all coefficients within ATOLLast frame
No NaN/Inf in any frameNumerical stability check

mfccSpec equivalence: white noise seed 42 (4 tests)

TestWhat it checks
Frame count matches Python
frame[0] all coefficients within ATOL1e-3
frame[-1] all coefficients within ATOL
No NaN/Inf

Integration: predict pipeline (1 test)

TestWhat it checks
predict with mock session returning 0.99Fires after 4 consecutive calls and returns boolean

Cross-language validation methodology

  1. test/generate_ww_vectors.py runs with the Python reference (sonopy, ovos-ww-plugin-precise-onnx) and writes exact float32 values to test/ww_vectors.json.
  2. test/wakeword.test.js loads the JSON and compares JS output against those values.
  3. MFCC coefficients use ATOL = 1e-3 to account for float32 truncation. Python stores np.float32, and intermediate calculations are float64 in both Python and JS.
  4. Probability/CDF comparisons use ATOL = 1e-6 or 1e-12 since those remain float64 throughout.

Test vectors (test/ww_vectors.json)

KeyContents
threshold_decodermin_out, max_out, out_range, center, cd_len, cd_first5, cd_last5, decode map
trigger_detectorcooldown, seq1 (fire pattern + activations), seq2, seq3
mfcc.zerosFrames for 4800-sample zero audio
mfcc.sine_440Frames for 6400-sample 440 Hz sine
mfcc.noise_seed42Frames for 6400-sample uniform noise (seed 42)
precise_propswindow_samples, hop_samples, buffer_samples, n_features, n_mfcc

← Wake word API · Home · AI usage →