Understanding Methods Chaining in Javascript - javascript

I'm new to ES6 and Javascript and I can't figure out what's wrong with chaining this dump() method in the following piece of code.
It returns "main.js:25 Uncaught TypeError: Cannot read property 'dump' of undefined":
class TaskCollection {
constructor(tasks = []) {
this.tasks = tasks;
}
addTasks(newTasks = []) {
this.tasks = this.tasks.concat(newTasks);
}
dump() {
console.log(this.tasks);
}
}
let myTasks = new TaskCollection([
'Do stuff'
]);
myTasks.addTasks([
'New Task'
]).dump();
Now if I don't chain that dump() method, everything would work just fine.
myTasks.addTasks([
'New Task'
]);
myTasks.dump();

Method addTasks is not returning a reference to the object. If you want chaining to work, your method needs to look like this:
addTasks(newTasks = []) {
this.tasks = this.tasks.concat(newTasks);
return this;
}

In order to use method chaining, you need to return this from the earlier method. In your case, you don't return this from addTasks, so the result of calling addTasks is undefined, and you can't call methods on undefined.
So just add
return this;
...to any method you want to be able to chain from.
Method chaining is not something special. When you do:
addTasks(/*...*/).dump();
what you're doing is effectively:
var x = addTasks(/*...*/);
x.dump();
...just without the variable. Depending on how addTasks is written, you might be calling dump on the same object (method chaining) or on some other object entirely (if addTasks returned something other than this).

You should return this in *addTasks* method
class TaskCollection {
constructor(tasks = []) {
this.tasks = tasks;
}
addTasks(newTasks = []) {
this.tasks = this.tasks.concat(newTasks);
return this;
}
dump() {
console.log(this.tasks);
}
}
let myTasks = new TaskCollection([
'Do stuff'
]);
myTasks.addTasks([
'New Task'
]).dump();

Related

Mock ES6 class to create a sequence of deterministic instances

My SUT (SoundPlayerConsumer class) creates multiple instances of a class that I need to mock (SoundPlayer). How can I mock this SoundPlayer class so that it returns a deterministic object each time it's called?
For example, my classes:
// sound-player.js
module.exports = class SoundPlayer {
constructor(sound) {
this.sound = sound;
}
playSound() {
console.log(`Playing ${sound}`);
}
}
// sound-player-consumer.js
module.exports = class SoundPlayerConsumer {
constructor(soundPlayer) {
this.helloSound = new SoundPlayer('hello');
this.goodbyeSounnd = new SoundPlayer('goodbye');
}
playSounds() {
this.helloSound.playSound();
this.goodbyeSounnd.playSound();
}
}
What I'm trying to achieve (something along these lines):
// sound-player-consumer.test.js
const mockHelloPlayer = { playSound: jest.fn() };
const mockGoodbyePlayer = { playSound: jest.fn() };
jest.mock('./sound-player', () => {
return jest.fn() // constructor function
.mockReturnValueOnce(mockHelloPlayer) // first returns the hello player
.mockReturnValueOnce(mockGoodbyePlayer); // then returns the goodbye player
});
test('hello then goodbye', () => {
const consumer = new SoundPlayerConsumer();
consumer.playSounds();
expect(mockHelloPlayer.playSound).toBeCalled();
expect(mockGoodbyePlayer.playSound).toBeCalled();
expect(mockHelloPlayer.playSound.mock.invocationCallOrder[0])
.toBeLessThan(mockGoodbyePlayer.playSound.mock.invocationCallOrder[0]);
});
This test throws an error:
TypeError: this.helloSound.playSound is not a function
I've read over the docs several times and still dont fully understand the module-factory approach - but this error is something to do with my mock objects "not wrapped in an arrow function and thus accessed before initialization after hoisting"
I'm sure there's something really obvious I'm missing here. Any help appreciated!

How to stub function that returns a promise?

I'm trying to stub a function using sinon. The function has the following signature
export function getIndexDocument(
svc: MetaHTTPService | ServiceConfig
): MetaPromise<RepoResponseResult<IndexDocument>> {
Is this the right way to sub it
sandbox.stub(getIndexDocument).resolves({} as RepoResponseResult)
I tried that but it returns an error.
Here's how this function is called.
I have a class called AssetsController with the following functions
public async exploreIndexDocument(): Promise<Asset | undefined> {
// it makes an HTTP request and returns a promise that resolves with the following info { repoId: "", assetId: "" }
const {
result: { assignedDirectories }
} = await getIndexDocument(this.serviceConfig).catch(err => {
throw new Error(`Bad repsonse`);
});
return {
repoId: result.repoId;
assetId: result.assetId
}
}
public async function copyAsset(asset) {
const res = await this.exploreIndexDocument();
const repoId = res.repoId;
return asset.copy(repoId);
}
I'm trying to test the function copyAsset, but it calls exploreIndexDocument which calls getIndexDocument. getIndexDocument is imported at the top of the file and lives in the module #ma/http.
getIndexDocument makes an HTTP request.
How can I test copyAsset given that it calls getIndexDocument which makes an HTTP request?
According to the docs, you can't stub an existing function.
You can:
// Create an anonymous sstub function
var stub = sinon.stub();
// Replaces object.method with a stub function. An exception is thrown
// if the property is not already a function.
var stub = sinon.stub(object, "method");
// Stubs all the object’s methods.
var stub = sinon.stub(obj);
What you can't do is stub just a function like:
var stub = sinon.stub(myFunctionHere);
This makes sense because if all you have is a reference to a function, then you can just create a new function to use instead, and then pass that into where ever your test needs it to go.
I think you just want:
const myStub = sandbox.stub().resolves({} as RepoResponseResult)
In your update it sounds like you want to put the stub on the AssetsController class. See this answer for more info on that, but in this case I think you want:
const myStub = sandbox
.stub(AssetsController.prototype, 'exploreIndexDocument')
.resolves({} as RepoResponseResult)
Now anytime an instance of AssetsController calls its exploreIndexDocument method, the stub should be used instead.
Playground
I think most of your problems can be solved by revisiting your architecture. For example, instead of creating an explicit dependency on getIndexDocument within your AssetController class you can simply inject it in. This will allow you to swap implementations depending on the context.
type IndexDocumentProvider = (svc: MetaHTTPService | ServiceConfig) => MetaPromise<RepoResponseResult<IndexDocument>>;
interface AssetControllerOptions {
indexDocumentProvider: IndexDocumentProvider
}
class AssetController {
private _getIndexDocument: IndexDocumentProvider;
public constructor(options: AssetControllerOptions) {
this._getIndexDocument = options.indexDocumentProvider;
}
}
Then you can use this._getIndexDocument wherever and not worry about how to make the original implementation behave like you want in your tests. You can simply provide an implementation that does whatever you'd like.
describe('copyAsset', () => {
it('fails on index document error.', () => {
const controller = new AssetController({
indexDocumentProvider: () => Promise.reject(new Error(':('));
});
....
});
it('copies asset using repo id.', () => {
const controller = new AssetController({
indexDocumentProvider: () => Promise.resolve({ repoId: "420" })
});
...
});
});
You can obviously use stubs instead of just functions or whatever if you need something fancy.
Above we removed an explicit dependency to an implementation and instead replaced it with a contract that must be provided to the controller. The is typically called Inversion of Control and Dependency Injection

How to add a custom property or method to a promise?

Regular promises have the beloved .then() and .catch() functions.
When promising to retrieve an object that itself has properties that return promises we find chains of promises such as the following:
require("clientside-view-loader")
.then((view)=>
return view.load("clientside-view-modal-login_signup");
})
.then((compiler)=>{
return compiler.generate()
})
.then((modal)=>{
document.body.appendChild(modal);
modal.show("login");
})
This is UGLY!
How can we modify a promise to attach a custom property so that we can convert the above into the following?
require("clientside-view-loader")
.load("clientside-view-modal-login_signup")
.generate()
.then((modal)=>{
document.body.appendChild(modal);
modal.show("login");
})
note, these examples use the clientside-require require and not the nodejs require
How can we modify a promise to attach a custom property so that we can convert the above into the following?
You don't modify promises at all. You just implement the builder pattern for the above promise chain.
class ClientSideViewLoader {
constructor(p = Promise.resolve()) {
this.promise = p;
}
static init() {
return new this(require("clientside-view-loader"));
}
load(x) {
return new this.constructor(this.promise.then(view =>
view.load(x)
));
}
generate() {
return new this.constructor(this.promise.then(compiler =>
compiler.generate()
));
}
then(...args) {
return this.promise.then(...args);
}
}
ClientSideViewLoader.init()
.load("clientside-view-modal-login_signup")
.generate()
.then(modal => {
document.body.appendChild(modal);
modal.show("login");
})
No need to do anything complicated like subclassing Promise. If you want, you can also dynamically generate all these methods.
This is UGLY!
Well, if you were looking for beautiful promise code, you would simply use modern async/await syntax instead of then callbacks:
const view = await require("clientside-view-loader");
const compiler = await view.load("clientside-view-modal-login_signup");
const modal = await compiler.generate();
document.body.appendChild(modal);
modal.show("login");
Your initial code can be made shorter and more readable simply by using different syntax for your arrow functions. These two rules of arrow function syntax are relevant:
parentheses are optional around the only argument of single-argument functions
single-statement functions that return a value can have the {} and the return removed
Thus, you could write your code like this, with the short form view => … instead of (view) => { return …; }:
require("clientside-view-loader")
.then(view => view.load("clientside-view-modal-login_signup"))
.then(compiler => compiler.generate())
.then(modal => {
document.body.appendChild(modal);
modal.show("login");
});
If you know the properties you wish to add in advance you can simply append a property to the promise like you would any other object:
view_loader.load = function(path){
return this.then((view_loader)=>{
return view_loader.load(path)
})
}
view_loader.load(...) // now works!
Here's a function that does this for a dynamic set of properties:
function modify_orig_promise(original_promise, properties_to_append){
var blacklist = ["then", "catch", "spread"];
var function_keys = Object.keys(properties_to_append);
for(var i = 0; i < function_keys.length; i++){
var function_key = function_keys[i];
if(blacklist.indexOf(function_key) > -1) {
console.warn("properties_to_append in require(__, {functions : {} }) included a blacklisted function name : `"+key+"`. skipping this property.")
} else {
var requested_function = properties_to_append[function_key];
original_promise[function_key] = requested_function; // append the function to the promise
}
}
return original_promise;
}
Then
var properties_to_append = {
load : function(path){
return this.then((view_loader)=>{ return view_loader.load(path)})
}
}
modified_require = modify_orig_promise(require("clientside-view-loader"), properties_to_append);
modified_require.load("clientside-view-modal-login_signup") // Works
If you dont know the properties in advance (e.g., the properties are determined from a promise) you'll need to use a proxy that waits until that promise resolves to respond. This is answered here: How to add properties to a promise asynchronously?

Why would you ever call .call() on Observable functions?

I am a relative beginner in Angular, and I am struggling to understand some source I am reading from the ng-bootstrap project. The source code can be found here.
I am very confused by the code in ngOnInit:
ngOnInit(): void {
const inputValues$ = _do.call(this._valueChanges, value => {
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
});
const results$ = letProto.call(inputValues$, this.ngbTypeahead);
const processedResults$ = _do.call(results$, () => {
if (!this.editable) {
this._onChange(undefined);
}
});
const userInput$ = switchMap.call(this._resubscribeTypeahead, () => processedResults$);
this._subscription = this._subscribeToUserInput(userInput$);
}
What is the point of calling .call(...) on these Observable functions? What kind of behaviour is this trying to achieve? Is this a normal pattern?
I've done a lot of reading/watching about Observables (no pun intended) as part of my Angular education but I have never come across anything like this. Any explanation would be appreciated
My personal opinion is that they were using this for RxJS prior 5.5 which introduced lettable operators. The same style is used internally by Angular. For example: https://github.com/angular/angular/blob/master/packages/router/src/router_preloader.ts#L91.
The reason for this is that by default they would have to patch the Observable class with rxjs/add/operators/XXX. The disadvantage of this is that some 3rd party library is modifying a global object that might unexpectedly cause problems somewhere else in your app. See https://github.com/ReactiveX/rxjs/blob/master/doc/lettable-operators.md#why.
You can see at the beginning of the file that they import each operator separately https://github.com/ng-bootstrap/ng-bootstrap/blob/master/src/typeahead/typeahead.ts#L22-L25.
So by using .call() they can use any operator and still avoid patching the Observable class.
To understand it, first you can have a look at the predefined JavaScript function method "call":
var person = {
firstName:"John",
lastName: "Doe",
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var myObject = {
firstName:"Mary",
lastName: "Doe",
}
person.fullName.call(myObject); // Will return "Mary Doe"
The reason of calling "call" is to invoke a function in object "person" and pass the context to it "myObject".
Similarly, the reason of this calling "call" below:
const inputValues$ = _do.call(this._valueChanges, value => {
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
});
is providing the context "this._valueChanges", but also provide the function to be called base on that context, that is the second parameter, the anonymous function
value => {
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
}
In the example that you're using:
this._valueChanges is the Input Event Observerable
The _do.call is for doing some side affects whenever the event input happens, then it returns a mirrored Observable of the source Observable (the event observable)
UPDATED
Example code: https://plnkr.co/edit/dJNRNI?p=preview
About the do calling:
You can call it on an Observable like this:
const source = Rx.Observable.of(1,2,3,4,5);
const example = source
.do(val => console.log(`BEFORE MAP: ${val}`))
.map(val => val + 10)
.do(val => console.log(`AFTER MAP: ${val}`));
const subscribe = example.subscribe(val => console.log(val));
In this case you don't have to pass the first parameter as the context "Observable".
But when you call it from its own place like you said, you need to pass the first parameter as the "Observable" that you want to call on. That's the different.
as #Fan Cheung mentioned, if you don't want to call it from its own place, you can do it like:
const inputValues$=this._valueChanges.do(value=>{
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
})
I suppose
const inputValues$ = _do.call(this._valueChanges, value => {
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
});
is equivalent to
const inputValues$=this._valueChanges.do(value=>{
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
})
In my opinion it's not an usual pattern(I think it is the same pattern but written in different fashion) for working with observable. _do() in the code is being used as standalone function take a callback as argument and required to be binded to the scope of the source Observable
https://github.com/ReactiveX/rxjs/blob/master/src/operator/do.ts

Modifying Angular Factory Object from inside a function

This is the function that I am working with to call my factory
var myService = function($http) {
return {
bf: null,
initialize: function() {
this.promise = $http.get(this.server + "/requestkey").success(function(data) {
myService.bf = new Blowfish(data.key);
});
}
}
And I am creating this object using
TicTacTorrent.service('AService', ['$http', myService]);
However, when calling AService.initialize() it creates the promise object like it should, but it doesn't update the BF object. I'm confused as to how to update the bf object to be the new value. How would I reference myService.bf since this.bf would create a local instance for .success function?
Try this:
var myService = function($http) {
this.bf = null;
return {
bf: this.bf,
initialize: function() {
this.promise = $http.get(this.server + "/requestkey").success(function(data) {
myService.bf = new Blowfish(data.key);
});
}
}
Where do you want to initialize?
Have you seen the $provider example code?
Search for "provider(name, provider)" and check if it suits your need.
Otherwise I'm unsure what the code you'vew written will run like.
I usually write factories like this:
angular.module('app').factory('myService', ['$http', function($http) {
var publicObj = {};
publicObj.bf = ""; // Just to make sure its initialized correctly.
publicObj.initialize = function() {snip/snap... myService.bf = new Blowfish(data.key);};
return publicObj;
}]);
The difference might be that you previous code returned an inline anonymous object which might have a hard time referring to itself. But by that logic it should work by just making myService return a predeclared var and returning that.

Categories