Debugging of Lodash chain functions - lodash

How to debug lodash chain functions in browser.
Ex:
if (_.size(_.values(_.omit(this.user, 'language')).filter(Boolean)) < 2)
If we want to debug _.omit(this.user, 'language') and then the end result with another function _.values() as shown in the example,what should be done.
I tried searching but can only find console.log but if we want to debug right in the browser how can we do it.

Chain functions and lodash sequences are usually "debugged" or "tapped" into via _.tap or _.thru:
tap: This method invokes interceptor and returns value. The interceptor is
invoked with one argument; (value). The purpose of this method is to
"tap into" a method chain sequence in order to modify intermediate
results.
so something like this:
const obj = { name: 'Ace', language: 'English', age: 3 }
const result = _(obj)
.tap(x => console.log(x))
.omit('language')
.tap(x => console.log(x))
.omit('age')
.tap(x=> console.log(x))
.value()
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
thru: This method is like _.tap except that it returns the result of
interceptor. The purpose of this method is to "pass thru" values
replacing intermediate results in a method chain sequence.

Related

Lodash way of creating a custom function

I'm trying to implement a simple function in pure lodash way.
function forward(i) => {
return (j) => {
return String.fromCharCode(i + j)
}
}
So that I can do _.range(26).map(forward(65)). Take me some time to make this work:
function a = _.wrap(String.fromCharCode, (fn, a, b) => fn(a + b))
function b = _.ary(a, 2)
function forward = _.curry(b)
Now my question is is there an easier way to do this? and how do I use sum to construct (fn, a, b) => fn(a + b)?
One last thing is I couldn't find wrap function file in Lodash repo.
The function _.curry(...) is kind of strange when it comes to calling functions with various parameters. Let me guide you with an example below.
The ary-function (_.ary(..., 2)) takes any function and ensures its never called with more than a specific amount of arguments (in this case two). Less arguments than specified, will just end up calling the underlying function with less arguments. A definition of this function could look like this:
function ary() {
const args = arguments;
// implementation
}
There is no way to tell how many arguments the function is expecting, as you would with a function with actual parameters (function(a, b) { }). If you would define const forward1 = _.curry(_.ary(target, 2)), and call it with forward1(42)(2), the curry function would just pass down the first argument to ary as it thinks its done.
We can get around this by using an overload of curry that specifies how many parameters the underlying function is expecting (const forward2 = _.curry(target, 2)). Only in the case where forward2 is called in a curry-style (not sure what its even called) with two parameters, it passes it down to target. A call with one argument will just return a new function, waiting for it to be called with the second argument. Now we can get rid of the ary-call, as it serves us no purpose anymore.
As for chaining actions, there's a helper for that. For example: c(b(a(...) can be rewritten to _.flow([a, b, c]). Lodash also provides a function for a + b, which is _.add().
Together your problem can be rewritten to:
const forward = _.curry(_.flow([_.add, String.fromCharCode]), 2);
or more verbose:
const methods = _.flow([
_.add,
String.fromCharCode
]);
const forward = _.curry(methods, 2);
Note that the 2 corresponds to the amount of parameters the _.add method expects.

Possible to manipulate CasperJS assertions?

My CasperJS asserts seem to be overly strict. I have a function where I am trying to test the names of client logo images from an array, using Casperjs. However I do not seem to be able to use a variable from a forLoop in casperJS.
I understand there are probably hoisting issues that I am not accounting for, but this does not seem to be the primary problem. I have tried several things to resolve hoisting issues, such as immediately invoked functions, try catch blocks, and using ES6 term "Let" in my loop. None seem to work. Then I notice if I simply hard-code the string my variable should represent, and stick a console.log into my assert of a PASSING test, right before the return, the passing test fails.
Here is my failing code
var clients = 'https://www.google.com/';
var logoArray = ["images/logos/AC.png", "images/logos/Affiny.png", "images/logos/ffintus.png", "images/logos/agileAsset.png"]
function checkClientsArrayTest() {
casper.test.begin('The layout is as expected', 10, function suite(test) {
casper.start(clients, function () {
casper.then(function () {
for (var i = 0; i < logoArray.length; i++) {
try { throw i }
catch (ii) {
console.log(ii);
console.log(i);
test.assertEvalEquals(function () {
return document.querySelectorAll('div.client_logo a img')[ii].getAttribute('src')
.match(logoArray[ii]).toString();
}, logoArray[ii], 'Test searches for Client Logos in DOM.');
}
}
});
}).run(function () {
test.done();
});
});
}
If I change logoArray[ii] to a hardcoded string from the first index of the array, it passes. If I consolelog logoArray[ii], it seems to be what I expect. But if I pass a variable to the assert, or even stick a console.log inside of it, the test fails with the following
Running check for the layout of URL: https://www.google.com
0
0
FAIL Test searches for Client Logos in DOM.
type: assertEvalEquals
file: headlessTester.js
subject: null
fn: undefined
params: undefined
expected: "images/logos/AC.png"
Is this an issue of me getting hoisting wrong (shouldn't fail by sticking in a logger if this is the case afaik), or is this due to strictly structured asserts in CasperJS?

Passing custom parameters in render function

I have below code to create column:
DTColumnBuilder.newColumn(null).withTitle('Validation').renderWith(validationRenderer)
and render function:
function validationRenderer(data, type, full, meta) {
.......
}
Now, I want to pass custom parameters to validationRenderer so that I can access it inside the function, like below:
DTColumnBuilder.newColumn(null).withTitle('Validation').renderWith(validationRenderer('abc'))
function validationRenderer(data, type, full, meta, additionalParam) {
// do something with additionalParam
}
I could not find it in the documentation but there must be something to pass additional parameters in meta as per the reference from here
Yes, you can. Or, better, you technically can, but you may use a clever workaround to handle your issue.
I had this issue today, and found a pretty sad (but working) solution.
Basically, the big problem is that the render function is a parameter passed to the datatable handler, which is (of course) isolated.
In my case, to make a pratical example, I had to add several dynamic buttons, each with a different action, to a dynamic datatable.
Apparently, there was no solution, until I thought the following: the problem seems to be that the renderer function scope is somewhat isolated and unaccessible. However, since the "return" of the function is called only when the datatable effectively renders the field, you may wrap the render function in a custom self-invoking-anonymous-function, providing arguments there to use them once the cell is being rendered.
Here is what I did with my practical example, considering the following points:
The goal was to pass the ID field of each row to several different custom functions, so the problem was passing the ID of the button to call when the button is effectively clicked (since you can't get any external reference of it when it is rendered).
I'm using a custom class, which is the following:
hxDatatableDynamicButton = function(label, onClick, classNames) {
this.label = label;
this.onClick = onClick;
this.classNames = this.classNames || 'col5p text-center';
}
Basically, it just creates an instance that I'm later using.
In this case, consider having an array of 2 different instances of these, one having a "test" label, and the other one having a "test2" label.
I'm injecting these instances through a for loop, hence I need to pass the "i" to my datatable to know which of the buttons is being pressed.
Since the code is actually quite big (the codebase is huge), here is the relevant snippet that you need to accomplish the trick:
scope.datatableAdditionalActionButtons.reverse();
scope._abstractDynamicClick = function(id, localReferenceID) {
scope.datatableAdditionalActionButtons[localReferenceID].onClick.call(null, id);
};
for (var i = 0; i < scope.datatableAdditionalActionButtons.length; i++) {
var _localReference = scope.datatableAdditionalActionButtons[i];
var hax = (function(i){
var _tmp = function (data, type, full, meta) {
var _label = scope.datatableAdditionalActionButtons[i].label;
return '<button class="btn btn-default" ng-click="_abstractDynamicClick('+full.id+', '+i+')">'+_label+'</button>';
}
return _tmp;
})(i);
dtColumns.unshift(DTColumnBuilder.newColumn(null).notSortable().renderWith(hax).withClass(_localReference.classNames));
}
So, where is the trick? the trick is entirely in the hax function, and here is why it works: instead of passing the regular renderWith function prototype, we are using a "custom" render, which has the same arguments (hence same parameters) as the default one. However, it is isolated in a self invoking anonymous function, which allows us to arbitrarely inject a parameter inside it and, so, allows us to distinguish, when rendering, which "i" it effectively is, since the isolated scope of the function is never lost in this case.
Basically, the output is as follow:
And the inspection actually shows that elements are effectively rendered differently, hence each "i" is being rendered properly, while it wouldn't have if the function wouldn't have been wrapped in a self invoking anonymous function:
So, basically, in your case, you would do something like this:
var _myValidator = (function(myAbcParam){
var _validate = function (data, type, full, meta) {
console.log("additional param is: ", myAbcParam); // logs "abc"
return '<button id="'+myAbcParam+'">Hello!</button>'; // <-- renders id ="abc"
}
return _validate ;
})('abc');
DTColumnBuilder.newColumn(null).withTitle('Validation').renderWith(_myValidator);
// <-- note that _myValidator is passed instead of "_myValidator()", since it is already executed and already returns a function.
I know this is not exactly the answer someone may be expecting, but if you need to accomplish something that complex in datatable it really looks like the only possible way to do this is using a self invoking anonymous function.
Hope this helps someone who is still having issues with this.

How jasmine spy example works

All;
I am just starting learning Jasmine( version 2.0.3 ), when I got to Spies section, the first example confused me:
describe("A spy", function() {
var foo, bar = null;
beforeEach(function() {
foo = {
setBar: function(value) {
bar = value;
}
};
spyOn(foo, 'setBar');
foo.setBar(123);
foo.setBar(456, 'another param');
});
it("tracks that the spy was called", function() {
expect(foo.setBar).toHaveBeenCalled();
});
it("tracks all the arguments of its calls", function() {
expect(foo.setBar).toHaveBeenCalledWith(123);
expect(foo.setBar).toHaveBeenCalledWith(456, 'another param');
});
it("stops all execution on a function", function() {
expect(bar).toBeNull();
});
});
I wonder if anyone could explain why the setBar function does not affect the bar defined inside describe block? How Jasmine spies deal with this?
Thanks
Because you are not actually executing the methods.
If you want this test to fail:
it("stops all execution on a function", function() {
expect(bar).toBeNull();
});
After these calls:
foo.setBar(123);
foo.setBar(456, 'another param');
Then you should call and.callThrough for your spy.
spyOn(foo, 'setBar').and.callThrough();
From the documentation
Spies: and.callThrough
By chaining the spy with and.callThrough, the spy will still track all
calls to it but in addition it will delegate to the actual
implementation.
With regard to your question, 'how jasmine deals with this?'
From here you can read a basic explanation:
Mocks work by implementing the proxy pattern. When you create a mock
object, it creates a proxy object that takes the place of the real
object. We can then define what methods are called and their returned
values from within our test method. Mocks can then be utilized to
retrieve run-time statistics on the spied function such as:
How many times the spied function was called.
What was the value that the function returned to the caller.
How many parameters the function was called with.
If you want all of the implementation details, you can check the Jasmine source code which is Open Source :)
In this source file CallTracker you can see how the gather data about the method calls.
A little more about the proxy pattern.

How do i check a count value in chai-as-promised?

I use cucumber and chai-as-promised as assertion library. What is the right way to check the count value. I use equal but it works only after converting string to integer.Is there a way to assert a integer value directly?
this.Then(/^the list should contain "([^"]*)" items$/, function (arg1, callback) {
var count=parseInt(arg1);
expect(element.all(by.repeater('item in list.items')).count()).to.eventually.equal(count).and.notify(callback);
});
If you really wanted to, I believe you could bypass parseInt() by using Chai's satisfy() method and JavaScript coercion, as shown below. However, I personally prefer the method you are currently using as it is easier to understand and coercion can be tricky.
this.Then(/^the list should contain "([^"]*)" items$/, function (arg1, callback) {
expect(element.all(by.repeater('item in list.items')).count()).to.eventually.satisfy(function(count) { return count == arg1 } ).and.notify(callback);
});