-
-
Notifications
You must be signed in to change notification settings - Fork 35
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
Phrasing of the 'keys' function is misleading #6
Comments
Hey, First off, sorry that this caused confusion! The reasoning behind it was to be as strict as possible by default on all matchers. False negatives in testing are less harming than a false positives. In this case it meant asserting that only the listed keys are found and none else. The case of confirming a subset of keys could then be handled with the existing obj.must.have.property("a")
obj.must.have.property("b")
obj.must.have.ownProperty("c") It is a tad longer, but I don't yet have input of how common testing for a subset of key names is to know if this is a problem. What do you think? Oh, and last, to have less surprises when migrating away from Should.js and Chai.js. :) |
Hello, and sorry for the late reply. Your reason to name those functions the way they are name is clear. Let me explain my case. The coding principle I use is to create object using factories, not constructors. What do you think of adding new must-js functions, for example: |
Or
What do you think? |
Thanks for your thoughts! I'll sleep on this a little and get back to you. The |
That confuses. First you say that "to have less surprises when migrating away from Should.js and Chai.js". I thought that is something important. So.
|
Aah, my bad for not elaborating what I meant. So, less surprises when migrating is something I value, but that goes for things that are good design choices. Making better design decisions trumps any API compatibility. That was one of the reasons I started Must.js — to simplify and not make it as complex as others are. I now realize my example of the |
I see. You think the syntax of I can clearly see from the code what the Any plans on adding other matchers? |
Definitely plan to add others. :) Just to double check, do I understand correctly that the decision you consider a bad one is that the Also, thanks for caring! |
Yeah, the first one. I thought "keys" matcher is a subset matcher. (See Thanks for listening!
|
Okay, last attempt. Let's enhance obj.must.contain(['a', 'b', 'c', 'd', 'e', 'f']); Untested sample code of must-js exports.include = function(expected) {
var found;
if (Array.isArray(expected)) { // New code starts here
found = true;
for (var i = 0; i < expected.length; i++) {
var expectedKey = expected[i];
if (!this.actual[expectedKey]) { found = false; break }
}
} // New code ends here
else if (Array.isArray(this.actual) || kindof(this.actual) == "string")
found = ~this.actual.indexOf(expected)
else
for (var key in this.actual)
if (this.actual[key] === expected) { found = true; break }
insist.call(this, found, "include", expected)
} However, now my implementation checks both value(s) (when used with a single argument), and keys (when array is passed in). This can be also a confusion. Mate, I really do not understand why the original must-js assertion function obj.must.have.values(valueHere) so that it looks like existing: obj.must.have.keys(keyHere) |
I have edited the previous comment about dozen times. :) Sorry. |
I had been similarly confused while reading over the api for // Check that specific keys exist
expect(x).to.have.properties(['k1', 'k2']);
// Check that specific key/value pairs exist and match
expect(x).to.have.properties({
k1: 'v1',
k2: 2
}); |
I tried to match your coding style for a temporary implementation. I would submit as a pull request, but don't currently have the time to write unit tests unfortunately (and I'm not sure you'd want to go this route), but here's what I'm using in the meantime. /**
* Assert that an object has proprties `properties`.
* Optionally assert they *equals* (`===`) to `value`.
*
* @example
* ({life: 42, love: 69, liberty: 500}).must.have.properties(['life', 'love'])
* ({life: 42, love: 69, liberty: 500}).must.have.properties({life: 42, love: 69})
*
* @method properties
* @param properties
*/
exports.properties = function(properties) {
var ok = true;
if (Array.isArray(properties)) {
var missing = [];
for (var i = 0; i < properties.length; i++) {
if (properties[i] in Object(this.actual) === false)
missing.push(properties[i])
}
ok = missing.length === 0
}
else {
var missing = {};
for (var key in properties)
if (this.actual[key] !== properties[key]) {
missing[key] = properties[key]
ok = false;
}
}
insist.call(this, ok, "have properties", missing)
} |
It's very good the must-js did not inherit the property assertion problems of Chai and Should. However must-js inherited their somewhat misleading API (including the one discussed here). Andri Möll, I love your must-js lib, though I do not share same feeling to its API. Привет. :) |
A few days ago I also realized that using the negative form of obj.must.not.have.keys(["name", "age"]) That would pass if the object had more or less than only those two keys. Which is a test I can't see any use in. So I might be leaning towards turning And thanks @koresar and @enobrev to your other suggestions with matchers, too! I'll get back to you later in more detail. :) |
To be honest, that was fairly arbitrary. I didn't have a good argument for either checking inclusion of keys nor values, precisely because include could be said to apply to both in this case. But now that I think about it, perhaps it does make more sense to check for values. Objects are associative arrays after all and if you check for values in regular arrays, you might as well check for them in associative arrays. Overloading |
I wholeheartedly concur that the |
Assume we have object:
We need to ensure the object has
a b c d e f
. So I used:My first impression of the
ownKeys
andkeys
functions was that they should check given properties for existence. However they also checkfoo
andbar
properties must be absent.The underlying reason is that these functions use
exports.eql
comparator, which ensures the key arrays are 100% equal.I would recommend to rename keys -> onlyKeys, and ownKeys -> ownOnlyKeys. And create two more functions
keys
andownKeys
which would use different comparator:The text was updated successfully, but these errors were encountered: