Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature]: Allow extending functionality of toEqual #12880

Closed
stephenpassero opened this issue May 26, 2022 · 17 comments 路 Fixed by #13654
Closed

[Feature]: Allow extending functionality of toEqual #12880

stephenpassero opened this issue May 26, 2022 · 17 comments 路 Fixed by #13654

Comments

@stephenpassero
Copy link

stephenpassero commented May 26, 2022

馃殌 Feature Proposal

I'd really like the ability to extend the toEqual matcher. In my case, I would like to call .equals on each of my objects (if it exists), and otherwise resort to the default functionality. I saw this issue (#7351), but it kinda looked like it just stalled...

Motivation

I may have mentioned some of this above, but I want the ability to add extra functionality to the toEqual matcher, without rewriting the entire thing.

Example

// Test setup somewhere (very rough on implementation)
expect.equalityTester((objectA, objectB) => {
  // Do custom .equals checking, otherwise resort to default functionality
})
// In a test
it('correctly checks equality', () => {
  const measurement1 = new Measurement(1, 'ft')
  const measurement2 = new Measurement(12, 'in')

  expect(measurement1).toEqual(measurement2) // Should pass, currently doesn't
})

Pitch

This allows users to extend equality checks as necessary, without large changes

@ittays
Copy link

ittays commented May 31, 2022

Did you try using expect.extend() to implement something like expect(measurement1).toEqualMeasurement(measurement2)?

@stephenpassero
Copy link
Author

@ittays I could do that, but I'd much rather just be able to use toEqual everywhere, and not have to specifically think if I'm comparing a number for this expectation, but then a measurement in another one.

That's kinda the biggest reason I want this feature, to avoid having to use many different matchers based on what I'm trying to compare is equal

@ittays
Copy link

ittays commented May 31, 2022

Got you. So if you're able to specify your special equality, you can still define your catch-it-all toEqualEx() and use it blindly everywhere instead of toEqual.

@stephenpassero
Copy link
Author

Yeah, I'd basically like to be able to use toEqual everywhere still, but just tweak its logic

@stephenpassero
Copy link
Author

Any update/thoughts here?

@github-actions
Copy link

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added Stale and removed Stale labels Jul 15, 2022
@github-actions
Copy link

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the Stale label Aug 14, 2022
@stephenh
Copy link

stephenh commented Aug 20, 2022

We really need something like this because sometimes our connection pool ends up in an toEqual and it OOMs/blows up (specifically when a failed assertion tries to do a expected/actual diff and ends up in the very cyclic connection pool data structures).

I.e. an assertion like:

expect(book.authors).toEqual([a1]);

When it fails will try to "kind of toJSON-but-not-really" a1, end up crawling into the connection pool/various very cyclical data structures, and blow up.

We've made our own custom matcher that works around this, expect(...).toMatchEntity(a1), and that's fine, but this approach requires constantly fixing/changing assertions that looks like "they should just work" (toEqual([a1])) over to our non-buggy alternative.

Kind of funny, for us its only a problem when the assertion fails and Jest tries to do the nifty diff of expected/actual; if the assertion passes, everything is just fine. Which makes it even easier for users to not realize they "should not use toEqual here", b/c it will only blow up/OOME Jest during some future refactoring that happens to fail the expect.

@github-actions github-actions bot removed the Stale label Aug 20, 2022
@stephenpassero
Copy link
Author

@ittays 鈽濓笍 ?

@michkot
Copy link

michkot commented Sep 19, 2022

Got you. So if you're able to specify your special equality, you can still define your catch-it-all toEqualEx() and use it blindly everywhere instead of toEqual.

While this feature ask specifically for toEqual, I'd like to stress out this: #7352 (comment)
.extend does not solve a) code duplication if it should be applied to toEqual, toContainEqual, toEqualStrict, toMatchObject ... and all spyMatchers!

I am aware of a very burning use-cases for this = if you use (immutable) value-objects with non-trivial equality semantics (typically implemented using .compare / .equal functions, e.g. bignumber.js or some Temporals) are used a lot in the code under test.

Synthetic example:
const testDate = Temporal.Instant.from("2019-11-14T00:55:31.820Z")

expect(someMockedApi.calculateCorrectedDate)
.toHaveBeenCalledWith(testDate);

would work if you would register .equal-based equality tester in jest (qualified using instanceof, let's say)
Without it, all developers have to do something like this in all tests:

expect(someMockedApi.calculateCorrectedDate)
.toHaveBeenCalledWith({asymmetricMatch(val) { return testDate.equal(val);}});

@github-actions
Copy link

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the Stale label Oct 19, 2022
@michkot
Copy link

michkot commented Oct 20, 2022

@stephenpassero I have a rough and semi-working idea of how this could be solved using an enhancement. It allows you to register custom equality testers to the internal jasmine equal machinery. The tester first check for applicability (e.g. does object have equals function?) and if it's applicable it returns true/false, shortcircuit ing the default behavior.

This applies also to toHave... mock matchers

Downside is, my current version is crude and affects all tests, might be worth looking for help making it configurable even per-test or per test-file.

Would you be willing to provide some review / alfa testing of this?

@github-actions github-actions bot removed the Stale label Oct 20, 2022
@github-actions
Copy link

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days.

@andrewiggins
Copy link
Contributor

Hello 馃憢 I've opened #13654 in an attempt to address this issue. Let me know what you think! Cheers!

@github-actions github-actions bot removed the Stale label Dec 1, 2022
@michkot
Copy link

michkot commented Dec 2, 2022

Thanks a lot @andrewiggins, this uses the same approach I attempted for my experimental hack!

@github-actions
Copy link

github-actions bot commented Jan 1, 2023

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the Stale label Jan 1, 2023
@SimenB SimenB linked a pull request Jan 3, 2023 that will close this issue
4 tasks
@SimenB SimenB removed the Stale label Jan 3, 2023
@github-actions
Copy link

github-actions bot commented Feb 3, 2023

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 3, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants