Skip to content

Commit 011e79a

Browse files
committed
fix: synchronize patching binding/createWriteStream/cwd/chdir
All the patches now check same realBinding._mockedBinding. This should fix the edge cases around the new feature bypass(). follows up #306
1 parent 47a7979 commit 011e79a

3 files changed

Lines changed: 114 additions & 79 deletions

File tree

lib/index.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ function overrideCreateWriteStream() {
8787
fs.createWriteStream = function(path, options) {
8888
const output = realCreateWriteStream(path, options);
8989
// disable _writev, this will over shadow WriteStream.prototype._writev
90-
output._writev = undefined;
90+
if (realBinding._mockedBinding) {
91+
output._writev = undefined;
92+
}
9193
return output;
9294
};
9395
}
@@ -126,13 +128,20 @@ exports = module.exports = function mock(config, options) {
126128
let currentPath = process.cwd();
127129
overrideProcess(
128130
function cwd() {
129-
return currentPath;
131+
if (realBinding._mockedBinding) {
132+
return currentPath;
133+
}
134+
return realProcessProps.cwd();
130135
},
131136
function chdir(directory) {
132-
if (!binding.stat(toNamespacedPath(directory)).isDirectory()) {
133-
throw new FSError('ENOTDIR');
137+
if (realBinding._mockedBinding) {
138+
if (!binding.stat(toNamespacedPath(directory)).isDirectory()) {
139+
throw new FSError('ENOTDIR');
140+
}
141+
currentPath = path.resolve(currentPath, directory);
142+
} else {
143+
return realProcessProps.chdir(directory);
134144
}
135-
currentPath = path.resolve(currentPath, directory);
136145
}
137146
);
138147

test/lib/bypass.spec.js

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
'use strict';
2+
3+
const helper = require('../helper');
4+
const fs = require('fs');
5+
const mock = require('../../lib/index');
6+
const path = require('path');
7+
const withPromise = helper.withPromise;
8+
9+
const assert = helper.assert;
10+
11+
describe('mock.bypass()', () => {
12+
afterEach(mock.restore);
13+
14+
it('runs a synchronous function using the real filesystem', () => {
15+
mock({'/path/to/file': 'content'});
16+
17+
assert.equal(fs.readFileSync('/path/to/file', 'utf8'), 'content');
18+
assert.isNotOk(fs.existsSync(__filename));
19+
assert.isOk(mock.bypass(() => fs.existsSync(__filename)));
20+
21+
assert.isNotOk(fs.existsSync(__filename));
22+
});
23+
24+
it('handles functions that throw', () => {
25+
mock({'/path/to/file': 'content'});
26+
27+
const error = new Error('oops');
28+
29+
assert.throws(() => {
30+
mock.bypass(() => {
31+
assert.isFalse(fs.existsSync('/path/to/file'));
32+
throw error;
33+
});
34+
}, error);
35+
36+
assert.equal(fs.readFileSync('/path/to/file', 'utf8'), 'content');
37+
});
38+
39+
it('bypasses patched process.cwd()', () => {
40+
const originalCwd = process.cwd();
41+
mock({
42+
dir: {}
43+
});
44+
45+
process.chdir('dir');
46+
assert.equal(process.cwd(), path.join(originalCwd, 'dir'));
47+
48+
mock.bypass(() => {
49+
assert.equal(process.cwd(), originalCwd);
50+
});
51+
assert.equal(process.cwd(), path.join(originalCwd, 'dir'));
52+
mock.restore();
53+
54+
assert.equal(process.cwd(), originalCwd);
55+
});
56+
57+
withPromise.it('runs an async function using the real filesystem', done => {
58+
mock({'/path/to/file': 'content'});
59+
60+
assert.equal(fs.readFileSync('/path/to/file', 'utf8'), 'content');
61+
assert.isFalse(fs.existsSync(__filename));
62+
63+
const promise = mock.bypass(() => fs.promises.stat(__filename));
64+
assert.instanceOf(promise, Promise);
65+
66+
promise
67+
.then(stat => {
68+
assert.isTrue(stat.isFile());
69+
assert.isFalse(fs.existsSync(__filename));
70+
done();
71+
})
72+
.catch(done);
73+
});
74+
75+
withPromise.it('handles promise rejection', done => {
76+
mock({'/path/to/file': 'content'});
77+
78+
assert.equal(fs.readFileSync('/path/to/file', 'utf8'), 'content');
79+
assert.isFalse(fs.existsSync(__filename));
80+
81+
const error = new Error('oops');
82+
83+
const promise = mock.bypass(() => {
84+
assert.isTrue(fs.existsSync(__filename));
85+
return Promise.reject(error);
86+
});
87+
assert.instanceOf(promise, Promise);
88+
89+
promise
90+
.then(() => {
91+
done(new Error('expected rejection'));
92+
})
93+
.catch(err => {
94+
assert.equal(err, error);
95+
96+
assert.equal(fs.readFileSync('/path/to/file', 'utf8'), 'content');
97+
done();
98+
});
99+
});
100+
});

test/lib/index.spec.js

Lines changed: 0 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ const path = require('path');
88
const File = require('../../lib/file');
99
const {fixWin32Permissions} = require('../../lib/item');
1010
const Directory = require('../../lib/directory');
11-
const withPromise = helper.withPromise;
1211

1312
const assert = helper.assert;
1413
const assetsPath = path.resolve(__dirname, '../assets');
@@ -185,79 +184,6 @@ describe('The API', function() {
185184
});
186185
});
187186

