Node.js Test Tips - File System

Unit tests are a crucial component of development. In the context of Node.js, I use vitest. Today, I want to show you my approach to working with the file system. There are a few tricks that make life considerably easier.

2 minutes

When working with Node.js and the file system, I recommend using an in-memory file system for testing. There are two reasons for this:

  1. The in-memory file system is high-speed compared to accessing the real file system – even with today's high-speed hard drives.
  2. The in-memory file system allows you to define preconditions and postconditions within a test, enabling it to be executed in isolation from all other tests. Even better: Multiple tests can run in parallel and make changes in their own virtual file systems.

As is often the case in IT, there are also drawbacks. A significant disadvantage of the packages I'm familiar with is that their permissions systems are either not implemented or only partially implemented. This means you can't test access rights – who has what permissions. I haven't yet found a viable solution for this. So, if you have any ideas, please leave a comment.

Necessary Installation and Configuration

I'm working with the memfs NPM package. To integrate it, you need to mock the internal Node.js libraries. The best way to do this is in a setup.ts file, which you configure in vitest. To round off my last tip: Make sure to reset the in-memory file system globally once. This will save you a lot of debugging time. I've tested it for you 😉.

export default {
  test: {
    // ...
   setupFiles: [
      'tests/helper/setupTests.ts',
    ]
    // ...
  },
}

An excerpt from vitest.config.js

// --- tests/helper/setupTest.ts
// mock fs
vi.mock('node:fs', async () => {
  const memfs: { fs: typeof fs } = await vi.importActual('memfs')

  return { default: memfs.fs, ...memfs.fs }
})

// mock fs.promises
vi.mock('node:fs/promises', async () => {
  const memfs: { fs: typeof fs } = await vi.importActual('memfs')

  return { default: memfs.fs.promises, ...memfs.fs.promises }
})

// reset the state of in-memory fs on each test 
beforeEach(() => {
  vol.reset()
})

Mocking Node.js and the default reset

Are you still using Jest and thinking about switching? Or would you like to read more details about using Memfs? Then you'll find further ideas in my article "Recap – ViTest replacing Jest."

call to action background image

Subscribe to my newsletter

Receive once a month news from the areas of software development and communication peppered with book and link recommendations.