A configurable mock file system for Node.js testing that replaces the built-in fs module with an in-memory implementation.
npx @tessl/cli install tessl/npm-mock-fs@5.5.0mock-fs allows Node.js's built-in fs module to be backed temporarily by an in-memory, mock file system. This enables testing against a set of mock files and directories without requiring actual test fixtures on disk.
Requirements: Node.js 12.0.0 or higher
npm install mock-fs --save-devconst mock = require('mock-fs');For ES modules:
import mock from 'mock-fs';const mock = require('mock-fs');
// Set up mock file system
mock({
'path/to/fake/dir': {
'some-file.txt': 'file content here',
'empty-dir': {/** empty directory */}
},
'path/to/some.png': Buffer.from([8, 6, 7, 5, 3, 0, 9]),
'some/other/path': {/** another empty directory */}
});
// Use regular fs operations
const fs = require('fs');
console.log(fs.readFileSync('path/to/fake/dir/some-file.txt', 'utf8'));
// Clean up
mock.restore();mock-fs works by replacing Node.js's internal file system bindings (process.binding('fs')) rather than patching the fs module directly. This approach:
fs (e.g., graceful-fs)fs implementationKey components:
file(), directory(), symlink() for creating mock items with metadataload() function for importing real files into the mock systembypass() function for temporarily accessing the real file systemConfigure the fs module to use an in-memory mock file system.
/**
* Configure the fs module so it is backed by an in-memory file system
* @param {Object} config - Mock file system configuration
* @param {Object} [options] - Filesystem options
* @param {boolean} [options.createCwd=true] - Create a directory for process.cwd()
* @param {boolean} [options.createTmp=true] - Create a directory for os.tmpdir()
*/
function mock(config: Object, options?: {
createCwd?: boolean;
createTmp?: boolean;
}): void;Usage Examples:
// Simple configuration with files and directories
mock({
'file.txt': 'content',
'dir': {
'nested-file.txt': 'nested content'
},
'binary-file': Buffer.from([1, 2, 3, 4])
});
// Disable default directories
mock({
'my-file.txt': 'content'
}, {
createCwd: false,
createTmp: false
});Create file objects with custom properties and metadata.
/**
* Generate a factory for new files
* @param {Object} [properties] - File configuration
* @param {string|Buffer} [properties.content] - File contents
* @param {number} [properties.mode=0666] - File mode (permission and sticky bits)
* @param {number} [properties.uid] - User id (defaults to process.getuid())
* @param {number} [properties.gid] - Group id (defaults to process.getgid())
* @param {Date} [properties.atime] - Last access time (defaults to new Date())
* @param {Date} [properties.ctime] - Last change time (defaults to new Date())
* @param {Date} [properties.mtime] - Last modification time (defaults to new Date())
* @param {Date} [properties.birthtime] - Creation time (defaults to new Date())
* @param {number} [properties.atimeMs] - Access time in milliseconds
* @param {number} [properties.ctimeMs] - Change time in milliseconds
* @param {number} [properties.mtimeMs] - Modification time in milliseconds
* @param {number} [properties.birthtimeMs] - Creation time in milliseconds
* @returns {Function} Factory function that creates a new file
*/
mock.file(properties);Usage Examples:
mock({
'custom-file.txt': mock.file({
content: 'file content',
mode: 0644,
mtime: new Date('2023-01-01'),
uid: 1000,
gid: 1000
})
});Create directory objects with custom properties and nested items.
/**
* Generate a factory for new directories
* @param {Object} [properties] - Directory configuration
* @param {number} [properties.mode=0777] - Directory mode (permission and sticky bits)
* @param {number} [properties.uid] - User id (defaults to process.getuid())
* @param {number} [properties.gid] - Group id (defaults to process.getgid())
* @param {Date} [properties.atime] - Last access time (defaults to new Date())
* @param {Date} [properties.ctime] - Last change time (defaults to new Date())
* @param {Date} [properties.mtime] - Last modification time (defaults to new Date())
* @param {Date} [properties.birthtime] - Creation time (defaults to new Date())
* @param {number} [properties.atimeMs] - Access time in milliseconds
* @param {number} [properties.ctimeMs] - Change time in milliseconds
* @param {number} [properties.mtimeMs] - Modification time in milliseconds
* @param {number} [properties.birthtimeMs] - Creation time in milliseconds
* @param {Object} [properties.items] - Directory contents
* @returns {Function} Factory function that creates a new directory
*/
mock.directory(properties);Usage Examples:
mock({
'custom-dir': mock.directory({
mode: 0755,
items: {
'file1.txt': 'content 1',
'file2.txt': 'content 2',
'subdir': {}
}
})
});Create symbolic link objects with custom properties.
/**
* Generate a factory for new symbolic links
* @param {Object} properties - Symlink configuration
* @param {string} properties.path - Path to the source (required)
* @param {number} [properties.mode=0666] - Symlink mode (permission and sticky bits)
* @param {number} [properties.uid] - User id (defaults to process.getuid())
* @param {number} [properties.gid] - Group id (defaults to process.getgid())
* @param {Date} [properties.atime] - Last access time (defaults to new Date())
* @param {Date} [properties.ctime] - Last change time (defaults to new Date())
* @param {Date} [properties.mtime] - Last modification time (defaults to new Date())
* @param {Date} [properties.birthtime] - Creation time (defaults to new Date())
* @param {number} [properties.atimeMs] - Access time in milliseconds
* @param {number} [properties.ctimeMs] - Change time in milliseconds
* @param {number} [properties.mtimeMs] - Modification time in milliseconds
* @param {number} [properties.birthtimeMs] - Creation time in milliseconds
* @returns {Function} Factory function that creates a new symbolic link
*/
mock.symlink(properties);Usage Examples:
mock({
'some/dir': {
'regular-file': 'file contents',
'a-symlink': mock.symlink({
path: 'regular-file'
})
}
});Load real files and directories from the actual file system into the mock system.
/**
* Load directory or file from real filesystem into mock system
* @param {string} path - Path to real file or directory
* @param {Object} [options] - Loading options
* @param {boolean} [options.lazy=true] - File content isn't loaded until explicitly read
* @param {boolean} [options.recursive=true] - Load all files and directories recursively
* @returns {*} Mock file system item
*/
mock.load(path, options);Usage Examples:
mock({
// Lazy-load single file
'my-file.txt': mock.load('/path/to/real/file.txt'),
// Pre-load JavaScript file
'ready.js': mock.load('/path/to/script.js', { lazy: false }),
// Load entire directory
'node_modules': mock.load('/path/to/node_modules'),
// Load directory without subdirectories, pre-loading content
'configs': mock.load('/etc/configs', {
recursive: false,
lazy: false
})
});Restore the real file system, undoing the effects of mock().
/**
* Restore the fs binding to the real file system
* This undoes the effect of calling mock()
*/
mock.restore();Usage Examples:
// Typical test setup
beforeEach(() => {
mock({
'test-file': 'content'
});
});
afterEach(() => {
mock.restore();
});
// Or manual cleanup
mock({ 'temp-file': 'data' });
// ... do work
mock.restore();Execute operations on the real file system while mock is active.
/**
* Perform action, bypassing mock filesystem
* Supports both synchronous and asynchronous functions
* @param {Function} fn - Function to execute with real filesystem access
* @returns {*} Result of executing fn, or Promise if fn returns Promise
*/
mock.bypass(fn);Usage Examples:
// Read from real filesystem while mock is active
const realData = mock.bypass(() => {
return fs.readFileSync('/real/path/file.txt', 'utf-8');
});
// Async operations (returns Promise)
const asyncData = await mock.bypass(async () => {
const stats = await fs.promises.stat('/real/file.txt');
const data = await fs.promises.readFile('/real/file.txt');
return { stats, data };
});Access the internal mock file system root object.
/**
* Get hold of the mocked filesystem's root
* Returns empty object if fs hasn't currently been replaced
* @returns {Object} The mock root directory object
*/
mock.getMockRoot();Usage Examples:
mock({ 'test-file': 'content' });
const root = mock.getMockRoot();
console.log(root); // Mock filesystem root object
mock.restore();
console.log(mock.getMockRoot()); // {}mock-fs throws standard Node.js filesystem errors that match the real fs module behavior:
ENOENT: File or directory not foundENOTDIR: Not a directory (when trying to traverse through a file)EACCES: Permission denied (when file/directory permissions prevent access)EEXIST: File already existsmode, process.getuid(), and process.getgid()/) in mock configuration, even on WindowsWhen using Jest snapshots, restore the mock before snapshot comparison:
const actual = testedFunction();
mock.restore(); // Must restore before snapshot matching
expect(actual).toMatchSnapshot();describe('My Tests', () => {
beforeEach(() => {
mock({
'test-data.json': '{"key": "value"}',
'empty-dir': {}
});
});
afterEach(() => {
mock.restore();
});
it('should read mock file', () => {
const data = fs.readFileSync('test-data.json', 'utf-8');
expect(JSON.parse(data)).to.deep.equal({ key: 'value' });
});
});graceful-fs@4.x (not compatible with graceful-fs@3.x)fs for best compatibilityfs.promises API and stream-based operations