Probably my misunderstanding of Testdouble, but I've created this example to illustrate the issue I'm having:
const test = require("ava");
const td = require("testdouble");
const reducer = async (state, event) => {
if (event.id === "123") {
const existing = await state.foo("", event.id);
console.log("existing:", existing);
}
};
test("foo", async (t) => {
const foo = td.func(".foo");
const state = td.object({
foo
});
td.when(foo(td.matchers.anything(), td.matchers.anything())).thenResolve({
id: "123"
});
await reducer(state, {
id: "123",
nickname: "foo"
});
});
This logs: existing: undefined
Whereas I believe it should log: existing: { id: "123" } as stated by the td.when()
What am I missing?
I think your issue is that td.object doesn't work the way you think it does:
td.object(realObject) - returns a deep imitation of the passed object, where each function is replaced with a test double function named for the property path (e.g. If realObject.invoices.send() was a function, the returned object would have property invoices.send set to a test double named '.invoices.send')
Source: https://github.com/testdouble/testdouble.js#tdobject
So when you do…
const foo = td.func();
const obj = td.object({foo});
… you're actually mocking foo twice.
Here's a demo:
const td = require('testdouble');
const num2str = td.func('num->string');
td.when(num2str(42)).thenReturn('forty two');
td.when(num2str(43)).thenReturn('forty three');
td.when(num2str(44)).thenReturn('forty four');
const x = {num2str};
const y = td.object({num2str});
num2str(42);
x.num2str(43);
y.num2str(44);
Then we can inspect x.num2str and we can see that it is the same test double as num2str:
td.explain(x.num2str).description;
/*
This test double `num->string` has 3 stubbings and 2 invocations.
Stubbings:
- when called with `(42)`, then return `"forty two"`.
- when called with `(43)`, then return `"forty three"`.
- when called with `(44)`, then return `"forty four"`.
Invocations:
- called with `(42)`.
- called with `(43)`.
*/
However y.num2str is a completely different test double:
td.explain(y.num2str).description;
/*
This test double `.num2str` has 0 stubbings and 1 invocations.
Invocations:
- called with `(44)`.
*/
I think what you're looking for is the "property replacement" behaviour of td.replace:
const z = {
str2num: str => parseInt(str),
num2str: num => {
throw new Error('42!');
}
};
td.replace(z, 'num2str');
td.when(z.num2str(42)).thenReturn('FORTY TWO!!');
The z.str2num function hasn't been mocked:
z.str2num("42");
//=> 42
However z.num2str is a fully-fledged test double:
z.num2str(42);
//=> 'FORTY TWO!!'
td.explain(z.num2str).description;
/*
This test double `num2str` has 1 stubbings and 1 invocations.
Stubbings:
- when called with `(42)`, then return `"FORTY TWO!!"`.
Invocations:
- called with `(42)`.
*/
Related
I think there is something that i'm missing about method chaining. To me it feels incomplete.
Method chaining works by having each method return this so that another method on that object can be called. However, the fact that the return value is this and not the result of the function seems inconvenient to me.
Here is a simple example.
const Obj = {
result: 0,
addNumber: function (a, b) {
this.result = a + b;
return this;
},
multiplyNumber: function (a) {
this.result = this.result * a;
return this;
},
}
const operation = Obj.addNumber(10, 20).multiplyNumber(10).result
console.log(operation)
key points:
Every method in the chain Obj.addNumber(10, 20).multiplyNumber(10) returns this.
The last part of the chain .result is the one that returns a value other than this.
The problem with this approach is that it require you to tack on a property / method to get a value at the end other thanthis.
Compare this with built-in functions in JavaScript.
const str = " SomE RandoM StRIng "
console.log(str.toUpperCase()) // " SOME RANDOM STRING "
console.log(str.toUpperCase().trim()) // "SOME RANDOM STRING"
console.log(str.toUpperCase().trim().length) // 18
key points:
Each function in the chain returns the result of the function not this (maybe this is done under the hood)
No property / method is required at the end of the chain just to get the result.
Can we implement method chaining to behave the way built-in functions in Javascript behave?
First of all, each of your console.log doesn't return properly:
console.log(str.toUpperCase.trim) //undefined
It returns undefined because str.toUpperCase returns the function object and does not execute the function itself so it won't work
The only correct usage is
console.log(str.toUpperCase().trim()
Now about your question, it is pretty easy to do it without a result and it is much more efficient.
Everything in javascript has a method called valueOf(), here is my example of calling everything like that for numbers, though I prefer just making functions instead of Objects.
const Obj = {
addNumber: function (a = 0) {
return a + this.valueOf();
},
multiplyNumber: function (a = 1) {
return a*this.valueOf();
},
}
const nr = 2;
Object.keys(Obj).forEach(method => {
Number.prototype[method] = Obj[method];
})
console.log(Number.prototype); // will print out addNumber and multiplyNumber
// Now You can call it like this
console.log(nr.addNumber().multiplyNumber()); // Prints out 2 because it becomes (nr+0)*1
console.log(nr.addNumber(3).multiplyNumber(2)) // Prints out 10;
I think you are misunderstanding what method chaining actually is. It is simply a shorthand for invoking multiple methods without storing each intermediate result in a variable. In other words, it is a way of expressing this:
const uppercase = " bob ".toUpperCase()
const trimmed = uppercase.trim()
as this
const result = " bob ".toUpperCase().trim()
Nothing special is happening. The trim method is simply being called on the result of " bob ".toUpperCase(). Fundamentally, this boils down to operator precedence and the order of operations. The . operator is an accessor, and is evaluated from left to right. This makes the above expression equivalent to this (parens used to show order of evaluation):
const result = (" bob ".toUpperCase()).trim()
This happens regardless of what is returned by each individual method. For instance, I could do something like this:
const result = " bob ".trim().split().map((v,i) => i)
Which is equivalent to
const trimmed = " bob ".trim()
const array = trimmed.split() //Note that we now have an array
const indexes = array.map((v,i) => i) //and can call array methods
So, back to your example. You have an object. That object has encapsulated a value internally, and adds methods to the object for manipulating the results. In order for those methods to be useful, you need to keep returning an object that has those methods available. The simplest mechanism is to return this. It also may be the most appropriate way to do this, if you actually are trying to make the object mutable. However, if immutability is an option, you can instead instantiate new objects to return, each of which have the methods you want in the prototype. An example would be:
function MyType(n) {
this.number = n
}
MyType.prototype.valueOf = function() {
return this.number
}
MyType.prototype.add = function(a = 0) {
return new MyType(a + this)
}
MyType.prototype.multiply = function(a = 1) {
return new MyType(a * this)
}
const x = new MyType(1)
console.log(x.add(1)) // { number: 2 }
console.log(x.multiply(2)) // { number: 2 }
console.log(x.add(1).multiply(2)) // { number: 4 }
console.log(x.add(1).multiply(2) + 3) // 7
The key thing to note about this is that you are still using your object, but the valueOf on the prototype is what allows you to directly utilize the number as the value of the object, while still making the methods available. This is shown in the last example, where we directly add 3 to it (without accessing number). It is leveraged throughout the implementation by adding this directly to the numeric argument of the method.
Method chaining is the mechanism of calling a method on another method of the same object in order to get a cleaner and readable code.
In JavaScript method chaining most use the this keyword in the object's class in order to access its method (because the this keyword refers to the current object in which it is called)
When a certain method returns this, it simply returns an instance of the object in which it is returned, so in another words, to chain methods together, we must make sure that each method we define has a return value so that we can call another method on it.
In your code above, the function addNumber returns the current executing context back from the function call. The next function then executes on this context (referring to the same object), and invokes the other functions associated with the object. it's is a must for this chaining to work. each of the functions in the function chaining returns the current Execution Context. the functions can be chained together because the previous execution returns results that can be processed further on.
This is part of the magic and uniqueness of JavaScript, if you're coming from another language like Java or C# it may look weird for you, but the this keyword in JavaScript behaves differently.
You can avoid the necessity of this and be able to return a value implicitly, using a Proxy object with a get-trap.
Here you find a more generic factory for it.
const log = Logger();
log(`<code>myNum(42)
.add(3)
.multiply(5)
.divide(3)
.roundUp()
.multiply(7)
.divide(12)
.add(-1.75)</code> => ${
myNum(42)
.add(3)
.multiply(5)
.divide(3)
.roundUp()
.multiply(7)
.divide(12)
.add(-1.75)}`,
);
log(`\n<code>myString(\`hello world\`)
.upper()
.trim()
.insertAt(6, \`cruel coding \`)
.upper()</code> => ${
myString(`hello world`)
.upper()
.trim()
.insertAt(6, `cruel coding `)
.upper()
}`);
log(`<br><code>myString(\`border-top-left-radius\`).toUndashed()</code> => ${
myString(`border-top-left-radius`).toUndashed()}`);
// the proxy handling
function proxyHandlerFactory() {
return {
get: (target, prop) => {
if (prop && target[prop]) {
return target[prop];
}
return target.valueOf;
}
};
}
// a wrapped string with chainable methods
function myString(str = ``) {
const proxyHandler = proxyHandlerFactory();
const obj2Proxy = {
trim: () => nwProxy(str.trim()),
upper: () => nwProxy(str.toUpperCase()),
lower: () => nwProxy(str.toLowerCase()),
insertAt: (at, insertStr) =>
nwProxy(str.slice(0, at) + insertStr + str.slice(at)),
toDashed: () =>
nwProxy(str.replace(/[A-Z]/g, a => `-${a.toLowerCase()}`.toLowerCase())),
toUndashed: () => nwProxy([...str.toLowerCase()]
.reduce((acc, v) => {
const isDash = v === `-`;
acc = { ...acc,
s: acc.s.concat(isDash ? `` : acc.nextUpcase ? v.toUpperCase() : v)
};
acc.nextUpcase = isDash;
return acc;
}, {
s: '',
nextUpcase: false
}).s),
valueOf: () => str,
};
function nwProxy(nwStr) {
str = nwStr || str;
return new Proxy(obj2Proxy, proxyHandler);
}
return nwProxy();
}
// a wrapped number with chainable methods
function myNum(n = 1) {
const proxyHandler = proxyHandlerFactory();
const obj2Proxy = {
add: x => nwProxy(n + x),
divide: x => nwProxy(n / x),
multiply: x => nwProxy(n * x),
roundDown: () => nwProxy(Math.floor(n)),
roundUp: () => nwProxy(Math.ceil(n)),
valueOf: () => n,
};
function nwProxy(nwN) {
n = nwN || n;
return new Proxy(obj2Proxy, proxyHandler);
}
return nwProxy();
}
// ---- for demo ---- //
function Logger() {
const report =
document.querySelector("#report") ||
document.body.insertAdjacentElement(
"beforeend",
Object.assign(document.createElement("pre"), {
id: "report"
})
);
return (...args) => {
if (!args.length) {
return report.textContent = ``;
}
args.forEach(arg =>
report.insertAdjacentHTML(`beforeEnd`,
`<div>${arg.replace(/\n/g, `<br>`)}</div>`)
);
};
}
body {
font: 12px/15px verdana, arial;
margin: 0.6rem;
}
code {
color: green;
}
I'm trying to do call a function that is imported as a function independently in another function that I'm calling from my unit test. How can I get callcount of 1 on the functionIWantToSpy in this scenario?
auditEvent.js:
const { verify } = require('#mycompany/verifylib');
const { functionIWantToSpy } = require('#mycompany/another-lib');
const auditEvent = () => {
verify();
functionIWantToSpy();
};
module.exports = { auditEvent };
test:
const { verify } = require('#mycompany/verify-lib');
const { functionIWantToSpy } = require('#mycompany/another-lib');
describe('mytest', () => {
let spiedFuntion;
let verifyStub;
beforeEach(() => {
verifyStub = sinon.stub();
({auditEvent} = proxyquire('./auditEvent', {
'#mycompny/verify-lib': {
verify: verifyStub,
'#noCallThru': true,
},
}));
spiedFunction = sinon.spy(functionIWantToSpy);
});
it('should work'), async () => {
auditEvent();
expect(functionIWantToSpy).to.have.callCount(1); // Getting callcount of 0 here...
});
});
Spying involves replacing the function with a new function. You are replacing what is referred to by the identifier functionIWantToSpy so that it refers to a new spy function, instead of the original function referred to by require('#mycompany/another-lib').functionIWantToSpy. The code inside the module can't see your new spy function. The expression require('#mycompany/another-lib').functionIWantToSpy refers to the original function, unchanged.
Because require caches results (i.e., only the first require("foo") executes foo, and any subsequent require("foo") summons up that same object returned by the first require call), you can modify the functionIWantToSpy method of the require('#mycompany/another-lib') object, using the two-argument form of sinon.spy:
spiedFunction = sinon.spy(require('#mycompany/another-lib'), "functionIWantToSpy");
You must do this before the property is ever accessed (and value stored) by the module being tested:
verifyStub = sinon.stub();
// IMPORANT: FIRST, spy the functionIWantToSpy property on the required object before importing auditEvent
spiedFunction = sinon.spy(require('#mycompany/another-lib'), "functionIWantToSpy");
({auditEvent} = proxyquire('./auditEvent', {
'#mycompny/verify-lib': {
verify: verifyStub,
'#noCallThru': true,
},
}));
This should work because when the auditEvent module runs for the first time and gets to
const { functionIWantToSpy } = require('#mycompany/another-lib');
then require('#mycompany/another-lib').functionIWantToSpy will refer to the spy function.
I am trying to mimic the behavior of Java to call the toString() method when we try to print the object using console.log statement or alert.
Currently, I have tried something like
class Some {
constructor(array = []) {
this.pvtData = array;
}
toString = () => JSON.stringify(this.pvtData);
}
const s = new Some([1, 2, 3]);
console.log(s);
The expected output should be
[1,2,3]
But, I am getting the output as
{
"toString": () => JSON.stringify(this.pvtData),
"pvtData": [
1,
2,
3
]
}
Can anyone help me in resolving the issue and getting the desired output?
Note:
I don't want to use console.log(s.toString());. Basically, the console.log statement shouldn't change.
What you're doing will work for alert because alert converts its argument to string, but not for console.log with most consoles, because they don't convert to string, they try to show you a representation of the object.
There is no equivalent method for console.log across environments.¹ If you want that to happen for console.log, you'll have to override it:
const oldLog = console.log.bind(console);
console.log = (...args) => oldLog(...args.map(String));
Live Example:
class Some {
constructor(array = []) {
this.pvtData = array;
}
toString = () => JSON.stringify(this.pvtData);
}
const oldLog = console.log.bind(console);
console.log = (...args) => oldLog(...args.map(String));
const s = new Some([1, 2, 3]);
console.log(s);
Obviously, don't do that in a general-purpose library that other people are going to use. It's fine in your own app or page, though.
Or better yet, just have your own logging function that you use instead that wraps console.log:
// The log function
const log = (...args) => console.log(...args.map(String));
// Usage
class Some {
constructor(array = []) {
this.pvtData = array;
}
toString = () => JSON.stringify(this.pvtData);
}
const s = new Some([1, 2, 3]);
log(s);
¹ In Node.js, the console used to look for a method called inspect, but they stopped doing that a while back.
Side note: There's usually no reason to make toString an arrow function. It works (in an environment that supports the class fields proposal), but it's usually unnecessary. Just make it a method:
class Some {
constructor(array = []) {
this.pvtData = array;
}
toString() {
return JSON.stringify(this.pvtData);
}
}
const f = (arg1) => (arg2) => { /* returns something */ }
Is it possible to memoize f with regard to the 2 arguments, namely:
f(1)(2);
f(1)(3); // Cache not hit
f(4)(2); // Cache not hit
f(1)(2); // Cache hit
You could take a Map as cache and take nested maps for all following arguments.
This cache works for arbitrary count of arguments and reuses the values from the former calls.
It works by taking a curried function and an optional Map. If the map is not supplied, a new map is created which serves as base cache for all other calls of the returned closure or the final result.
The inner function takes a single argument and checks if this value is in the map.
If not, call the curried function and check the returned value
if function, create a new closure over the function and a new map,
if no function take the result,
as value for a new element of the map.
Finally return the value from the map.
const cached = (fn, map = new Map()) => arg => {
const inCache = map.has(arg);
const hint = inCache ? 'in cache' : 'not in cache';
console.log(arg, hint);
if (!inCache) {
const value = fn(arg);
const result = typeof value === 'function' ? cached(value, new Map()) : value;
map.set(arg, result);
}
return map.get(arg);
};
const f = a => b => c => a * b * c; // the original curried function
const g = cached(f); // its cached variant
console.log(g(1)(2)(5)); // not not not 10
console.log(g(1)(3)(4)); // in not not 12
console.log(g(4)(2)(3)); // not not not 24
console.log(g(1)(2)(6)); // in in not 12
console.log(g(4)(2)(3)); // in in in 24
.as-console-wrapper { max-height: 100% !important; top: 0; }
Interesting question — you could have independent caches for each function. The cache on the outside function will hold functions. Each inside function could get its own independent cache. So calling f(10)(1) followed by f(10)(2) would result in calling a cached version of the inside function. Calling f(10)(1) again would hit both caches:
function getCachedF() {
// outer cache holds functions keyed to argument
let outer_memo = {}
const f = (arg1) => {
if (!outer_memo.hasOwnProperty(arg1)) {
// Create inner function on outer cache
// each inner function needs its own cache
// because it will return different values
// given different outer function calls
let inner_memo = {}
console.log("outer cache miss")
outer_memo[arg1] = (arg2) => {
// just a normal memoized function
// cache is simple key:value pair
if (!inner_memo.hasOwnProperty(arg2)) {
console.log("inner cache miss")
inner_memo[arg2] = arg1 + arg2
}
return inner_memo[arg2]
}
}
return outer_memo[arg1]
}
return f
}
let f = getCachedF()
// both caches miss
console.log("3+5", f(3)(5))
// cached result
console.log("3+5", f(3)(5))
// only inside cache hit
console.log("3+8", f(3)(8))
// inside cache only hits if both args are the same
console.log("10+8", f(10)(8))
Another alternative would be to have single cache with keys that are a combination of both arguments, but then the inner function would always have to be called.
This probably isn't the canonical memoization function.
A function that needs to cache its result is given a cache function that is used to store and retrieve previous results:
const sum = memo(cache => a => b => cache(`${a}+${b}`, () => a + b));
// ^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^
// A B C
A — The cache function is provided by the memo function.(A memoized function can opt-out from caching some results if necessary.)
B — A unique key for the result. (e.g. cache['1+2'] = 3)
C — A thunk that returns the result.(So we can check if we have it already before computing it.)
This supports both curried and non-curried functions but also functions that return a function as a value.
The memo function can be implemented as follow:
const memo = fn => {
const ns = Symbol();
const cache = (key, thunk) => cache[ns][key] ??= thunk();
cache[ns] = {};
return fn(cache);
};
I quite like the logical nullish assignment operator for managing the cache:
a ??= answer()
The expression on the right is evaluated and assigned to a if and only if a is not already defined. Then it returns the value of a:
const answer = () => (console.log('returning the answer'), 42);
let a;
a ??= answer();
//=> LOG: returning the answer
//=> 42
a ??= answer();
//=> 42
a ??= 40;
//=> 42
I've used a symbol to hide the actual cache set on the cache function. A symbol is not returned when enumerating properties of an object:
const foo = {};
const key1 = Symbol();
const key2 = 'bar';
foo[key1] = 42;
foo[key2] = 41;
Object.keys(foo);
//=> ['bar']
Object.entries(foo);
//=> [['bar', 41]]
Demo
// curried memoized function
const sum = memo(cache => a => b =>
cache(`${a}+${b}`,
() => (console.log(`computing ${a}+${b}…`), a+b)));
console.log(sum(1)(2));
console.log(sum(1)(2));
console.log(sum(1)(2));
// non-curried memoized function
const mul = memo(cache => (a, b) =>
cache(`${a}*${b}`,
() => (console.log(`computing ${a}*${b}…`), a*b)));
console.log(mul(2, 3));
console.log(mul(2, 3));
console.log(mul(2, 3));
// function-returning function
const deferred_sum = memo(cache => a => b =>
cache(`${a}+${b}`,
() => (console.log(`defer computing ${a}+${b}…`), () => a+b)));
console.log(deferred_sum(1)(2)());
console.log(deferred_sum(1)(2)());
console.log(deferred_sum(1)(2)());
<script>
const memo = fn => {
const ns = Symbol();
const cache = (key, thunk) => cache[ns][key] ??= thunk();
cache[ns] = {};
return fn(cache);
};
</script>
You can not to pass map to every function.
You can do like the next:
const memoize = fn => {
const cache = {};
return (...args) => {
const curriedFn = fn(...args);
return (...next) => {
const key = // generate your key
if (key in cache) return cache[key];
return (cache[key] = curriedFn(...next));
}
}
}
In this example, barStub.called === false, presumably because the execution flow of fooStub does not wait for barStub to resolve.
I also put assert(barStub.called) in a 10 sec setTimeout, and it still was uncalled.
Is there a way to stub a method like bar?
const sinon = require('sinon')
const assert = require('assert')
const functionHolder2 = {
bar: function() {
return Promise.resolve('bar')
}
}
const functionHolder = {
foo: function() {
functionHolder2.bar()
return Promise.resolve('foo')
}
}
const fooStub = sinon.stub(functionHolder, 'foo').returns(Promise.resolve({}))
const barStub = sinon.stub(functionHolder2, 'bar').returns(Promise.resolve({}))
functionHolder.foo()
assert(fooStub.called) // this passes
assert(barStub.called) // this fails
The problem here is that a stub replaces the functionality of the function you are stubbing.
This means that when you stub foo to return a promise, it totally replaces the original foo function.
What you need to do is spy on foo, which will keep its original functionality and flow, while allowing you to find out if its been called and how many times etc.
The actual stubbing of bar is correct - its just that the stub will never actually get called.
What you want (including waiting for the foo call to finish):
const sinon = require('sinon');
const assert = require('assert')
const functionHolder2 = {
bar: function() {
return Promise.resolve('bar')
}
}
const functionHolder = {
foo: function() {
functionHolder2.bar()
return Promise.resolve('foo')
}
}
const fooStub = sinon.spy(functionHolder, 'foo')
const barStub = sinon.stub(functionHolder2, 'bar').returns(Promise.resolve({}))
functionHolder.foo().then(() => {
assert(fooStub.called)
assert(barStub.called)
});
Documentation link: http://sinonjs.org/releases/v4.1.2/spies/