Jasmine - how to write custom matcher to sum two numbers? - javascript

I'm using Jasmine 2.1.3 and trying to create a custom matcher to sum two numbers.
However I am getting:
Expected 24 not to equal 12
So far I have
it("is 24 for 24", function() {
result = simpleMath.sum_of(12,12); // gets 24
expect(result).toBeSumOf([12,12]);
});
and
beforeEach(function() {
simpleMath = new SimpleMath();
jasmine.addMatchers({
toBeSumOf: function (util, customEqualityTesters) {
return {
compare: function(actual, expected) {
// var passed = actual == expected // comparison example that worked
var passed = (actual[0]+actual[1]) == expected;
return {
pass: passed,
message: 'Expected ' + actual + (passed ? '' : ' not') + ' to equal ' + expected
};
}
};
}
});
});

Your actual and expected are the wrong way around, just add:
console.log(actual);
console.log(expected);
To your matcher and you'll see, you can use either format for the parameters 12, 12 or [12, 12] but for the former you'll need to add another parameter so the array format is probably preferable. You could of course use an object if that helps for more complex comparisons/matchers.
Working (array based) example:
describe("My custom test", function() {
it("should work", function() {
var result = 12 + 12;
expect(result).toBeSumOf([12, 12]);
});
});
and:
beforeEach(function () {
jasmine.addMatchers({
toBeSumOf: function () {
return {
compare: function (actual, expected) {
var passed = (actual == expected[0] + expected[1]);
return {
pass: passed,
message: 'Expected value ' + (expected[0] + expected[1]) + (passed ? '' : ' not') + ' equal to ' + actual
};
}
};
}
});
});
Gives:
Changing one of the values gives:

Related

Javascript parameters on a function [duplicate]

This question already has answers here:
How can I make var a = add(2)(3); //5 work?
(33 answers)
Closed 4 years ago.
I have got a quiz that asks the following question, but Im quite not sure if it is possible to pass multiple variables like that on Javascript functions:
Write a function called "MultiplyBy" which will produce the following outputs when invoked:
console.log(mul(2)(3)(4)); // output : 24
console.log(mul(4)(3)(4)); // output : 48
You can do it returning functions at each call. The name of this technique is currying.
// For three chained calls
function mul(i) {
return function(j) {
return function(k) {
return i * j * k;
}
}
}
console.log('result: ' + mul(2)(3)(4)); // output : 24
console.log('result: ' + mul(4)(3)(4)); // output : 48
// For an arbitrary number of chained calls, must resort to .toString
function mulN(i) {
var m = (j) => mulN(i * j);
m.toString = () => ''+i;
m.valueOf = () => i; // call .valueOf() at any point to get the current val
return m;
}
console.log('result: ' + mulN(2));
console.log('result: ' + mulN(2)(3));
console.log('result: ' + mulN(2)(3)(4));
console.log('result: ' + mulN(2)(3)(4)(5));
console.log('result: ' + (mulN(2)(3)(4)(5) == 120)); // true because of .valueOf

Object.defineProperty get set return wrong value

