Open
Description
Tell us about your runtime:
- QUnit version: 2.7.1
- What environment are you running QUnit in? (e.g., browser, Node): Browser
- How are you running QUnit? (e.g., script, testem, Grunt): Script
What are you trying to do?
Code that reproduces the problem:
https://jsfiddle.net/bzomqak8/11/
class Foo {
constructor(a = 1) {
this.a = a;
}
}
Object.defineProperty(Foo.prototype, 'b', {
enumerable: true,
get() {
return new Foo(this.a + 1);
}
})
QUnit.test("hello test", function(assert) {
assert.deepEqual(new Foo(), new Foo());
});
If you have any relevant configuration information, please include that here:
What did you expect to happen?
I expected QUnit to not compare computed properties.
What actually happened?
QUnit compares computed properties by using a for..in
loop which (due to BFS) recurses infinitely without ever hitting a stack limit.
This is a minimal reproduction extracted from one of our Ember apps. In the actual app we use an Ember.Object
and a computed
property instead of the code above, but the effect is the same.
Activity
rwjblue commentedon Oct 24, 2018
Should be fixed by #1326.
[-]deepEqual goes into infinite recursion[/-][+]deepEqual should not infinitely recurse a getter-based lazy infinite chain[/+][-]deepEqual should not infinitely recurse a getter-based lazy infinite chain[/-][+]deepEqual should not infinitely recurse an infinite lazy getter chain[/+]Krinkle commentedon Jun 27, 2020
Per #1326, I don't think is is feasible for QUnit to solve the problem of predicting whether infinite getter chains will be considered equivalent by some definition. @gibson042 pointed there to #1327, and indeed an QUnit assertion plugin could work here.
Having said that, I do think that this ticket still represents a bug we should solve. Namely that QUnit should not infinitely recurse or timeout without some meaningful feedback.
Two ideas come to mind, not mutually exclusive:
Krinkle commentedon Sep 19, 2021
For comparison to Node.js, the following passes on Node.js 10 and Node.js 16:
Tests: Add coverage for basic "getter" behaviour in status quo
gibson042 commentedon Sep 20, 2021
Sure, but Node.js
assert.deepEqual
also ignores prototypes (among many other differences between it and QUnit). They also document comparison details, although this particular detail seems to be absent. But regardless, I guess adding an operational theory to our documentation would be the first step for addressing both this and #1327.Krinkle commentedon Mar 3, 2024
Counter-example, unaffected by the lack of prototype comparison in Node.js' assert module:
Ostensibly equal (non-random):
Ostensibly non-equal (random):