# Testing signals — auth0/node-jsonwebtoken

> Canonical page: https://codevetter.com/unpack/jsonwebtoken/testing-signals

# Testing signals — auth0/node-jsonwebtoken

Scanned commit b924272f29192e12926b5414546f7c5bfcc9579d (2026-06-25). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Testing is the strongest part of the repo: ~258 `it()` blocks across 30 mocha files in `test/`, backed by chai assertions, sinon fake timers, and 17 checked-in PEM fixtures covering RSA, RSA-PSS, EC (three curves), DSA, and deliberately-invalid keys. The signature move is `test/test-utils.js`, which runs every sign/verify twice — once sync, once async — under a frozen clock and asserts the two produce byte-identical tokens or deep-equal errors; this is why the sync/async parity invariant actually holds. Coverage is configured with hard nyc thresholds, but the CI workflow runs bare `mocha`, so those thresholds and eslint are never enforced on PRs. Test naming is split between a per-claim convention (`claim-*.test.js`, `option-*.test.js`) and older topic/regression files (`*.tests.js`, `issue_*.tests.js`).
- The framework stack is mocha 5 + chai 4 + sinon 6, with `atob` used to independently decode base64url segments in encoding tests. There is no `.mocharc`, so mocha's default `./test/*.js` glob picks up every file in `test/`. — [package.json#L52-67](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/package.json#L52-L67) [test/encoding.tests.js#L3](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/encoding.tests.js#L3) [test/verify.tests.js#L5-9](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/verify.tests.js#L5-L9)
- `test/test-utils.js` exports `signJWTHelper` and `verifyJWTHelper`, both of which freeze time with `sinon.useFakeTimers({now: Date.now()})`, run the sync call in a try/catch, then run the async call and assert equality of token or error before restoring the clock. — [test/test-utils.js#L59-118](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/test-utils.js#L59-L118)
- `expectEqualError` exists because chai does not deep-equal errors (the helper cites chaijs/chai#1009); it compares `message` and `name` explicitly plus every enumerable property, which is how `expiredAt`/`date` payloads on the error subclasses get verified. — [test/test-utils.js#L27-37](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/test-utils.js#L27-L37)
- Option/claim validation is tested exhaustively by table-driven loops over ~15 bad values (`true, false, null, -1.1, Infinity, NaN, ' ', '', [], ['foo'], {}, {foo:'bar'}` …), applied per-claim in `claim-exp.test.js`, `header-kid.test.js`, and siblings. — [test/claim-exp.test.js#L19-45](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/claim-exp.test.js#L19-L45) [test/header-kid.test.js#L18-40](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/header-kid.test.js#L18-L40)
- `test/claim-aud.test.js` is the largest test file at 436 lines and 36 `it()` blocks, reflecting that audience matching (string/regex/array cross-product) is the most branch-heavy claim check. — [test/claim-aud.test.js](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/claim-aud.test.js) [verify.js#L194-207](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L194-L207)
- `test/jwt.asymmetric_signing.tests.js` is parameterized: it builds an `algorithms` map of RS256/ES256 (plus PS256 when `PS_SUPPORTED`) each with `pub_key`, `priv_key`, and an `invalid_pub_key` that is deliberately not the pair of `priv_key`, then runs the same describe block per algorithm. — [test/jwt.asymmetric_signing.tests.js#L13-46](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/jwt.asymmetric_signing.tests.js#L13-L46)
- Security regressions are explicitly locked in by `test/jwt.malicious.tests.js`: HMAC-with-RSA-key confusion (both KeyObject and PEM form) and the malicious-`toString` Buffer-impersonation RCE vector. — [test/jwt.malicious.tests.js#L21-38](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/jwt.malicious.tests.js#L21-L38)
- Historical bugs are pinned by dedicated regression files: `issue_70.tests.js` (PEM headers), `issue_147.tests.js` (signing an `Object.seal`ed payload), `issue_304.tests.js`, and `rsa-public-key.tests.js`. — [test/issue_70.tests.js#L1-15](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/issue_70.tests.js#L1-L15) [test/issue_147.tests.js#L6-11](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/issue_147.tests.js#L6-L11) [test/issue_304.tests.js](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/issue_304.tests.js) [test/rsa-public-key.tests.js](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/rsa-public-key.tests.js)
- `test/validateAsymmetricKey.tests.js` unit-tests the key-matrix module directly (not through sign/verify), including the no-key and no-algorithm short-circuit paths and the PS/curve branches gated on the feature-detection booleans. — [test/validateAsymmetricKey.tests.js#L1-50](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/validateAsymmetricKey.tests.js#L1-L50) [lib/validateAsymmetricKey.js#L16-21](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/lib/validateAsymmetricKey.js#L16-L21)
- nyc is configured with `check-coverage: true` and thresholds of 95% lines, 95% statements, 100% functions, 95% branches, excluding `./test/**` — a genuinely strict bar. — [package.json#L6-20](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/package.json#L6-L20)
- GAP: `test.yml` runs only `npm test` (bare mocha). Neither `npm run coverage` nor `npm run lint` appears in any workflow, so the nyc thresholds and the eslint ruleset are advisory only and can silently regress. — [.github/workflows/test.yml#L31-38](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/.github/workflows/test.yml#L31-L38) [package.json#L21-27](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/package.json#L21-L27)
- A known-broken case is parked rather than fixed: `it.skip('should work with none algorithm where secret is falsy')` in async_sign, annotated with a link to node-jws issue #62 — the async `alg: none` path with a falsy secret is untested and known not to work. — [test/async_sign.tests.js#L45-52](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/async_sign.tests.js#L45-L52)
- A coverage hole is deliberately carved out with `/* istanbul ignore next */` around the entire `ASYMMETRIC_KEY_DETAILS_SUPPORTED` block in validateAsymmetricKey, with a comment explaining it would otherwise sink coverage on Node < 15.7.0 — meaning EC curve matching and RSA-PSS parameter checks are excluded from the coverage numbers. — [lib/validateAsymmetricKey.js#L32-65](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/lib/validateAsymmetricKey.js#L32-L65)
- Test fixtures include intentionally-bad keys used as negative cases: `invalid_pub.pem`, `ecdsa-public-invalid.pem`, `rsa-pss-invalid-salt-length-private.pem`, and `dsa-public.pem` (to assert `Unknown key type "dsa".`). — [test/verify.tests.js#L272-282](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/verify.tests.js#L272-L282) [lib/validateAsymmetricKey.js#L24-26](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/lib/validateAsymmetricKey.js#L24-L26)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