Say I have an object instance like this :
var objectA = {"a": 1, "b": 2, "c" : 3};
and in my code I access the property like this:
cc.log(objectA.a); // output 1
now I want to add a get/set for this object to provide some simple encrypt/decrypt feature:
hookSetGet: function (someObject) {
for (var key in someObject) {
cc.log("key: " + key);
// store the origin value before Object.defineProperty
var pureValue = someObject[key];
// add a property to store the encrypted value
var hiddenValueKey = "__" + key;
someObject[hiddenValueKey] = undefined;
Object.defineProperty (
someObject,
key,
{
set: function (val) {
// simulate encrypt
this.hiddenValueKey = val + 1;
cc.log("hooked set: " + val + " - " + this.hiddenValueKey);
},
get: function () {
cc.log("hooked get: " + this.hiddenValueKey + " - " + (this.hiddenValueKey - 1));
// simulate decrypt
return this.hiddenValueKey - 1;
}
}
);
// trigger set to encrypt
someObject[key] = pureValue;
}
}
but when I test the function like this:
var objectA = {"a": 1, "b": 2, "c" : 3};
this.hookSetGet(objectA);
cc.log(objectA.a);
cc.log(objectA.b);
cc.log(objectA.c);
I do not get the result I want :
key: a
hooked set: 1 - 2
key: b
hooked set: 2 - 3
key: c
hooked set: 3 - 4
hooked get: 4 - 3
3
hooked get: 4 - 3
3
hooked get: 4 - 3
3
It seems like even when I call
objectA.a
I will get the value of
objectA.c
The problem seems quite simple but I just can not figure out where is wrong.
Any suggestion will be appreciated, thanks :)
UPDATE:
I tried the following code without change the code of hookSetGet :
cc.log(objectA.__a);
cc.log(objectA.__b);
cc.log(objectA.__c);
and get:
undefined
undefined
undefined
Then I changed the hookSetGet function:
set: function (val) {
// simulate encrypt
someObject[hiddenValueKey] = val + 1;
cc.log("hooked set: " + val + " - " + someObject[hiddenValueKey]);
},
get: function () {
cc.log("hooked get: " + someObject[hiddenValueKey] + " - " + (someObject[hiddenValueKey] - 1));
// simulate decrypt
return someObject[hiddenValueKey] - 1;
}
I changed all the this.hiddenValueKey to someObject[hiddenValueKey].
and the output is :
cc.log(objectA.__a); // 2 good
cc.log(objectA.__b); // 3 good
cc.log(objectA.__c); // 4 good
cc.log(objectA.a); // hooked get: 4 - 3 still wrong
cc.log(objectA.b); // hooked get: 4 - 3 still wrong
cc.log(objectA.c); // hooked get: 4 - 3 still wrong
So, you wrote this:
Object.defineProperty (
someObject,
key,
{
set: function (val) {
// simulate encrypt
this.hiddenValueKey = val + 1;
cc.log("hooked set: " + val + " - " + this.hiddenValueKey);
},
get: function () {
cc.log("hooked get: " + this.hiddenValueKey + " - " + (this.hiddenValueKey - 1));
// simulate decrypt
return this.hiddenValueKey - 1;
}
}
);
In your getter and setter this from this.hiddenValueKey refers to your objectA Object in all cases, not to each property. So when you want to set a value for each property you're actually over-writing objectA.hiddenValueKey. This is why when you try to get back the values you only get the last value which was set.
Even though you set hiddenValueKey to be unique, in the getter and setter you acess the same property. This is because this.hiddenValueKey is the same as writing this['hiddenValueKey']. Did you mean to write this[hiddenValueKey] ? Even if you do it, you might have some scoping issues with the hiddenValueKey always having the latest key value after you exit the loop.
So, you can try this:
Object.defineProperty (
someObject,
key,
{
set: function (val) {
// simulate encrypt
this[hiddenValueKey] = val + 1;
cc.log("hooked set: " + val + " - " + this[hiddenValueKey]);
},
get: function () {
cc.log("hooked get: " + this[hiddenValueKey] + " - " + (this[hiddenValueKey] - 1));
// simulate decrypt
return this[hiddenValueKey] - 1;
}
}
);
But, as I said, you might have to create a closure for the hiddenValueKey variable so it will be unique for each property getter and setter.
You can create a closure like this:
(function(hiddenValueKey) {
Object.defineProperty (
someObject,
key,
{
set: function (val) {
// simulate encrypt
this[hiddenValueKey] = val + 1;
cc.log("hooked set: " + val + " - " + this[hiddenValueKey]);
},
get: function () {
cc.log("hooked get: " + this[hiddenValueKey] + " - " + (this[hiddenValueKey] - 1));
// simulate decrypt
return this[hiddenValueKey] - 1;
}
}
);
}(hiddenValueKey));
There are several issues with your code. One of them is that key and hiddenValueKey are set in the scope of the hookGetSet function. Therefore whenever you use them, you use the last value in the loop (3 and __c). You can fix this in two ways:
use let instead of var to define key and hiddenValueKey within the loop scope, but that only works in ES6
use a closure to scope the inside of the loop
The other problem is that inside the properties you use this.hiddenValueKey, which is the same as this['hiddenValueKey'], not this[hiddenValueKey] as I assume you intended.
Here is code that works (EcmaScript6):
hookSetGet : function (someObject) {
for (let key in someObject) {
cc.log("key: " + key);
// store the origin value before Object.defineProperty
var pureValue = someObject[key];
// add a property to store the encrypted value
let hiddenValueKey = "__" + key;
someObject[hiddenValueKey] = undefined;
Object.defineProperty(
someObject,
key, {
set : function (val) {
// simulate encrypt
this[hiddenValueKey] = val + 1000;
cc.log("hooked set: " + val + " - " + this[hiddenValueKey]);
},
get : function () {
// simulate decrypt
var result = this[hiddenValueKey] - 1000;
cc.log("hooked get: " + this[hiddenValueKey] + " - " + result);
return result;
}
});
// trigger set to encrypt
someObject[key] = pureValue;
}
}
and here is same code for classic ES5 Javascript:
hookSetGet : function (someObject) {
for (var k in someObject) {
(function () {
var key = k;
cc.log("key: " + key);
// store the origin value before Object.defineProperty
var pureValue = someObject[key];
// add a property to store the encrypted value
var hiddenValueKey = "__" + key;
someObject[hiddenValueKey] = undefined;
Object.defineProperty(
someObject,
key, {
set : function (val) {
// simulate encrypt
this[hiddenValueKey] = val + 1000;
cc.log("hooked set: " + val + " - " + this[hiddenValueKey]);
},
get : function () {
// simulate decrypt
var result = this[hiddenValueKey] - 1000;
cc.log("hooked get: " + this[hiddenValueKey] + " - " + result);
return result;
}
});
// trigger set to encrypt
someObject[key] = pureValue;
})();
}
}

