josemigallas
josemigallas

Reputation: 3918

NodeJS fs.appendFile not working within promise in mocha

I want to keep a log during my integration test suite. I'm testing that every 'item' is being compiled and logging how much time it took. I'm using node 4.3.

First of all I create the log file:

before(function() {
    if (!fs.existsSync("./log.csv")) {
        fs.writeFile("./log.csv", "Name; Time");
    }
});

Then within each it block I would do this:

for (const item of items) {    
    it('compiles', function() {
        return item.testCompile();
    });
}

And item class has these methods:

testCompile() {
    return this
        .buildItem()
        .then(result => {
            // whatever testing stuff
        });
}

buildItem() {
    return this
        .internalLogicForCompiling()
        .then(result => {
            // This is not appending anything 
            fs.appendFile("./log.csv", `${item.name}; ${result.compileTime}`);

            return result;
        });
}

So far the file is created but never updated... Any clue what I'm doing wrong?

PS: I assume if the file doesn't exists, fs should throw an error, however it doesn't.

Upvotes: 0

Views: 3939

Answers (1)

Louis
Louis

Reputation: 151491

Your code is generally ignoring the fact that your fs calls are asynchronous. Promises are not magic. If you use code that is asynchronous but does not use promises, you need to do more than plop that code in a promise can call it done.

The easiest way to deal with the issue would be to use fs.writeFileSync and fs.appendFileSync instead of the calls you make. Otherwise, you should write your before like this:

before(function(done) {
    if (!fs.existsSync("./log.csv")) {
        fs.writeFile("./log.csv", "Name; Time", done);
    }
});

I've just added the done callback.

And buildItem could be something like this so that the promise it returns won't resolve before appendFile is done doing its work:

buildItem() {
    return this
        .internalLogicForCompiling()
        .then(result => {
            return new Promise((resolve, reject) => {
                fs.appendFile("./log.csv", `${item.name}; ${result.compileTime}`, (err) => {
                    if (err) {
                        reject(err);
                        return;
                    }
                    resolve(result);
                });
            });
        });
}

Upvotes: 1

Related Questions