Skip to content

ExpectationResult of a custom asymmetric matcher is ignored #7730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
6 tasks done
kettanaito opened this issue Mar 24, 2025 · 5 comments
Open
6 tasks done

ExpectationResult of a custom asymmetric matcher is ignored #7730

kettanaito opened this issue Mar 24, 2025 · 5 comments

Comments

@kettanaito
Copy link
Contributor

kettanaito commented Mar 24, 2025

Describe the bug

When I have a custom asymmetric matcher, Vitest applies it correctly but disregards the matcher's ExpectationResult properties like message, actual, and expected if the matcher fails. I expect the inverse assertions (.not) to have the same problem.

Reproduction

Here's a sandbox: https://stackblitz.com/edit/vitest-dev-vitest-je43znvc?file=vite.config.ts,vitest.setup.ts,test%2Fbasic.test.ts&initialPath=__vitest__/

System Info

Irrelevant.

Used Package Manager

npm

Validations

@kettanaito
Copy link
Contributor Author

kettanaito commented Mar 24, 2025

It looks like Vitest is performing the pass check correctly but instead of printing the message from the matcher (and other options in the expectation result), it falls back to the default equality reporting:

Actual

AssertionError: expected { state: 'mediocre' } to deeply equal { state: toBeGorgeous<> }

- Expected
+ Received

  {
-   "state": toBeGorgeous<>,
+   "state": "mediocre",
  }

This equality is effectively useless because it compares the actual value with the asymmetric matcher itself. Instead, it should print what I'm specifying in the message of my expectation result.

Expected

Error: Is not gorgeous
 ❯ eval test/basic.test.ts:7:22
      5|    * @note how the failure is reported here.
      6|    */
      7|   expect('mediocre').toBeGorgeous();
       |                      ^
      8| });

@sheremet-va
Copy link
Member

it falls back to the default equality reporting:

It does not fallback to the equality reporting, it performs equality reporting. You are calling expect().toEqual after all, not expect().toBeGorgeous.

I agree that the message can be improved, but as far as I understand this is not a bug.

@hi-ogawa
Copy link
Contributor

What kind of improvement do you suggest? Current scheme doesn't look too bad since it allows things like:

{
- "value": toSatisfy<[Function isOdd]>,
+ "value": 2,
}",

{
- "name": toBeOneOf<Array [
- "apple",
- "banana",
- "orange",
- ]>,
+ "name": "mango",
}",

@kettanaito
Copy link
Contributor Author

@sheremet-va, you're right. My focus here is not in the behavior but in how the expectation result is being printed.

@hi-ogawa, I suggest that if the currently applied matcher is a custom matcher, always use its message (and other properties like actual, if applicable) when reporting the matching result. Basically, as I stated above, I expect the same behavior as when I use

expect(b).toBeGorgeous()

Given the asymmetric nature of the matcher, which likely implies it's being nested somewhere in the actual data structure, the output for this particular case may be appended with the place where the matcher errors. But performing diff as it is right now makes little sense as it always compares the actual value with the matcher, and that brings me no value as a developer.

@hi-ogawa
Copy link
Contributor

Basically, as I stated above, I expect the same behavior as when I use expect(b).toBeGorgeous()

I'm not sure if that approach makes sense in a general, for example when there is multiple asymmetric matcher involved. https://stackblitz.com/edit/vitest-dev-vitest-gp95rpax?file=test%2Fbasic.test.ts

  expect({ x: 'mediocre', y: 'gorgeous' }).toEqual({
    x: expect.toBeGorgeous(),
    y: expect.not.toBeGorgeous()
  });
- Expected
+ Received

  {
-   "x": toBeGorgeous<>,
-   "y": not.toBeGorgeous<>,
+   "x": "mediocre",
+   "y": "gorgeous",
  }

Btw, can you explain an actual use case? I appreciate the minimal repro, but simplified "gorgeous" example can make it less convincing about the change you're suggesting.

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

No branches or pull requests

3 participants