Vitest doesn't snapshot `Error.cause` like Jest does

Open
#10,339 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
52/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Quiet
Tech stack
typescript
Domain
testing-qa

Research direction

Start by running the linked minimal reproduction and comparing Vitest 4 with Jest 30 for toThrowErrorMatchingInlineSnapshot. Read the @vitest/pretty-format Error plugin and the snapshot serializer entry points mentioned in the issue; done means Error.cause is captured by default without unnecessarily changing unrelated error snapshots.

Written by the indexing model from the issue text.

Description

breaking change p2-to-be-discussed pending triage
Describe the bug

Error.cause is now a standard ES feature.

Jest 30 implemented snapshot serialization of Error.cause: https://github.com/jestjs/jest/pull/13965

Vitest 4 doesn't serialize Error.cause by default, which IMHO should be considered as a bug and makes the migration from Jest to Vitest harder for me (https://github.com/facebook/docusaurus/pull/12010).

All modern tools and browser consoles now integrate with that new feature by default, so it would be great if Vitest did too.

When asserting errors and when we care about our project/framework DX, we often care about the full error chain, not just the top-level parent error.

Follow-up of discussion with @hi-ogawa here: https://github.com/vitest-dev/vitest/pull/10052#pullrequestreview-4274451482

Related request: https://github.com/vitest-dev/vitest/issues/5697#issuecomment-2453085114

Reproduction

Here's a minimal repro using Vitest 4 and Jest 30:

https://github.com/slorber/jest-vitest-snapshot-error-cause

Jest 30:

test('Hello World', () => {
  expect(() => throwError()).toThrowErrorMatchingInlineSnapshot(`
"my parent error
Cause: x is not defined"
`)
});

Vitest 4:

test('Hello World', () => {
  expect(() => throwError()).toThrowErrorMatchingInlineSnapshot(`[Error: my parent error]`)
});

Doing some research, I found out about a pretty-format Error plugin that could help:

import { plugins } from '@vitest/pretty-format'

expect.addSnapshotSerializer(plugins.Error)

test('Hello World', () => {
  expect(() => throwError()).toThrowErrorMatchingInlineSnapshot(`
    Error {
      "message": "my parent error",
      "cause": ReferenceError {
        "message": "x is not defined",
      },
    }
  `)
});

However, it was not so easy to find. It makes sense to do like Jest and serialize error causes by default, or at least provide clear documentation on how to officially achieve that, and eventually provide a top-level config option to make it easier.

Also note that this plugin significantly changes the snapshot format for errors, also serializing more things like error attributes, which may be a bit too verbose in some cases, and may reduce DX compared to what Jest currently offers natively.

In our case, we can't apply this plugin globally easily without increasing the size of many snapshots. For example, MDX parser and Joi validation errors contain a lot of attributes that we do not really need to snapshot.

Our best option is likely to create our own snapshot serializer, while I believe it should be something provided out of the box by Vitest.

Possible alternatives

It's possible to use matchers instead of snapshots: https://github.com/vitest-dev/vitest/issues/5697#issuecomment-2395624275

 test('timeout', async () => { 
   await expect(async () => { 
     await expect.poll(() => false, { timeout: 100, interval: 10 }).toBe(true) 
   }).rejects.toThrowError(expect.objectContaining({ 
     message: 'Matcher did not succeed in 100ms', 
     stack: expect.stringContaining('expect-poll.test.ts:38:68'), 
     cause: expect.objectContaining({ 
       message: 'expected false to be true // Object.is equality', 
     }), 
   })) 
 }) 

However, I find this less ergonomic. We do want to use snapshots on purpose, we just want to capture regressions in our error messages and freeze them, and do not want to maintain the error messages on both impl/test sides.

System Info
Vitest 4 / Jest 30
Used Package Manager

npm

Validations
Dominant language
TypeScript
Stars
17.1k
Forks
2k
Avg merge
1d 21h
Merged PRs (30d)
92

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from vitest-dev/vitest

All issues in vitest-dev/vitest

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.