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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

assert: add matchObjectStrict and matchObject #53415

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

synapse
Copy link

@synapse synapse commented Jun 11, 2024

fixes #50399

What is this PR doing:

  • Added 2 new assert functions matchObjectStrict & matchObject
  • Added tests to check different object types (Feel free to suggest more types to be tested)
  • Added a new section in the Assert documentation to explain the usage

The compareBranch (used by matchObject) works as follows:

  • matchObject recursively traverses the actual objects, Map, and Set and rely on deepEqual to compare its values (event across different realms) - N.B. array are directly compared using deepEqual and will not match if they are from different realms
  • if the value is a plain object then it will retrigger the compareBranch from that branch onward
  • else will compare the actual and expected values using the built-in isDeepEqual or isDeepStrictEqual based on the loose/strict param
  • it compares keys - (using Reflect.ownKeys() instead of Object.keys() to include symbol properties)
  • checks for recursive object values

@nodejs-github-bot nodejs-github-bot added assert Issues and PRs related to the assert subsystem. needs-ci PRs that need a full CI run. labels Jun 11, 2024
Copy link
Contributor

@aduh95 aduh95 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a lot of unrelated changes, making this hard to review. Consider removing those (maybe a problem with the configuration of your text editor?), and run the linters (NODE=node make test-doc -j and make lint-js).

test/parallel/test-assert-objects.js Outdated Show resolved Hide resolved
- `expected` {any}
- `message` {string|Error}

Tests strict equality between the `actual` and `expected` parameters.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's hardly what's happening, is it? At least I find the wording very confusing (I would expect the same behavior as strictEqual with the current wording), we should explain in more details what's happening here, what's being compared: is it only own properties? is the prototype important?

Comment on lines 2579 to 2580
- `actual` {any}
- `expected` {any}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it actually any? What happens if we pass a primitive?

Copy link
Author

@synapse synapse Jun 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's any because it compares the values (and the keys), which could be primitives. I'll add a couple of tests for primitives too.

doc/api/assert.md Outdated Show resolved Hide resolved
doc/api/assert.md Outdated Show resolved Hide resolved
@aduh95 aduh95 changed the title lib: Added assert.matchObjectStrict & assert.matchObject assert: add matchObjectStrict and matchObject Jun 11, 2024
doc/api/assert.md Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
@targos
Copy link
Member

targos commented Jun 11, 2024

@nodejs/assert

Copy link
Member

@panva panva left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to suggest more types to be tested.

Should't this fall back on assert.deepEqual and assert.deepStrictEqual respectively when dealing with anything but simple objects?

If I pass two different KeyObject or CryptoKey instances to matchObject, despite them being different cryptographic keys this doens't throw.

If it falled back on on assert.deepEqual and assert.deepStrictEqual then handling of those respective objects would be handled (#50897).

lib/internal/util/comparisons.js already has these already in

doc/api/assert.md Outdated Show resolved Hide resolved
@panva
Copy link
Member

panva commented Jun 11, 2024

Based on the docs I find it very confusing to discern between this and assert.deep(Strict)Equal. "Matching" suggests (to me at least) that the "expected" argument might be an object with more properties than "actual" but that's not what's documented nor implemented.

lib/assert.js Outdated Show resolved Hide resolved
@synapse
Copy link
Author

synapse commented Jun 11, 2024

Feel free to suggest more types to be tested.

Should't this fall back on assert.deepEqual and assert.deepStrictEqual respectively when dealing with anything but simple objects?

If I pass two different KeyObject or CryptoKey instances to matchObject, despite them being different cryptographic keys this doens't throw.

If it falled back on on assert.deepEqual and assert.deepStrictEqual then handling of those respective objects would be handled (#50897).

lib/internal/util/comparisons.js already has these already in

Should be handled now

lib/assert.js Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
doc/api/assert.md Outdated Show resolved Hide resolved
doc/api/assert.md Outdated Show resolved Hide resolved
@synapse synapse force-pushed the main branch 2 times, most recently from 9b2b89c to c7e9950 Compare June 13, 2024 14:18
doc/api/assert.md Outdated Show resolved Hide resolved
doc/api/assert.md Outdated Show resolved Hide resolved
doc/api/assert.md Outdated Show resolved Hide resolved
lib/assert.js Outdated Show resolved Hide resolved
@MoLow
Copy link
Member

MoLow commented Jun 14, 2024

please remove merge commit. changes generally LGTM, I think this is a great addition to node:assert

@Trott Trott added the commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. label Jun 16, 2024
@Trott Trott force-pushed the main branch 2 times, most recently from d977fd6 to 6921e96 Compare June 16, 2024 22:02
@Trott Trott added the semver-minor PRs that contain new features and should be released in the next minor version. label Jun 16, 2024
@Trott
Copy link
Member

Trott commented Jun 16, 2024

@nodejs/assert How sure are we that we want to add this? If it lands, should it be added as experimental for a while to give us the option to change it as we see fit for a while or even remove it entirely without waiting for a major release?

// OK

assert.matchObject({ a: 1, b: 2, c: 3 }, { a: 1, b: 2 });
// OK
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not convinced that this is sufficiently different from deepEqual and deepStrictEqual to warrant a new API. At the absolute least the documentation does not provide enough information for someone to be able to decide which to use

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jasnell If the expected object has fewer properties than the actual object, deepEqual will throw an error based on your example. On the other hand, matchObject will compare the existing properties and values in the expected object, allowing for a partial comparison.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I get that, I just do not think there's enough justification for a new api. A new option to the existing method could do the same.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was some conversation in the original issue about whether it should be:

  1. a new method, e.g. matchObject
  2. an option to the existing method, e.g. deepStrictEqual(..., { partial: tru })
  3. a utility function for the existing method, e.g. deepStrictEqual(..., objectContaining(...))

here @synapse decided to go with option 1, lacking a clear consensus on which option made the most sense

Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
assert Issues and PRs related to the assert subsystem. commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. needs-ci PRs that need a full CI run. semver-minor PRs that contain new features and should be released in the next minor version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Proposal: assert.matchObject
10 participants