react-native/local-cli/util/__tests__/findSymlinkedModules-test.js
Adam Miskiewicz 39f83c4a12 Refactor how symlinks are discovered in local-cli, support scoped modules
Summary:
This PR refactors the symlink finding logic in local-cli in order to support nested symlinked modules as well as symlinked scoped NPM modules.

Run tests, or try project with `npm link`'ed or `yarn link`'ed dependencies.
Closes https://github.com/facebook/react-native/pull/15776

Reviewed By: cpojer

Differential Revision: D5823008

Pulled By: jeanlauliac

fbshipit-source-id: f2daeceef37bed2f8a136a0a5918730f9832884c
2017-09-14 04:31:57 -07:00

355 lines
8.9 KiB
JavaScript

/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @format
* @emails oncall+javascript_foundation
*/
jest.mock('fs');
const fs = require('fs');
const findSymlinkedModules = require('../findSymlinkedModules');
describe('findSymlinksForProjectRoot', () => {
it('correctly finds normal module symlinks', () => {
fs.__setMockFilesystem({
root: {
projectA: {
'package.json': JSON.stringify({
name: 'projectA',
main: 'main.js',
}),
node_modules: {
depFoo: {
'package.json': JSON.stringify({
name: 'depFoo',
main: 'main.js',
}),
},
projectB: {
SYMLINK: '/root/projectB',
},
},
},
projectB: {
'package.json': JSON.stringify({
name: 'projectB',
main: 'main.js',
}),
node_modules: {
depBar: {
'package.json': JSON.stringify({
name: 'depBar',
main: 'main.js',
}),
},
},
},
},
});
const symlinkedModules = findSymlinkedModules('/root/projectA', []);
expect(symlinkedModules).toEqual(['/root/projectB']);
});
it('correctly finds scoped module symlinks', () => {
fs.__setMockFilesystem({
root: {
projectA: {
'package.json': JSON.stringify({
name: 'projectA',
main: 'main.js',
}),
node_modules: {
depFoo: {
'package.json': JSON.stringify({
name: 'depFoo',
main: 'main.js',
}),
},
'@scoped': {
projectC: {
SYMLINK: '/root/@scoped/projectC',
},
},
projectB: {
SYMLINK: '/root/projectB',
},
},
},
projectB: {
'package.json': JSON.stringify({
name: 'projectB',
main: 'main.js',
}),
node_modules: {
depBar: {
'package.json': JSON.stringify({
name: 'depBar',
main: 'main.js',
}),
},
},
},
'@scoped': {
projectC: {
'package.json': JSON.stringify({
name: '@scoped/projectC',
main: 'main.js',
}),
},
},
},
});
const symlinkedModules = findSymlinkedModules('/root/projectA', []);
expect(symlinkedModules).toEqual([
'/root/@scoped/projectC',
'/root/projectB',
]);
});
it('correctly finds module symlinks within other module symlinks', () => {
fs.__setMockFilesystem({
root: {
projectA: {
'package.json': JSON.stringify({
name: 'projectA',
main: 'main.js',
}),
node_modules: {
depFoo: {
'package.json': JSON.stringify({
name: 'depFoo',
main: 'main.js',
}),
},
'@scoped': {
projectC: {
SYMLINK: '/root/@scoped/projectC',
},
},
projectB: {
SYMLINK: '/root/projectB',
},
},
},
projectB: {
'package.json': JSON.stringify({
name: 'projectB',
main: 'main.js',
}),
node_modules: {
depBar: {
'package.json': JSON.stringify({
name: 'depBar',
main: 'main.js',
}),
},
projectD: {
SYMLINK: '/root/projectD',
},
},
},
'@scoped': {
projectC: {
'package.json': JSON.stringify({
name: '@scoped/projectC',
main: 'main.js',
}),
},
},
projectD: {
'package.json': JSON.stringify({
name: 'projectD',
main: 'main.js',
}),
},
},
});
const symlinkedModules = findSymlinkedModules('/root/projectA', []);
expect(symlinkedModules).toEqual([
'/root/@scoped/projectC',
'/root/projectB',
'/root/projectD',
]);
});
it('correctly handles duplicate symlink paths', () => {
// projectA ->
// -> projectC
// -> projectB -> projectC
// Final list should only contain projectC once
fs.__setMockFilesystem({
root: {
projectA: {
'package.json': JSON.stringify({
name: 'projectA',
main: 'main.js',
}),
node_modules: {
depFoo: {
'package.json': JSON.stringify({
name: 'depFoo',
main: 'main.js',
}),
},
'@scoped': {
projectC: {
SYMLINK: '/root/@scoped/projectC',
},
},
projectB: {
SYMLINK: '/root/projectB',
},
},
},
projectB: {
'package.json': JSON.stringify({
name: 'projectB',
main: 'main.js',
}),
node_modules: {
depBar: {
'package.json': JSON.stringify({
name: 'depBar',
main: 'main.js',
}),
},
'@scoped': {
projectC: {
SYMLINK: '/root/@scoped/projectC',
},
},
},
},
'@scoped': {
projectC: {
'package.json': JSON.stringify({
name: '@scoped/projectC',
main: 'main.js',
}),
},
},
},
});
const symlinkedModules = findSymlinkedModules('/root/projectA', []);
expect(symlinkedModules).toEqual([
'/root/@scoped/projectC',
'/root/projectB',
]);
});
it('correctly handles symlink recursion', () => {
// projectA ->
// -> projectC -> projectD -> projectA
// -> projectB -> projectC -> projectA
// -> projectD -> projectC -> projectA
// Should not infinite loop, should not contain projectA
fs.__setMockFilesystem({
root: {
projectA: {
'package.json': JSON.stringify({
name: 'projectA',
main: 'main.js',
}),
node_modules: {
depFoo: {
'package.json': JSON.stringify({
name: 'depFoo',
main: 'main.js',
}),
},
'@scoped': {
projectC: {
SYMLINK: '/root/@scoped/projectC',
},
},
projectB: {
SYMLINK: '/root/projectB',
},
},
},
projectB: {
'package.json': JSON.stringify({
name: 'projectB',
main: 'main.js',
}),
node_modules: {
depBar: {
'package.json': JSON.stringify({
name: 'depBar',
main: 'main.js',
}),
},
projectD: {
SYMLINK: '/root/projectD',
},
'@scoped': {
projectC: {
SYMLINK: '/root/@scoped/projectC',
},
},
},
},
'@scoped': {
projectC: {
'package.json': JSON.stringify({
name: '@scoped/projectC',
main: 'main.js',
}),
node_modules: {
projectA: {
SYMLINK: '/root/projectA',
},
projectD: {
SYMLINK: '/root/projectD',
},
projectE: {
SYMLINK: '/root/projectE',
},
},
},
},
projectD: {
'package.json': JSON.stringify({
name: 'projectD',
main: 'main.js',
}),
node_modules: {
'@scoped': {
projectC: {
SYMLINK: '/root/@scoped/projectC',
},
},
projectE: {
SYMLINK: '/root/projectE',
},
},
},
projectE: {
'package.json': JSON.stringify({
name: 'projectD',
main: 'main.js',
}),
},
},
});
const symlinkedModules = findSymlinkedModules('/root/projectA');
expect(symlinkedModules).toEqual([
'/root/@scoped/projectC',
'/root/projectB',
'/root/projectD',
'/root/projectE',
]);
});
});