0

I'm new to Node.js and jasmine, and my JavaScript experience is old and rusty, so I'm a newbie there too. I finished Manuel Kiessling's book, The Node Beginner Book, and I am working my way through his second book, The Node Craftsman Book. I'm stuck on the FilesizeWatcher tutorial. I've been able to run earlier tests but this one is not working. There is a similar question on SO: No output from jasmine-node but the answer isn't working for me.

I'll post my code here and hopefully somebody can tell me what I'm doing wrong.

FilesizeWatcherSpec.js:

'use strict';

var FilesizeWatcher = require('./FilesizeWatcher');
var exec = require('child_process').exec;

describe('FilesizeWatcher', function() {
    var watcher;

    afterEach(function() {
        watcher.stop();
    });

    it('should fire a "grew" event when the file grew in size', function(done) {

        var path = './var/tmp/filesizewatcher.test';
        exec('rm -f ' + path + ' ; touch ' + path, function() {
            watcher = new FilesizeWatcher(path);

            watcher.on('grew', function(gain) {
                expect(gain).toBe(5);
                done();
            });

            exec('echo "test" > ' + path, function(){});

        });
    });

    it('should fire a "shrank" event when the file shrank in size', function(done) {

        var path = './var/tmp/filesizewatcher.test';
        exec('rm -f ' + path + ' ; echo "test" > ' + path, function() {
            watcher = new FilesizeWather(path);

            watcher.on('shrank', function(loss) {
                expect(loss).toBe(3);
                done();
            });

            exec('echo "a" > ' + path, function(){});

        });
    });

    it('should fire an "error" if path does not start', function(done) {

        var path = 'var/tmp/filesizewatcher.test';        
        watcher = new FilesizeWather(path); 

        watcher.on('error', function(err) {
            expect(err).toBe('Path does not start with a slash');
            done();
        });

    });

});

FilesizeWatcher.js:

'use strict';

var fs = require('fs');
var util = require('util');
var EventEmitter = require('events').EventEmitter;

var FilesizeWatcher = function (path) {
    var self = this;

    if (/^\//.test(path) === false) {
        process.nextTick(function() {
            self.emit('error', 'Path does not start with a slash');
        });
        return;
    }

    fs.stat(path, function (err, stats) {
        console.log('stats= ' + stats);
        self.lastfilesize = stats.size;
    });

    self.interval = setInterval(            
            function () {
                console.log('We are in function()');
                fs.stat(path, function (err, stats) {
                    if (stats.size > self.lastfilesize) {
                        self.emit('grew', stats.size - self.lastfilesize);
                        self.lastfilesize = stats.size;
                    }
                    if (stats.size < self.lastfilesize) {
                        self.emit('shrank', self.lastfilesize - stats.size);
                        self.lastfilesize = stats.size;
                    }
                }, 1000);
            });
};

util.inherits(FilesizeWatcher, EventEmitter);

FilesizeWatcher.prototype.stop = function () {
    clearInterval(this.interval);
};

module.exports = FilesizeWatcher;

Console output:

C:\Users\pdl\Projects\NodeCraftsman>jasmine-node ./FilesizeWatcherSpec.js

C:\Users\pdl\Projects\NodeCraftsman>

Other tests run fine:

C:\Users\pdl\Projects\NodeCraftsmanTestDrivenDevelopment>jasmine-node spec\greetSpec.js
..

Finished in 0.006 seconds
2 tests, 2 assertions, 0 failures, 0 skipped


C:\Users\pdl\Projects\NodeCraftsmanTestDrivenDevelopment>

I added --captureExceptions to see if I could get any information and I got the TypeError: self.callbacks.error is not a function.

My first problem was as Eppilo suggested below, that I needed to use process.nextTick on self.callbacks'error'. Mixing async code with sync code causes the error event to be fired before the error handler is registered. So I made the changes and am now using the EventEmitter but I'm still getting the following errors:

If I include the "." in the path: var path = './var/tmp/filesizewatcher.test'; then the file gets written. Otherwise, it does not.

If the file does NOT get written, stats= undefined and I receive this error:

TypeError: Cannot read property 'size' of undefined
    at C:\Users\pdl\Projects\NodeCraftsman\FilesizeWatcher.js:19:34
    at FSReqWrap.oncomplete (fs.js:82:15)

If the file DOES get written, then I receive this error:

Error: Uncaught, unspecified "error" event. (Path does not start with a slash)
    at emit (events.js:144:17)
    at C:\Users\pdl\Projects\NodeCraftsman\FilesizeWatcher.js:12:18
    at nextTickCallbackWith0Args (node.js:419:9)
    at process._tickCallback (node.js:348:13)

Of course, it's not supposed to start with a slash. That is the test. But when I remove the --captureExceptions from the command, I still get no output.

Community
  • 1
  • 1
Patricia
  • 5,019
  • 14
  • 72
  • 152

2 Answers2

2

First of all try and run Jasmine on verbose mode and capture exceptions:

jasmine-node ./FilesizeWatcherSpec.js --verbose --captureExceptions

Link: https://github.com/mhevery/jasmine-node/wiki/Command-Line-Usage

Also try to make the error checking asynchronous:

if (/^\//.test(path) === false) {
    process.nextTick(function() {
        self.callbacks['error']('Path does not start with a slash');
    });
    return;
}
Eppilo
  • 763
  • 6
  • 19
  • I tried using `--verbose` but nothing happened. I clicked on your link and got results with `--captureExceptions` and I received the following error: TypeError: Cannot read property 'size' of undefined at C:\Users\pdl\Projects\NodeCraftsman\FilesizeWatcher.js:16:34 at FSReqWrap.oncomplete (fs.js:82:15) It's in this code: fs.stat(path, function (err, stats) { console.log('stats= ' + stats); self.lastfilesize = stats.size; }); Sure enough, `stats= undefined` – Patricia Feb 26 '16 at 16:04
  • This is a Windows OS. Do I need to create the file or do something special to write to it that is different than in the unit test? – Patricia Feb 26 '16 at 16:04
  • I started testing the cmd commands. I needed a "." in my var path and the folder structure must exist to create the file. Now I'm getting a different error, which I will post along with my updated code according to your suggestions. Thank you for your help. – Patricia Feb 26 '16 at 17:00
  • Ok will delete part of the answer and wait to see what the error is. You are right on the --captureExceptions option is the one you want, --verbose won't cut it. As a learner myself, I actually use both to figure things out. – Eppilo Feb 26 '16 at 17:10
  • No, Eppilo, you're great! I've updated the question with the error. I'll keep researching but I appreciate your help so much. Thank you again. – Patricia Feb 26 '16 at 17:24
  • 1
    Ok I think you got it. I seem to remember that the new error you are getting is intended and you need to fix it using process.nextTick on self.callbacks['error']('blahblah'). In node.JS, as I have recently learned, you never mix async code with sync code. In this case the error event is probably fired before you register the error handler. Hence the use of nextTick() – Eppilo Feb 26 '16 at 17:38
  • Eppilo: Please take another look at my code, if you can. You are correct and I'll give you the points but something is still wrong. Can you please help? – Patricia Feb 26 '16 at 20:14
  • I think you are correct in assuming that Windows file system is to blame. "/var/tmp" on a Mac / Unix would refer to a path that exists already from "home" (your HD in practice). This is an exercise so you should probably change it to fit your system. What if you create a C:\var\tmp folder and drop the "."? Would it work? – Eppilo Feb 26 '16 at 20:44
  • Hey, Eppilo: Have you ever worked with the npm db-migration? – Patricia Mar 04 '16 at 21:59
  • Not really much. But shoot the question. I wonder how we can open this comments trail as a chat, we are starting to pollute the question and answer. – Eppilo Mar 06 '16 at 10:46
1

Newbie as well, with not enough reputation to comment.

I got the same no output on my Mac too, and was able to get the test to work with this.

There is an error in FilesizeWatcher.js.

Currently:

self.interval = setInterval(
    function (){ 
       ...          
       fs.stat(path, function (err, stats) {
          ...
    }, 1000); 
});

It should instead be:

self.interval = setInterval(
    function (){ 
       ...          
       fs.stat(path, function (err, stats) {
          ...
    }); 
},1000);

Just sharing my findings, cheers.