1

Overview

I have a simple module written in nodejs that uses fs-extra package to test if a file exists. The module throws when the path exists and proceed to next procedure otherwise. Here is the source file:

// - main.js -
import fs from 'fs-extra'

export default async (pathName) => {
  // Do not proceed if path already exists.
  if (await fs.pathExists(projectPath)) {
    throw new Error(chalk.red.bold(`${projectPath} already exists`))
  }

  // more logic here
}

I want to write a unit test that tests the bellow logic:

  • If filepath exists, we expect to throw an error

I don't want to mess up with the real filesystem -in case my code contains some nasty bug that could destroy it- so I went to an alternative solution, mocking the filesystem using mock-fs. Here is the spec file:

// - main.js spec file -
import mainFunction from '../main'
import mockfs from 'mock-fs'

describe('test main function', () => {
  beforeEach(() => {
    mockfs({
      home: {
        user: {
          dummy: {}
        }
      }
    })
  })

  test('expect to throw', async () => {
    await mainFunction('/home/user/dummy')
  })

  afterEach(() => {
    mockfs.restore()
  })
})

What's the problem?

Every time I run the test, the main function does not throw. This happens because mockfs fake-filesystem was declared in the spec file, so the fs module in main source file does not know for the mockfs fake-filesystem and checks the real one. By the time that I do not have a folder named /home/user/dummy in my real filesystem the check always fails.

Expected behaviour

mainFunction in spec file should throw

Actual behaviour

mainFunction in spec file DOES NOT throw

Other info

I guess that I can turn this unit test into an integration test. But I do not want to. Is there any fix for this? Do I have to use another packages? My test suit is Jest 22.3.0.

5
  • Why don't you just test some random path that is guaranteed to not exist? Like /does/not/exist. I'm pretty sure this won't destroy your filesystem since you're relying on the fs-extra module, so as long as that module doesn't destroy filesystems you should be good to go. Commented Feb 27, 2018 at 12:17
  • @devius thanks for the reply. The meaning of this is to find a way to do this with unit tests and not e2e. I know that your answer is a nice alternative, but I wondered if there is a way to do this otherwise. Commented Feb 27, 2018 at 12:20
  • Well.... it's super convoluted, but you could modify the fs-extra module in the requires cache to point to your mock-fs module instead, and then after the test is done reload the proper fs-extra module. But it seems too much trouble just for fear of damaging file system, or to try to take "unit" testing extremely to the letter. Maybe I should add this as an answer. Commented Feb 27, 2018 at 12:26
  • Possibly of interest for consideration: stackoverflow.com/questions/15630072/… Commented Feb 27, 2018 at 12:29
  • @devius thank you for your comments. I found the solution. See bellow. Commented Feb 27, 2018 at 12:45

1 Answer 1

1

After some search, I found the appropriate way to unit test the branch. We really do not have to use the mock-fs module. We just have to mock pathExists method of fs-extra module to return one time the value false and one time the value true. Bellow, I post a working version of my spec file:

import mainFunction from '../main'

require('fs-extra').pathExists = jest.fn().mockReturnValueOnce(false).mockReturnValueOnce(true)

describe('test main function', () => {
  beforeEach(() => {
    jest.clearAllMocks()
  })

  test('expect to not throw', async () => {
    await expect(mainFunction('/dummy/path/does/not/matter')).resolves
  })

  test('expect to throw', async () => {
    await expect(mainFunction('/dummy/path/does/not/matter')).rejects.toBeInstanceOf(Error)
  })
})
Sign up to request clarification or add additional context in comments.

1 Comment

It is working because you have handled the promise rejection. Can you re-run the same by removing the promise rejection and confirm if it still works?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.