metro: traverseDependencies-integration-test: switch to the memory FS

Reviewed By: rafeca

Differential Revision: D7257733

fbshipit-source-id: a82583bfed0921a69e4518bf32bcdb4515f50c94
This commit is contained in:
Jean Lauliac 2018-04-11 18:00:02 -07:00 committed by Facebook Github Bot
parent 13e0844dcf
commit 55e7e50232
1 changed files with 145 additions and 137 deletions

View File

@ -12,16 +12,16 @@
jest.useRealTimers();
jest
.mock('fs')
.mock('graceful-fs')
.mock('metro-core')
.mock('../../lib/TransformCaching')
// It's noticeably faster to prevent running watchman from FileWatcher.
.mock('child_process', () => ({}))
.mock('os', () => ({
...require.requireActual('os'),
platform: () => 'test',
}));
tmpdir: () => (process.platform === 'win32' ? 'C:\\tmp' : '/tmp'),
hostname: () => 'testhost',
endianness: () => 'LE',
}))
.mock('graceful-fs', () => require('fs'));
// Super-simple mock for extracting dependencies
const extractDependencies = function(sourceCode: string) {
@ -36,8 +36,6 @@ const extractDependencies = function(sourceCode: string) {
return deps;
};
jest.mock('graceful-fs', () => require('fs'));
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
beforeEach(() => {
@ -94,6 +92,7 @@ describe('traverseDependencies', function() {
beforeEach(function() {
jest.resetModules();
jest.mock('fs', () => new (require('metro-memory-fs'))());
Module = require('../../node-haste/Module');
traverseDependencies = require('../traverseDependencies');
@ -2336,6 +2335,8 @@ describe('traverseDependencies', function() {
// reload path module
jest.resetModules();
jest.mock('path', () => require.requireActual('path').win32);
jest.mock('fs', () => new (require('metro-memory-fs'))('win32'));
require('os').tmpdir = () => 'c:\\tmp';
DependencyGraph = require('../../node-haste/DependencyGraph');
processDgraph = processDgraphFor.bind(null, DependencyGraph);
});
@ -2984,10 +2985,16 @@ describe('traverseDependencies', function() {
expect(error.originModulePath).toBe('/root/index.js');
expect(error.targetModuleName).toBe('dontWork');
}
filesystem.root['index.js'] = filesystem.root['index.js']
.replace('require("dontWork")', '')
.replace('require("wontWork")', '');
return triggerAndProcessWatchEvent(dgraph, 'change', root + '/index.js')
return triggerAndProcessWatchEvent(dgraph, () => {
const fs = require('fs');
const code = fs.readFileSync(root + '/index.js', 'utf8');
fs.writeFileSync(
root + '/index.js',
code
.replace('require("dontWork")', '')
.replace('require("wontWork")', ''),
);
})
.then(() => getOrderedDependenciesAsJSON(dgraph, '/root/index.js'))
.then(deps => {
expect(deps).toEqual([
@ -3416,6 +3423,8 @@ describe('traverseDependencies', function() {
// reload path module
jest.resetModules();
jest.mock('path', () => require.requireActual('path').win32);
jest.mock('fs', () => new (require('metro-memory-fs'))('win32'));
require('os').tmpdir = () => 'c:\\tmp';
DependencyGraph = require('../../node-haste/DependencyGraph');
processDgraph = processDgraphFor.bind(null, DependencyGraph);
({
@ -3900,10 +3909,16 @@ describe('traverseDependencies', function() {
expect(error.originModulePath).toBe('C:\\root\\index.js');
expect(error.targetModuleName).toBe('dontWork');
}
filesystem.root['index.js'] = filesystem.root['index.js']
.replace('require("dontWork")', '')
.replace('require("wontWork")', '');
await triggerAndProcessWatchEvent(dgraph, 'change', entryPath);
await triggerAndProcessWatchEvent(dgraph, () => {
const fs = require('fs');
fs.writeFileSync(
entryPath,
fs
.readFileSync(entryPath, 'utf8')
.replace('require("dontWork")', '')
.replace('require("wontWork")', ''),
);
});
const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath);
expect(deps).toEqual([
{
@ -4275,6 +4290,7 @@ describe('traverseDependencies', function() {
describe('file watch updating', function() {
let DependencyGraph;
let processDgraph;
let fs;
beforeEach(function() {
Object.defineProperty(process, 'platform', {
@ -4285,11 +4301,12 @@ describe('traverseDependencies', function() {
DependencyGraph = require('../../node-haste/DependencyGraph');
processDgraph = processDgraphFor.bind(null, DependencyGraph);
fs = require('fs');
});
it('updates module dependencies', async () => {
var root = '/root';
var filesystem = setMockFileSystem({
setMockFileSystem({
root: {
'index.js': [
'/**',
@ -4318,11 +4335,12 @@ describe('traverseDependencies', function() {
const entryPath = '/root/index.js';
await processDgraph(opts, async dgraph => {
await getOrderedDependenciesAsJSON(dgraph, entryPath);
filesystem.root['index.js'] = filesystem.root['index.js'].replace(
'require("foo")',
'',
);
await triggerAndProcessWatchEvent(dgraph, 'change', entryPath);
await triggerAndProcessWatchEvent(dgraph, () => {
fs.writeFileSync(
entryPath,
fs.readFileSync(entryPath, 'utf8').replace('require("foo")', ''),
);
});
const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath);
expect(deps).toEqual([
{
@ -4345,7 +4363,7 @@ describe('traverseDependencies', function() {
it('updates module dependencies on file change', async () => {
var root = '/root';
var filesystem = setMockFileSystem({
setMockFileSystem({
root: {
'index.js': [
'/**',
@ -4374,11 +4392,12 @@ describe('traverseDependencies', function() {
const entryPath = '/root/index.js';
await processDgraph(opts, async dgraph => {
await getOrderedDependenciesAsJSON(dgraph, entryPath);
filesystem.root['index.js'] = filesystem.root['index.js'].replace(
'require("foo")',
'',
);
await triggerAndProcessWatchEvent(dgraph, 'change', root + '/index.js');
await triggerAndProcessWatchEvent(dgraph, () => {
fs.writeFileSync(
entryPath,
fs.readFileSync(entryPath, 'utf8').replace('require("foo")', ''),
);
});
const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath);
expect(deps).toEqual([
{
@ -4401,7 +4420,7 @@ describe('traverseDependencies', function() {
it('updates module dependencies on file delete', async () => {
var root = '/root';
var filesystem = setMockFileSystem({
setMockFileSystem({
root: {
'index.js': [
'/**',
@ -4430,8 +4449,9 @@ describe('traverseDependencies', function() {
const entryPath = '/root/index.js';
await processDgraph(opts, async dgraph => {
await getOrderedDependenciesAsJSON(dgraph, entryPath);
delete filesystem.root['foo.js'];
await triggerAndProcessWatchEvent(dgraph, 'change', root + '/foo.js');
await triggerAndProcessWatchEvent(dgraph, () => {
fs.unlinkSync(root + '/foo.js');
});
try {
await getOrderedDependenciesAsJSON(dgraph, '/root/index.js');
throw new Error('should be unreachable');
@ -4448,7 +4468,7 @@ describe('traverseDependencies', function() {
it('updates module dependencies on file add', async () => {
expect.assertions(1);
var root = '/root';
var filesystem = setMockFileSystem({
setMockFileSystem({
root: {
'index.js': [
'/**',
@ -4477,19 +4497,15 @@ describe('traverseDependencies', function() {
const entryPath = '/root/index.js';
await processDgraph(opts, async dgraph => {
await getOrderedDependenciesAsJSON(dgraph, entryPath);
filesystem.root['bar.js'] = [
'/**',
' * @providesModule bar',
' */',
'require("foo")',
].join('\n');
await triggerAndProcessWatchEvent(dgraph, 'change', root + '/bar.js');
filesystem.root.aPackage['main.js'] = 'require("bar")';
await triggerAndProcessWatchEvent(
dgraph,
'change',
root + '/aPackage/main.js',
);
await triggerAndProcessWatchEvent(dgraph, () => {
fs.writeFileSync(
root + '/bar.js',
['/**', ' * @providesModule bar', ' */', 'require("foo")'].join(
'\n',
),
);
fs.writeFileSync(root + '/aPackage/main.js', 'require("bar")');
});
const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath);
expect(deps).toEqual([
{
@ -4528,7 +4544,7 @@ describe('traverseDependencies', function() {
it('updates module dependencies on relative asset add', async () => {
var root = '/root';
var filesystem = setMockFileSystem({
setMockFileSystem({
root: {
'index.js': [
'/**',
@ -4555,8 +4571,9 @@ describe('traverseDependencies', function() {
expect(error.originModulePath).toBe('/root/index.js');
expect(error.targetModuleName).toBe('./foo.png');
}
filesystem.root['foo.png'] = '';
await triggerAndProcessWatchEvent(dgraph, 'change', root + '/foo.png');
await triggerAndProcessWatchEvent(dgraph, () => {
fs.writeFileSync(root + '/foo.png', '');
});
const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath);
expect(deps).toEqual([
{
@ -4582,7 +4599,7 @@ describe('traverseDependencies', function() {
it('changes to browser field', async () => {
expect.assertions(1);
var root = '/root';
var filesystem = setMockFileSystem({
setMockFileSystem({
root: {
'index.js': [
'/**',
@ -4605,16 +4622,16 @@ describe('traverseDependencies', function() {
const entryPath = '/root/index.js';
await processDgraph(opts, async dgraph => {
await getOrderedDependenciesAsJSON(dgraph, entryPath);
filesystem.root.aPackage['package.json'] = JSON.stringify({
name: 'aPackage',
main: 'main.js',
browser: 'browser.js',
await triggerAndProcessWatchEvent(dgraph, () => {
fs.writeFileSync(
root + '/aPackage/package.json',
JSON.stringify({
name: 'aPackage',
main: 'main.js',
browser: 'browser.js',
}),
);
});
await triggerAndProcessWatchEvent(
dgraph,
'change',
root + '/aPackage/package.json',
);
const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath);
expect(deps).toEqual([
{
@ -4639,7 +4656,7 @@ describe('traverseDependencies', function() {
it('removes old package from cache', async () => {
var root = '/root';
var filesystem = setMockFileSystem({
setMockFileSystem({
root: {
'index.js': [
'/**',
@ -4662,20 +4679,23 @@ describe('traverseDependencies', function() {
const entryPath = '/root/index.js';
await processDgraph(opts, async dgraph => {
await getOrderedDependenciesAsJSON(dgraph, entryPath);
filesystem.root['index.js'] = [
'/**',
' * @providesModule index',
' */',
'require("bPackage")',
].join('\n');
filesystem.root.aPackage['package.json'] = JSON.stringify({
name: 'bPackage',
main: 'main.js',
});
await new Promise(resolve => {
dgraph.once('change', () => resolve());
triggerWatchEvent('change', root + '/index.js');
triggerWatchEvent('change', root + '/aPackage/package.json');
await triggerAndProcessWatchEvent(dgraph, () => {
fs.writeFileSync(
root + '/index.js',
[
'/**',
' * @providesModule index',
' */',
'require("bPackage")',
].join('\n'),
);
fs.writeFileSync(
root + '/aPackage/package.json',
JSON.stringify({
name: 'bPackage',
main: 'main.js',
}),
);
});
const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath);
expect(deps).toEqual([
@ -4701,7 +4721,7 @@ describe('traverseDependencies', function() {
it('should update node package changes', async () => {
expect.assertions(2);
var root = '/root';
var filesystem = setMockFileSystem({
setMockFileSystem({
root: {
'index.js': [
'/**',
@ -4761,12 +4781,9 @@ describe('traverseDependencies', function() {
},
]);
filesystem.root.node_modules.foo['main.js'] = 'lol';
await triggerAndProcessWatchEvent(
dgraph,
'change',
root + '/node_modules/foo/main.js',
);
await triggerAndProcessWatchEvent(dgraph, () => {
fs.writeFileSync(root + '/node_modules/foo/main.js', 'lol');
});
const deps2 = await getOrderedDependenciesAsJSON(dgraph, entryPath);
expect(deps2).toEqual([
{
@ -4793,7 +4810,7 @@ describe('traverseDependencies', function() {
it('should update node package main changes', async () => {
expect.assertions(1);
var root = '/root';
var filesystem = setMockFileSystem({
setMockFileSystem({
root: {
'index.js': [
'/**',
@ -4818,16 +4835,16 @@ describe('traverseDependencies', function() {
const entryPath = '/root/index.js';
await processDgraph(opts, async dgraph => {
await getOrderedDependenciesAsJSON(dgraph, entryPath);
filesystem.root.node_modules.foo['package.json'] = JSON.stringify({
name: 'foo',
main: 'main.js',
browser: 'browser.js',
await triggerAndProcessWatchEvent(dgraph, () => {
fs.writeFileSync(
root + '/node_modules/foo/package.json',
JSON.stringify({
name: 'foo',
main: 'main.js',
browser: 'browser.js',
}),
);
});
await triggerAndProcessWatchEvent(
dgraph,
'change',
root + '/node_modules/foo/package.json',
);
const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath);
expect(deps).toEqual([
{
@ -4851,40 +4868,10 @@ describe('traverseDependencies', function() {
});
});
it('should not error when the watcher reports a known file as added', async () => {
expect.assertions(1);
var root = '/root';
setMockFileSystem({
root: {
'index.js': [
'/**',
' * @providesModule index',
' */',
'var b = require("b");',
].join('\n'),
'b.js': [
'/**',
' * @providesModule b',
' */',
'module.exports = function() {};',
].join('\n'),
},
});
const opts = {...defaults, projectRoots: [root]};
const entryPath = '/root/index.js';
await processDgraph(opts, async dgraph => {
await getOrderedDependenciesAsJSON(dgraph, entryPath);
await triggerAndProcessWatchEvent(dgraph, 'change', root + '/index.js');
const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath);
expect(deps).toBeDefined();
});
});
it('should recover from multiple modules with the same name', async () => {
const root = '/root';
console.warn = jest.fn();
const filesystem = setMockFileSystem({
setMockFileSystem({
root: {
'index.js': [
'/**',
@ -4902,12 +4889,14 @@ describe('traverseDependencies', function() {
const entryPath = '/root/index.js';
await processDgraph(opts, async dgraph => {
await getOrderedDependenciesAsJSON(dgraph, entryPath);
filesystem.root['b.js'] = ['/**', ' * @providesModule a', ' */'].join(
'\n',
);
await triggerAndProcessWatchEvent(dgraph, 'change', root + '/b.js');
await triggerAndProcessWatchEvent(dgraph, () => {
fs.writeFileSync(
root + '/b.js',
['/**', ' * @providesModule a', ' */'].join('\n'),
);
});
try {
await getOrderedDependenciesAsJSON(dgraph, root + '/index.js');
await getOrderedDependenciesAsJSON(dgraph, entryPath);
throw new Error('expected `getOrderedDependenciesAsJSON` to fail');
} catch (error) {
const {AmbiguousModuleResolutionError} = require('metro-core');
@ -4915,11 +4904,13 @@ describe('traverseDependencies', function() {
throw error;
}
expect(console.warn).toBeCalled();
filesystem.root['b.js'] = ['/**', ' * @providesModule b', ' */'].join(
'\n',
);
await triggerAndProcessWatchEvent(dgraph, 'change', root + '/b.js');
}
await triggerAndProcessWatchEvent(dgraph, () => {
fs.writeFileSync(
root + '/b.js',
['/**', ' * @providesModule b', ' */'].join('\n'),
);
});
const deps = await getOrderedDependenciesAsJSON(dgraph, entryPath);
expect(deps).toMatchSnapshot();
});
@ -5340,20 +5331,37 @@ describe('traverseDependencies', function() {
}
function setMockFileSystem(object) {
return require('fs').__setMockFilesystem(object);
const fs = require('fs');
const root = process.platform === 'win32' ? 'c:\\' : '/';
mockDir(fs, root, {...object, tmp: {}});
}
function triggerAndProcessWatchEvent(dgraphPromise, eventType, filename) {
function mockDir(fs, dirPath, desc) {
for (const entName in desc) {
const ent = desc[entName];
const entPath = require('path').join(dirPath, entName);
if (typeof ent === 'string') {
fs.writeFileSync(entPath, ent);
continue;
}
if (typeof ent !== 'object') {
throw new Error(require('util').format('invalid entity:', ent));
}
fs.mkdirSync(entPath);
mockDir(fs, entPath, ent);
}
}
function triggerAndProcessWatchEvent(dgraphPromise, fsOperation) {
return Promise.resolve(dgraphPromise).then(
dgraph =>
new Promise(resolve => {
dgraph.once('change', () => resolve());
triggerWatchEvent(eventType, filename);
// FIXME: Timeout is needed to wait for thing to settle down a bit.
// This adds flakiness to this test, and normally should not be
// needed.
dgraph.once('change', () => setTimeout(resolve, 100));
fsOperation();
}),
);
}
function triggerWatchEvent(eventType, filename) {
return require('fs').__triggerWatchEvent(eventType, filename);
}
});