Skip to content

test: hexEqual accepts SkipCompare in TypeScript but rejects it at runtime #399

Description

@Kewe63

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions