packager: DependencyGraph-test: go through fs.watch mock rather than manual API

Reviewed By: davidaurelio

Differential Revision: D4628593

fbshipit-source-id: 43ccdb038bd387e87096f2a7020c98d915fa5bba
This commit is contained in:
Jean Lauliac 2017-03-01 07:50:39 -08:00 committed by Facebook Github Bot
parent 556c432260
commit 9aa1215e21
3 changed files with 111 additions and 66 deletions

View File

@ -8,6 +8,7 @@
*/
'use strict';
const {EventEmitter} = require('events');
const {dirname} = require.requireActual('path');
const fs = jest.genMockFromModule('fs');
const path = require('path');
@ -96,7 +97,12 @@ fs.readFileSync.mockImplementation(function(filepath, encoding) {
function makeStatResult(node) {
const isSymlink = node != null && node.SYMLINK != null;
return {
isBlockDevice: () => false,
isCharacterDevice: () => false,
isDirectory: () => node != null && typeof node === 'object' && !isSymlink,
isFIFO: () => false,
isFile: () => node != null && typeof node === 'string',
isSocket: () => false,
isSymbolicLink: () => isSymlink,
mtime,
};
@ -242,6 +248,34 @@ fs.createWriteStream.mock.returned = [];
fs.__setMockFilesystem = object => (filesystem = object);
const watcherListByPath = new Map();
fs.watch.mockImplementation((filename, options, listener) => {
if (options.recursive) {
throw new Error('recursive watch not implemented');
}
let watcherList = watcherListByPath.get(filename);
if (watcherList == null) {
watcherList = [];
watcherListByPath.set(filename, watcherList);
}
const fsWatcher = new EventEmitter();
fsWatcher.on('change', listener);
fsWatcher.close = () => {
watcherList.splice(watcherList.indexOf(fsWatcher), 1);
fsWatcher.close = () => { throw new Error('FSWatcher is already closed'); };
};
watcherList.push(fsWatcher);
});
fs.__triggerWatchEvent = (eventType, filename) => {
const directWatchers = watcherListByPath.get(filename) || [];
directWatchers.forEach(wtc => wtc.emit('change', eventType));
const dirPath = path.dirname(filename);
const dirWatchers = watcherListByPath.get(dirPath) || [];
dirWatchers.forEach(wtc => wtc.emit('change', eventType, path.relative(dirPath, filename)));
};
function getToNode(filepath) {
// Ignore the drive for Windows paths.
if (filepath.match(/^[a-zA-Z]:\\/)) {

View File

@ -130,7 +130,7 @@ describe('DependencyGraph', function() {
},
getTransformCacheKey: () => 'abcdef',
reporter: require('../../lib/reporting').nullReporter,
watch: false,
watch: true,
};
});
@ -3111,70 +3111,74 @@ describe('DependencyGraph', function() {
filesystem.root['index.js'] = filesystem.root['index.js']
.replace('require("dontWork")', '')
.replace('require("wontWork")', '');
dgraph.processFileChange('change', root + '/index.js', mockStat);
return getOrderedDependenciesAsJSON(dgraph, '/root/index.js')
.then(deps => {
expect(deps).toEqual([
{
id: 'index',
path: '/root/index.js',
dependencies: [
'shouldWork',
'ember',
'internalVendoredPackage',
'anotherIndex',
],
isAsset: false,
isJSON: false,
isPolyfill: false,
resolution: undefined,
},
{
id: 'shouldWork',
path: '/root/node_modules/react-haste/main.js',
dependencies: ['submodule'],
isAsset: false,
isJSON: false,
isPolyfill: false,
resolution: undefined,
},
{
id: 'submodule/main.js',
path: '/root/node_modules/react-haste/node_modules/submodule/main.js',
dependencies: [],
isAsset: false,
isJSON: false,
isPolyfill: false,
resolution: undefined,
},
{
id: 'ember/main.js',
path: '/root/node_modules/ember/main.js',
dependencies: [],
isAsset: false,
isJSON: false,
isPolyfill: false,
resolution: undefined,
},
{
id: 'internalVendoredPackage',
path: '/root/vendored_modules/a-vendored-package/main.js',
dependencies: [],
isAsset: false,
isJSON: false,
isPolyfill: false,
resolution: undefined,
},
{
id: 'anotherIndex',
path: '/anotherRoot/index.js',
dependencies: [],
isAsset: false,
isJSON: false,
isPolyfill: false,
resolution: undefined,
},
]);
triggerWatchEvent('change', root + '/index.js');
return new Promise(resolve => {
dgraph.once('change', () => {
return resolve(getOrderedDependenciesAsJSON(dgraph, '/root/index.js')
.then(deps => {
expect(deps).toEqual([
{
id: 'index',
path: '/root/index.js',
dependencies: [
'shouldWork',
'ember',
'internalVendoredPackage',
'anotherIndex',
],
isAsset: false,
isJSON: false,
isPolyfill: false,
resolution: undefined,
},
{
id: 'shouldWork',
path: '/root/node_modules/react-haste/main.js',
dependencies: ['submodule'],
isAsset: false,
isJSON: false,
isPolyfill: false,
resolution: undefined,
},
{
id: 'submodule/main.js',
path: '/root/node_modules/react-haste/node_modules/submodule/main.js',
dependencies: [],
isAsset: false,
isJSON: false,
isPolyfill: false,
resolution: undefined,
},
{
id: 'ember/main.js',
path: '/root/node_modules/ember/main.js',
dependencies: [],
isAsset: false,
isJSON: false,
isPolyfill: false,
resolution: undefined,
},
{
id: 'internalVendoredPackage',
path: '/root/vendored_modules/a-vendored-package/main.js',
dependencies: [],
isAsset: false,
isJSON: false,
isPolyfill: false,
resolution: undefined,
},
{
id: 'anotherIndex',
path: '/anotherRoot/index.js',
dependencies: [],
isAsset: false,
isJSON: false,
isPolyfill: false,
resolution: undefined,
},
]);
}));
});
});
});
});
@ -5455,4 +5459,8 @@ describe('DependencyGraph', function() {
function setMockFileSystem(object) {
return require('graceful-fs').__setMockFilesystem(object);
}
function triggerWatchEvent(eventType, filename) {
return require('graceful-fs').__triggerWatchEvent(eventType, filename);
}
});

View File

@ -36,6 +36,7 @@ const {
createActionStartEntry,
log,
} = require('../Logger');
const {EventEmitter} = require('events');
import type {Options as TransformOptions} from '../JSTransformer/worker/worker';
import type GlobalTransformCache from '../lib/GlobalTransformCache';
@ -72,7 +73,7 @@ type Options = {
watch: boolean,
};
class DependencyGraph {
class DependencyGraph extends EventEmitter {
_opts: Options;
_haste: JestHasteMap;
_hasteFS: HasteFS;
@ -84,6 +85,7 @@ class DependencyGraph {
_loading: Promise<void>;
constructor(opts: Options) {
super();
this._opts = {...opts};
this._helpers = new DependencyGraphHelpers(this._opts);
this.load();
@ -154,6 +156,7 @@ class DependencyGraph {
eventsQueue.forEach(({type, filePath, stat}) =>
this.processFileChange(type, filePath, stat)
);
this.emit('change');
});
const buildingHasteMapLogEntry =