diff --git a/lib/bypass.js b/lib/bypass.js
index 770e81bd..22163f08 100755
--- a/lib/bypass.js
+++ b/lib/bypass.js
@@ -13,43 +13,38 @@ exports = module.exports = function bypass(fn) {
throw new Error(`Must provide a function to perform for mock.bypass()`);
}
- exports.disable();
+ disable();
+ let result;
try {
- // Perform action
- const res = fn();
-
- // Handle promise return
- if (typeof res.then === 'function') {
- res.then(exports.enable);
- res.catch(exports.enable);
+ result = fn();
+ } finally {
+ if (result && typeof result.finally === 'function') {
+ result.finally(enable);
} else {
- exports.enable();
+ enable();
}
-
- return res;
- } catch (e) {
- exports.enable();
- throw e;
}
+
+ return result;
};
/**
* Temporarily disable Mocked FS
*/
-exports.disable = () => {
+function disable() {
if (realBinding._mockedBinding) {
storedBinding = realBinding._mockedBinding;
delete realBinding._mockedBinding;
}
-};
+}
/**
- * Enables Mocked FS after being disabled by mock.disable()
+ * Enables Mocked FS after being disabled by disable()
*/
-exports.enable = () => {
+function enable() {
if (storedBinding) {
realBinding._mockedBinding = storedBinding;
storedBinding = undefined;
}
-};
+}
diff --git a/lib/loader.js b/lib/loader.js
index f2d549dc..f8442e4a 100755
--- a/lib/loader.js
+++ b/lib/loader.js
@@ -10,7 +10,7 @@ const createContext = ({output, options = {}, target}, newContext) =>
// Assign options and set defaults if needed
options: {
recursive: options.recursive !== false,
- lazyLoad: options.lazyLoad !== false
+ lazy: options.lazy !== false
},
output,
target
@@ -20,7 +20,7 @@ const createContext = ({output, options = {}, target}, newContext) =>
function addFile(context, stats, isRoot) {
const {output, target} = context;
- const {lazyLoad} = context.options;
+ const {lazy} = context.options;
if (!stats.isFile()) {
throw new Error(`${target} is not a valid file!`);
@@ -29,10 +29,10 @@ function addFile(context, stats, isRoot) {
const outputPropKey = isRoot ? target : path.basename(target);
output[outputPropKey] = () => {
- const content = !lazyLoad ? fs.readFileSync(target) : '';
+ const content = !lazy ? fs.readFileSync(target) : '';
const file = FileSystem.file(Object.assign({}, stats, {content}))();
- if (lazyLoad) {
+ if (lazy) {
Object.defineProperty(file, '_content', {
get() {
const res = bypass(() => fs.readFileSync(target));
diff --git a/readme.md b/readme.md
index 15901b21..e56342b2 100644
--- a/readme.md
+++ b/readme.md
@@ -67,13 +67,13 @@ You can load real files and directories into the mock system using `mock.load()`
#### Notes
- All stat information is duplicated (dates, permissions, etc)
-- By default, all files are lazy-loaded, unless you specify the `{ lazyLoad: false }` option
+- By default, all files are lazy-loaded, unless you specify the `{lazy: false}` option
#### options
| Option | Type | Default | Description |
| --------- | ------- | ------- | ------------
-| lazyLoad | boolean | true | File content isn't loaded until explicitly read
+| lazy | boolean | true | File content isn't loaded until explicitly read
| recursive | boolean | true | Load all files and directories recursively
#### `mock.load(path, options)`
@@ -84,13 +84,13 @@ mock({
'my-file.txt': mock.load(path.resolve(__dirname, 'assets/special-file.txt')),
// Pre-load js file
- 'ready.js': mock.load(path.resolve(__dirname, 'scripts/ready.js'), { lazyLoad: false }),
+ 'ready.js': mock.load(path.resolve(__dirname, 'scripts/ready.js'), {lazy: false}),
// Recursively loads all node_modules
'node_modules': mock.load(path.resolve(__dirname, '../node_modules')),
// Creates a directory named /tmp with only the files in /tmp/special_tmp_files (no subdirectories), pre-loading all content
- '/tmp': mock.load('/tmp/special_tmp_files', { recursive: false, lazyLoad:false }),
+ '/tmp': mock.load('/tmp/special_tmp_files', {recursive: false, lazy:false}),
'fakefile.txt': 'content here'
});
@@ -237,6 +237,8 @@ const realFilePath = '/path/to/real/file.txt';
const myData = mock.bypass(() => fs.readFileSync(realFilePath, 'utf-8'));
```
+If you pass an asynchronous function or a promise-returning function to `bypass()`, a promise will be returned.
+
#### Async Warning
Asynchronous calls are supported, however, they are not recommended as they could produce unintended consequences if
@@ -247,7 +249,7 @@ async function getFileInfo(fileName) {
return await mock.bypass(async () => {
const stats = await fs.promises.stat(fileName);
const data = await fs.promises.readFile(fileName);
- return { stats, data };
+ return {stats, data};
});
}
```
diff --git a/test/lib/index.spec.js b/test/lib/index.spec.js
index 017dcb11..802e011d 100644
--- a/test/lib/index.spec.js
+++ b/test/lib/index.spec.js
@@ -188,7 +188,7 @@ describe('The API', function() {
describe(`mock.bypass()`, () => {
afterEach(mock.restore);
- it('(synchronous) bypasses mock FS & restores after', () => {
+ it('runs a synchronous function using the real filesystem', () => {
mock({'/path/to/file': 'content'});
assert.equal(fs.readFileSync('/path/to/file', 'utf8'), 'content');
@@ -198,28 +198,63 @@ describe('The API', function() {
assert.isNotOk(fs.existsSync(__filename));
});
- withPromise.it('(async) bypasses mock FS & restores after', done => {
+ it('handles functions that throw', () => {
mock({'/path/to/file': 'content'});
+ const error = new Error('oops');
+
+ assert.throws(() => {
+ mock.bypass(() => {
+ assert.isFalse(fs.existsSync('/path/to/file'));
+ throw error;
+ });
+ }, error);
+
assert.equal(fs.readFileSync('/path/to/file', 'utf8'), 'content');
- assert.isNotOk(fs.existsSync(__filename));
+ });
- mock.bypass(() =>
- fs.promises
- .stat(__filename)
- .then(stat => {
- assert.isTrue(stat.isFile());
- return fs.promises.stat(__filename);
- })
- .then(stat => assert.isTrue(stat.isFile()))
- .then(() => {
- setTimeout(() => {
- assert.isNotOk(fs.existsSync(__filename));
- done();
- }, 0);
- })
- .catch(err => done(err))
- );
+ withPromise.it('runs an async function using the real filesystem', done => {
+ mock({'/path/to/file': 'content'});
+
+ assert.equal(fs.readFileSync('/path/to/file', 'utf8'), 'content');
+ assert.isFalse(fs.existsSync(__filename));
+
+ const promise = mock.bypass(() => fs.promises.stat(__filename));
+ assert.instanceOf(promise, Promise);
+
+ promise
+ .then(stat => {
+ assert.isTrue(stat.isFile());
+ assert.isFalse(fs.existsSync(__filename));
+ done();
+ })
+ .catch(done);
+ });
+
+ withPromise.it('handles promise rejection', done => {
+ mock({'/path/to/file': 'content'});
+
+ assert.equal(fs.readFileSync('/path/to/file', 'utf8'), 'content');
+ assert.isFalse(fs.existsSync(__filename));
+
+ const error = new Error('oops');
+
+ const promise = mock.bypass(() => {
+ assert.isTrue(fs.existsSync(__filename));
+ return Promise.reject(error);
+ });
+ assert.instanceOf(promise, Promise);
+
+ promise
+ .then(() => {
+ done(new Error('expected rejection'));
+ })
+ .catch(err => {
+ assert.equal(err, error);
+
+ assert.equal(fs.readFileSync('/path/to/file', 'utf8'), 'content');
+ done();
+ });
});
});
@@ -260,7 +295,7 @@ describe('The API', function() {
assert.instanceOf(file, File);
assert.deepEqual(filterStats(file), filterStats(stats));
});
- describe('lazyLoad=true', () => {
+ describe('lazy=true', () => {
let file;
beforeEach(() => (file = mock.load(filePath)()));
@@ -309,9 +344,9 @@ describe('The API', function() {
});
});
- it('lazyLoad=false loads file content', () => {
+ it('lazy=false loads file content', () => {
const file = mock.load(path.join(assetsPath, 'file1.txt'), {
- lazyLoad: false
+ lazy: false
})();
assert.equal(
@@ -348,18 +383,18 @@ describe('The API', function() {
assert.instanceOf(baseDirSubdir, Directory);
assert.instanceOf(baseDirSubdir._items['file3.txt'], File);
});
- it('respects lazyLoad setting', () => {
+ it('respects lazy setting', () => {
let dir;
const getFile = () =>
dir._items.dir._items.subdir._items['file3.txt'];
- dir = mock.load(assetsPath, {recursive: true, lazyLoad: true})();
+ dir = mock.load(assetsPath, {recursive: true, lazy: true})();
assert.typeOf(
Object.getOwnPropertyDescriptor(getFile(), '_content').get,
'function'
);
- dir = mock.load(assetsPath, {recursive: true, lazyLoad: false})();
+ dir = mock.load(assetsPath, {recursive: true, lazy: false})();
assert.instanceOf(
Object.getOwnPropertyDescriptor(getFile(), '_content').value,
Buffer