Pass typing information for equality through Error.equal().#440
Pass typing information for equality through Error.equal().#440alexjeffburke wants to merge 1 commit intounexpectedjs:masterfrom alexjeffburke:fix/enumerablePropertyEdgeCaseInToEqual
Conversation
| equalityTypes = equalityTypes || { | ||
| aType: this, | ||
| bType: this | ||
| }; |
There was a problem hiding this comment.
This seems like the wrong place to default these values, couldn't this be handled by the caller.
There was a problem hiding this comment.
@sunesimonsen I definitely agree, but in this case I was very concerned there might be external plugins that have made assumptions that would cause calling .equal() to break. That said, it may well be that all the places that set these values are actually in core (I confess it's been a little tricky to follow all the calls to equality).
There was a problem hiding this comment.
I think the equal calls on the types will always be called by core only, but I could be mistaken.
|
Could you try to explain the problem and the solution presented here. The current version of equal, takes two values of type T1 and T2, then a common super type and use that for equality. If you call equal from within the method, this process if repeated. That seems like pretty reasonable implementation, so I would like to know how this is different. |
|
@sunesimonsen The issue is that the Error type defers to it's baseType .equal() method. Once inside the baseType (in this case object), keys are retrieved using the object type What I believe needs to happen is that the base object equality still needs to use the specific types of |
|
Yes, was just about to say that I see the problem caused by the call the base type and the taped on |
|
I'll try to think about it, this PR touches a pretty fundamental part of Unexpected, so we should watch out for introducing even more complexity. |
|
@sunesimonsen yep :-) and absolutely - please consider this a suggestion. There was an alternative I considered, which would be to carve out all the equality code into a method on utils (so that would include the identity check, key fetching, length check etc) - that method would also take the |
|
This problem also affects the |
|
Looks like the same error happened with node 9 here: https://travis-ci.org/unexpectedjs/unexpected-http/jobs/357654632#L1736 |
|
@papandreou It's definitely a general thing - from what I've observed, version of node >=9.7.0 seem to attach certain error messages "after the fact" which makes them enumerable. I have a half written bug report that I intend to send over to them, but in the meantime my inclination would be that it's important to protect against this in core. The attempt represented by this PR is one option, but I understand the concern around it - another option I floated earlier in the thread was to avoid the call into the super-type for the Error types by carving out object equality into a util method, something like objectsEqualByType method, and calling that explicitly. This would at least allow fixing the Error case. |
|
The case I'm outlining should be fixed by removing the length check here, right? Let's add a test like this and see if we can beat it into shape: describe('with objects that differ only in the enumerability of keys', function () {
it('should succeed when the lhs object has a non-enumerable key', function () {
var a = { a: 123 };
var b = { a: 123, b: 456 };
Object.defineProperty(a, 'b', {
value: 456,
enumerable: false
});
expect(a, 'to equal', b);
});
it('should succeed when the rhs object has a non-enumerable key', function () {
var a = { a: 123, b: 456 };
var b = { a: 123 };
Object.defineProperty(b, 'b', {
value: 456,
enumerable: false
});
expect(a, 'to equal', b);
});
}); |
|
@papandreou with the object type hooks stuff done I'll look at picking this up again. Even if this is fixed by node (which it should have been but somehow it missed the last v9), I think it's worth hardening this. I've had an idea rattling about how to do this more cleanly, will move this back up "the list". |
|
@alexjeffburke, great to hear that! |
Add a new findAllTypesOf() utility function that returns all the type information required for .equal(). Arrange for this to be passed into the .equal() method. Pass it through the overridden Error type equality method but ensure that in the absence of specific hints the type objects are defaulted to the current type itself which ensures backwards compatibility. This commit also removes a number of bind() calls from definitions attached within createWrappedExpectProto because the base methods are defined using arrow functions thus fixing this is not required.
| }); | ||
| }); | ||
|
|
||
| describe('when comparing error with differeing enumarable keys', () => { |
|
The attempted fix here is superseded by the comprehensive enumerable property support in #482. Closing this PR. |
This branch attempts to address #439 by passing typing information through to the underlying baseType
.equal()call. There is likely a concern around the performance of adding type evaluation within the base equality method given how many places defer to it hence this approach was chosen to minimise the impact.