188-
describe(`mock.bypass()`, () => {
189-
afterEach(mock.restore);
190-
191-
it('runs a synchronous function using the real filesystem', () => {
192-
mock({'/path/to/file': 'content'});
193-
194-
assert.equal(fs.readFileSync('/path/to/file', 'utf8'), 'content');
195-
assert.isNotOk(fs.existsSync(__filename));
196-
assert.isOk(mock.bypass(() => fs.existsSync(__filename)));
197-
198-
assert.isNotOk(fs.existsSync(__filename));
199-
});
200-
201-
it('handles functions that throw', () => {
202-
mock({'/path/to/file': 'content'});
203-
204-
const error = new Error('oops');
205-
206-
assert.throws(() => {
207-
mock.bypass(() => {
208-
assert.isFalse(fs.existsSync('/path/to/file'));
209-
throw error;
210-
});
211-
}, error);
212-
213-
assert.equal(fs.readFileSync('/path/to/file', 'utf8'), 'content');
214-
});
215-
216-
withPromise.it('runs an async function using the real filesystem', done => {
217-
mock({'/path/to/file': 'content'});
218-
219-
assert.equal(fs.readFileSync('/path/to/file', 'utf8'), 'content');
220-
assert.isFalse(fs.existsSync(__filename));
221-
222-
const promise = mock.bypass(() => fs.promises.stat(__filename));
223-
assert.instanceOf(promise, Promise);
224-
225-
promise
226-
.then(stat => {
227-
assert.isTrue(stat.isFile());
228-
assert.isFalse(fs.existsSync(__filename));
229-
done();
230-
})
231-
.catch(done);
232-
});
233-
234-
withPromise.it('handles promise rejection', done => {
235-
mock({'/path/to/file': 'content'});
236-
237-
assert.equal(fs.readFileSync('/path/to/file', 'utf8'), 'content');
238-
assert.isFalse(fs.existsSync(__filename));
239-
240-
const error = new Error('oops');
241-
242-
const promise = mock.bypass(() => {
243-
assert.isTrue(fs.existsSync(__filename));
244-
return Promise.reject(error);
245-
});
246-
assert.instanceOf(promise, Promise);
247-
248-
promise
249-
.then(() => {
250-
done(new Error('expected rejection'));
251-
})
252-
.catch(err => {
253-
assert.equal(err, error);
254-
255-
assert.equal(fs.readFileSync('/path/to/file', 'utf8'), 'content');
256-
done();
257-
});
258-
});
259-
});
260-
261187
describe(`mock.load()`, () => {
262188
const statsCompareKeys = [
263189
'birthtime',

0 commit comments

Comments
 (0)