donnapep donnapep - 3 months ago 11
Node.js Question

Mocha returns undefined for prototype method

I'm trying to run some Mocha tests against a Node module that uses the prototype pattern for creating objects. The code itself runs just fine, but the tests don't.

Here's the code I'm trying to test:

"use strict";

const fs = require("fs"),
request = require("request"),
EventEmitter = require("events").EventEmitter,
util = require("util");

const FileController = function(url, path) {
EventEmitter.call(this);

this.url = url;
this.path = path;
};

FileController.prototype.downloadFile = function() {
if (this.url) {
let file = fs.createWriteStream(this.path);

file.on("finish", function() {
file.close(function() {
this.emit("downloaded");
});
}).on("error", function(err) {
this.handleDownloadError(err, "file-error");
});

// Download the file.
request.get(this.url)
.on("response", function(res) {
if (res.statusCode == 200) {
res.pipe(file);
} else {
fs.unlink(this.path);
}

this.emit("stream", res);
})
.on("error", function(err) {
this.handleDownloadError(err, "request-error");
});
}
};

FileController.prototype.handleDownloadError = function(err, type) {
fs.unlink(this.path);
this.emit(type, err);
};

util.inherits(FileController, EventEmitter);

module.exports = FileController;


And then here's the relevant parts of my test code where I instantiate an object:

beforeEach(function() {
let url = "http://example.com/logo.png",
path = config.downloadPath + "/cdf42c077fe6037681ae3c003550c2c5";

fileController = new FileController(url, path);
// Outputs 'undefined'.
console.log(fileController.downloadFile);
});


When I make the call to
new FileController(url, path)
, it is not attaching the
downloadFile
method that I've attached to the prototype. Instead, trying to call that function gives me
fileController.downloadFile is not a function
.

Any thoughts as to where the problem lies?

Thx!

Answer

This has nothing to do with mocha. You need to inherit before defining your own prototype methods.

From docs

Inherit the prototype methods from one constructor into another. The prototype of constructor will be set to a new object created from superConstructor.

util.inherits(FileController, EventEmitter);

FileController.prototype.downloadFile = function() {}

UPD As for new versions of node. It now sets ctor.prototype prototype so the order doesn't matter anymore.

exports.inherits = function(ctor, superCtor) {

  //...Args check

  ctor.super_ = superCtor;
  Object.setPrototypeOf(ctor.prototype, superCtor.prototype);
};