diff --git a/packages/nx/src/hasher/file-hasher.ts b/packages/nx/src/hasher/file-hasher.ts index 9a70c35349fac..20b522ea031dc 100644 --- a/packages/nx/src/hasher/file-hasher.ts +++ b/packages/nx/src/hasher/file-hasher.ts @@ -8,12 +8,13 @@ import { join } from 'path'; import { NativeFileHasher } from './native-file-hasher'; function createFileHasher(): FileHasherBase { - // special case for unit tests - if (workspaceRoot === '/root') { - return new NodeBasedFileHasher(); - } try { - if (process.env.NX_NATIVE_HASHER) { + if ( + !( + process.env.NX_NON_NATIVE_HASHER && + process.env.NX_NON_NATIVE_HASHER == 'false' + ) + ) { return new NativeFileHasher(); } diff --git a/packages/nx/src/project-graph/build-dependencies/explicit-package-json-dependencies.spec.ts b/packages/nx/src/project-graph/build-dependencies/explicit-package-json-dependencies.spec.ts index 1e7745c2a18ca..3f4f3b7174f8c 100644 --- a/packages/nx/src/project-graph/build-dependencies/explicit-package-json-dependencies.spec.ts +++ b/packages/nx/src/project-graph/build-dependencies/explicit-package-json-dependencies.spec.ts @@ -1,6 +1,8 @@ -import '../../utils/testing/mock-fs'; +import { TempFs } from '../../utils/testing/temp-fs'; +const tempFs = new TempFs('explicit-package-json'); + import { buildExplicitPackageJsonDependencies } from './explicit-package-json-dependencies'; -import { vol } from 'memfs'; + import { createProjectFileMap } from '../file-map-utils'; import { defaultFileHasher } from '../../hasher/file-hasher'; import { @@ -9,15 +11,11 @@ import { } from '../../config/project-graph'; import { ProjectGraphBuilder } from '../project-graph-builder'; -jest.mock('nx/src/utils/workspace-root', () => ({ - workspaceRoot: '/root', -})); - describe('explicit package json dependencies', () => { let ctx: ProjectGraphProcessorContext; let projects: Record; - let fsJson; - beforeEach(() => { + + beforeEach(async () => { const projectsConfigurations = { projects: { proj: { @@ -39,12 +37,12 @@ describe('explicit package json dependencies', () => { npmScope: 'proj', }; - fsJson = { + await tempFs.createFiles({ './package.json': `{ - "name": "test", - "dependencies": [], - "devDependencies": [] - }`, + "name": "test", + "dependencies": [], + "devDependencies": [] + }`, './nx.json': JSON.stringify(nxJsonConfiguration), './tsconfig.base.json': JSON.stringify({}), './libs/proj2/package.json': JSON.stringify({ name: 'proj2' }), @@ -53,10 +51,9 @@ describe('explicit package json dependencies', () => { dependencies: { proj2: '*', external: '12.0.0' }, devDependencies: { proj3: '*' }, }), - }; - vol.fromJSON(fsJson, '/root'); + }); - defaultFileHasher.init(); + await defaultFileHasher.init(); ctx = { projectsConfigurations, @@ -89,6 +86,10 @@ describe('explicit package json dependencies', () => { }; }); + afterEach(() => { + tempFs.cleanup(); + }); + it(`should add dependencies for projects based on deps in package.json`, () => { const builder = new ProjectGraphBuilder(); Object.values(projects).forEach((p) => { diff --git a/packages/nx/src/project-graph/build-dependencies/explicit-project-dependencies.spec.ts b/packages/nx/src/project-graph/build-dependencies/explicit-project-dependencies.spec.ts index 017e2ea0aca37..4c598cb3477e0 100644 --- a/packages/nx/src/project-graph/build-dependencies/explicit-project-dependencies.spec.ts +++ b/packages/nx/src/project-graph/build-dependencies/explicit-project-dependencies.spec.ts @@ -1,14 +1,11 @@ -import '../../utils/testing/mock-fs'; -import { vol } from 'memfs'; +import { TempFs } from '../../utils/testing/temp-fs'; +const tempFs = new TempFs('explicit-project-deps'); + import { defaultFileHasher } from '../../hasher/file-hasher'; import { createProjectFileMap } from '../file-map-utils'; import { ProjectGraphBuilder } from '../project-graph-builder'; import { buildExplicitTypeScriptDependencies } from './explicit-project-dependencies'; -jest.mock('nx/src/utils/workspace-root', () => ({ - workspaceRoot: '/root', -})); - // projectName => tsconfig import path const dependencyProjectNamesToImportPaths = { proj2: '@proj/my-second-proj', @@ -18,13 +15,13 @@ const dependencyProjectNamesToImportPaths = { describe('explicit project dependencies', () => { beforeEach(() => { - vol.reset(); + tempFs.reset(); }); describe('static imports, dynamic imports, and commonjs requires', () => { - it('should build explicit dependencies for static imports, and top-level dynamic imports and commonjs requires', () => { + it('should build explicit dependencies for static imports, and top-level dynamic imports and commonjs requires', async () => { const sourceProjectName = 'proj'; - const { ctx, builder } = createVirtualWorkspace({ + const { ctx, builder } = await createVirtualWorkspace({ sourceProjectName, sourceProjectFiles: [ { @@ -68,9 +65,9 @@ describe('explicit project dependencies', () => { ]); }); - it('should build explicit dependencies for static exports', () => { + it('should build explicit dependencies for static exports', async () => { const sourceProjectName = 'proj'; - const { ctx, builder } = createVirtualWorkspace({ + const { ctx, builder } = await createVirtualWorkspace({ sourceProjectName, sourceProjectFiles: [ { @@ -108,9 +105,9 @@ describe('explicit project dependencies', () => { ]); }); - it(`should build explicit dependencies for TypeScript's import/export require syntax, and side-effectful import`, () => { + it(`should build explicit dependencies for TypeScript's import/export require syntax, and side-effectful import`, async () => { const sourceProjectName = 'proj'; - const { ctx, builder } = createVirtualWorkspace({ + const { ctx, builder } = await createVirtualWorkspace({ sourceProjectName, sourceProjectFiles: [ { @@ -148,9 +145,9 @@ describe('explicit project dependencies', () => { ]); }); - it('should build explicit dependencies for nested dynamic imports and commonjs requires', () => { + it('should build explicit dependencies for nested dynamic imports and commonjs requires', async () => { const sourceProjectName = 'proj'; - const { ctx, builder } = createVirtualWorkspace({ + const { ctx, builder } = await createVirtualWorkspace({ sourceProjectName, sourceProjectFiles: [ { @@ -209,9 +206,9 @@ describe('explicit project dependencies', () => { ]); }); - it('should build explicit dependencies when relative paths are used', () => { + it('should build explicit dependencies when relative paths are used', async () => { const sourceProjectName = 'proj'; - const { ctx, builder } = createVirtualWorkspace({ + const { ctx, builder } = await createVirtualWorkspace({ sourceProjectName, sourceProjectFiles: [ { @@ -248,9 +245,9 @@ describe('explicit project dependencies', () => { ]); }); - it('should not build explicit dependencies when nx-ignore-next-line comments are present', () => { + it('should not build explicit dependencies when nx-ignore-next-line comments are present', async () => { const sourceProjectName = 'proj'; - const { ctx, builder } = createVirtualWorkspace({ + const { ctx, builder } = await createVirtualWorkspace({ sourceProjectName, sourceProjectFiles: [ { @@ -340,9 +337,9 @@ describe('explicit project dependencies', () => { expect(res).toEqual([]); }); - it('should not build explicit dependencies for stringified or templatized import/require statements', () => { + it('should not build explicit dependencies for stringified or templatized import/require statements', async () => { const sourceProjectName = 'proj'; - const { ctx, builder } = createVirtualWorkspace({ + const { ctx, builder } = await createVirtualWorkspace({ sourceProjectName, sourceProjectFiles: [ { @@ -423,9 +420,9 @@ describe('explicit project dependencies', () => { * https://angular.io/guide/deprecations#loadchildren-string-syntax */ describe('legacy Angular loadChildren string syntax', () => { - it('should build explicit dependencies for legacy Angular loadChildren string syntax', () => { + it('should build explicit dependencies for legacy Angular loadChildren string syntax', async () => { const sourceProjectName = 'proj'; - const { ctx, builder } = createVirtualWorkspace({ + const { ctx, builder } = await createVirtualWorkspace({ sourceProjectName, sourceProjectFiles: [ { @@ -476,9 +473,9 @@ describe('explicit project dependencies', () => { ]); }); - it('should not build explicit dependencies when nx-ignore-next-line comments are present', () => { + it('should not build explicit dependencies when nx-ignore-next-line comments are present', async () => { const sourceProjectName = 'proj'; - const { ctx, builder } = createVirtualWorkspace({ + const { ctx, builder } = await createVirtualWorkspace({ sourceProjectName, sourceProjectFiles: [ { @@ -544,7 +541,7 @@ interface VirtualWorkspaceConfig { * Prepares a minimal workspace and virtual file-system for the given files and dependency * projects in order to be able to execute `buildExplicitTypeScriptDependencies()` in the tests. */ -function createVirtualWorkspace(config: VirtualWorkspaceConfig) { +async function createVirtualWorkspace(config: VirtualWorkspaceConfig) { const nxJson = { npmScope: 'proj', }; @@ -625,9 +622,9 @@ function createVirtualWorkspace(config: VirtualWorkspaceConfig) { fsJson['./tsconfig.base.json'] = JSON.stringify(tsConfig); - vol.fromJSON(fsJson, '/root'); + await tempFs.createFiles(fsJson); - defaultFileHasher.init(); + await defaultFileHasher.init(); return { ctx: { diff --git a/packages/nx/src/project-graph/build-project-graph.spec.ts b/packages/nx/src/project-graph/build-project-graph.spec.ts index fb98f90202d95..ea63bf98f4065 100644 --- a/packages/nx/src/project-graph/build-project-graph.spec.ts +++ b/packages/nx/src/project-graph/build-project-graph.spec.ts @@ -1,14 +1,9 @@ -import '../utils/testing/mock-fs'; +import { TempFs } from '../utils/testing/temp-fs'; +const tempFs = new TempFs('explicit-package-json'); -import { vol, fs } from 'memfs'; - -jest.mock('nx/src/utils/workspace-root', () => ({ - workspaceRoot: '/root', -})); import { buildProjectGraph } from './build-project-graph'; import * as fastGlob from 'fast-glob'; import { defaultFileHasher } from '../hasher/file-hasher'; -import { ProjectsConfigurations } from '../config/workspace-json-project-json'; import { NxJsonConfiguration } from '../config/nx-json'; import { stripIndents } from '../utils/strip-indents'; import { DependencyType } from '../config/project-graph'; @@ -16,7 +11,6 @@ import { DependencyType } from '../config/project-graph'; describe('project graph', () => { let packageJson: any; let packageLockJson: any; - let projects: ProjectsConfigurations; let nxJson: NxJsonConfiguration; let tsConfigJson: any; let filesJson: any; @@ -190,8 +184,8 @@ describe('project graph', () => { './apps/api/project.json': JSON.stringify(apiProjectJson), }; - vol.reset(); - vol.fromJSON(filesJson, '/root'); + tempFs.reset(); + await tempFs.createFiles(filesJson); await defaultFileHasher.init(); const globResults = [ @@ -208,17 +202,13 @@ describe('project graph', () => { }); it('should throw an appropriate error for an invalid json config', async () => { - vol.appendFileSync('/root/tsconfig.base.json', 'invalid'); + tempFs.appendFile('tsconfig.base.json', 'invalid'); try { await buildProjectGraph(); fail('Invalid tsconfigs should cause project graph to throw error'); } catch (e) { - expect(e.message).toMatchInlineSnapshot(` - "InvalidSymbol in /root/tsconfig.base.json at 1:248 - > 1 | {\\"compilerOptions\\":{\\"baseUrl\\":\\".\\",\\"paths\\":{\\"@nrwl/shared/util\\":[\\"libs/shared/util/src/index.ts\\"],\\"@nrwl/shared-util-data\\":[\\"libs/shared/util/data/src/index.ts\\"],\\"@nrwl/ui\\":[\\"libs/ui/src/index.ts\\"],\\"@nrwl/lazy-lib\\":[\\"libs/lazy-lib/src/index.ts\\"]}}}invalid -   |  ^^^^^^^ - " - `); + expect(e.message).toContain(`${tempFs.tempDir}/tsconfig.base.json`); + expect(e.message).toContain(`invalid`); } }); @@ -284,8 +274,8 @@ describe('project graph', () => { }); it('should handle circular dependencies', async () => { - fs.writeFileSync( - '/root/libs/shared/util/src/index.ts', + tempFs.writeFile( + 'libs/shared/util/src/index.ts', `import * as ui from '@nrwl/ui';` ); diff --git a/packages/nx/src/utils/testing/temp-fs.ts b/packages/nx/src/utils/testing/temp-fs.ts new file mode 100644 index 0000000000000..76926fa15b612 --- /dev/null +++ b/packages/nx/src/utils/testing/temp-fs.ts @@ -0,0 +1,57 @@ +import { join } from 'path'; +import { tmpdir } from 'os'; +import { + mkdtempSync, + readFile, + outputFile, + rmSync, + emptyDirSync, +} from 'fs-extra'; +import { joinPathFragments } from '../path'; +import { appendFileSync, writeFileSync } from 'fs'; + +type NestedFiles = { + [fileName: string]: string; +}; + +export class TempFs { + readonly tempDir: string; + constructor(private dirname: string, overrideWorkspaceRoot = true) { + this.tempDir = mkdtempSync(join(tmpdir(), this.dirname)); + if (overrideWorkspaceRoot) { + process.env.NX_WORKSPACE_ROOT_PATH = this.tempDir; + } + } + + async createFiles(fileObject: NestedFiles) { + await Promise.all( + Object.keys(fileObject).map(async (path) => { + await this.createFile(path, fileObject[path]); + }) + ); + } + + async createFile(filePath: string, content: string) { + await outputFile(joinPathFragments(this.tempDir, filePath), content); + } + + async readFile(filePath: string): Promise { + return await readFile(filePath, 'utf-8'); + } + + appendFile(filePath: string, content: string) { + appendFileSync(joinPathFragments(this.tempDir, filePath), content); + } + + writeFile(filePath: string, content: string) { + writeFileSync(joinPathFragments(this.tempDir, filePath), content); + } + + cleanup() { + rmSync(this.tempDir, { recursive: true }); + } + + reset() { + emptyDirSync(this.tempDir); + } +}