@bytesnz

Jack Farley, Web Application Engineer

Testing on the Filesystem

Testing on the Filesystem

Testing Javascript modules that use the filesystem can be a little annoying
to test sometimes, especially when using awesome parallel test runners like
Ava. While developing
MARSS, my Markdown blogging system, I
tried to find a good way of running the tests, so they could effectively
have their own environment (read folder) to test in. I came accross
memfs, which implements the
fs module in a virtual filesystem in memory.
The author also created
fs-monkey, which allows you to
patch the fs module with a given fs-like implementation.

With these, you are able to make the code you are testing use your own
specially crafted filesystem. Woot. (Un)fortunately, the require function
also uses the fs module to read files, so when you patch the fs module,
you also restrict importing any more modules. Luckily, the author has
unionfs which allows you to
patch two file systems together - phew.

Wiring it all together it allows you to create a test file system that you
can then use to test Javascript that does operations on the file system. Below
is the module I created for doing such a thing and how I used it in my
tests.

Test file system module

The below module sets up the virtual test file system and patches the fs
module for the tests.

1
2
3
4
5
6
7
8
9
10
11
12
import { patchFs } from 'fs-monkey';
import { Volume } from 'memfs';
import { ufs } from 'unionfs';
import * as fs from 'fs';
export const vol = new Volume();
const fs2 = Object.assign({}, fs);
ufs.use(fs2).use(vol);
patchFs(ufs);

Test that uses the test file system module

The test loads above module, loads tests files into is using the
memfs .fromJson() function into a folder based on the test process id.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { vol } from '../unionfs';
import * as process from 'process';
// Import the module to test that uses the fs, eg runs a glob
import { someFunction as thingToTest } from './someFunction';
const exampleFiles = {
'folder/file1.txt': `This is the contents of file 1`,
'folder/file2.txt': `This is the contents of file 2`,
'another.txt': `You get the point`
};
const testFolder = `/test/${process.pid()}`
vol.fromJSON(exampleFiles, testFolder);
test('it returns an array of files in the directory', async (t) => {
const results = await thingToTest(testFolder);
t.deepEqual(Object.keys(exampleFiles), results);
});