How to Test an optional member of an object? - javascript

What is the best technique to test an optional object member. Right now we are prefacing the expect statements with an if:
if(object.member) expect(object).to.have.a.property('member').that.is.a('string');
but there must be a method that is more inline stylistically. E.g.
expect(object).to.have.an.optional.property('member').that.is.a('string');
or (adding would as an empty chain, for readability):
expect(object).to.have.an.optional.property('member').that.would.be.a('string');
or (moving the optional to provide an alternative version of expect):
optionally.expect(object).to.have.a.property('member').that.is.a('string');
update - I started to write this code (new to chai) to see if I could accomplish what I was targeting, so I added a small plugin:
module.exports = function(chai, utils) {
var Assertion = chai.Assertion
, i = utils.inspect
, flag = utils.flag;
var OPTIONAL_FLAG = 'chai-optional/option'
Assertion.addProperty('optional', function() {
flag(this, OPTIONAL_FLAG, true)
return this;
})
Assertion.overwriteMethod('property', function (_super) {
return function assertProperty (propertyName) {
if (flag(this, OPTIONAL_FLAG)) {
flag(this, OPTIONAL_FLAG, false) ;
var obj = this._obj;
var isPropertyPresent = (obj[propertyName]) ? true : false ;
if(isPropertyPresent) {
return _super.apply(this, arguments);
}
} else {
_super.apply(this, arguments);
}
};
});
Assertion.addProperty('would', function () {
return this;
});
};
WIth usage:
it('could be null or have a value', function(done){
var objWithout = {}
var objWith = {}
objWith.someProperty = 'blah'
expect(objWith).to.have.optional.property('someProperty').that.would.be.a('string');
expect(objWithout).to.have.optional.property('someProperty').that.would.be.a('string');
return done();
})
The current problem even when the property isn't present, the control of the function ends - but the evaluation chain continues. I need to end the evaluation with out a failing assertion - is this possible?
update either solution (simplistic solution):
var either = function(firstCondition){
var returnObject = {}
try{
firstCondition()
returnObject.or = function(secondCondition){ return }
} catch(e) {
returnObject.or = function(secondCondition){ return secondCondition() }
}
return returnObject ;
}
module.exports = either
I think the implementation is a little clunky - but fat arrow functions will hap thin out some of the syntax. So here is waiting on that!

The current problem even when the property isn't present, the control of the function ends - but the evaluation chain continues. I need to end the evaluation with out a failing assertion - is this possible?
After having read about chai's plugin guide I would have used a similar approach with a flag. However, I have reached the same conclusion - you cannot simply stop a chain.
A possibility I though of would be not only to implement new properties and a new flag, but to overwrite the assert method itself - to not throw when the OPTIONAL_FLAG flag on the current Assertion object is set. However, the chance to destroy everything or to miss an edge case is too hight.
After all, I don't think it's a good idea. Citing from this "confusing syntax" issue:
I think the misunderstanding comes from your expectation that Chai
follows most/all English grammar rules. Unfortunately, English grammar
has way too many rules (and exceptions to those rules) for it to be a
reasonable undertaking to implement.
The challenge with designing Chai's chain-able assertions is finding
the balance between being expressive and concise. Even if full grammar
wasn't a daunting task to implement and document, it would make the
API less concise, which is not good for a testing environment.
RULE: Any "flag" which modifies the behavior of an assertion (negation
not or inclusion include/contain , etc...), once set to true
should remain true until the end of the chain.
This means it is impossible to implement something like an .or operator as well.
What is possible though would be to implement something like
either(function(){
expect(object).not.to.have.a.property('member');
}).or(function(){
expect(object).to.have.a.property('member').that.is.a('string');
});
Maybe one can build a more appealing syntax on that.

Related

Can you trap/identify if an object is being "invoked" as a function in runtime?

