Unsure why a jest test is failing - node.js

I have the following test code. The test is failing, but I'm not entirely sure why (I have a suspicion, but I'm unsure of how to fix it). Here are the high level classes:
// file myFile.js
const EventEmitter = require('events').EventEmitter;
const em = new EventEmitter();
class Foo {
constructor () {
this.support = 0;
em.on('onNewValue', this._handleNewValue.bind(this));
}
_handleNewValue (newValue) {
this.support = newValue;
console.log(this.support); // Prints whatever newValue is
}
}
class Bar {
setValue (newValue) {
em.emit('onNewValue', newValue);
}
}
Here's the test
const foo = new Foo();
expect(foo.support).toEqual(0); // Passes - initial value of support is 0
const bar = new Bar();
bar.setValue(10); // Emits an event that causes foo to set it's internal support value to 10.
console.log('Checking support'); // This prints after the console.log in foo._handleNewValue.
expect(foo.support).toEqual(10); // This fails - still reports initial value of 0
The high-level idea is that bar.setValue() emits an event that is listened to by the Foo class. The event listener updates the value of it's internal member support to be what the event payload is.
The test fails and reports the initial value of support. My hunch is that there is some timing issue going on (the expect gets called first, and then the event listener inside the Foo class).
However, if I console.log, the log in the event listener prints first, and then the log for 'Checking support', which does not seem to go along that theory.
Could someone help me figure out why this test is failing, and how to fix it? I don't want to explicitly call foo._handleNewValue in the test.

I tried your code using jest and it worked perfectly. Here's what I've tried
// file myFile.js
const EventEmitter = require('events').EventEmitter;
const em = new EventEmitter();
class Foo {
constructor() {
this.support = 0;
em.on('onNewValue', this._handleNewValue.bind(this));
}
_handleNewValue(newValue) {
this.support = newValue;
console.log(this.support); // Prints whatever newValue is
}
}
class Bar {
setValue(newValue) {
em.emit('onNewValue', newValue);
}
}
test('should catch bar emitted event', () => {
const foo = new Foo();
expect(foo.support).toBe(0)
const bar = new Bar()
bar.setValue(10)
expect(foo.support).toBe(10)
})

Related

Does nodejs requires bind class method?