(FunctionReturn() - 1) fails but (-1 + FunctionReturn()) succeeds?

I have a getter/setter function that returns an absolute value. So I presumed that JavaScript would allow me to perform arithmetic with it. But it only works in a certain order...
NOTE: pos.get("log", pos.get("log") + 1) always returns 1 in these examples.
console.log("initial log: " + (-1 + pos.get("log", pos.get("log") + 1)));
// PSEUDO-CODE: -1 + (log += 1)
// RESULT: 0
The above code works as expected. But switch around the order and it all changes... Despite pos.get() always returning an absolute value of the same type. (Number)
console.log("initial log: " + (pos.get("log", pos.get("log") + 1) - 1));
// PSEUDO-CODE: (log += 1) - 1
// RESULT: 1
If log was equal to 0 from the beginning, the first console.log() prints 0. However, the second prints 1. I get no errors in the console whatsoever. Took me a while to figure out that the "- 1" was just being completely disregarded.
Why?
EDIT: Definition of pos.get()
get: function(str, val) {
switch(str) {
case "start": {
if(val != undefined) {
start = val;
}
return start;
}
case "log": {
if(val != undefined) {
log = val;
}
return log;
}
case "offset": {
if(val != undefined) {
offset = val;
}
return offset;
}
}
}
Be sure that your function returns a number (e.g. float), eventually with parseFloat(). Now, I think the js parser doesn't know.
With 1 - yourFunction() the js parser suggests that the return value of your function is numeric.

Access arguments of a function passed as argument

I'm trying to flip the parameters of a function passed to another function:
function dash(a,b) {
return a + " - " + b;
}
function flipArgs(fn) {
return fn;
}
flipArgs(dash)(1,2);
Currently it returns "1 - 2", I need to return "2 - 1". How can I access to the arguments passed to my "flipArgs" function?
You can do this :
function flipArgs(fn) {
return function(){
return fn(arguments[1], arguments[0]);
}
}
Of course, depending on your needs, you could use a larger swap, or test arguments.length.
#dystroy answer is great, but there is a more generic way, take a look:
function dash(a,b,c) {
return a + " - " + b + " - " + c;
}
function flipArgs(fn) {
return function(){
return fn.apply(this, Array.prototype.reverse.call(arguments));
}
}
var r = flipArgs(dash)(1,2,3);
console.log(r); // 3 - 2 - 1
JSFiddle: http://jsfiddle.net/u3f4t919/1/

Modify value using a lambda

Let's say for an intance I have this template I wanted to render with hogan.js:
var template = '{{#numbers}}'
+ '{{#capitalize}}{{percentage}}{{/capitalize}} complete.\n'
+ '{{/numbers}}';
And I compile it with the ff:
var hello = hogan.compile(template);
var rendered = hello.render({
numbers: [
{ percentage: .3 },
{ percentage: .6 },
{ percentage: .8 }
],
capitalize: function() {
return function(num) {
// console.log(num);
return num * 100;
}
}
})
console.log(rendered)
How do I get the number multiplied by 100 isntead of geting NaN?
NaN complete.
NaN complete.
NaN complete.
Also, when you uncomment the line above, num = {{percentage}} instead of the number itself.
Based on the response by #akonsu, here's an example on how you might get the value for a lambda in Hogan.js.
I have two helper functions in the example, manual and automatic, which can wrap around the lambda function definition depending on the desired behavior.
var source = '{{#numbers}}'
+ 'test1 = {{#test1}}{{percentage}}{{/test1}}\n'
+ '{{/numbers}}'
+ '{{#numbers}}'
+ 'test2 = {{#test2}}{{percentage}}{{/test2}}\n'
+ '{{/numbers}}';
var template = Hogan.compile(source);
var renderer = function(context) {
return function(text) {
return template.c.compile(text, template.options).render(context);
};
};
var manual = function(lambda) {
return function(text) {
var render = renderer(this);
return lambda.call(this, text, render);
};
};
var automatic = function(lambda) {
return manual(function(text, render) {
return lambda.call(this, render(text));
});
};
var rendered = template.render({
numbers: [
{ percentage: .3 },
{ percentage: .6 },
{ percentage: .8 }
],
test1: manual(function(text, render) {
return render(text) * 100;
}),
test2: automatic(function(num) {
return num * 100;
})
});
console.log(rendered);
The output looks like this:
test1 = 30
test1 = 60
test1 = 80
test2 = 30
test2 = 60
test2 = 80
Here's a jsfiddle demonstrating the solution: http://jsfiddle.net/potatosalad/h5cU4/2/
Please note that this solution will not work with partials (if they are referenced from inside the lambda section).
The relevant code for Hogan.js 2.0.0 are lambda replace section and higher order functions.
I think this example is relevant: https://github.com/janl/mustache.js#functions. My guess is that this should help:
capitalize: function() {
return function(text, render) {
return render(text) * 100;
}
}
a similar post: How to get the value when using Lambda in Hogan.js
capitalize: function(num) {
return num * 100;
}
should work for you

Categories

Resources