Given some basic class, such as a logical predicate class here:
const isACat = new Predicate(obj => obj.cat === true);
Is there a way to determine/trap/identify (perhaps via Reflection?) the context under which isACat is being "invoked/evaluated"? By "invoke/evaluate"--because I can't really think of a better word to use right now--I mean something like this:
console.log(isACat(object1)); // being "invoked/evaluated" as a function
console.log(isACat); // being "invoked/evaluated" as a non-function
I specifically mean this in the "runtime" sense, not in the typeof/instanceof sense.
For the ultimate goal of performing contingent behavior, such as (perhaps via a Proxy) returning a default function if that instance is being "invoked/evaluated" as a function.
Edit: Maybe in more precise terms, is there such a thing as a "default getter" when no further child prop is passed (i.e. isACat, but not isACat[ prop ])?
I am not seriously suggesting that you do any of the things presented bellow and you will spot their limitation immediately but I thought it was kind of fun to demonstrate.
[{dog: true}, {cat: true}].filter(isACat);// (referenced(), [{cat: true}])
isACat({dog: true}); // (referenced(), false)
let lives = 0;
lives += isACat; // (referenced(), 7)
`Felix ${isACat}` // (referenced(), "Felix is a cat")
The above requires the following, which you could probably generate with a Babel plugin or something (I mean: don't, obviously)
const referenced = (obj) => () => {
console.log(obj, 'was referenced');
return obj;
}
const _isACat = obj => obj.cat === true;
Object.defineProperty(_isACat, 'toString', {
value: () => 'is a cat'
});
Object.defineProperty(_isACat, 'valueOf', {
value: () => 7
});
Object.defineProperty(window, 'isACat', {
get: referenced(_isACat)
});
I don't know what I like the most about it: deceiving expectations thanks to getters, magical type coercion, or local variables leaking to the global scope. It is pure poetry.
More seriously, I don't think Javascript is the language for this but if for some reason you need meta-programming power, maybe give Clojure a go. You can also use macros with ClojureScript, which compiles to Javascript and has Javascript interop, but there is a runtime/compile time distinction which will limit what you can do.
No, there is no such thing. You're just accessing a variable, or whatever the reference to your object is stored in, and you get back a reference value. The object itself has no say about this process - it isn't even looked at yet. This is not "invocation" or "evaluation".
Really, if you need something like this, make the invocation explicit, and write isACat() (vs isACat(object) vs isACat.prop()).

Can I prevent passing wrong number of parameters to methods with JS Lint, JS Hint, or some other tool?

I'm new to javascript programming (and scripting languages in general), but I've been using JS Lint to help me when I make syntax errors or accidentally declare a global variable.
However, there is a scenario that JS Lint does not cover, which I feel would be incredibly handy. See the code below:
(function () {
"use strict";
/*global alert */
var testFunction = function (someMessage) {
alert("stuff is happening: " + someMessage);
};
testFunction(1, 2);
testFunction();
}());
Notice that I am passing the wrong number of parameters to testFunction. I don't foresee myself ever in a situation where I would intentionally leave out a parameter or add an extra one like that. However, neither JS Lint nor JS Hint consider this an error.
Is there some other tool that would catch this for me? Or is there some reason why passing parameters like that shouldn't be error checked?
This is not generally possible with any static analysis tool. There are several reasons for this:
In general, JS functions can accept any number of arguments.
Most (all?) linters only work on a single file at a time. They do not know anything about functions declared in other files
There is no guarantee that a property being invoked as a function is the function that you expect. Consider this snippet:
var obj = { myFunc : function(a,b) { ... } };
var doSomething(x) { x.myFunc = function(a) { ... }; };
doSomething(obj);
obj.myFunc();
There is no way to know that myFunc now takes a different number of args after the call to doSomething.
JavaScript is a dynamic language and you should accept and embrace that.
Instead of relying on linting to catch problems that it wasn't intended to I would recommend adding preconditions to your functions that does the check.
Create a helper function like this:
function checkThat(expression, message) {
if (!expression) {
throw new Error(message);
}
}
Then use it like this:
function myFunc(a, b) {
checkThat(arguments.length === 2, "Wrong number of arguments.");
And with proper unit testing, you should never see this error message in production.
It's not natively possible in javascript. You would have to do something like this:
var testFunction = function (someMessage) {
var args = Array.prototype.slice.call(arguments);
if (args.length !== 1) throw new Error ("Wrong number of arguments");
if (typeof args[1] !== string) throw new Error ("Must pass a string");
// continue
};
Paul Irish demoed a hack for this a while back...passing undefined at the end of the parameters...
var testFunction = function (someMessage, undefined) {
alert("stuff is happening: " + someMessage);
};
testFunction("one", "two", "three");
He demos it here...see if it's what your looking for.

Should I return a method call like console.log()?

Good day everyone. I haven't found any research or articles regarding this. Maybe I was using the wrong search terms. but my question was lets say for example that I am writing a small utility library in JavaScript for myself and I want to include 2 small functions out(arg) and outln(arg). My question is should i simply call console.log() or return console.log().
I've seen it done both ways but never saw a reason to return a method call. I was wondering which way is better or does it make a difference at all?
EX.
// This way:
var lib = {
out: function(args){
console.log(args);
},
outln: function(args){
console.log(args + "\n");
}
};
// Or this way?
var lib = {
out: function(args){
return console.log(args);
},
outln: function(args){
return console.log(args + "\n");
}
};
Do you have any use for the return value from console.log (which is always undefined anyway iirc ) ? You might plan to override log or create your own console object, though (not recommended).
More important, check for the presence of the console object and the log method, as some user agents have been known not to provide them:
var lib = {
out: function(args) {
if (console && console.log) {
console.log(args);
}
},
outln: function(args) {
if (console && console.log) {
console.log(args+"\n");
}
}
}
Promoting robustness, test this way instead of once during your lib's initialization and setting a global ( you might even consider to add the test to your lib if you have a use case, eg. users/code tampering with the console object ).

coffeescript always returns

So I have what's probably a stupid question to ask about Coffee Script. I'm giving it a second chance but why does it return everything?
Is it anything to do with being the last statement/line of the function? and how do I disable this? Putting a comment or something as the final "expression", I know it's a "documented" feature but no; no it's not really, how do I not have returns everywhere? and save download/execution times?
Surely this behaviour kind of screws the jit over?
(locate =
getPosition: () ->
# Check we support geolocation
throw Exception 'Your browser doesn\'t support location based services!' if !navigator.geolocation
navigator.geolocation.getCurrentPosition (pos) ->
console.log pos
)
Compiles to
(function() {
var locate;
locate = {
getPosition: function() {
if (!navigator.geolocation) {
throw Exception('Your browser doesn\'t support location based services!');
}
return navigator.geolocation.getCurrentPosition(function(pos) {
return console.log(pos);
});
}
};
}).call(this);
[Edit]
The reason I care is this is just one of a very large library for an app I've built, if we say there's 500 functions and 200 of those do something to the dom instead of return something like a number or object, that extra 200 returns is an extra 1.2k of data I don't want or need.
Also, a function with no return, returns undefined and a function that returns null well, no need to explain that. If I was stupid enough to check this, it'd be wrong across the board.
I'm sure there would be some perf differences but I don't know about that and right now I don't have time to do some jsperfs but I'd be interested.
Yes coffeescript will always return the last line of the function. It can do this since everything in coffeescript is an expression.
From the docs:
Everything is an Expression (at least, as much as possible)
You might have noticed how even though we don't add return statements to CoffeeScript functions, they nonetheless return their final value. The CoffeeScript compiler tries to make sure that all statements in the language can be used as expressions. Watch how the return gets pushed down into each possible branch of execution in the function below.
Their example can be seen here
You can still do short-circuit returns with the return statement
Even though functions will always return their final value, it's both possible and encouraged to return early from a function body writing out the explicit return (return value), when you know that you're done.
It is because it's the last statement/line of the function, yes. By default, functions in CoffeeScript always return a value. This isn't normally a bad thing, but you can just add a return line if you really don't want to return anything.
If you want to return something specific, you can just make that the last line of your function:
(locate =
getPosition: () ->
# Check we support geolocation
throw Exception 'Your browser doesn\'t support location based services!' if !navigator.geolocation
navigator.geolocation.getCurrentPosition (pos) ->
console.log pos
'Return this string'
return
)
JS:
var locate;
locate = {
getPosition: function() {
if (!navigator.geolocation) {
throw Exception('Your browser doesn\'t support location based services!');
}
navigator.geolocation.getCurrentPosition(function(pos) {
console.log(pos);
return 'Return this string';
});
}
};

Javascript Module pattern - how to reveal all methods?

I have module pattern done like this:
var A = (function(x) {
var methodA = function() { ... }
var methodB = function() { ... }
var methodC = function() { ... }
...
...
return {
methA: methodA,
methB: methodB
}
})(window)
This code let's me call only methA and methB() on A which is what I want and what I like. Now the problem I have - I want to unit test it with no pain ot at least with minimal efforts.
First I though I can simply return this but I was wrong. It returns window object.(can someone explain why?).
Second - I found solution somewhere online - to include this method inside my return block:
__exec: function() {
var re = /(\(\))$/,
args = [].slice.call(arguments),
name = args.shift(),
is_method = re.test(name),
name = name.replace(re, ''),
target = eval(name);
return is_method ? target.apply(this, args) : target;
}
This method let's me call the methods like this: A.__exec('methA', arguments);
It is almost what I want, but quite ugly. I would prefer A.test.methA() where test would never be used in production code - just for revealing private methods.
EDIT
I see people telling me to test the big thing instead of the small parts. Let me explain. In my opinion API should reveal only the needed methods not a bunch of internal functions. The internals because of their small size and limited functionality are much easier to test then test the whole thing and guess which part gone wrong.
While I may be wrong, I would still like to see how I could return references to all the methods from the object itself :).
Answer to your first question(you return this, but it returns window, not the object you wanted): in javascript this inside the function returns global object unless this function is a method of the object.
Consider next examples:
1) this points to the global object ():
function(){
return this;
}
2) this points to the object:
var obj = {
value: "foo",
getThisObject: function(){
return this;
}
}
Your case is example #1, because you have a function, that returns an object. This function is not a method of any object.
The best answer to your second question is to test only public methods, but if
that is so important for you, I can propose next:
create your modules dynamically on server side.
How it works:
create separate scripts for functionality you want;
create tests for these separate scripts;
create method that will combine scripts into one however you want;
to load script, reference to the combining scripts method.
Hopefully, it can solve your problem. Good luck!
Why not use namespaces to add your modules and public methods to js engine. Like this:
window['MyApp']['MODULE1'] = { "METHOD1" : {}, "METHOD2" : {}};
I write modules like this Sample module in JavaScript.
And test it like this: Simple unit testing in JavaScript
The use of eval() is generally not good idea.

Categories

Resources