I am using node 12 in my project. Back to 2 years ago, I remember I need to bind method for class instance method like below:
class Logger {
constructor () {
this.printName = this.printName.bind(this);
}
printName (name = 'there') {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
But recently I found I don't need to call bind in the constructor. Does the latest node version support auto-bind already?
The behavior hasn't changed. The situation in which you need to .bind is when the instance's printName method would otherwise get called without a calling context. For example:
class Logger {
printName (name = 'there') {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
const l = new Logger();
const fn = l.printName;
fn();
or with, instead of fn:
setTimeout(l.printName)
or with:
button.addEventListener('click', l.printName)`
In all of these situations, an error will be thrown if you don't use .bind, because the method gets called without a calling context - but the calling context of the Logger instance is needed for this to refer to the instance, so that this.print refers to the print method of the instance.
This sort of thing has always been true in Javascript. Nothing's changed in the past few years, except that it's now a bit easier to bind - you can use new class field syntax instead of having a constructor:
class Logger {
printName = (name = 'there') => {
this.print(`Hello ${name}`);
}
print (text) {
console.log(text);
}
}
const l = new Logger();
const fn = l.printName;
fn();

passing function to a class in nodejs

I have a function that I need to pass to a class I have defined in nodeJs.
The use case scenario is I want to give the implementer of the class the control of what to do with the data received from createCall function. I don't mind if the method becomes a member function of the class. Any help would be appreciated.
//Function to pass. Defined by the person using the class in their project.
var someFunction = function(data){
console.log(data)
}
//And I have a class i.e. the library.
class A {
constructor(user, handler) {
this.user = user;
this.notificationHandler = handler;
}
createCall(){
var result = new Promise (function(resolve,reject) {
resolve(callApi());
});
//doesn't work. Keeps saying notificationHandler is not a function
result.then(function(resp) {
this.notificationHandler(resp);
}) ;
//I want to pass this resp back to the function I had passed in the
// constructor.
//How do I achieve this.
}
callApi(){ ...somecode... }
}
// The user creates an object of the class like this
var obj = new A("abc#gmail.com", someFunction);
obj.createCall(); // This call should execute the logic inside someFunction after the resp is received.
Arrow functions (if your Node version supports them) are convenient here:
class A {
constructor(user, handler) {
this.user = user;
this.notificationHandler = handler;
}
createCall() {
var result = new Promise(resolve => {
// we're fine here, `this` is the current A instance
resolve(this.callApi());
});
result.then(resp => {
this.notificationHandler(resp);
});
}
callApi() {
// Some code here...
}
}
Inside arrow functions, this refers to the context that defined such functions, in our case the current instance of A. The old school way (ECMA 5) would be:
createCall() {
// save current instance in a variable for further use
// inside callback functions
var self = this;
var result = new Promise(function(resolve) {
// here `this` is completely irrelevant;
// we need to use `self`
resolve(self.callApi());
});
result.then(function(resp) {
self.notificationHandler(resp);
});
}
Check here for details: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this

Overriding util.format affects util.(other)

Exploring NodeJS..
BaseClass.js:
const util = require("util");
class BaseClass {
constructor() {
this.util = util;
this.init();
}
init() {
console.log( util.format( "%s", "baseclass format" ) );
console.log( util.isArray( [1,2,3] ) );
util.log( "baseclass log" );
}
}
module.exports = BaseClass;
SubClass.js:
const BaseClass = require("./BaseClass");
class SubClass extends BaseClass {
constructor() {
super();
}
init() {
this.util.format = function() { return "subclass format"; }
this.util.isArray = function() { return "subclass isArray"; }
this.util.log = function() { console.log( "subclass log" ); }
super.init();
}
}
new SubClass();
Output (of node SubClass.js):
subclass format
subclass format
subclass format
Hmm. Comment out util.format override in SubClass.js:
// this.util.format = function() { return "subclass format"; }
Try again. Output (of node SubClass.js):
baseclass format
subclass isArray
subclass log
Can someone tell me why this is happening? I'd've guessed that isArray and log call format within the util module but I'm not sure where to look to verify this. node_modules/node/index.d.ts isn't really enlightening me.
Your intuition is correct. The easiest place to verify this is the docs for console.log (emphasis mine):
console.log([data][, ...args])
Added in: v0.1.100
data <any>
...args <any>
Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).
In the Node.js source you can see where this happens in lib/console.js (line 140).
In your code, this.util is a reference to the object returned by require('util'), so when you replace this.util.format you're replacing it for all code, not just the code inside your class.

ES6, PreloadJS and scope

In PreloadJS' callback functions I'm losing scope. Have tried different methods such as an arrow function (which aren't valid on the highest level etc... Any tips? (sorry for the malformed code block (class defenition etc), still getting used to this editor, trust me, all is working code)...
import Navigation from './Navigation'
import ajax from "./Ajax";
import Helper from "./Helper";
let preload = null;
export default class Page{
constructor(){
this.preload = new createjs.LoadQueue();
this.preload.addEventListener("fileprogress", this.handleFileProgress);
this.preload.addEventListener("fileload", this.handleFileComplete);
}
initPage(_arg = []){
this.buildPage(this.thePage);
}
buildPage(_content){
this.loadImage(item.featured_image_thumbnail_url);
}
handleFileComplete(event){
console.log(event);
console.log(this); // undefined
let el = document.getElementById('heroImage');
let loader = el.getElementsByClassName('loader')[0];
this.showPage(); // cannot read property showPage of undefined
}
// small arrow test, doesn't seem valid
//handleFileComplete = (event) =>{
// this.showPage();
//}
handleFileProgress(event){
let hero = document.getElementById('heroImage')
let loader = hero.getElementsByClassName('loader')[0];
}
loadImage(_img){
let el = document.getElementById('heroImage');
let loader = el.getElementsByClassName('loader')[0];
let loadManifest = [
{
id: 'pat',
src: _img,
scope: this
}];
this.preload.loadManifest(loadManifest, true);
}
showPage(){
//Helper.removeClass(document.getElementById('mytest','hidden'));
}
}
Ok, update after only 5 min....
Addded an arrow function as a variable and passed that on to the event listener. This is not my preferred way but it does work though...
constructor(){
let handleFileCompleted = (event) => {
this.showPage(event)
}
this.preload = new createjs.LoadQueue();
this.preload.addEventListener("fileprogress", this.handleFileProgress);
this.preload.addEventListener("fileload", handleFileCompleted);
}
showPage(event){
console.log('I'm now reachable!');
console.log(event); // fileload event
}
Perhaps this can help anybody out.
Still interested to see if there's a better way though...

Adding event listener on instance, not function

See example below. I am trying to trigger an event on a.
var events = require("events");
function foo() {
this.on("ping", function() {
console.log("bar!");
})
}
foo.prototype = new events.EventEmitter();
var a = new foo();
var b = new foo();
a.emit("ping");
This prints "bar!" two times, so I am assuming I am adding the event listener on "all" the functions, not the specific instance. Since I am running foo two times, I am adding two event listeners, nothing strange really, althought not so intuitive.
Is there a way to add the event listener only on a?
(Please edit this question if I am using the wrong terminology, used to class-based programming)
edit: So I suspect it is because I am using the same event emitter as prototype.. But in that case, how can I create one for each new foo()?
Typically you inherit (from EventEmitter) like this:
var inherits = require('util').inherits,
EventEmitter = require('events').EventEmitter;
function Foo() {
if (!(this instanceof Foo))
return new Foo();
EventEmitter.call(this);
this.on('ping', function() {
console.log('bar!');
});
}
inherits(Foo, EventEmitter);
// add Foo-specific prototype functions *after* `inherits()`
Foo.prototype.myfunc = function(a, b) {
return a + b;
});
var a = new Foo();
var b = new Foo();
a.emit('ping');
This is the setup that most modules on npm and objects in node core use to inherit from another object.

Resources