Skip to content

Instantly share code, notes, and snippets.

@barthap
Last active February 25, 2023 23:20
Show Gist options
  • Save barthap/e0a672e9000e72cdfbca73e4f2702f5e to your computer and use it in GitHub Desktop.
Save barthap/e0a672e9000e72cdfbca73e4f2702f5e to your computer and use it in GitHub Desktop.
Mocking filesystem in Node.js with `memfs`
// __mocks__/fs/promises.js
const { fs } = require("memfs");
module.exports = fs.promises;
// __mocks__/fs.js
const { fs } = require("memfs");
module.exports = fs;
// src/__tests__/checkHello.test.js
// fs-extra is used for demonstrational purposes
const fs = require("fs-extra");
const { vol } = require("memfs");
// mock `fs` if you use either `fs` or `fs-extra`
jest.mock("fs");
// mock `fs/promises` if you use it either in code or tests
jest.mock("fs/promises");
const { checkHelloAsync, checkHelloExtra } = require("../checkHello");
describe(checkHelloAsync, () => {
beforeEach(() => {
// we reset virtual filesystem before each test
vol.reset();
});
it("should return true if file starts with hello", async () => {
const filePath = "/file.txt";
//we save file in virtual filesystem
await fs.writeFile(filePath, "hello Test");
/**
* You can swap lines below for different implementation
* and this test will work anyway
*/
// const result = await checkHelloExtra(filePath)
const result = await checkHelloAsync(filePath);
expect(result).toBe(true);
});
it("tests checkHelloAsync on multiple files", async () => {
vol.fromJSON(
{
"./some/file1.txt": "hello world",
"./other/file2.txt": "h3ll0 w0rld",
},
"/tmp" // cwd (current working directory)
);
await expect(checkHelloAsync("/tmp/some/file1.txt")).resolves.toBe(true);
await expect(checkHelloAsync("/tmp/other/file2.txt")).resolves.toBe(false);
});
});
// src/checkHello.js
const fs = require("fs");
const fsPromises = require("fs/promises");
const fsExtra = require("fs-extra");
// using fs sync calls
function checkHelloSync(filePath) {
const fd = fs.openSync(filePath);
const content = Buffer.alloc(5);
const bytesRead = fs.readSync(fd, content, 0, 5, 0);
fs.closeSync(fd);
if (bytesRead !== 5) return false;
return content.toString() === "hello";
}
// using fsPromises
async function checkHelloAsync(filePath) {
const fd = await fsPromises.open(filePath, "r");
const { buffer, bytesRead } = await fd.read(Buffer.alloc(5), 0, 5, 0);
await fd.close();
return bytesRead === 5 && buffer.toString("utf8") === "hello";
}
// using fs-extra
async function checkHelloExtra(filePath) {
const fd = await fsExtra.open(filePath, "r");
const { buffer, bytesRead } = await fsExtra.read(
fd,
Buffer.alloc(5),
0, 5, 0
);
await fs.close(fd);
return bytesRead === 5 && buffer.toString("utf8") === "hello";
}
module.exports = {
checkHelloSync,
checkHelloAsync,
checkHelloExtra,
};
@DavNej
Copy link

DavNej commented Dec 19, 2022

Hello ☀️
I tried to test a simple function using fs-extra with memfs but the test fails, and the function called in the test is not aware of the in-memory fs.

I posted a question on stackoverflow. Could you help me with making this work, please ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment