Skip to content

Commit

Permalink
Make mockFs use caching (prevent leak from: tschaub/mock-fs#302)
Browse files Browse the repository at this point in the history
  • Loading branch information
nonara committed Jul 27, 2020
1 parent c773cbc commit cada510
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 24 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ts-patch",
"version": "1.2.5",
"version": "1.3.0",
"description": "Patch typescript to support custom transformers in tsconfig.json",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand Down Expand Up @@ -65,6 +65,7 @@
"jest-mock-process": "^1.4.0",
"mock-fs": "^4.12.0",
"resolve": "^1.15.1",
"rfdc": "^1.1.4",
"rimraf": "^3.0.2",
"rollup": "^2.1.0",
"rollup-plugin-dts": "^1.4.7",
Expand Down
44 changes: 32 additions & 12 deletions test/lib/mock-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,21 @@ import { resourcesDir, testAssetsDir, tsInstallationDirs, tsProjectsDir } from '
import { patch } from '../../src/installer';
import { normalizeSlashes } from 'ts-node';
import resolve from 'resolve';
import FileSystem from 'mock-fs/lib/filesystem';


/* ****************************************************************************************************************** */
// region: Constants
/* ****************************************************************************************************************** */

const vanillaFiles = [
...cacheDirectory(tsProjectsDir),
...cacheDirectory(resourcesDir),
...cacheDirectory(testAssetsDir)
];
const vanillaFiles = cacheDirectories(
tsProjectsDir,
resourcesDir,
testAssetsDir
);

let patchedFiles = new Map<string, { ts: any, tscCode: string }>();
const cachedFiles = new Map<string, Buffer>();

// endregion

Expand All @@ -28,11 +30,28 @@ let patchedFiles = new Map<string, { ts: any, tscCode: string }>();
// region: Helpers
/* ****************************************************************************************************************** */

function cacheDirectory(dir: string): [ string, string | {} ][] {
return (shell.ls('-RAl', dir) as unknown as (fs.Stats & { name: string })[]).map(stat => {
const statPath = normalizeSlashes(path.join(dir, stat.name));
return [ statPath, stat.isFile() ? fs.readFileSync(statPath, 'utf-8') : {} ]
});
/**
* Create a DirectoryItems from actual files and directories for mock-fs (uses caching)
*/
function cacheDirectories(...directory: string[]): FileSystem.DirectoryItems {
const res: FileSystem.DirectoryItems = {};
for (const dir of directory)
for (const stat of shell.ls('-RAl', dir) as unknown as (fs.Stats & { name: string })[]) {
const statPath = normalizeSlashes(path.join(dir, stat.name));
res[statPath] =
!stat.isFile() ? {} :
<ReturnType<typeof mock.file>>(() => {
const fileData = fs.readFileSync(statPath);
cachedFiles.set(statPath, fileData);

return Object.defineProperty(mock.file({ content: '' })(), '_content', {
get: () => cachedFiles.get(statPath),
set: (data: any) => cachedFiles.set(statPath, data)
});
});
}

return res;
}

// endregion
Expand All @@ -42,12 +61,13 @@ function cacheDirectory(dir: string): [ string, string | {} ][] {
// region: FileSystem
/* ****************************************************************************************************************** */

export function mockFs(fileEntries: [ string, string | {} ][] = vanillaFiles) {
mock(fileEntries.reduce((p, [key, value]) => { p[key] = value; return p; }, <Record<string, string | {}>>{}));
export function mockFs() {
mock(vanillaFiles);
}

export function restoreFs() {
mock.restore();
cachedFiles.clear();
}

export function resetFs() {
Expand Down
26 changes: 16 additions & 10 deletions test/patch/specified-project.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* Test cases for specifying tsconfig as 'project' in config.
*
* Note: Unfortunately, because of jest's sandbox, we cannot directly test path mapping. It is not able to resolve
* Notes: Unfortunately, because of jest's sandbox, we cannot directly test path mapping. It is not able to resolve
* mapped paths. Ideally, we'd be able to execute virtually in a context outside of
* jest, but there is not currently a clear way to do this.
*
Expand All @@ -16,14 +16,20 @@ import child_process from 'child_process';
import { getPatchedTS } from '../lib/mock-utils';


/* ****************************************************************************************************************** *
* Config
* ****************************************************************************************************************** */

const srcFilesPath = path.join(testAssetsDir, 'src-files/transformer-with-project');
const destDir = path.join(os.tmpdir(), 'tmpTSC');
const tscPath = path.join(destDir, 'node_modules/typescript/lib/tsc.js');


/* ****************************************************************************************************************** *
* Tests
* ****************************************************************************************************************** */

describe('Specify Project', () => {
const srcFilesPath = path.join(testAssetsDir, 'src-files/transformer-with-project');
const destDir = path.join(os.tmpdir(), 'tmpTSC');
const tscPath = path.join(destDir, 'node_modules/typescript/lib/tsc.js');
beforeAll(() => {
const { tscCode } = getPatchedTS('latest');

Expand All @@ -39,21 +45,21 @@ describe('Specify Project', () => {

test(`Loads project file & path mapping works`, () => {
const cmd = `node ${tscPath} --noEmit false -p ${srcFilesPath}`;
const res = child_process.execSync(cmd, { stdio: 'pipe' });
expect(res.toString()).toMatch(/Path-Mapping Success!/);
const res = child_process.spawnSync(cmd, { stdio: 'pipe', shell: true });
expect(res.stdout.toString()).toMatch(/Path-Mapping Success!/);
});

test(`Mapping fails without project specified`, () => {
const cmd = `node ${tscPath} --noEmit false -p ${path.join(srcFilesPath, 'tsconfig.noproject.json')}`;
const fail = () => child_process.execSync(cmd, { stdio: 'pipe' });
expect(fail).toThrow(/Cannot find module '#a'/);
const res = child_process.spawnSync(cmd, { stdio: 'pipe', shell: true });
expect(res.stderr.toString()).toMatch(/Cannot find module '#a'/);
});

test(`Logs warning if can't find tsconfig-paths`, () => {
shell.rm('-r', path.join(destDir, 'node_modules/tsconfig-paths'));

const cmd = `node ${tscPath} --noEmit false -p ${srcFilesPath}`;
const fail = () => child_process.execSync(cmd, { stdio: 'pipe' });
expect(fail).toThrow(/Try adding 'tsconfig-paths'/);
const res = child_process.spawnSync(cmd, { stdio: 'pipe', shell: true });
expect(res.stderr.toString()).toMatch(/Try adding 'tsconfig-paths'/);
});
});
2 changes: 1 addition & 1 deletion tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"lib": [ "es2019" ],
"outDir": "dist",
"target": "es5",
"module":"CommonJS",
"module": "CommonJS",
"moduleResolution": "node",

"newLine": "LF",
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3439,6 +3439,11 @@ ret@~0.1.10:
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==

rfdc@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.4.tgz#ba72cc1367a0ccd9cf81a870b3b58bd3ad07f8c2"
integrity sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==

rimraf@^3.0.0, rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
Expand Down

0 comments on commit cada510

Please sign in to comment.