Skip to content

Commit 127f331

Browse files
davidaureliofacebook-github-bot
authored andcommitted
Fix mock inclusion
Summary: The 'fs' mock was set up to require 'graceful-fs', which used to delegate to the corresponding mock. After turning off automocking, this no longer necessarily works. This moves the mock to `fs.js` and makes the mock for graceful-fs require the fs mock via a relative path. Reviewed By: cpojer Differential Revision: D5209130 fbshipit-source-id: d468577e09d18382d0b9602ad0964dd880ec2366
1 parent 795c436 commit 127f331

File tree

2 files changed

+299
-299
lines changed

2 files changed

+299
-299
lines changed

packages/metro-bundler/src/node-haste/__mocks__/fs.js

+298-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,301 @@
88
*/
99
'use strict';
1010

11-
module.exports = require('graceful-fs');
11+
const {EventEmitter} = require('events');
12+
const {dirname} = require.requireActual('path');
13+
const fs = jest.genMockFromModule('fs');
14+
const path = require('path');
15+
const stream = require.requireActual('stream');
16+
17+
const noop = () => {};
18+
19+
function asyncCallback(cb) {
20+
return function() {
21+
setImmediate(() => cb.apply(this, arguments));
22+
};
23+
}
24+
25+
const mtime = {
26+
getTime: () => Math.ceil(Math.random() * 10000000),
27+
};
28+
29+
fs.realpath.mockImplementation((filepath, callback) => {
30+
callback = asyncCallback(callback);
31+
let node;
32+
try {
33+
node = getToNode(filepath);
34+
} catch (e) {
35+
return callback(e);
36+
}
37+
if (node && typeof node === 'object' && node.SYMLINK != null) {
38+
return callback(null, node.SYMLINK);
39+
}
40+
return callback(null, filepath);
41+
});
42+
43+
fs.readdirSync.mockImplementation(filepath => Object.keys(getToNode(filepath)));
44+
45+
fs.readdir.mockImplementation((filepath, callback) => {
46+
callback = asyncCallback(callback);
47+
let node;
48+
try {
49+
node = getToNode(filepath);
50+
if (node && typeof node === 'object' && node.SYMLINK != null) {
51+
node = getToNode(node.SYMLINK);
52+
}
53+
} catch (e) {
54+
return callback(e);
55+
}
56+
57+
if (!(node && typeof node === 'object' && node.SYMLINK == null)) {
58+
return callback(new Error(filepath + ' is not a directory.'));
59+
}
60+
61+
return callback(null, Object.keys(node));
62+
});
63+
64+
fs.readFile.mockImplementation(function(filepath, encoding, callback) {
65+
callback = asyncCallback(callback);
66+
if (arguments.length === 2) {
67+
callback = encoding;
68+
encoding = null;
69+
}
70+
71+
let node;
72+
try {
73+
node = getToNode(filepath);
74+
// dir check
75+
if (node && typeof node === 'object' && node.SYMLINK == null) {
76+
callback(new Error('Error readFile a dir: ' + filepath));
77+
}
78+
if (node == null) {
79+
return callback(Error('No such file: ' + filepath));
80+
} else {
81+
return callback(null, node);
82+
}
83+
} catch (e) {
84+
return callback(e);
85+
}
86+
});
87+
88+
fs.readFileSync.mockImplementation(function(filepath, encoding) {
89+
const node = getToNode(filepath);
90+
// dir check
91+
if (node && typeof node === 'object' && node.SYMLINK == null) {
92+
throw new Error('Error readFileSync a dir: ' + filepath);
93+
}
94+
return node;
95+
});
96+
97+
function makeStatResult(node) {
98+
const isSymlink = node != null && node.SYMLINK != null;
99+
return {
100+
isBlockDevice: () => false,
101+
isCharacterDevice: () => false,
102+
isDirectory: () => node != null && typeof node === 'object' && !isSymlink,
103+
isFIFO: () => false,
104+
isFile: () => node != null && typeof node === 'string',
105+
isSocket: () => false,
106+
isSymbolicLink: () => isSymlink,
107+
mtime,
108+
};
109+
}
110+
111+
function statSync(filepath) {
112+
const node = getToNode(filepath);
113+
if (node != null && node.SYMLINK) {
114+
return statSync(node.SYMLINK);
115+
}
116+
return makeStatResult(node);
117+
}
118+
119+
fs.stat.mockImplementation((filepath, callback) => {
120+
callback = asyncCallback(callback);
121+
let result;
122+
try {
123+
result = statSync(filepath);
124+
} catch (e) {
125+
callback(e);
126+
return;
127+
}
128+
callback(null, result);
129+
});
130+
131+
fs.statSync.mockImplementation(statSync);
132+
133+
function lstatSync(filepath) {
134+
const node = getToNode(filepath);
135+
return makeStatResult(node);
136+
}
137+
138+
fs.lstat.mockImplementation((filepath, callback) => {
139+
callback = asyncCallback(callback);
140+
let result;
141+
try {
142+
result = lstatSync(filepath);
143+
} catch (e) {
144+
callback(e);
145+
return;
146+
}
147+
callback(null, result);
148+
});
149+
150+
fs.lstatSync.mockImplementation(lstatSync);
151+
152+
fs.open.mockImplementation(function(filepath) {
153+
const callback = arguments[arguments.length - 1] || noop;
154+
let data, error, fd;
155+
try {
156+
data = getToNode(filepath);
157+
} catch (e) {
158+
error = e;
159+
}
160+
161+
if (error || data == null) {
162+
error = Error(`ENOENT: no such file or directory, open ${filepath}`);
163+
}
164+
if (data != null) {
165+
/* global Buffer: true */
166+
fd = {buffer: new Buffer(data, 'utf8'), position: 0};
167+
}
168+
169+
callback(error, fd);
170+
});
171+
172+
fs.read.mockImplementation((fd, buffer, writeOffset, length, position, callback = noop) => {
173+
let bytesWritten;
174+
try {
175+
if (position == null || position < 0) {
176+
({position} = fd);
177+
}
178+
bytesWritten = fd.buffer.copy(buffer, writeOffset, position, position + length);
179+
fd.position = position + bytesWritten;
180+
} catch (e) {
181+
callback(Error('invalid argument'));
182+
return;
183+
}
184+
callback(null, bytesWritten, buffer);
185+
});
186+
187+
fs.close.mockImplementation((fd, callback = noop) => {
188+
try {
189+
fd.buffer = fs.position = undefined;
190+
} catch (e) {
191+
callback(Error('invalid argument'));
192+
return;
193+
}
194+
callback(null);
195+
});
196+
197+
let filesystem;
198+
199+
fs.createReadStream.mockImplementation(filepath => {
200+
if (!filepath.startsWith('/')) {
201+
throw Error('Cannot open file ' + filepath);
202+
}
203+
204+
const parts = filepath.split('/').slice(1);
205+
let file = filesystem;
206+
207+
for (const part of parts) {
208+
file = file[part];
209+
if (!file) {
210+
break;
211+
}
212+
}
213+
214+
if (typeof file !== 'string') {
215+
throw Error('Cannot open file ' + filepath);
216+
}
217+
218+
return new stream.Readable({
219+
read() {
220+
this.push(file, 'utf8');
221+
this.push(null);
222+
},
223+
});
224+
});
225+
226+
fs.createWriteStream.mockImplementation(file => {
227+
let node;
228+
try {
229+
node = getToNode(dirname(file));
230+
} finally {
231+
if (typeof node === 'object') {
232+
const writeStream = new stream.Writable({
233+
write(chunk) {
234+
this.__chunks.push(chunk);
235+
},
236+
});
237+
writeStream.__file = file;
238+
writeStream.__chunks = [];
239+
writeStream.end = jest.fn(writeStream.end);
240+
fs.createWriteStream.mock.returned.push(writeStream);
241+
return writeStream;
242+
} else {
243+
throw new Error('Cannot open file ' + file);
244+
}
245+
}
246+
});
247+
fs.createWriteStream.mock.returned = [];
248+
249+
fs.__setMockFilesystem = object => (filesystem = object);
250+
251+
const watcherListByPath = new Map();
252+
253+
fs.watch.mockImplementation((filename, options, listener) => {
254+
if (options.recursive) {
255+
throw new Error('recursive watch not implemented');
256+
}
257+
let watcherList = watcherListByPath.get(filename);
258+
if (watcherList == null) {
259+
watcherList = [];
260+
watcherListByPath.set(filename, watcherList);
261+
}
262+
const fsWatcher = new EventEmitter();
263+
fsWatcher.on('change', listener);
264+
fsWatcher.close = () => {
265+
watcherList.splice(watcherList.indexOf(fsWatcher), 1);
266+
fsWatcher.close = () => { throw new Error('FSWatcher is already closed'); };
267+
};
268+
watcherList.push(fsWatcher);
269+
});
270+
271+
fs.__triggerWatchEvent = (eventType, filename) => {
272+
const directWatchers = watcherListByPath.get(filename) || [];
273+
directWatchers.forEach(wtc => wtc.emit('change', eventType));
274+
const dirPath = path.dirname(filename);
275+
const dirWatchers = watcherListByPath.get(dirPath) || [];
276+
dirWatchers.forEach(wtc => wtc.emit('change', eventType, path.relative(dirPath, filename)));
277+
};
278+
279+
function getToNode(filepath) {
280+
// Ignore the drive for Windows paths.
281+
if (filepath.match(/^[a-zA-Z]:\\/)) {
282+
filepath = filepath.substring(2);
283+
}
284+
285+
if (filepath.endsWith(path.sep)) {
286+
filepath = filepath.slice(0, -1);
287+
}
288+
const parts = filepath.split(/[\/\\]/);
289+
if (parts[0] !== '') {
290+
throw new Error('Make sure all paths are absolute.');
291+
}
292+
let node = filesystem;
293+
parts.slice(1).forEach(part => {
294+
if (node && node.SYMLINK) {
295+
node = getToNode(node.SYMLINK);
296+
}
297+
node = node[part];
298+
if (node == null) {
299+
const err = new Error('ENOENT: no such file or directory');
300+
err.code = 'ENOENT';
301+
throw err;
302+
}
303+
});
304+
305+
return node;
306+
}
307+
308+
module.exports = fs;

0 commit comments

Comments
 (0)