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

Closed
wants to merge 1 commit into from

Conversation

synapse
Copy link
Contributor

@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
Contributor 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
Contributor 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
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
Contributor 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

Copy link
Contributor

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

I agree. I would love to see node:assert have a match function equivalent to https://github.com/tapjs/tapjs/blob/8f2baa7eb5e1f4cd0fcf8b60da4fb4e41ea680f1/docs/src/content/docs/api/asserts/index.md?plain=1#L318-L338

But the proposal here seems like a less consistent deepStrictEqual.

Comment on lines +2619 to +2620
present in the `actual` parameter with equivalent values, permitting type coercion
where necessary.
Copy link
Member

Choose a reason for hiding this comment

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

these seem flipped - the strict variant should not allow type coercion, and the loose variant should permit it.

@danielbayley
Copy link
Contributor

@synapse See #50399 (comment).

@simoneb
Copy link
Contributor

simoneb commented Sep 13, 2024

This PR can be closed as work on the linked issue is being done elsewhere.

@jsumners
Copy link
Contributor

This PR can be closed as work on the linked issue is being done elsewhere.

Where is that work happening?

@simoneb
Copy link
Contributor

simoneb commented Sep 23, 2024

This PR can be closed as work on the linked issue is being done elsewhere.

Where is that work happening?

#54630

@RedYetiDev RedYetiDev added the stalled Issues and PRs that are stalled. label Sep 23, 2024
Copy link
Contributor

This issue/PR was marked as stalled, it will be automatically closed in 30 days. If it should remain open, please leave a comment explaining why it should remain open.

@RedYetiDev
Copy link
Member

@synapse are you still interested in this PR, given that it is possibly superceded by #54630?

@synapse
Copy link
Contributor Author

synapse commented Sep 23, 2024

@synapse are you still interested in this PR, given that it is possibly superceded by #54630?

No, I will close this off

@synapse synapse closed this Sep 23, 2024
@jsumners
Copy link
Contributor

This PR can be closed as work on the linked issue is being done elsewhere.

Where is that work happening?

#54630

Thank you.

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. stalled Issues and PRs that are stalled.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Proposal: assert.matchObject