-
Notifications
You must be signed in to change notification settings - Fork 16
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
Map equality issue #24
Comments
This case is actually a duplicate of #23. Your problem is not that key ordering matters with non-primitive parameters, but that you are changing the operator from |
I am not sure. Issue #23 is concerned with List. In my case it's about Map. I believe if you have a plain object in a Map, you cannot test equality with The last |
Oh my, you're right, it is related to the ordering, my bad: var map = new Map({
loaded: false,
message: {
firstName: 'john',
lastName: 'due'
},
working: true
});
// Passes
expect(map).to.eql(new Map({
loaded: false
message: {
firstName: 'john',
lastName: 'due'
},
working: true,
}));
// Fails
expect(map).to.eql(new Map({
message: {
firstName: 'john',
lastName: 'due'
},
working: true,
loaded: false
})); (Yes, it's what you have in example, but I am using this in the test file) I do not define |
Nop, as this passes: expect({
foo: 'bar',
one: 'two'
}).to.eql({
one: 'two',
foo: 'bar'
}); |
Got it. Here is the output when testing against this example: AssertionError: expected { Object (size, _root, ...) } to deeply equal { Object (size, _root, ...) }
+ expected - actual
"__ownerID": [undefined]
"_root": {
"entries": [
[
- "loaded"
- false
- ]
- [
"message"
{
"firstName": "john"
"lastName": "due"
[
"working"
true
]
+ [
+ "loaded"
+ false
+ ]
]
"ownerID": {}
}
"size": 3 It means that Immutable stores the key-value pairs in an array, as they are defined. When Anyway, I should probably using |
Well, that's a bummer. Chai uses var map1 = new Map({
foo: 'bar',
message: new Map({ bar: 'foo' })
});
// Prints `true`
console.log(map1.equals(new Map({
foo: 'bar',
message: new Map({ bar: 'foo' })
})));
var map2 = new Map({
foo: 'bar',
message: { bar: 'foo' })
});
// Prints `false`
console.log(map2.equals(new Map({
foo: 'bar',
message: { bar: 'foo' })
}))); Right now, your original example will fail because it uses On one hand, Really, I'm not sure how to fix this. I am open to ideas and suggestions (that would not make |
Great explanation. Thanks for your time. I am interested to see if some one has a solution for this. Alex |
Actually, I have two sort-of solutions, very similar in spirit. Nothing ideal though, but might be a start:
I can see many false positives on that (a |
I think that should work. It would be nice if you (or any adapters) could identify any false positive and come up with a solution to address the situation. Thanks! |
Hey @alexw668, I'll work on something as soon as I get some free time. Depending on how it goes, I'll probably add a caveat to the README if there are false positives that should be expected (if these are only those I listed, it can be easily predicted, and one can add an additional check to balance it; not the cleanest solution, but better than nothing, right?). In the meantime, that would be very helpful if you can list different cases you can think of as examples. By covering different sorts of inputs, I'll be able to feed the tests and make sure we do not ship any regressions if we can improve the selected solution over time. Thanks! |
Hi @astorije. Sorry for late response. Looking back at what I did in my immutable Map or List, I realized that it's not a good practice to mix mutable data (like plain object) within an immutable object, particularly based on the principal of Flux (or React Redux). So I made sure mutable data is mixed in my immutable object. By doing so, I think chai-immutable does a very good job. I don't ever use Because of this, I don't think you want or should to deal with various cases I mentioned or other developers may have. I think in your README, you could state that it's not a good idea to have mutable data contained in immutable object, and if a developer does not follow good practice, he/she would need to test things differently. What do you think about my statement here? Sorry for bringing this "issue" up; I should have followed the good practice at the first place. Thanks very much! |
So you think having arrays and objects in Lists and Maps is not a good practice? Where did you take that statement from, by curiosity? I don't know the principle of Flux, by the way. Your recommendation is to leave the code as is, right? Thanks! |
Yes, I read it on some one's blog. Also here is a review about the Flux pattern (Redux is an implementation of that pattern): https://facebook.github.io/flux/docs/overview.html. I believe you've heard of React.js, a Javascript library for building UI. It achieves lots of its goal with a virtual DOM; having a pure immutable state, it can quickly calculate the diffs between the virtual and actual DOM and renders things quickly. Having mutable objects in immutable Map and List will confuse the algorithm, as I've seen in our project. In other words, having mutable data in immutable object will turn that object mutable. |
This explains that immutable structures should only contain other immutable structures when used against `.equal()`, or the result is likely to be unexpected.
This is only true when inner elements are all immutable, but #24 shows up that it should always be the case anyway.
Both for TDD and BDD styles This explains that immutable structures should only contain other immutable structures when used against `.equal()`, or the result is likely to be unexpected.
This is only true when inner elements are all immutable, but #24 shows up that it should always be the case anyway.
Thanks for all these precisions, @alexw668. I have opened #25 with additions to the README and tests to to make sure our assumptions were true. Thanks for your help on this, @alexw668! |
@astorije I like what you changed in README. If I have any more suggestion, I would also add a reference to the case for Immutability which emphasizes that immutable data structures should be treated as values rather than objects. Thanks for your time and work! |
I'd rather leave that out for the following reasons:
Let me know if this seems reasonable and please give your 👍 to #25 or add any more comments. |
@alexw668, ping? |
I'll take your silence as a 👍 and will merge #25 then. I will release a minor version right after this and will also close this issue. Thanks for reporting this in the first place! |
Released in version 1.4.0, closing this. |
Thanks for your work! Sorry for not responding sooner because 1) I have been too busy at work, and 2) I thought I already endorsed your change. ;-) |
No worries, all good! And plenty to do on the latest issues now :-) |
This probably isn't the best place for this, but, it seems kind of related. I'm new to working with immutables so go easy on me. I noticed that in certain scenarios, like the example below, I get output from the tests that makes it really difficult to understand what's wrong. Am I using the library incorrectly or is this something that could be enhanced? it('does not give helpful test output?', () => {
const expected = Map({
entries: List.of('Trainspotting')
});
const actual = Map({
entries: List.of('28 Days Later')
});
expect(expected).to.eql(actual);
}); That test gives me the following output: AssertionError: expected { Object (size, _root, ...) } to equal { Object (size, _root, ...) } If I convert my immutables to regular JS objects, like below, I get output like what I was expecting: it('has helpful output with JS objects', () => {
const expected = Map({
entries: List.of('Trainspotting')
});
const actual = Map({
entries: List.of('28 Days Later')
});
expect(expected.toJS()).to.eql(actual.toJS());
}); Output: AssertionError: expected { entries: [ 'Trainspotting' ] } to deeply equal { entries: [ '28 Days Later' ] }
+ expected - actual
{
"entries": [
- "Trainspotting"
+ "28 Days Later"
]
} Again, sorry to crash this thread :) |
Anything new on this? |
@black-snow, about what specifically? Lots was said on this thread 😄 |
@astorije I've just got in a weird situation: var z = Record({a: []});
var a = new z({a: [1]});
var b = new z({a: [1]});
expect(Immutable.is(a, b)).to.be.true; // false Now I don't know if I can use |
So I've changed the code and it's working. I've switched from var z = Record({a: List()}); |
The inability to do deep comparisons of immutable objects that have data structures not from ImmutableJS along the way is problematic. I'm using TypeScript with class Foo {
readonly a: string;
readonly b: number;
readonly c: List<string>;
constructor(a: string, b: number, c: List<string>) {
this.a = a;
this.b = b;
this.c = c;
}
}
// this is a compiler error, because Foo is immutable
// new Foo("a", 1, List<string>()).a = 5;
const first = List<Foo>(new Foo("hello", 5, List<string>()));
const second = List<Foo>(new Foo("hello", 5, List<string>()));
expect(first).to.deep.equal(second); // fails So in this case, the code is sound as I am only using Immutable datastructures all the way down. However, I'm not using datastructures provided by the ImmutableJs library all the way down. Unfortunately |
Hi,
First of all, it appears (and it makes sense) that key order in an immutable Map with primitive fields does not matter, as illustrated by the following test:
However, if an immutable Map contains one or more key with plain object in it will cause equality to fail if the order of keys is different, as illustrated in the following test (notice I use
to.eql
, notto.equal
):The second
expect
fails.Is that an intended behavior or a bug in chai-immutable?
Thanks,
Alex
PS. I am using chai-immutable v. 1.3.0.
The text was updated successfully, but these errors were encountered: