-
Notifications
You must be signed in to change notification settings - Fork 30k
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.deepEqual()
report difference between promises during test
#55198
Comments
I've preemptively added the
known limitation
|
CC @nodejs/test_runner |
FWIW import assert from 'node:assert';
const a = Promise.resolve('foo');
const b = Promise.resolve('bar');
assert.deepStrictEqual(a, b); Also doesn't report anything so maybe that's a seperate bug 🤔 |
Fixing this will require refactoring https://github.com/nodejs/node/blob/main/lib/internal/test_runner/harness.js to remove async_hooks (which should probably be done anyway). Commenting out this line fixes the issue. |
This isn't specific to the test runner, though: import assert from 'node:assert';
import asyncHooks from 'async_hooks';
const hook = asyncHooks.createHook({ promiseResolve() {} });
hook.enable();
const a = Promise.resolve('foo');
const b = Promise.resolve('bar');
assert.deepStrictEqual(a, b);
|
We use symbols, when we want to have something internal. Enumerable symbol properties are however always compared by assert.deepStrictEqual. I personally would like to mark them as non-enumerable or use actual private properties. That way the internals would not be compared anymore. |
I was hoping we could migrate to 'use strict';
const { AsyncLocalStorage } = require('node:async_hooks');
const { deepEqual } = require('node:assert/strict');
const asyncLocalStorage = new AsyncLocalStorage();
asyncLocalStorage.run({}, () => {
deepEqual(Promise.resolve('foo'), Promise.resolve('foo'));
}); |
The issue goes away with |
Folks. Quick question. Is there anything to assert promises? Something like this maybe? This comment shows an example that reports nothing because it is unable to compare the values held in Promises i.e. When inside of Ref: https://github.com/nodejs/node/blob/main/lib/internal/util/comparisons.js#L361-L366 'use strict';
import assert from 'node:assert';
import { test } from 'node:test';
test(() => {
const a = Promise.resolve('foo');
const b = Promise.resolve('bar');
const symbols = Object.getOwnPropertySymbols(a);
symbols.forEach((s) => {
Object.defineProperty(a, s, {
enumerable: false
});
Object.defineProperty(b, s, {
enumerable: false
});
});
assert.deepStrictEqual(a, b); // reports nothing
}); I hope it makes sense. |
It is actually not possible to look into a Promise value with JavaScript alone without using then / await. To achieve that during inspection, we use a V8 API. For me, it is questionable, if we would want to compare promises. It could end up with flaky tests in case a promise is sometimes already settled and sometimes still pending. That can only be resolved by awaiting the promise result and if that is already the case, the value itself can easily be compared instead of the promise. Thus, two things come to my mind:
|
I prefer assert to support promises. In my unit tests, I check the arguments of a function. So I compare a promise in an array: assert.deepEqual(listener.mock.calls[0].arguments, [
Promise.resolve("two_four_five"),
{
prop: "quux",
args: ["four", "five"],
metadata: {},
},
]); If the promises are removed, I'd have to make an assert for the promise and asserts for every other element in the array: assert.equal(listener.mock.calls[0].arguments.length, 2);
assert.equal(await listener.mock.calls[0].arguments[0], "two_four_five");
assert.deepEqual(listener.mock.calls[0].arguments[1], {
prop: "quux",
args: ["four", "five"],
metadata: {},
}); |
@regseb your "work around" is indeed the way to go. Everything else would also potentially cause race conditions in your test, as I tried to outline above. |
I think For |
I would consider two promises to be deep equal only if they are equal. |
@mcollina are two pending promises equal? I would not consider them equal. It is natively also not possible to compare a settled promise value in an synchronous way without internal V8 methods. The only real solution for this is to wait for the promise result. |
I meant that two promises are only equal if they are the same promise. |
Version
v22.9.0
Platform
Subsystem
Ubuntu 24.04.1 LTS
What steps will reproduce the bug?
test.mjs
node --test test.mjs
How often does it reproduce? Is there a required condition?
Always.
What is the expected behavior? Why is that the expected behavior?
The
assert.deepEqual()
doesn't report difference between the two identical promises.What do you see instead?
The
assert.deepEqual()
find difference between the two identical promises.Additional information
The problem only occurs in#55198 (comment)test
.index.mjs
node index.mjs
assert.deepEqual()
doesn't report difference between the two identical promises. 👍The text was updated successfully, but these errors were encountered: