Initial Prerequisites

For our unit test assertions we’re going to be using Mocha and Chai. Let’s add these to our project:

npm i mocha chai --save-dev

Additionally, you’ll see that our checkFileAccess private method uses promises. Chai has an additional library to handle promises. Let’s add this library to our project:

npm i chai-as-promised --save-dev

Finally, let’s import these for use in our specs by adding the following to the top of the test file:

var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised).should();

One Final Note

There are a number of node modules that will “mock” the filesystem for unit testing against methods using fs. In essence, they create a physical, temporary file structure. This, in my opinion, is a terrible idea as 1) this is, technically, an integration test; 2) your test runner may execute tests in parallel and create race issues where the file exists and shouldn’t, or vice versa; and, 3) if your test runner errors out in the middle of testing, then the filesystem isn’t cleaned up and will requiring manual cleaning (e.g. deleting temporary files and folders) before the next run. For these reasons, it is my preference to, instead, stub fs and control the results.

In order to stub fs, we’re going to need to stub the error code that’s returned by fs.access. So let’s go ahead and add that variable just inside our top describe:

var err;

First Three Tests

The first three tests are pretty simple to complete. You’ll see in the code below. However, our tests won’t actually pass yet as we haven’t stubbed fs or printTempPdfMessage. We’ll do that in a minute. But, let’s go ahead and add the necessary code to the tests.

We’ll cover each test individually.

        it('should return true for "temppdf.md" not existing', () => {
            err = { 
                code: 'ENOENT'
            };

            return tempFile.deleteTempPdf().should.eventually.be.true;
        })

In our first test, fs.access should return an object with the code ENOENT indicating that the temppdf.md doesn’t exist. So, we mock the object to ensure that fs.access returns the correct result. In turn, checkFileAccess will return ‘0’ and satisfy our first condition. As for the test, the should.eventually.be assertion is an extension of Chai made available to us through chai-as-promised. This test will allow us to test our promise in checkFileAccess. The final note is that tempFile is referencing the imported module of our methods under test. We’ll import this file later in this post.

        it('should return false for "temppdf.md" being readonly', () => {
            err = {
                code: 'SOMETHING_ELSE'
            };

            return tempFile.deleteTempPdf().should.eventually.be.false;
        })

This test is very similar to our first with the exception of the error code. In the first, we’re expecting ENOENT for indicating that the temppdf.md file doesn’t exist. However, for this case, we do want the file to exist, but be read-only. In order to test this, we simply need the error code to be anything but ENOENT. Therefore, we simply provide a random value.

        it('should return false for "temppdf.md" existing, being writable, but not deleted successfully', () => {
            err = null;

            return tempFile.deleteTempPdf().should.eventually.be.false;
        })

Our third test will pass in null for our error. This will force checkFileAccess to return ‘2’ both times it is called from deleteTempPdf eventually resulting in a return value of false.

At this point, we’ve completed three of our five tests. Again, they won’t run yet as we still need to stub a couple of methods, but that’s where the real magic happens and we’ll take a look at that on the next page. As for now, your tests should look like the following:

describe('tempFile', () => {
    var err;

    describe('deleteTempPdf', () => {
        it('should return true for "temppdf.md" not existing', () => {
            err = { 
                code: 'ENOENT'
            };

            return tempFile.deleteTempPdf().should.eventually.be.true;
        })

        it('should return false for "temppdf.md" being readonly', () => {
            err = {
                code: 'SOMETHING_ELSE'
            };

            return tempFile.deleteTempPdf().should.eventually.be.false;
        })

        it('should return true for "temppdf.md" existing, being writable and being deleted successfully', () => {

        })

        it('should return false for "temppdf.md" existing, being writable, but not deleted successfully', () => {
            err = null;

            return tempFile.deleteTempPdf().should.eventually.be.false;
        })

        it('should return false for unknown error when checking access of "temppdf.md"', () => {

        })
    })
})

Like What You See?

Subscribe to receive new posts in your inbox.

Privacy Preference Center