Skip to content

toEqual failure message truncation#26

Open
themattspiral wants to merge 5 commits into
mainfrom
to-equal-formatting
Open

toEqual failure message truncation#26
themattspiral wants to merge 5 commits into
mainfrom
to-equal-formatting

Conversation

@themattspiral
Copy link
Copy Markdown
Owner

@themattspiral themattspiral commented May 21, 2026

  • Rework toEqual failure output:
    • short-form (inline) line is character-budgeted and emits …(N) truncation markers at element/field boundaries (Addresses the "Stringified user objects are printed fully, and never truncated currently, which may result in unwieldy error messages" known issue from Deep Equality Matching #23)
    • multi-line diff body matches vitest pretty-format's 2-space nested indentation and is never truncated
  • Bundle error-handling improvements to surface stack traces for crashes that previously became unhandled rejections
  • Meta suite config fix so coverage-table assertions work when vitest is run inside an AI-agent environment

Also bundles error handling changes with the truncation work to surface stack traces for crashes that previously became unhandled rejections.

Rework AS-side stringification so the `toEqual` diff body matches vitest
pretty-format's nested 2-space indentation. The short-form "expected X
to deeply equal Y" message remains single-line.
- New `escapeToDiffString` matches pretty-format's `escapeString: true`
  default (escapes only `"` and `\`; raw newlines/tabs/controls pass
  through, so diff lines break naturally as vitest renders them).
- `depth: i32` threaded through `stringifyValue`, the global stringify
  bridge, and the transform-injected `__vitest_assemblyscript_stringify`
  method so each nesting level adds 2 spaces of indent
- `arrayMessageString` / `setMessageString` / `mapMessageString` now
  propagate `formatForDiff` and `depth`
- `assertComparison` stringifies actual/expected separately for the
  short inline message vs the full diff body

Also restores 100%-covered coverage-table rows when the meta suite is
run via an AI-agent tool. Vitest now forces `skipFull: true` when it
detects an agent environment (CLAUDECODE, CURSOR_AGENT, etc.), which had
been hiding rows like `partial-all-covered.meta.ts` and breaking
meta-verify's coverage assertions for any agent-driven run.
- Add explicit `skipFull: false` to the text reporter for meta suite
When the inline `expected X to deeply equal Y` line of a toEqual failure
would render large or deeply nested values past a fixed character
budget, container and user-object stringification now emit `…(N)`
markers at element/field boundaries (matching chai/loupe/vitest output).
The multi-line diff body below the inline line remains untruncated.

- `STRINGIFY_SHORT_FORM_BUDGET = 40` (matches chai's
  `config.truncateThreshold` default); diff form passes
  budget=-1 (unlimited)
- New @inline @global `exceedsBudget` predicate centralizes overflow
  arithmetic for both container helpers and the transform-injected body
- New `truncateStringContent` truncates string vals with a trailing `…`
  inside the quotes (surrogate-pair-aware)
- `stringifyValue`, `arrayMessageString`, `setMessageString`,
  `mapMessageString`, the `__vitest_assemblyscript_stringify_value`
  bridge, and the transform-injected `__vitest_assemblyscript_stringify`
  method all thread a `budget: i32 = -1` argument
- Map entry budget split: key gets the entry budget; value gets the
  remainder after subtracting key length + ` => ` (loupe parity)
- Super-class chain rendered as an atomic single piece (called with
  budget=-1 so super produces full output, then accepted-whole or
  rejected-whole at this level) — at most one truncation marker per
  nesting level
- Container helpers and the transform-generated body switched from `+`
  chains to template literal style: multi-piece template literals lower
  to a single `StaticArray<string>#join("")` allocation in AS, vs one
  intermediate string allocation per `+` operator
- Workaround for an AS @VarArgs quirk: subclass `super.method(...)`
  calls that omit default args route through the base's @VarArgs
  trampoline, which then virtually dispatches on `this` and resolves
  back to the subclass override, causing infinite recursion. Super calls
  now pass every argument explicitly.

Also bundles error-handling improvements to surface stack traces for
crashes that previously became unhandled rejections:
- `runSuite` wraps its work in try/catch/finally: uncaught errors inside
  suite execution (internal pool faults, unexpected runtime state) are
  converted to a `WASMExecutionHarnessError` PoolError, the file is
  marked failed via `failFile`, and the failure is reported via
  `reportFileError`. Previously these escaped as unhandled rejections.
  The finally block also flushes RPC unconditionally.
- `executeWASMTest` reroutes unexpected (non-`WASMExecutionAbortError`)
  errors that carry an actual `Error` instance to now call `failTest`.
  This is the same path the abort() import takes, so the test's meta
  gets the error + raw call stack, and the existing `enhanceTestError`
  step source-maps the frames like any other failure. Net effect: a
  stack overflow or other V8-thrown runtime error fails only that test
  (with AS source frames) instead of failing the whole file. Errors
  without usable `Error` info still fall through to file-level failure.
- `wasm-errors.ts` `processWASMErrorStack` adds a passthrough fallback:
  when every frame in the raw stack failed to source-map (mapped stack
  is empty), it preserves the raw frames (function name + file/line/
  column) so the user still gets a stack trace instead of nothing.
- `enhanceTestError`'s `diff` assembly is also hardened to tolerate
  null primary-frame / source-code strings (previously they'd render
  as the literal `null`) and to suppress connector newlines when an
  adjacent piece is missing
@themattspiral themattspiral self-assigned this May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant