From ef861958a93e95c29ea91c533ff5145d3f60f145 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Sun, 28 Apr 2019 20:47:57 +0100 Subject: [PATCH] refactor(ivy): ngcc - add MockFileSystem (#29643) PR Close #29643 --- .../test/analysis/decoration_analyzer_spec.ts | 16 +- .../dependencies/dependency_resolver_spec.ts | 4 +- .../dependencies/esm_dependency_host_spec.ts | 127 ++++++------- .../test/dependencies/module_resolver_spec.ts | 62 +++---- .../ngcc/test/helpers/mock_file_system.ts | 173 ++++++++++++++++++ .../compiler-cli/ngcc/test/helpers/utils.ts | 9 + .../ngcc/test/packages/build_marker_spec.ts | 31 +--- .../test/packages/entry_point_finder_spec.ts | 13 +- .../ngcc/test/packages/entry_point_spec.ts | 41 ++--- .../test/rendering/esm2015_renderer_spec.ts | 14 +- .../ngcc/test/rendering/esm5_renderer_spec.ts | 33 ++-- .../ngcc/test/rendering/renderer_spec.ts | 30 +-- .../test/writing/in_place_file_writer_spec.ts | 45 ++--- .../new_entry_point_file_writer_spec.ts | 114 +++++------- 14 files changed, 408 insertions(+), 304 deletions(-) create mode 100644 packages/compiler-cli/ngcc/test/helpers/mock_file_system.ts diff --git a/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts b/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts index afca349809..7dddb28c6b 100644 --- a/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts @@ -12,14 +12,16 @@ import {Decorator} from '../../../src/ngtsc/reflection'; import {DecoratorHandler, DetectResult} from '../../../src/ngtsc/transform'; import {CompiledClass, DecorationAnalyses, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; -import {NodeJSFileSystem} from '../../src/file_system/node_js_file_system'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; +import {Folder, MockFileSystem} from '../helpers/mock_file_system'; import {MockLogger} from '../helpers/mock_logger'; -import {makeTestBundleProgram} from '../helpers/utils'; +import {createFileSystemFromProgramFiles, makeTestBundleProgram} from '../helpers/utils'; + +const _ = AbsoluteFsPath.fromUnchecked; const TEST_PROGRAM = [ { - name: 'test.js', + name: _('/test.js'), contents: ` import {Component, Directive, Injectable} from '@angular/core'; @@ -34,7 +36,7 @@ const TEST_PROGRAM = [ `, }, { - name: 'other.js', + name: _('/other.js'), contents: ` import {Component} from '@angular/core'; @@ -46,7 +48,7 @@ const TEST_PROGRAM = [ const INTERNAL_COMPONENT_PROGRAM = [ { - name: 'entrypoint.js', + name: _('/entrypoint.js'), contents: ` import {Component, NgModule} from '@angular/core'; import {ImportedComponent} from './component'; @@ -62,7 +64,7 @@ const INTERNAL_COMPONENT_PROGRAM = [ ` }, { - name: 'component.js', + name: _('/component.js'), contents: ` import {Component} from '@angular/core'; export class ImportedComponent {} @@ -137,7 +139,7 @@ describe('DecorationAnalyzer', () => { const reflectionHost = new Esm2015ReflectionHost(new MockLogger(), false, program.getTypeChecker()); const referencesRegistry = new NgccReferencesRegistry(reflectionHost); - const fs = new NodeJSFileSystem(); + const fs = new MockFileSystem(createFileSystemFromProgramFiles(...progArgs)); const analyzer = new DecorationAnalyzer( fs, program, options, host, program.getTypeChecker(), reflectionHost, referencesRegistry, [AbsoluteFsPath.fromUnchecked('/')], false); diff --git a/packages/compiler-cli/ngcc/test/dependencies/dependency_resolver_spec.ts b/packages/compiler-cli/ngcc/test/dependencies/dependency_resolver_spec.ts index b97ee13820..9b5a5c8016 100644 --- a/packages/compiler-cli/ngcc/test/dependencies/dependency_resolver_spec.ts +++ b/packages/compiler-cli/ngcc/test/dependencies/dependency_resolver_spec.ts @@ -9,8 +9,8 @@ import {AbsoluteFsPath} from '../../../src/ngtsc/path'; import {DependencyResolver, SortedEntryPointsInfo} from '../../src/dependencies/dependency_resolver'; import {EsmDependencyHost} from '../../src/dependencies/esm_dependency_host'; import {ModuleResolver} from '../../src/dependencies/module_resolver'; -import {NodeJSFileSystem} from '../../src/file_system/node_js_file_system'; import {EntryPoint} from '../../src/packages/entry_point'; +import {MockFileSystem} from '../helpers/mock_file_system'; import {MockLogger} from '../helpers/mock_logger'; const _ = AbsoluteFsPath.from; @@ -19,7 +19,7 @@ describe('DependencyResolver', () => { let host: EsmDependencyHost; let resolver: DependencyResolver; beforeEach(() => { - const fs = new NodeJSFileSystem(); + const fs = new MockFileSystem(); host = new EsmDependencyHost(fs, new ModuleResolver(fs)); resolver = new DependencyResolver(new MockLogger(), host); }); diff --git a/packages/compiler-cli/ngcc/test/dependencies/esm_dependency_host_spec.ts b/packages/compiler-cli/ngcc/test/dependencies/esm_dependency_host_spec.ts index bb3dc79c9b..bea7dc250f 100644 --- a/packages/compiler-cli/ngcc/test/dependencies/esm_dependency_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/dependencies/esm_dependency_host_spec.ts @@ -5,27 +5,23 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import * as mockFs from 'mock-fs'; import * as ts from 'typescript'; import {AbsoluteFsPath} from '../../../src/ngtsc/path'; import {EsmDependencyHost} from '../../src/dependencies/esm_dependency_host'; import {ModuleResolver} from '../../src/dependencies/module_resolver'; -import {NodeJSFileSystem} from '../../src/file_system/node_js_file_system'; +import {MockFileSystem} from '../helpers/mock_file_system'; const _ = AbsoluteFsPath.from; describe('DependencyHost', () => { let host: EsmDependencyHost; beforeEach(() => { - const fs = new NodeJSFileSystem(); + const fs = createMockFileSystem(); host = new EsmDependencyHost(fs, new ModuleResolver(fs)); }); describe('getDependencies()', () => { - beforeEach(createMockFileSystem); - afterEach(restoreRealFileSystem); - it('should not generate a TS AST if the source does not contain any imports or re-exports', () => { spyOn(ts, 'createSourceFile'); @@ -98,7 +94,7 @@ describe('DependencyHost', () => { }); it('should support `paths` alias mappings when resolving modules', () => { - const fs = new NodeJSFileSystem(); + const fs = createMockFileSystem(); host = new EsmDependencyHost(fs, new ModuleResolver(fs, { baseUrl: '/dist', paths: { @@ -115,68 +111,65 @@ describe('DependencyHost', () => { expect(missing.size).toBe(0); expect(deepImports.size).toBe(0); }); - - function createMockFileSystem() { - mockFs({ - '/no/imports/or/re-exports/index.js': '// some text but no import-like statements', - '/no/imports/or/re-exports/package.json': '{"esm2015": "./index.js"}', - '/no/imports/or/re-exports/index.metadata.json': 'MOCK METADATA', - '/external/imports/index.js': `import {X} from 'lib-1';\nimport {Y} from 'lib-1/sub-1';`, - '/external/imports/package.json': '{"esm2015": "./index.js"}', - '/external/imports/index.metadata.json': 'MOCK METADATA', - '/external/re-exports/index.js': `export {X} from 'lib-1';\nexport {Y} from 'lib-1/sub-1';`, - '/external/re-exports/package.json': '{"esm2015": "./index.js"}', - '/external/re-exports/index.metadata.json': 'MOCK METADATA', - '/external/imports-missing/index.js': - `import {X} from 'lib-1';\nimport {Y} from 'missing';`, - '/external/imports-missing/package.json': '{"esm2015": "./index.js"}', - '/external/imports-missing/index.metadata.json': 'MOCK METADATA', - '/external/deep-import/index.js': `import {Y} from 'lib-1/deep/import';`, - '/external/deep-import/package.json': '{"esm2015": "./index.js"}', - '/external/deep-import/index.metadata.json': 'MOCK METADATA', - '/internal/outer/index.js': `import {X} from '../inner';`, - '/internal/outer/package.json': '{"esm2015": "./index.js"}', - '/internal/outer/index.metadata.json': 'MOCK METADATA', - '/internal/inner/index.js': `import {Y} from 'lib-1/sub-1'; export declare class X {}`, - '/internal/circular-a/index.js': - `import {B} from '../circular-b'; import {X} from '../circular-b'; export {Y} from 'lib-1/sub-1';`, - '/internal/circular-b/index.js': - `import {A} from '../circular-a'; import {Y} from '../circular-a'; export {X} from 'lib-1';`, - '/internal/circular-a/package.json': '{"esm2015": "./index.js"}', - '/internal/circular-a/index.metadata.json': 'MOCK METADATA', - '/re-directed/index.js': `import {Z} from 'lib-1/sub-2';`, - '/re-directed/package.json': '{"esm2015": "./index.js"}', - '/re-directed/index.metadata.json': 'MOCK METADATA', - '/path-alias/index.js': - `import {TestHelper} from '@app/components';\nimport {Service} from '@app/shared';\nimport {TestHelper} from '@lib/shared/test';\nimport {X} from 'lib-1';`, - '/path-alias/package.json': '{"esm2015": "./index.js"}', - '/path-alias/index.metadata.json': 'MOCK METADATA', - '/node_modules/lib-1/index.js': 'export declare class X {}', - '/node_modules/lib-1/package.json': '{"esm2015": "./index.js"}', - '/node_modules/lib-1/index.metadata.json': 'MOCK METADATA', - '/node_modules/lib-1/deep/import/index.js': 'export declare class DeepImport {}', - '/node_modules/lib-1/sub-1/index.js': 'export declare class Y {}', - '/node_modules/lib-1/sub-1/package.json': '{"esm2015": "./index.js"}', - '/node_modules/lib-1/sub-1/index.metadata.json': 'MOCK METADATA', - '/node_modules/lib-1/sub-2.js': `export * from './sub-2/sub-2';`, - '/node_modules/lib-1/sub-2/sub-2.js': `export declare class Z {}';`, - '/node_modules/lib-1/sub-2/package.json': '{"esm2015": "./sub-2.js"}', - '/node_modules/lib-1/sub-2/sub-2.metadata.json': 'MOCK METADATA', - '/dist/components/index.js': `class MyComponent {};`, - '/dist/components/package.json': '{"esm2015": "./index.js"}', - '/dist/components/index.metadata.json': 'MOCK METADATA', - '/dist/shared/index.js': `import {X} from 'lib-1';\nexport class Service {}`, - '/dist/shared/package.json': '{"esm2015": "./index.js"}', - '/dist/shared/index.metadata.json': 'MOCK METADATA', - '/dist/lib/shared/test/index.js': `export class TestHelper {}`, - '/dist/lib/shared/test/package.json': '{"esm2015": "./index.js"}', - '/dist/lib/shared/test/index.metadata.json': 'MOCK METADATA', - }); - } - - function restoreRealFileSystem() { mockFs.restore(); } }); + function createMockFileSystem() { + return new MockFileSystem({ + '/no/imports/or/re-exports/index.js': '// some text but no import-like statements', + '/no/imports/or/re-exports/package.json': '{"esm2015": "./index.js"}', + '/no/imports/or/re-exports/index.metadata.json': 'MOCK METADATA', + '/external/imports/index.js': `import {X} from 'lib-1';\nimport {Y} from 'lib-1/sub-1';`, + '/external/imports/package.json': '{"esm2015": "./index.js"}', + '/external/imports/index.metadata.json': 'MOCK METADATA', + '/external/re-exports/index.js': `export {X} from 'lib-1';\nexport {Y} from 'lib-1/sub-1';`, + '/external/re-exports/package.json': '{"esm2015": "./index.js"}', + '/external/re-exports/index.metadata.json': 'MOCK METADATA', + '/external/imports-missing/index.js': `import {X} from 'lib-1';\nimport {Y} from 'missing';`, + '/external/imports-missing/package.json': '{"esm2015": "./index.js"}', + '/external/imports-missing/index.metadata.json': 'MOCK METADATA', + '/external/deep-import/index.js': `import {Y} from 'lib-1/deep/import';`, + '/external/deep-import/package.json': '{"esm2015": "./index.js"}', + '/external/deep-import/index.metadata.json': 'MOCK METADATA', + '/internal/outer/index.js': `import {X} from '../inner';`, + '/internal/outer/package.json': '{"esm2015": "./index.js"}', + '/internal/outer/index.metadata.json': 'MOCK METADATA', + '/internal/inner/index.js': `import {Y} from 'lib-1/sub-1'; export declare class X {}`, + '/internal/circular-a/index.js': + `import {B} from '../circular-b'; import {X} from '../circular-b'; export {Y} from 'lib-1/sub-1';`, + '/internal/circular-b/index.js': + `import {A} from '../circular-a'; import {Y} from '../circular-a'; export {X} from 'lib-1';`, + '/internal/circular-a/package.json': '{"esm2015": "./index.js"}', + '/internal/circular-a/index.metadata.json': 'MOCK METADATA', + '/re-directed/index.js': `import {Z} from 'lib-1/sub-2';`, + '/re-directed/package.json': '{"esm2015": "./index.js"}', + '/re-directed/index.metadata.json': 'MOCK METADATA', + '/path-alias/index.js': + `import {TestHelper} from '@app/components';\nimport {Service} from '@app/shared';\nimport {TestHelper} from '@lib/shared/test';\nimport {X} from 'lib-1';`, + '/path-alias/package.json': '{"esm2015": "./index.js"}', + '/path-alias/index.metadata.json': 'MOCK METADATA', + '/node_modules/lib-1/index.js': 'export declare class X {}', + '/node_modules/lib-1/package.json': '{"esm2015": "./index.js"}', + '/node_modules/lib-1/index.metadata.json': 'MOCK METADATA', + '/node_modules/lib-1/deep/import/index.js': 'export declare class DeepImport {}', + '/node_modules/lib-1/sub-1/index.js': 'export declare class Y {}', + '/node_modules/lib-1/sub-1/package.json': '{"esm2015": "./index.js"}', + '/node_modules/lib-1/sub-1/index.metadata.json': 'MOCK METADATA', + '/node_modules/lib-1/sub-2.js': `export * from './sub-2/sub-2';`, + '/node_modules/lib-1/sub-2/sub-2.js': `export declare class Z {}';`, + '/node_modules/lib-1/sub-2/package.json': '{"esm2015": "./sub-2.js"}', + '/node_modules/lib-1/sub-2/sub-2.metadata.json': 'MOCK METADATA', + '/dist/components/index.js': `class MyComponent {};`, + '/dist/components/package.json': '{"esm2015": "./index.js"}', + '/dist/components/index.metadata.json': 'MOCK METADATA', + '/dist/shared/index.js': `import {X} from 'lib-1';\nexport class Service {}`, + '/dist/shared/package.json': '{"esm2015": "./index.js"}', + '/dist/shared/index.metadata.json': 'MOCK METADATA', + '/dist/lib/shared/test/index.js': `export class TestHelper {}`, + '/dist/lib/shared/test/package.json': '{"esm2015": "./index.js"}', + '/dist/lib/shared/test/index.metadata.json': 'MOCK METADATA', + }); + } + describe('isStringImportOrReexport', () => { it('should return true if the statement is an import', () => { expect(host.isStringImportOrReexport(createStatement('import {X} from "some/x";'))) diff --git a/packages/compiler-cli/ngcc/test/dependencies/module_resolver_spec.ts b/packages/compiler-cli/ngcc/test/dependencies/module_resolver_spec.ts index b6c96c824d..245a191f0a 100644 --- a/packages/compiler-cli/ngcc/test/dependencies/module_resolver_spec.ts +++ b/packages/compiler-cli/ngcc/test/dependencies/module_resolver_spec.ts @@ -5,17 +5,14 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ - -import * as mockFs from 'mock-fs'; - import {AbsoluteFsPath} from '../../../src/ngtsc/path'; import {ModuleResolver, ResolvedDeepImport, ResolvedExternalModule, ResolvedRelativeModule} from '../../src/dependencies/module_resolver'; -import {NodeJSFileSystem} from '../../src/file_system/node_js_file_system'; +import {MockFileSystem} from '../helpers/mock_file_system'; const _ = AbsoluteFsPath.from; function createMockFileSystem() { - mockFs({ + return new MockFileSystem({ '/libs': { 'local-package': { 'package.json': 'PACKAGE.JSON for local-package', @@ -68,19 +65,12 @@ function createMockFileSystem() { }); } -function restoreRealFileSystem() { - mockFs.restore(); -} describe('ModuleResolver', () => { - beforeEach(createMockFileSystem); - afterEach(restoreRealFileSystem); - describe('resolveModule()', () => { describe('with relative paths', () => { it('should resolve sibling, child and aunt modules', () => { - const fs = new NodeJSFileSystem(); - const resolver = new ModuleResolver(fs); + const resolver = new ModuleResolver(createMockFileSystem()); expect(resolver.resolveModuleImport('./x', _('/libs/local-package/index.js'))) .toEqual(new ResolvedRelativeModule(_('/libs/local-package/x.js'))); expect(resolver.resolveModuleImport('./sub-folder', _('/libs/local-package/index.js'))) @@ -90,16 +80,14 @@ describe('ModuleResolver', () => { }); it('should return `null` if the resolved module relative module does not exist', () => { - const fs = new NodeJSFileSystem(); - const resolver = new ModuleResolver(fs); + const resolver = new ModuleResolver(createMockFileSystem()); expect(resolver.resolveModuleImport('./y', _('/libs/local-package/index.js'))).toBe(null); }); }); describe('with non-mapped external paths', () => { it('should resolve to the package.json of a local node_modules package', () => { - const fs = new NodeJSFileSystem(); - const resolver = new ModuleResolver(fs); + const resolver = new ModuleResolver(createMockFileSystem()); expect(resolver.resolveModuleImport('package-1', _('/libs/local-package/index.js'))) .toEqual(new ResolvedExternalModule(_('/libs/local-package/node_modules/package-1'))); expect( @@ -110,8 +98,7 @@ describe('ModuleResolver', () => { }); it('should resolve to the package.json of a higher node_modules package', () => { - const fs = new NodeJSFileSystem(); - const resolver = new ModuleResolver(fs); + const resolver = new ModuleResolver(createMockFileSystem()); expect(resolver.resolveModuleImport('package-2', _('/libs/local-package/index.js'))) .toEqual(new ResolvedExternalModule(_('/libs/node_modules/package-2'))); expect(resolver.resolveModuleImport('top-package', _('/libs/local-package/index.js'))) @@ -119,23 +106,20 @@ describe('ModuleResolver', () => { }); it('should return `null` if the package cannot be found', () => { - const fs = new NodeJSFileSystem(); - const resolver = new ModuleResolver(fs); + const resolver = new ModuleResolver(createMockFileSystem()); expect(resolver.resolveModuleImport('missing-2', _('/libs/local-package/index.js'))) .toBe(null); }); it('should return `null` if the package is not accessible because it is in a inner node_modules package', () => { - const fs = new NodeJSFileSystem(); - const resolver = new ModuleResolver(fs); + const resolver = new ModuleResolver(createMockFileSystem()); expect(resolver.resolveModuleImport('package-3', _('/libs/local-package/index.js'))) .toBe(null); }); it('should identify deep imports into an external module', () => { - const fs = new NodeJSFileSystem(); - const resolver = new ModuleResolver(fs); + const resolver = new ModuleResolver(createMockFileSystem()); expect( resolver.resolveModuleImport('package-1/sub-folder', _('/libs/local-package/index.js'))) .toEqual( @@ -145,9 +129,8 @@ describe('ModuleResolver', () => { describe('with mapped path external modules', () => { it('should resolve to the package.json of simple mapped packages', () => { - const fs = new NodeJSFileSystem(); - const resolver = - new ModuleResolver(fs, {baseUrl: '/dist', paths: {'*': ['*', 'sub-folder/*']}}); + const resolver = new ModuleResolver( + createMockFileSystem(), {baseUrl: '/dist', paths: {'*': ['*', 'sub-folder/*']}}); expect(resolver.resolveModuleImport('package-4', _('/libs/local-package/index.js'))) .toEqual(new ResolvedExternalModule(_('/dist/package-4'))); @@ -157,8 +140,7 @@ describe('ModuleResolver', () => { }); it('should select the best match by the length of prefix before the *', () => { - const fs = new NodeJSFileSystem(); - const resolver = new ModuleResolver(fs, { + const resolver = new ModuleResolver(createMockFileSystem(), { baseUrl: '/dist', paths: { '@lib/*': ['*'], @@ -176,7 +158,7 @@ describe('ModuleResolver', () => { it('should follow the ordering of `paths` when matching mapped packages', () => { let resolver: ModuleResolver; - const fs = new NodeJSFileSystem(); + const fs = createMockFileSystem(); resolver = new ModuleResolver(fs, {baseUrl: '/dist', paths: {'*': ['*', 'sub-folder/*']}}); expect(resolver.resolveModuleImport('package-4', _('/libs/local-package/index.js'))) .toEqual(new ResolvedExternalModule(_('/dist/package-4'))); @@ -187,17 +169,15 @@ describe('ModuleResolver', () => { }); it('should resolve packages when the path mappings have post-fixes', () => { - const fs = new NodeJSFileSystem(); - const resolver = - new ModuleResolver(fs, {baseUrl: '/dist', paths: {'*': ['sub-folder/*/post-fix']}}); + const resolver = new ModuleResolver( + createMockFileSystem(), {baseUrl: '/dist', paths: {'*': ['sub-folder/*/post-fix']}}); expect(resolver.resolveModuleImport('package-5', _('/libs/local-package/index.js'))) .toEqual(new ResolvedExternalModule(_('/dist/sub-folder/package-5/post-fix'))); }); it('should match paths against complex path matchers', () => { - const fs = new NodeJSFileSystem(); - const resolver = - new ModuleResolver(fs, {baseUrl: '/dist', paths: {'@shared/*': ['sub-folder/*']}}); + const resolver = new ModuleResolver( + createMockFileSystem(), {baseUrl: '/dist', paths: {'@shared/*': ['sub-folder/*']}}); expect(resolver.resolveModuleImport('@shared/package-4', _('/libs/local-package/index.js'))) .toEqual(new ResolvedExternalModule(_('/dist/sub-folder/package-4'))); expect(resolver.resolveModuleImport('package-5', _('/libs/local-package/index.js'))) @@ -206,17 +186,17 @@ describe('ModuleResolver', () => { it('should resolve path as "relative" if the mapped path is inside the current package', () => { - const fs = new NodeJSFileSystem(); - const resolver = new ModuleResolver(fs, {baseUrl: '/dist', paths: {'@shared/*': ['*']}}); + const resolver = new ModuleResolver( + createMockFileSystem(), {baseUrl: '/dist', paths: {'@shared/*': ['*']}}); expect(resolver.resolveModuleImport( '@shared/package-4/x', _('/dist/package-4/sub-folder/index.js'))) .toEqual(new ResolvedRelativeModule(_('/dist/package-4/x.js'))); }); it('should resolve paths where the wildcard matches more than one path segment', () => { - const fs = new NodeJSFileSystem(); const resolver = new ModuleResolver( - fs, {baseUrl: '/dist', paths: {'@shared/*/post-fix': ['*/post-fix']}}); + createMockFileSystem(), + {baseUrl: '/dist', paths: {'@shared/*/post-fix': ['*/post-fix']}}); expect( resolver.resolveModuleImport( '@shared/sub-folder/package-5/post-fix', _('/dist/package-4/sub-folder/index.js'))) diff --git a/packages/compiler-cli/ngcc/test/helpers/mock_file_system.ts b/packages/compiler-cli/ngcc/test/helpers/mock_file_system.ts new file mode 100644 index 0000000000..c47e2f359e --- /dev/null +++ b/packages/compiler-cli/ngcc/test/helpers/mock_file_system.ts @@ -0,0 +1,173 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import {AbsoluteFsPath, PathSegment} from '../../../src/ngtsc/path'; +import {FileStats, FileSystem} from '../../src/file_system/file_system'; + +/** + * An in-memory file system that can be used in unit tests. + */ +export class MockFileSystem implements FileSystem { + files: Folder = {}; + constructor(...folders: Folder[]) { + folders.forEach(files => this.processFiles(this.files, files)); + } + + exists(path: AbsoluteFsPath): boolean { return this.findFromPath(path) !== null; } + + readFile(path: AbsoluteFsPath): string { + const file = this.findFromPath(path); + if (isFile(file)) { + return file; + } else { + throw new MockFileSystemError('ENOENT', path, `File "${path}" does not exist.`); + } + } + + writeFile(path: AbsoluteFsPath, data: string): void { + const [folderPath, basename] = this.splitIntoFolderAndFile(path); + const folder = this.findFromPath(folderPath); + if (!isFolder(folder)) { + throw new MockFileSystemError( + 'ENOENT', path, `Unable to write file "${path}". The containing folder does not exist.`); + } + folder[basename] = data; + } + + readdir(path: AbsoluteFsPath): PathSegment[] { + const folder = this.findFromPath(path); + if (folder === null) { + throw new MockFileSystemError( + 'ENOENT', path, `Unable to read directory "${path}". It does not exist.`); + } + if (isFile(folder)) { + throw new MockFileSystemError( + 'ENOTDIR', path, `Unable to read directory "${path}". It is a file.`); + } + return Object.keys(folder) as PathSegment[]; + } + + lstat(path: AbsoluteFsPath): FileStats { + const fileOrFolder = this.findFromPath(path); + if (fileOrFolder === null) { + throw new MockFileSystemError('ENOENT', path, `File "${path}" does not exist.`); + } + return new MockFileStats(fileOrFolder); + } + + stat(path: AbsoluteFsPath): FileStats { + const fileOrFolder = this.findFromPath(path, {followSymLinks: true}); + if (fileOrFolder === null) { + throw new MockFileSystemError('ENOENT', path, `File "${path}" does not exist.`); + } + return new MockFileStats(fileOrFolder); + } + + pwd(): AbsoluteFsPath { return AbsoluteFsPath.fromUnchecked('/'); } + + copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { + this.writeFile(to, this.readFile(from)); + } + + moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { + this.writeFile(to, this.readFile(from)); + const folder = this.findFromPath(AbsoluteFsPath.dirname(from)) as Folder; + const basename = PathSegment.basename(from); + delete folder[basename]; + } + + ensureDir(path: AbsoluteFsPath): void { this.ensureFolders(this.files, path.split('/')); } + + private processFiles(current: Folder, files: Folder): void { + Object.keys(files).forEach(path => { + const segments = path.split('/'); + const lastSegment = segments.pop() !; + const containingFolder = this.ensureFolders(current, segments); + const entity = files[path]; + if (isFolder(entity)) { + const processedFolder = containingFolder[lastSegment] = {} as Folder; + this.processFiles(processedFolder, entity); + } else { + containingFolder[lastSegment] = entity; + } + }); + } + + private ensureFolders(current: Folder, segments: string[]): Folder { + for (const segment of segments) { + if (isFile(current[segment])) { + throw new Error(`Folder already exists as a file.`); + } + if (!current[segment]) { + current[segment] = {}; + } + current = current[segment] as Folder; + } + return current; + } + + private findFromPath(path: AbsoluteFsPath, options?: {followSymLinks: boolean}): Entity|null { + const followSymLinks = !!options && options.followSymLinks; + const segments = path.split('/'); + let current = this.files; + while (segments.length) { + const next: Entity = current[segments.shift() !]; + if (next === undefined) { + return null; + } + if (segments.length > 0 && (!isFolder(next))) { + return null; + } + if (isFile(next)) { + return next; + } + if (isSymLink(next)) { + return followSymLinks ? + this.findFromPath(AbsoluteFsPath.resolve(next.path, ...segments), {followSymLinks}) : + next; + } + current = next; + } + return current || null; + } + + private splitIntoFolderAndFile(path: AbsoluteFsPath): [AbsoluteFsPath, string] { + const segments = path.split('/'); + const file = segments.pop() !; + return [AbsoluteFsPath.fromUnchecked(segments.join('/')), file]; + } +} + +export type Entity = Folder | File | SymLink; +export interface Folder { [pathSegments: string]: Entity; } +export type File = string; +export class SymLink { + constructor(public path: AbsoluteFsPath) {} +} + +class MockFileStats implements FileStats { + constructor(private entity: Entity) {} + isFile(): boolean { return isFile(this.entity); } + isDirectory(): boolean { return isFolder(this.entity); } + isSymbolicLink(): boolean { return isSymLink(this.entity); } +} + +class MockFileSystemError extends Error { + constructor(public code: string, public path: string, message: string) { super(message); } +} + +function isFile(item: Entity | null): item is File { + return typeof item === 'string'; +} + +function isSymLink(item: Entity | null): item is SymLink { + return item instanceof SymLink; +} + +function isFolder(item: Entity | null): item is Folder { + return item !== null && !isFile(item) && !isSymLink(item); +} diff --git a/packages/compiler-cli/ngcc/test/helpers/utils.ts b/packages/compiler-cli/ngcc/test/helpers/utils.ts index 0cd665c246..f4eae77e54 100644 --- a/packages/compiler-cli/ngcc/test/helpers/utils.ts +++ b/packages/compiler-cli/ngcc/test/helpers/utils.ts @@ -12,6 +12,7 @@ import {makeProgram} from '../../../src/ngtsc/testing/in_memory_typescript'; import {BundleProgram} from '../../src/packages/bundle_program'; import {EntryPointFormat, EntryPointJsonProperty} from '../../src/packages/entry_point'; import {EntryPointBundle} from '../../src/packages/entry_point_bundle'; +import {Folder} from './mock_file_system'; export {getDeclaration} from '../../../src/ngtsc/testing/in_memory_typescript'; @@ -121,3 +122,11 @@ export function convertToDirectTsLibImport(filesystem: {name: string, contents: return {...file, contents}; }); } + +export function createFileSystemFromProgramFiles( + ...fileCollections: ({name: string, contents: string}[] | undefined)[]): Folder { + const folder: Folder = {}; + fileCollections.forEach( + files => files && files.forEach(file => folder[file.name] = file.contents)); + return folder; +} diff --git a/packages/compiler-cli/ngcc/test/packages/build_marker_spec.ts b/packages/compiler-cli/ngcc/test/packages/build_marker_spec.ts index da3b3d124f..8e12ce8d37 100644 --- a/packages/compiler-cli/ngcc/test/packages/build_marker_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/build_marker_spec.ts @@ -5,16 +5,12 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ - -import {readFileSync} from 'fs'; -import * as mockFs from 'mock-fs'; - import {AbsoluteFsPath} from '../../../src/ngtsc/path'; -import {NodeJSFileSystem} from '../../src/file_system/node_js_file_system'; import {hasBeenProcessed, markAsProcessed} from '../../src/packages/build_marker'; +import {MockFileSystem} from '../helpers/mock_file_system'; function createMockFileSystem() { - mockFs({ + return new MockFileSystem({ '/node_modules/@angular/common': { 'package.json': `{ "fesm2015": "./fesm2015/common.js", @@ -90,38 +86,31 @@ function createMockFileSystem() { }); } -function restoreRealFileSystem() { - mockFs.restore(); -} - describe('Marker files', () => { - beforeEach(createMockFileSystem); - afterEach(restoreRealFileSystem); - const COMMON_PACKAGE_PATH = AbsoluteFsPath.from('/node_modules/@angular/common/package.json'); describe('markAsProcessed', () => { it('should write a property in the package.json containing the version placeholder', () => { - let pkg = JSON.parse(readFileSync(COMMON_PACKAGE_PATH, 'utf8')); - expect(pkg.__processed_by_ivy_ngcc__).toBeUndefined(); - expect(pkg.__processed_by_ivy_ngcc__).toBeUndefined(); + const fs = createMockFileSystem(); - const fs = new NodeJSFileSystem(); + let pkg = JSON.parse(fs.readFile(COMMON_PACKAGE_PATH)); + expect(pkg.__processed_by_ivy_ngcc__).toBeUndefined(); + expect(pkg.__processed_by_ivy_ngcc__).toBeUndefined(); markAsProcessed(fs, pkg, COMMON_PACKAGE_PATH, 'fesm2015'); - pkg = JSON.parse(readFileSync(COMMON_PACKAGE_PATH, 'utf8')); + pkg = JSON.parse(fs.readFile(COMMON_PACKAGE_PATH)); expect(pkg.__processed_by_ivy_ngcc__.fesm2015).toEqual('0.0.0-PLACEHOLDER'); expect(pkg.__processed_by_ivy_ngcc__.esm5).toBeUndefined(); markAsProcessed(fs, pkg, COMMON_PACKAGE_PATH, 'esm5'); - pkg = JSON.parse(readFileSync(COMMON_PACKAGE_PATH, 'utf8')); + pkg = JSON.parse(fs.readFile(COMMON_PACKAGE_PATH)); expect(pkg.__processed_by_ivy_ngcc__.fesm2015).toEqual('0.0.0-PLACEHOLDER'); expect(pkg.__processed_by_ivy_ngcc__.esm5).toEqual('0.0.0-PLACEHOLDER'); }); it('should update the packageJson object in-place', () => { - const fs = new NodeJSFileSystem(); - let pkg = JSON.parse(readFileSync(COMMON_PACKAGE_PATH, 'utf8')); + const fs = createMockFileSystem(); + let pkg = JSON.parse(fs.readFile(COMMON_PACKAGE_PATH)); expect(pkg.__processed_by_ivy_ngcc__).toBeUndefined(); markAsProcessed(fs, pkg, COMMON_PACKAGE_PATH, 'fesm2015'); expect(pkg.__processed_by_ivy_ngcc__.fesm2015).toEqual('0.0.0-PLACEHOLDER'); diff --git a/packages/compiler-cli/ngcc/test/packages/entry_point_finder_spec.ts b/packages/compiler-cli/ngcc/test/packages/entry_point_finder_spec.ts index c2630db9af..e93af39185 100644 --- a/packages/compiler-cli/ngcc/test/packages/entry_point_finder_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/entry_point_finder_spec.ts @@ -6,15 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import * as mockFs from 'mock-fs'; - import {AbsoluteFsPath} from '../../../src/ngtsc/path'; import {DependencyResolver} from '../../src/dependencies/dependency_resolver'; import {EsmDependencyHost} from '../../src/dependencies/esm_dependency_host'; import {ModuleResolver} from '../../src/dependencies/module_resolver'; -import {NodeJSFileSystem} from '../../src/file_system/node_js_file_system'; import {EntryPoint} from '../../src/packages/entry_point'; import {EntryPointFinder} from '../../src/packages/entry_point_finder'; +import {MockFileSystem, SymLink} from '../helpers/mock_file_system'; import {MockLogger} from '../helpers/mock_logger'; const _ = AbsoluteFsPath.from; @@ -23,7 +21,7 @@ describe('findEntryPoints()', () => { let resolver: DependencyResolver; let finder: EntryPointFinder; beforeEach(() => { - const fs = new NodeJSFileSystem(); + const fs = createMockFileSystem(); resolver = new DependencyResolver(new MockLogger(), new EsmDependencyHost(fs, new ModuleResolver(fs))); spyOn(resolver, 'sortEntryPointsByDependency').and.callFake((entryPoints: EntryPoint[]) => { @@ -31,8 +29,6 @@ describe('findEntryPoints()', () => { }); finder = new EntryPointFinder(fs, new MockLogger(), resolver); }); - beforeEach(createMockFileSystem); - afterEach(restoreRealFileSystem); it('should find sub-entry-points within a package', () => { const {entryPoints} = finder.findEntryPoints(_('/sub_entry_points')); @@ -90,7 +86,7 @@ describe('findEntryPoints()', () => { }); function createMockFileSystem() { - mockFs({ + return new MockFileSystem({ '/sub_entry_points': { 'common': { 'package.json': createPackageJson('common'), @@ -142,7 +138,7 @@ describe('findEntryPoints()', () => { }, }, '/symlinked_folders': { - 'common': mockFs.symlink({path: '/sub_entry_points/common'}), + 'common': new SymLink(_('/sub_entry_points/common')), }, '/nested_node_modules': { 'outer': { @@ -158,7 +154,6 @@ describe('findEntryPoints()', () => { }, }); } - function restoreRealFileSystem() { mockFs.restore(); } }); function createPackageJson(packageName: string): string { diff --git a/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts b/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts index 7505027557..375fa013ac 100644 --- a/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts @@ -6,25 +6,20 @@ * found in the LICENSE file at https://angular.io/license */ -import {readFileSync} from 'fs'; -import * as mockFs from 'mock-fs'; - import {AbsoluteFsPath} from '../../../src/ngtsc/path'; -import {NodeJSFileSystem} from '../../src/file_system/node_js_file_system'; +import {FileSystem} from '../../src/file_system/file_system'; import {getEntryPointInfo} from '../../src/packages/entry_point'; +import {MockFileSystem} from '../helpers/mock_file_system'; import {MockLogger} from '../helpers/mock_logger'; const _ = AbsoluteFsPath.fromUnchecked; describe('getEntryPointInfo()', () => { - beforeEach(createMockFileSystem); - afterEach(restoreRealFileSystem); - const SOME_PACKAGE = _('/some_package'); it('should return an object containing absolute paths to the formats of the specified entry-point', () => { - const fs = new NodeJSFileSystem(); + const fs = createMockFileSystem(); const entryPoint = getEntryPointInfo( fs, new MockLogger(), SOME_PACKAGE, _('/some_package/valid_entry_point')); expect(entryPoint).toEqual({ @@ -32,20 +27,20 @@ describe('getEntryPointInfo()', () => { package: SOME_PACKAGE, path: _('/some_package/valid_entry_point'), typings: _(`/some_package/valid_entry_point/valid_entry_point.d.ts`), - packageJson: loadPackageJson('/some_package/valid_entry_point'), + packageJson: loadPackageJson(fs, '/some_package/valid_entry_point'), compiledByAngular: true, }); }); it('should return null if there is no package.json at the entry-point path', () => { - const fs = new NodeJSFileSystem(); + const fs = createMockFileSystem(); const entryPoint = getEntryPointInfo( fs, new MockLogger(), SOME_PACKAGE, _('/some_package/missing_package_json')); expect(entryPoint).toBe(null); }); it('should return null if there is no typings or types field in the package.json', () => { - const fs = new NodeJSFileSystem(); + const fs = createMockFileSystem(); const entryPoint = getEntryPointInfo(fs, new MockLogger(), SOME_PACKAGE, _('/some_package/missing_typings')); expect(entryPoint).toBe(null); @@ -53,7 +48,7 @@ describe('getEntryPointInfo()', () => { it('should return an object with `compiledByAngular` set to false if there is no metadata.json file next to the typing file', () => { - const fs = new NodeJSFileSystem(); + const fs = createMockFileSystem(); const entryPoint = getEntryPointInfo( fs, new MockLogger(), SOME_PACKAGE, _('/some_package/missing_metadata')); expect(entryPoint).toEqual({ @@ -61,13 +56,13 @@ describe('getEntryPointInfo()', () => { package: SOME_PACKAGE, path: _('/some_package/missing_metadata'), typings: _(`/some_package/missing_metadata/missing_metadata.d.ts`), - packageJson: loadPackageJson('/some_package/missing_metadata'), + packageJson: loadPackageJson(fs, '/some_package/missing_metadata'), compiledByAngular: false, }); }); it('should work if the typings field is named `types', () => { - const fs = new NodeJSFileSystem(); + const fs = createMockFileSystem(); const entryPoint = getEntryPointInfo( fs, new MockLogger(), SOME_PACKAGE, _('/some_package/types_rather_than_typings')); expect(entryPoint).toEqual({ @@ -75,13 +70,13 @@ describe('getEntryPointInfo()', () => { package: SOME_PACKAGE, path: _('/some_package/types_rather_than_typings'), typings: _(`/some_package/types_rather_than_typings/types_rather_than_typings.d.ts`), - packageJson: loadPackageJson('/some_package/types_rather_than_typings'), + packageJson: loadPackageJson(fs, '/some_package/types_rather_than_typings'), compiledByAngular: true, }); }); it('should work with Angular Material style package.json', () => { - const fs = new NodeJSFileSystem(); + const fs = createMockFileSystem(); const entryPoint = getEntryPointInfo(fs, new MockLogger(), SOME_PACKAGE, _('/some_package/material_style')); expect(entryPoint).toEqual({ @@ -89,13 +84,13 @@ describe('getEntryPointInfo()', () => { package: SOME_PACKAGE, path: _('/some_package/material_style'), typings: _(`/some_package/material_style/material_style.d.ts`), - packageJson: JSON.parse(readFileSync('/some_package/material_style/package.json', 'utf8')), + packageJson: loadPackageJson(fs, '/some_package/material_style'), compiledByAngular: true, }); }); it('should return null if the package.json is not valid JSON', () => { - const fs = new NodeJSFileSystem(); + const fs = createMockFileSystem(); const entryPoint = getEntryPointInfo( fs, new MockLogger(), SOME_PACKAGE, _('/some_package/unexpected_symbols')); expect(entryPoint).toBe(null); @@ -103,7 +98,7 @@ describe('getEntryPointInfo()', () => { }); function createMockFileSystem() { - mockFs({ + return new MockFileSystem({ '/some_package': { 'valid_entry_point': { 'package.json': createPackageJson('valid_entry_point'), @@ -150,10 +145,6 @@ function createMockFileSystem() { }); } -function restoreRealFileSystem() { - mockFs.restore(); -} - function createPackageJson( packageName: string, {excludes}: {excludes?: string[]} = {}, typingsProp: string = 'typings'): string { @@ -172,6 +163,6 @@ function createPackageJson( return JSON.stringify(packageJson); } -export function loadPackageJson(packagePath: string) { - return JSON.parse(readFileSync(packagePath + '/package.json', 'utf8')); +export function loadPackageJson(fs: FileSystem, packagePath: string) { + return JSON.parse(fs.readFile(_(packagePath + '/package.json'))); } diff --git a/packages/compiler-cli/ngcc/test/rendering/esm2015_renderer_spec.ts b/packages/compiler-cli/ngcc/test/rendering/esm2015_renderer_spec.ts index 9b6b808798..34ba2583bf 100644 --- a/packages/compiler-cli/ngcc/test/rendering/esm2015_renderer_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/esm2015_renderer_spec.ts @@ -11,21 +11,21 @@ import {AbsoluteFsPath} from '../../../src/ngtsc/path'; import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; -import {NodeJSFileSystem} from '../../src/file_system/node_js_file_system'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {EsmRenderer} from '../../src/rendering/esm_renderer'; import {makeTestEntryPointBundle} from '../helpers/utils'; +import {MockFileSystem} from '../helpers/mock_file_system'; import {MockLogger} from '../helpers/mock_logger'; const _ = AbsoluteFsPath.fromUnchecked; -function setup(file: {name: string, contents: string}) { +function setup(file: {name: AbsoluteFsPath, contents: string}) { + const fs = new MockFileSystem(); const logger = new MockLogger(); const bundle = makeTestEntryPointBundle('es2015', 'esm2015', false, [file]) !; const typeChecker = bundle.src.program.getTypeChecker(); const host = new Esm2015ReflectionHost(logger, false, typeChecker); const referencesRegistry = new NgccReferencesRegistry(host); - const fs = new NodeJSFileSystem(); const decorationAnalyses = new DecorationAnalyzer( fs, bundle.src.program, bundle.src.options, bundle.src.host, typeChecker, host, referencesRegistry, [_('/')], false) @@ -40,7 +40,7 @@ function setup(file: {name: string, contents: string}) { } const PROGRAM = { - name: '/some/file.js', + name: _('/some/file.js'), contents: ` /* A copyright notice */ import 'some-side-effect'; @@ -76,7 +76,7 @@ function compileNgModuleFactory__POST_R3__(injector, options, moduleType) { }; const PROGRAM_DECORATE_HELPER = { - name: '/some/file.js', + name: _('/some/file.js'), contents: ` import * as tslib_1 from "tslib"; var D_1; @@ -142,7 +142,7 @@ import * as i1 from '@angular/common';`); {from: _('/some/a.js'), dtsFrom: _('/some/a.d.ts'), identifier: 'ComponentA1'}, {from: _('/some/a.js'), dtsFrom: _('/some/a.d.ts'), identifier: 'ComponentA2'}, {from: _('/some/foo/b.js'), dtsFrom: _('/some/foo/b.d.ts'), identifier: 'ComponentB'}, - {from: _(PROGRAM.name), dtsFrom: _(PROGRAM.name), identifier: 'TopLevelComponent'}, + {from: PROGRAM.name, dtsFrom: PROGRAM.name, identifier: 'TopLevelComponent'}, ]); expect(output.toString()).toContain(` // Some other content @@ -159,7 +159,7 @@ export {TopLevelComponent};`); {from: _('/some/a.js'), alias: 'eComponentA1', identifier: 'ComponentA1'}, {from: _('/some/a.js'), alias: 'eComponentA2', identifier: 'ComponentA2'}, {from: _('/some/foo/b.js'), alias: 'eComponentB', identifier: 'ComponentB'}, - {from: _(PROGRAM.name), alias: 'eTopLevelComponent', identifier: 'TopLevelComponent'}, + {from: PROGRAM.name, alias: 'eTopLevelComponent', identifier: 'TopLevelComponent'}, ]); const outputString = output.toString(); expect(outputString).not.toContain(`{eComponentA1 as ComponentA1}`); diff --git a/packages/compiler-cli/ngcc/test/rendering/esm5_renderer_spec.ts b/packages/compiler-cli/ngcc/test/rendering/esm5_renderer_spec.ts index 8cf050426a..83c8b253cf 100644 --- a/packages/compiler-cli/ngcc/test/rendering/esm5_renderer_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/esm5_renderer_spec.ts @@ -11,25 +11,26 @@ import {AbsoluteFsPath} from '../../../src/ngtsc/path'; import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; -import {NodeJSFileSystem} from '../../src/file_system/node_js_file_system'; import {Esm5ReflectionHost} from '../../src/host/esm5_host'; import {Esm5Renderer} from '../../src/rendering/esm5_renderer'; import {makeTestEntryPointBundle, getDeclaration} from '../helpers/utils'; +import {MockFileSystem} from '../helpers/mock_file_system'; import {MockLogger} from '../helpers/mock_logger'; const _ = AbsoluteFsPath.fromUnchecked; -function setup(file: {name: string, contents: string}) { +function setup(file: {name: AbsoluteFsPath, contents: string}) { + const fs = new MockFileSystem(); const logger = new MockLogger(); const bundle = makeTestEntryPointBundle('module', 'esm5', false, [file]); const typeChecker = bundle.src.program.getTypeChecker(); const host = new Esm5ReflectionHost(logger, false, typeChecker); const referencesRegistry = new NgccReferencesRegistry(host); - const fs = new NodeJSFileSystem(); - const decorationAnalyses = new DecorationAnalyzer( - fs, bundle.src.program, bundle.src.options, bundle.src.host, - typeChecker, host, referencesRegistry, [_('/')], false) - .analyzeProgram(); + const decorationAnalyses = + new DecorationAnalyzer( + fs, bundle.src.program, bundle.src.options, bundle.src.host, typeChecker, host, + referencesRegistry, [AbsoluteFsPath.fromUnchecked('/')], false) + .analyzeProgram(); const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(bundle.src.program); const renderer = new Esm5Renderer(fs, logger, host, false, bundle); return { @@ -40,7 +41,7 @@ function setup(file: {name: string, contents: string}) { } const PROGRAM = { - name: '/some/file.js', + name: _('/some/file.js'), contents: ` /* A copyright notice */ import 'some-side-effect'; @@ -100,7 +101,7 @@ export {A, B, C, NoIife, BadIife};` }; const PROGRAM_DECORATE_HELPER = { - name: '/some/file.js', + name: _('/some/file.js'), contents: ` import * as tslib_1 from "tslib"; /* A copyright notice */ @@ -179,7 +180,7 @@ import * as i1 from '@angular/common';`); {from: _('/some/a.js'), dtsFrom: _('/some/a.d.ts'), identifier: 'ComponentA1'}, {from: _('/some/a.js'), dtsFrom: _('/some/a.d.ts'), identifier: 'ComponentA2'}, {from: _('/some/foo/b.js'), dtsFrom: _('/some/foo/b.d.ts'), identifier: 'ComponentB'}, - {from: _(PROGRAM.name), dtsFrom: _(PROGRAM.name), identifier: 'TopLevelComponent'}, + {from: PROGRAM.name, dtsFrom: PROGRAM.name, identifier: 'TopLevelComponent'}, ]); expect(output.toString()).toContain(` export {A, B, C, NoIife, BadIife}; @@ -193,10 +194,10 @@ export {TopLevelComponent};`); const {renderer} = setup(PROGRAM); const output = new MagicString(PROGRAM.contents); renderer.addExports(output, _(PROGRAM.name.replace(/\.js$/, '')), [ - {from: _('/some/a.js'), alias: 'eComponentA1', identifier: 'ComponentA1'}, - {from: _('/some/a.js'), alias: 'eComponentA2', identifier: 'ComponentA2'}, - {from: _('/some/foo/b.js'), alias: 'eComponentB', identifier: 'ComponentB'}, - {from: _(PROGRAM.name), alias: 'eTopLevelComponent', identifier: 'TopLevelComponent'}, + {from: _('/some/a.js'), alias: _('eComponentA1'), identifier: 'ComponentA1'}, + {from: _('/some/a.js'), alias: _('eComponentA2'), identifier: 'ComponentA2'}, + {from: _('/some/foo/b.js'), alias: _('eComponentB'), identifier: 'ComponentB'}, + {from: PROGRAM.name, alias: 'eTopLevelComponent', identifier: 'TopLevelComponent'}, ]); const outputString = output.toString(); expect(outputString).not.toContain(`{eComponentA1 as ComponentA1}`); @@ -285,14 +286,14 @@ SOME DEFINITION TEXT const noIifeDeclaration = getDeclaration(program, sourceFile.fileName, 'NoIife', ts.isFunctionDeclaration); - const mockNoIifeClass: any = {declaration: noIifeDeclaration, name: 'NoIife'}; + const mockNoIifeClass: any = {declaration: noIifeDeclaration, name: _('NoIife')}; expect(() => renderer.addDefinitions(output, mockNoIifeClass, 'SOME DEFINITION TEXT')) .toThrowError( 'Compiled class declaration is not inside an IIFE: NoIife in /some/file.js'); const badIifeDeclaration = getDeclaration(program, sourceFile.fileName, 'BadIife', ts.isVariableDeclaration); - const mockBadIifeClass: any = {declaration: badIifeDeclaration, name: 'BadIife'}; + const mockBadIifeClass: any = {declaration: badIifeDeclaration, name: _('BadIife')}; expect(() => renderer.addDefinitions(output, mockBadIifeClass, 'SOME DEFINITION TEXT')) .toThrowError( 'Compiled class wrapper IIFE does not have a return statement: BadIife in /some/file.js'); diff --git a/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts b/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts index 9738585813..f47ac9b248 100644 --- a/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts @@ -5,7 +5,6 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import * as fs from 'fs'; import MagicString from 'magic-string'; import * as ts from 'typescript'; import {fromObject, generateMapFileComment} from 'convert-source-map'; @@ -18,11 +17,11 @@ import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {RedundantDecoratorMap, Renderer} from '../../src/rendering/renderer'; import {EntryPointBundle} from '../../src/packages/entry_point_bundle'; -import {makeTestEntryPointBundle} from '../helpers/utils'; +import {makeTestEntryPointBundle, createFileSystemFromProgramFiles} from '../helpers/utils'; import {Logger} from '../../src/logging/logger'; +import {MockFileSystem} from '../helpers/mock_file_system'; import {MockLogger} from '../helpers/mock_logger'; import {FileSystem} from '../../src/file_system/file_system'; -import {NodeJSFileSystem} from '../../src/file_system/node_js_file_system'; const _ = AbsoluteFsPath.fromUnchecked; @@ -58,14 +57,15 @@ class TestRenderer extends Renderer { function createTestRenderer( packageName: string, files: {name: string, contents: string}[], - dtsFiles?: {name: string, contents: string}[]) { + dtsFiles?: {name: string, contents: string}[], + mappingFiles?: {name: string, contents: string}[]) { const logger = new MockLogger(); + const fs = new MockFileSystem(createFileSystemFromProgramFiles(files, dtsFiles, mappingFiles)); const isCore = packageName === '@angular/core'; const bundle = makeTestEntryPointBundle('es2015', 'esm2015', isCore, files, dtsFiles); const typeChecker = bundle.src.program.getTypeChecker(); const host = new Esm2015ReflectionHost(logger, isCore, typeChecker, bundle.dts); const referencesRegistry = new NgccReferencesRegistry(host); - const fs = new NodeJSFileSystem(); const decorationAnalyses = new DecorationAnalyzer( fs, bundle.src.program, bundle.src.options, bundle.src.host, typeChecker, host, referencesRegistry, bundle.rootDirs, isCore) @@ -200,8 +200,8 @@ describe('Renderer', () => { const addDefinitionsSpy = renderer.addDefinitions as jasmine.Spy; expect(addDefinitionsSpy.calls.first().args[0].toString()).toEqual(RENDERED_CONTENTS); expect(addDefinitionsSpy.calls.first().args[1]).toEqual(jasmine.objectContaining({ - name: 'A', - decorators: [jasmine.objectContaining({name: 'Directive'})], + name: _('A'), + decorators: [jasmine.objectContaining({name: _('Directive')})] })); expect(addDefinitionsSpy.calls.first().args[2]) .toEqual( @@ -259,15 +259,15 @@ describe('Renderer', () => { it('should merge any external source map from the original file and write the output to an external source map', () => { - // Mock out reading the map file from disk - spyOn(fs, 'readFileSync').and.returnValue(INPUT_PROGRAM_MAP.toJSON()); + const sourceFiles = [{ + ...INPUT_PROGRAM, + contents: INPUT_PROGRAM.contents + '\n//# sourceMappingURL=file.js.map' + }]; + const mappingFiles = + [{name: INPUT_PROGRAM.name + '.map', contents: INPUT_PROGRAM_MAP.toJSON()}]; const {decorationAnalyses, renderer, switchMarkerAnalyses, privateDeclarationsAnalyses, moduleWithProvidersAnalyses} = - createTestRenderer( - 'test-package', [{ - ...INPUT_PROGRAM, - contents: INPUT_PROGRAM.contents + '\n//# sourceMappingURL=file.js.map' - }]); + createTestRenderer('test-package', sourceFiles, undefined, mappingFiles); const result = renderer.renderProgram( decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses, moduleWithProvidersAnalyses); @@ -275,7 +275,7 @@ describe('Renderer', () => { expect(result[0].contents) .toEqual(RENDERED_CONTENTS + '\n' + generateMapFileComment('file.js.map')); expect(result[1].path).toEqual('/src/file.js.map'); - expect(result[1].contents).toEqual(MERGED_OUTPUT_PROGRAM_MAP.toJSON()); + expect(JSON.parse(result[1].contents)).toEqual(MERGED_OUTPUT_PROGRAM_MAP.toObject()); }); }); diff --git a/packages/compiler-cli/ngcc/test/writing/in_place_file_writer_spec.ts b/packages/compiler-cli/ngcc/test/writing/in_place_file_writer_spec.ts index c47474af37..f3c13a01db 100644 --- a/packages/compiler-cli/ngcc/test/writing/in_place_file_writer_spec.ts +++ b/packages/compiler-cli/ngcc/test/writing/in_place_file_writer_spec.ts @@ -5,20 +5,16 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ - -import {existsSync, readFileSync} from 'fs'; -import * as mockFs from 'mock-fs'; - import {AbsoluteFsPath} from '../../../src/ngtsc/path'; -import {NodeJSFileSystem} from '../../src/file_system/node_js_file_system'; import {EntryPoint} from '../../src/packages/entry_point'; import {EntryPointBundle} from '../../src/packages/entry_point_bundle'; import {InPlaceFileWriter} from '../../src/writing/in_place_file_writer'; +import {MockFileSystem} from '../helpers/mock_file_system'; const _ = AbsoluteFsPath.fromUnchecked; function createMockFileSystem() { - mockFs({ + return new MockFileSystem({ '/package/path': { 'top-level.js': 'ORIGINAL TOP LEVEL', 'folder-1': { @@ -34,16 +30,9 @@ function createMockFileSystem() { }); } -function restoreRealFileSystem() { - mockFs.restore(); -} - describe('InPlaceFileWriter', () => { - beforeEach(createMockFileSystem); - afterEach(restoreRealFileSystem); - it('should write all the FileInfo to the disk', () => { - const fs = new NodeJSFileSystem(); + const fs = createMockFileSystem(); const fileWriter = new InPlaceFileWriter(fs); fileWriter.writeBundle({} as EntryPoint, {} as EntryPointBundle, [ {path: _('/package/path/top-level.js'), contents: 'MODIFIED TOP LEVEL'}, @@ -51,16 +40,16 @@ describe('InPlaceFileWriter', () => { {path: _('/package/path/folder-2/file-4.js'), contents: 'MODIFIED FILE 4'}, {path: _('/package/path/folder-3/file-5.js'), contents: 'NEW FILE 5'}, ]); - expect(readFileSync('/package/path/top-level.js', 'utf8')).toEqual('MODIFIED TOP LEVEL'); - expect(readFileSync('/package/path/folder-1/file-1.js', 'utf8')).toEqual('MODIFIED FILE 1'); - expect(readFileSync('/package/path/folder-1/file-2.js', 'utf8')).toEqual('ORIGINAL FILE 2'); - expect(readFileSync('/package/path/folder-2/file-3.js', 'utf8')).toEqual('ORIGINAL FILE 3'); - expect(readFileSync('/package/path/folder-2/file-4.js', 'utf8')).toEqual('MODIFIED FILE 4'); - expect(readFileSync('/package/path/folder-3/file-5.js', 'utf8')).toEqual('NEW FILE 5'); + expect(fs.readFile(_('/package/path/top-level.js'))).toEqual('MODIFIED TOP LEVEL'); + expect(fs.readFile(_('/package/path/folder-1/file-1.js'))).toEqual('MODIFIED FILE 1'); + expect(fs.readFile(_('/package/path/folder-1/file-2.js'))).toEqual('ORIGINAL FILE 2'); + expect(fs.readFile(_('/package/path/folder-2/file-3.js'))).toEqual('ORIGINAL FILE 3'); + expect(fs.readFile(_('/package/path/folder-2/file-4.js'))).toEqual('MODIFIED FILE 4'); + expect(fs.readFile(_('/package/path/folder-3/file-5.js'))).toEqual('NEW FILE 5'); }); it('should create backups of all files that previously existed', () => { - const fs = new NodeJSFileSystem(); + const fs = createMockFileSystem(); const fileWriter = new InPlaceFileWriter(fs); fileWriter.writeBundle({} as EntryPoint, {} as EntryPointBundle, [ {path: _('/package/path/top-level.js'), contents: 'MODIFIED TOP LEVEL'}, @@ -68,19 +57,19 @@ describe('InPlaceFileWriter', () => { {path: _('/package/path/folder-2/file-4.js'), contents: 'MODIFIED FILE 4'}, {path: _('/package/path/folder-3/file-5.js'), contents: 'NEW FILE 5'}, ]); - expect(readFileSync('/package/path/top-level.js.__ivy_ngcc_bak', 'utf8')) + expect(fs.readFile(_('/package/path/top-level.js.__ivy_ngcc_bak'))) .toEqual('ORIGINAL TOP LEVEL'); - expect(readFileSync('/package/path/folder-1/file-1.js.__ivy_ngcc_bak', 'utf8')) + expect(fs.readFile(_('/package/path/folder-1/file-1.js.__ivy_ngcc_bak'))) .toEqual('ORIGINAL FILE 1'); - expect(existsSync('/package/path/folder-1/file-2.js.__ivy_ngcc_bak')).toBe(false); - expect(existsSync('/package/path/folder-2/file-3.js.__ivy_ngcc_bak')).toBe(false); - expect(readFileSync('/package/path/folder-2/file-4.js.__ivy_ngcc_bak', 'utf8')) + expect(fs.exists(_('/package/path/folder-1/file-2.js.__ivy_ngcc_bak'))).toBe(false); + expect(fs.exists(_('/package/path/folder-2/file-3.js.__ivy_ngcc_bak'))).toBe(false); + expect(fs.readFile(_('/package/path/folder-2/file-4.js.__ivy_ngcc_bak'))) .toEqual('ORIGINAL FILE 4'); - expect(existsSync('/package/path/folder-3/file-5.js.__ivy_ngcc_bak')).toBe(false); + expect(fs.exists(_('/package/path/folder-3/file-5.js.__ivy_ngcc_bak'))).toBe(false); }); it('should error if the backup file already exists', () => { - const fs = new NodeJSFileSystem(); + const fs = createMockFileSystem(); const fileWriter = new InPlaceFileWriter(fs); expect( () => fileWriter.writeBundle( diff --git a/packages/compiler-cli/ngcc/test/writing/new_entry_point_file_writer_spec.ts b/packages/compiler-cli/ngcc/test/writing/new_entry_point_file_writer_spec.ts index 5775af81ff..051c85f084 100644 --- a/packages/compiler-cli/ngcc/test/writing/new_entry_point_file_writer_spec.ts +++ b/packages/compiler-cli/ngcc/test/writing/new_entry_point_file_writer_spec.ts @@ -5,24 +5,20 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ - -import {existsSync, readFileSync} from 'fs'; -import * as mockFs from 'mock-fs'; - import {AbsoluteFsPath} from '../../../src/ngtsc/path'; import {FileSystem} from '../../src/file_system/file_system'; -import {NodeJSFileSystem} from '../../src/file_system/node_js_file_system'; import {EntryPoint, EntryPointFormat, EntryPointJsonProperty, getEntryPointInfo} from '../../src/packages/entry_point'; import {EntryPointBundle, makeEntryPointBundle} from '../../src/packages/entry_point_bundle'; import {FileWriter} from '../../src/writing/file_writer'; import {NewEntryPointFileWriter} from '../../src/writing/new_entry_point_file_writer'; +import {MockFileSystem} from '../helpers/mock_file_system'; import {MockLogger} from '../helpers/mock_logger'; import {loadPackageJson} from '../packages/entry_point_spec'; const _ = AbsoluteFsPath.from; function createMockFileSystem() { - mockFs({ + return new MockFileSystem({ '/node_modules/test': { 'package.json': '{"module": "./esm5.js", "es2015": "./es2015/index.js", "typings": "./index.d.ts"}', @@ -75,14 +71,7 @@ function createMockFileSystem() { }); } -function restoreRealFileSystem() { - mockFs.restore(); -} - describe('NewEntryPointFileWriter', () => { - beforeEach(createMockFileSystem); - afterEach(restoreRealFileSystem); - let fs: FileSystem; let fileWriter: FileWriter; let entryPoint: EntryPoint; @@ -91,7 +80,7 @@ describe('NewEntryPointFileWriter', () => { describe('writeBundle() [primary entry-point]', () => { beforeEach(() => { - fs = new NodeJSFileSystem(); + fs = createMockFileSystem(); fileWriter = new NewEntryPointFileWriter(fs); entryPoint = getEntryPointInfo( fs, new MockLogger(), _('/node_modules/test'), _('/node_modules/test')) !; @@ -107,14 +96,12 @@ describe('NewEntryPointFileWriter', () => { }, {path: _('/node_modules/test/esm5.js.map'), contents: 'MODIFIED MAPPING DATA'}, ]); - expect(readFileSync('/node_modules/test/__ivy_ngcc__/esm5.js', 'utf8')) + expect(fs.readFile(_('/node_modules/test/__ivy_ngcc__/esm5.js'))) .toEqual('export function FooTop() {} // MODIFIED'); - expect(readFileSync('/node_modules/test/esm5.js', 'utf8')) - .toEqual('export function FooTop() {}'); - expect(readFileSync('/node_modules/test/__ivy_ngcc__/esm5.js.map', 'utf8')) + expect(fs.readFile(_('/node_modules/test/esm5.js'))).toEqual('export function FooTop() {}'); + expect(fs.readFile(_('/node_modules/test/__ivy_ngcc__/esm5.js.map'))) .toEqual('MODIFIED MAPPING DATA'); - expect(readFileSync('/node_modules/test/esm5.js.map', 'utf8')) - .toEqual('ORIGINAL MAPPING DATA'); + expect(fs.readFile(_('/node_modules/test/esm5.js.map'))).toEqual('ORIGINAL MAPPING DATA'); }); it('should also copy unmodified files in the program', () => { @@ -124,13 +111,12 @@ describe('NewEntryPointFileWriter', () => { contents: 'export class FooTop {} // MODIFIED' }, ]); - expect(readFileSync('/node_modules/test/__ivy_ngcc__/es2015/foo.js', 'utf8')) + expect(fs.readFile(_('/node_modules/test/__ivy_ngcc__/es2015/foo.js'))) .toEqual('export class FooTop {} // MODIFIED'); - expect(readFileSync('/node_modules/test/es2015/foo.js', 'utf8')) - .toEqual('export class FooTop {}'); - expect(readFileSync('/node_modules/test/__ivy_ngcc__/es2015/index.js', 'utf8')) + expect(fs.readFile(_('/node_modules/test/es2015/foo.js'))).toEqual('export class FooTop {}'); + expect(fs.readFile(_('/node_modules/test/__ivy_ngcc__/es2015/index.js'))) .toEqual('export {FooTop} from "./foo";'); - expect(readFileSync('/node_modules/test/es2015/index.js', 'utf8')) + expect(fs.readFile(_('/node_modules/test/es2015/index.js'))) .toEqual('export {FooTop} from "./foo";'); }); @@ -141,7 +127,7 @@ describe('NewEntryPointFileWriter', () => { contents: 'export function FooTop() {} // MODIFIED' }, ]); - expect(loadPackageJson('/node_modules/test')).toEqual(jasmine.objectContaining({ + expect(loadPackageJson(fs, '/node_modules/test')).toEqual(jasmine.objectContaining({ module_ivy_ngcc: '__ivy_ngcc__/esm5.js', })); @@ -151,7 +137,7 @@ describe('NewEntryPointFileWriter', () => { contents: 'export class FooTop {} // MODIFIED' }, ]); - expect(loadPackageJson('/node_modules/test')).toEqual(jasmine.objectContaining({ + expect(loadPackageJson(fs, '/node_modules/test')).toEqual(jasmine.objectContaining({ module_ivy_ngcc: '__ivy_ngcc__/esm5.js', es2015_ivy_ngcc: '__ivy_ngcc__/es2015/index.js', })); @@ -161,27 +147,26 @@ describe('NewEntryPointFileWriter', () => { fileWriter.writeBundle(entryPoint, esm2015bundle, [ { path: _('/node_modules/test/index.d.ts'), - contents: 'export declare class FooTop {} // MODIFIED', + contents: 'export declare class FooTop {} // MODIFIED' }, {path: _('/node_modules/test/index.d.ts.map'), contents: 'MODIFIED MAPPING DATA'}, ]); - expect(readFileSync('/node_modules/test/index.d.ts', 'utf8')) + expect(fs.readFile(_('/node_modules/test/index.d.ts'))) .toEqual('export declare class FooTop {} // MODIFIED'); - expect(readFileSync('/node_modules/test/index.d.ts.__ivy_ngcc_bak', 'utf8')) + expect(fs.readFile(_('/node_modules/test/index.d.ts.__ivy_ngcc_bak'))) .toEqual('export declare class FooTop {}'); - expect(existsSync('/node_modules/test/__ivy_ngcc__/index.d.ts')).toBe(false); + expect(fs.exists(_('/node_modules/test/__ivy_ngcc__/index.d.ts'))).toBe(false); - expect(readFileSync('/node_modules/test/index.d.ts.map', 'utf8')) - .toEqual('MODIFIED MAPPING DATA'); - expect(readFileSync('/node_modules/test/index.d.ts.map.__ivy_ngcc_bak', 'utf8')) + expect(fs.readFile(_('/node_modules/test/index.d.ts.map'))).toEqual('MODIFIED MAPPING DATA'); + expect(fs.readFile(_('/node_modules/test/index.d.ts.map.__ivy_ngcc_bak'))) .toEqual('ORIGINAL MAPPING DATA'); - expect(existsSync('/node_modules/test/__ivy_ngcc__/index.d.ts.map')).toBe(false); + expect(fs.exists(_('/node_modules/test/__ivy_ngcc__/index.d.ts.map'))).toBe(false); }); }); describe('writeBundle() [secondary entry-point]', () => { beforeEach(() => { - fs = new NodeJSFileSystem(); + fs = createMockFileSystem(); fileWriter = new NewEntryPointFileWriter(fs); entryPoint = getEntryPointInfo( fs, new MockLogger(), _('/node_modules/test'), _('/node_modules/test/a')) !; @@ -196,10 +181,9 @@ describe('NewEntryPointFileWriter', () => { contents: 'export function FooA() {} // MODIFIED' }, ]); - expect(readFileSync('/node_modules/test/__ivy_ngcc__/a/esm5.js', 'utf8')) + expect(fs.readFile(_('/node_modules/test/__ivy_ngcc__/a/esm5.js'))) .toEqual('export function FooA() {} // MODIFIED'); - expect(readFileSync('/node_modules/test/a/esm5.js', 'utf8')) - .toEqual('export function FooA() {}'); + expect(fs.readFile(_('/node_modules/test/a/esm5.js'))).toEqual('export function FooA() {}'); }); it('should also copy unmodified files in the program', () => { @@ -209,13 +193,12 @@ describe('NewEntryPointFileWriter', () => { contents: 'export class FooA {} // MODIFIED' }, ]); - expect(readFileSync('/node_modules/test/__ivy_ngcc__/a/es2015/foo.js', 'utf8')) + expect(fs.readFile(_('/node_modules/test/__ivy_ngcc__/a/es2015/foo.js'))) .toEqual('export class FooA {} // MODIFIED'); - expect(readFileSync('/node_modules/test/a/es2015/foo.js', 'utf8')) - .toEqual('export class FooA {}'); - expect(readFileSync('/node_modules/test/__ivy_ngcc__/a/es2015/index.js', 'utf8')) + expect(fs.readFile(_('/node_modules/test/a/es2015/foo.js'))).toEqual('export class FooA {}'); + expect(fs.readFile(_('/node_modules/test/__ivy_ngcc__/a/es2015/index.js'))) .toEqual('export {FooA} from "./foo";'); - expect(readFileSync('/node_modules/test/a/es2015/index.js', 'utf8')) + expect(fs.readFile(_('/node_modules/test/a/es2015/index.js'))) .toEqual('export {FooA} from "./foo";'); }); @@ -226,7 +209,7 @@ describe('NewEntryPointFileWriter', () => { contents: 'export function FooA() {} // MODIFIED' }, ]); - expect(loadPackageJson('/node_modules/test/a')).toEqual(jasmine.objectContaining({ + expect(loadPackageJson(fs, '/node_modules/test/a')).toEqual(jasmine.objectContaining({ module_ivy_ngcc: '../__ivy_ngcc__/a/esm5.js', })); @@ -236,7 +219,7 @@ describe('NewEntryPointFileWriter', () => { contents: 'export class FooA {} // MODIFIED' }, ]); - expect(loadPackageJson('/node_modules/test/a')).toEqual(jasmine.objectContaining({ + expect(loadPackageJson(fs, '/node_modules/test/a')).toEqual(jasmine.objectContaining({ module_ivy_ngcc: '../__ivy_ngcc__/a/esm5.js', es2015_ivy_ngcc: '../__ivy_ngcc__/a/es2015/index.js', })); @@ -249,17 +232,17 @@ describe('NewEntryPointFileWriter', () => { contents: 'export declare class FooA {} // MODIFIED' }, ]); - expect(readFileSync('/node_modules/test/a/index.d.ts', 'utf8')) + expect(fs.readFile(_('/node_modules/test/a/index.d.ts'))) .toEqual('export declare class FooA {} // MODIFIED'); - expect(readFileSync('/node_modules/test/a/index.d.ts.__ivy_ngcc_bak', 'utf8')) + expect(fs.readFile(_('/node_modules/test/a/index.d.ts.__ivy_ngcc_bak'))) .toEqual('export declare class FooA {}'); - expect(existsSync('/node_modules/test/__ivy_ngcc__/a/index.d.ts')).toBe(false); + expect(fs.exists(_('/node_modules/test/__ivy_ngcc__/a/index.d.ts'))).toBe(false); }); }); describe('writeBundle() [entry-point (with files placed outside entry-point folder)]', () => { beforeEach(() => { - fs = new NodeJSFileSystem(); + fs = createMockFileSystem(); fileWriter = new NewEntryPointFileWriter(fs); entryPoint = getEntryPointInfo( fs, new MockLogger(), _('/node_modules/test'), _('/node_modules/test/b')) !; @@ -274,10 +257,9 @@ describe('NewEntryPointFileWriter', () => { contents: 'export function FooB() {} // MODIFIED' }, ]); - expect(readFileSync('/node_modules/test/__ivy_ngcc__/lib/esm5.js', 'utf8')) + expect(fs.readFile(_('/node_modules/test/__ivy_ngcc__/lib/esm5.js'))) .toEqual('export function FooB() {} // MODIFIED'); - expect(readFileSync('/node_modules/test/lib/esm5.js', 'utf8')) - .toEqual('export function FooB() {}'); + expect(fs.readFile(_('/node_modules/test/lib/esm5.js'))).toEqual('export function FooB() {}'); }); it('should also copy unmodified files in the program', () => { @@ -287,13 +269,13 @@ describe('NewEntryPointFileWriter', () => { contents: 'export class FooB {} // MODIFIED' }, ]); - expect(readFileSync('/node_modules/test/__ivy_ngcc__/lib/es2015/foo.js', 'utf8')) + expect(fs.readFile(_('/node_modules/test/__ivy_ngcc__/lib/es2015/foo.js'))) .toEqual('export class FooB {} // MODIFIED'); - expect(readFileSync('/node_modules/test/lib/es2015/foo.js', 'utf8')) + expect(fs.readFile(_('/node_modules/test/lib/es2015/foo.js'))) .toEqual('import {FooA} from "test/a"; import "events"; export class FooB {}'); - expect(readFileSync('/node_modules/test/__ivy_ngcc__/lib/es2015/index.js', 'utf8')) + expect(fs.readFile(_('/node_modules/test/__ivy_ngcc__/lib/es2015/index.js'))) .toEqual('export {FooB} from "./foo"; import * from "other";'); - expect(readFileSync('/node_modules/test/lib/es2015/index.js', 'utf8')) + expect(fs.readFile(_('/node_modules/test/lib/es2015/index.js'))) .toEqual('export {FooB} from "./foo"; import * from "other";'); }); @@ -301,11 +283,11 @@ describe('NewEntryPointFileWriter', () => { () => { fileWriter.writeBundle(entryPoint, esm2015bundle, [ { - path: '/node_modules/test/lib/es2015/foo.js', + path: _('/node_modules/test/lib/es2015/foo.js'), contents: 'export class FooB {} // MODIFIED' }, ]); - expect(existsSync('/node_modules/test/__ivy_ngcc__/a/index.d.ts')).toEqual(false); + expect(fs.exists(_('/node_modules/test/__ivy_ngcc__/a/index.d.ts'))).toEqual(false); }); it('should not copy files outside of the package', () => { @@ -315,8 +297,8 @@ describe('NewEntryPointFileWriter', () => { contents: 'export class FooB {} // MODIFIED' }, ]); - expect(existsSync('/node_modules/test/other/index.d.ts')).toEqual(false); - expect(existsSync('/node_modules/test/events/events.js')).toEqual(false); + expect(fs.exists(_('/node_modules/test/other/index.d.ts'))).toEqual(false); + expect(fs.exists(_('/node_modules/test/events/events.js'))).toEqual(false); }); it('should update the package.json properties', () => { @@ -326,7 +308,7 @@ describe('NewEntryPointFileWriter', () => { contents: 'export function FooB() {} // MODIFIED' }, ]); - expect(loadPackageJson('/node_modules/test/b')).toEqual(jasmine.objectContaining({ + expect(loadPackageJson(fs, '/node_modules/test/b')).toEqual(jasmine.objectContaining({ module_ivy_ngcc: '../__ivy_ngcc__/lib/esm5.js', })); @@ -336,7 +318,7 @@ describe('NewEntryPointFileWriter', () => { contents: 'export class FooB {} // MODIFIED' }, ]); - expect(loadPackageJson('/node_modules/test/b')).toEqual(jasmine.objectContaining({ + expect(loadPackageJson(fs, '/node_modules/test/b')).toEqual(jasmine.objectContaining({ module_ivy_ngcc: '../__ivy_ngcc__/lib/esm5.js', es2015_ivy_ngcc: '../__ivy_ngcc__/lib/es2015/index.js', })); @@ -349,11 +331,11 @@ describe('NewEntryPointFileWriter', () => { contents: 'export declare class FooB {} // MODIFIED' }, ]); - expect(readFileSync('/node_modules/test/typings/index.d.ts', 'utf8')) + expect(fs.readFile(_('/node_modules/test/typings/index.d.ts'))) .toEqual('export declare class FooB {} // MODIFIED'); - expect(readFileSync('/node_modules/test/typings/index.d.ts.__ivy_ngcc_bak', 'utf8')) + expect(fs.readFile(_('/node_modules/test/typings/index.d.ts.__ivy_ngcc_bak'))) .toEqual('export declare class FooB {}'); - expect(existsSync('/node_modules/test/__ivy_ngcc__/typings/index.d.ts')).toBe(false); + expect(fs.exists(_('/node_modules/test/__ivy_ngcc__/typings/index.d.ts'))).toBe(false); }); }); });