Skip to content

Commit

Permalink
Clarified bypassing methods & added restoration test
Browse files Browse the repository at this point in the history
  • Loading branch information
nonara committed Jul 29, 2020
1 parent 92ca9c8 commit 172e698
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 7 deletions.
35 changes: 30 additions & 5 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,26 @@ exports.directory = FileSystem.directory;
*/
exports.symlink = FileSystem.symlink;

let storedBinding;

/**
* Temporarily disable Mocked FS
*/
exports.disable = () => {
storedBinding = realBinding._mockedBinding;
delete realBinding._mockedBinding;
};

/**
* Enables Mocked FS after being disabled by mock.disable()
*/
exports.enable = () => {
if (storedBinding) {
realBinding._mockedBinding = storedBinding;
storedBinding = undefined;
}
};

/**
* Perform action, bypassing mock FS
* @example
Expand All @@ -198,16 +218,21 @@ exports.bypass = function(fn) {
}

// Deactivate mocked bindings
const binding = realBinding._mockedBinding;
exports.disable();
delete realBinding._mockedBinding;

let res;
try {
// Perform action
res = fn();
res = fn(); // Perform action
} finally {
// Reactivate mocked bindings
realBinding._mockedBinding = binding;
exports.enable();
}

if (res.then) {
// eslint-disable-next-line no-console
console.warn(
`Async functions are not supported with exports.bypass(). See https://github.com/tschaub/mock-fs/#advancedbypass`
);
}

return res;
Expand Down
24 changes: 22 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,16 +255,36 @@ afterEach(mock.restore);

### Bypassing the mock file system

Sometimes you will want to execute calls against the actual file-system. In order to do that, we've provided a helper.
#### <a id='mockbypass'>`mock.bypass(fn)`</a>

### <a id='mockrestore'>`mock.bypass(fn)`</a>
Execute _synchronous calls_ to the real filesystem with mock.bypass()

```js
// This file exists only on the real FS, not on the mocked FS
const realFilePath = '/path/to/real/file.txt';
const myData = mock.bypass(() => fs.readFileSync(realFilePath, 'utf-8'));
```

#### <a id='advancedbypass'>Advanced Bypassing</a>

Asynchronous calls are not recommended as they could produce unintended consequences if anything else tries to access the
mocked filesystem before they've completed.

However, if you know what you're doing, you can selectively disable and re-enable the mock filesystem.

```js
async function getFileInfo(fileName) {
mock.disable();
try {
const stats = await fs.promises.stat(fileName);
const data = await fs.promises.readFile(fileName);
return { stats, data };
} finally {
mock.enable();
}
}
```

## Install

Using `npm`:
Expand Down
8 changes: 8 additions & 0 deletions test/lib/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,14 @@ describe('The API', function() {
assert.throws(() => fs.readFileSync(__filename));
assert.doesNotThrow(() => mock.bypass(() => fs.readFileSync(__filename)));
});

it('restores mock FS after bypass', () => {
mock({'/path/to/file': 'content'});

assert.throws(() => fs.readFileSync(__filename));
assert.doesNotThrow(() => mock.bypass(() => fs.readFileSync(__filename)));
assert.throws(() => fs.readFileSync(__filename));
});
});

describe(`Mapping functions`, () => {
Expand Down

0 comments on commit 172e698

Please # to comment.