Summary
The TypeScript declaration for the custom hexEqual Chai matcher accepts SkipCompare, but the registered runtime implementation rejects the same value as invalid hexadecimal input.
This creates a deterministic mismatch between the test-helper contract and its runtime behavior.
Tested against commit: 3f1efe99bf129b16c276ae5b44b7a35247ffe5c5
Environment: Node.js v22.22.2, clean checkout, npm ci
Reproduction
Create tests/helpers/matchers/skipCompare.repro.test.ts:
/// <reference path="./types.d.ts" />
import { expect } from 'chai'
import './plugin'
import { skipCompare } from './skippable'
describe('hexEqual SkipCompare contract', () => {
it('accepts SkipCompare as declared by the TypeScript signature', () => {
expect(() => expect('0x12').to.hexEqual(skipCompare)).not.to.throw()
})
})
Run:
node node_modules/mocha/bin/mocha.js \
--require ts-node/register/transpile-only \
tests/helpers/matchers/skipCompare.repro.test.ts
Observed result:
0 passing
1 failing
AssertionError: expected [Function] to not throw an error but
'AssertionError: Expected "0x12" to be a hex string equal to
"[object Object]", but "[object Object]" is not a valid hex string'
was thrown
An isolated TypeScript check accepts the call without errors. As a control, the standard skippable comparison succeeds at runtime:
expect('0x12').to.eq(skipCompare)
Expected behavior
Either:
hexEqual(skipCompare) skips the comparison as declared; or
SkipCompare is removed from the TypeScript signature if the behavior is intentionally unsupported.
Actual behavior
tests/helpers/matchers/types.d.ts accepts SkipCompare, but supportHexEqual() passes it to isHex(). Because the marker is an object, the matcher throws before comparison.
Root cause
The declaration includes the marker:
hexEqual(other: `0x${string}` | SkipCompare, message?: string): void
The runtime implementation validates both operands as hex strings without first checking isSkipCompare(other).
The generic supportSkippable() plugin only overwrites built-in comparison methods and does not wrap the custom hexEqual method.
Impact
This is a test-helper correctness defect, not a production or security vulnerability.
Callers following the TypeScript contract can write valid, compiling tests that fail deterministically at runtime. This makes partial expected-value structures using skipCompare unreliable when passed to hexEqual.
Suggested fix
If skip semantics are intended, handle SkipCompare before hexadecimal validation and add a regression test for:
expect('0x12').to.hexEqual(skipCompare)
Otherwise, remove SkipCompare from the declared hexEqual parameter type.
Duplicate check
I searched open and closed issues and pull requests using the affected symbol, marker type, file paths, error text, and behavior. I also inspected pull-request refs that touched the matcher files. No matching report or implementation was found.
#369 concerns the separate problem that the Hardhat unit-test suite is not executed by CI; it does not cover this runtime contract mismatch.
Summary
The TypeScript declaration for the custom
hexEqualChai matcher acceptsSkipCompare, but the registered runtime implementation rejects the same value as invalid hexadecimal input.This creates a deterministic mismatch between the test-helper contract and its runtime behavior.
Tested against commit:
3f1efe99bf129b16c276ae5b44b7a35247ffe5c5Environment: Node.js
v22.22.2, clean checkout,npm ciReproduction
Create
tests/helpers/matchers/skipCompare.repro.test.ts:Run:
Observed result:
An isolated TypeScript check accepts the call without errors. As a control, the standard skippable comparison succeeds at runtime:
Expected behavior
Either:
hexEqual(skipCompare)skips the comparison as declared; orSkipCompareis removed from the TypeScript signature if the behavior is intentionally unsupported.Actual behavior
tests/helpers/matchers/types.d.tsacceptsSkipCompare, butsupportHexEqual()passes it toisHex(). Because the marker is an object, the matcher throws before comparison.Root cause
The declaration includes the marker:
The runtime implementation validates both operands as hex strings without first checking
isSkipCompare(other).The generic
supportSkippable()plugin only overwrites built-in comparison methods and does not wrap the customhexEqualmethod.Impact
This is a test-helper correctness defect, not a production or security vulnerability.
Callers following the TypeScript contract can write valid, compiling tests that fail deterministically at runtime. This makes partial expected-value structures using
skipCompareunreliable when passed tohexEqual.Suggested fix
If skip semantics are intended, handle
SkipComparebefore hexadecimal validation and add a regression test for:Otherwise, remove
SkipComparefrom the declaredhexEqualparameter type.Duplicate check
I searched open and closed issues and pull requests using the affected symbol, marker type, file paths, error text, and behavior. I also inspected pull-request refs that touched the matcher files. No matching report or implementation was found.
#369 concerns the separate problem that the Hardhat unit-test suite is not executed by CI; it does not cover this runtime contract mismatch.