From 09c1aa900f459834f36df1914a3e6fa0a10a5082 Mon Sep 17 00:00:00 2001 From: "anh.pham" Date: Tue, 26 Apr 2022 00:13:12 +0200 Subject: [PATCH] feat: allow running `ngcc` with specific `tsconfig` path --- src/config/global-setup.ts | 9 ++-- .../ngcc-jest-processor.spec.ts.snap | 31 +++++++++++++ src/utils/ngcc-jest-processor.spec.ts | 20 +++++++++ src/utils/ngcc-jest-processor.ts | 43 ++++++++++--------- 4 files changed, 79 insertions(+), 24 deletions(-) create mode 100644 src/utils/__snapshots__/ngcc-jest-processor.spec.ts.snap create mode 100644 src/utils/ngcc-jest-processor.spec.ts diff --git a/src/config/global-setup.ts b/src/config/global-setup.ts index fbceb008f8..18937c2486 100644 --- a/src/config/global-setup.ts +++ b/src/config/global-setup.ts @@ -1,4 +1,5 @@ import type { Config } from '@jest/types'; +import type { TsJestGlobalOptions } from 'ts-jest/dist/types'; import { runNgccJestProcessor } from '../utils/ngcc-jest-processor'; @@ -7,11 +8,13 @@ interface NgJestProjectConfig extends Omit { ngJest?: { skipNgcc: boolean; }; + tsJest?: TsJestGlobalOptions; }; } -export = async (_globalConfig: Config.GlobalConfig, projectConfig: NgJestProjectConfig) => { - if (!projectConfig.globals.ngJest?.skipNgcc) { - runNgccJestProcessor(); +export = async (_globalConfig: Config.GlobalConfig, { globals }: NgJestProjectConfig) => { + if (!globals.ngJest?.skipNgcc) { + const tsconfig = globals.tsJest?.tsconfig; + runNgccJestProcessor(typeof tsconfig === 'string' ? tsconfig : undefined); } }; diff --git a/src/utils/__snapshots__/ngcc-jest-processor.spec.ts.snap b/src/utils/__snapshots__/ngcc-jest-processor.spec.ts.snap new file mode 100644 index 0000000000..859be72f0e --- /dev/null +++ b/src/utils/__snapshots__/ngcc-jest-processor.spec.ts.snap @@ -0,0 +1,31 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ngcc-jest-processor should execute @angular/compiler-cli ngcc with tsconfig path foo 1`] = ` +Array [ + "/node_modules/@angular/compiler-cli/bundles/ngcc/main-ngcc.js", + "--source", + "/node_modules/", + "--properties", + "es2015", + "main", + "--first-only", + "false", + "--async", + "--tsconfig", + "foo", +] +`; + +exports[`ngcc-jest-processor should execute @angular/compiler-cli ngcc with tsconfig path undefined 1`] = ` +Array [ + "/node_modules/@angular/compiler-cli/bundles/ngcc/main-ngcc.js", + "--source", + "/node_modules/", + "--properties", + "es2015", + "main", + "--first-only", + "false", + "--async", +] +`; diff --git a/src/utils/ngcc-jest-processor.spec.ts b/src/utils/ngcc-jest-processor.spec.ts new file mode 100644 index 0000000000..35e9900703 --- /dev/null +++ b/src/utils/ngcc-jest-processor.spec.ts @@ -0,0 +1,20 @@ +import childProcess from 'child_process'; + +import { runNgccJestProcessor } from './ngcc-jest-processor'; + +describe('ngcc-jest-processor', () => { + test.each(['foo', undefined])('should execute @angular/compiler-cli ngcc with tsconfig path %s', (tsconfigPath) => { + const mockedSpawnSync = (childProcess.spawnSync = jest.fn().mockReturnValueOnce({ + status: 0, + })); + + runNgccJestProcessor(tsconfigPath); + + expect(childProcess.spawnSync).toHaveBeenCalled(); + expect(mockedSpawnSync.mock.calls[0][0]).toBe(process.execPath); + const ngccArgs = (mockedSpawnSync.mock.calls[0][1] as string[]).map((arg) => arg.replace(process.cwd(), '')); + expect(ngccArgs).toMatchSnapshot(); + + jest.restoreAllMocks(); + }); +}); diff --git a/src/utils/ngcc-jest-processor.ts b/src/utils/ngcc-jest-processor.ts index f0c18363ca..f0645e009f 100644 --- a/src/utils/ngcc-jest-processor.ts +++ b/src/utils/ngcc-jest-processor.ts @@ -20,34 +20,35 @@ function findNodeModulesDirectory(): string { const nodeModuleDirPath = findNodeModulesDirectory(); -export const runNgccJestProcessor = (): void => { +export const runNgccJestProcessor = (tsconfigPath: string | undefined): void => { if (nodeModuleDirPath) { process.stdout.write('\nngcc-jest-processor: running ngcc\n'); + + const ngccBaseArgs = [ + ngccPath, + '--source' /** basePath */, + nodeModuleDirPath, + '--properties' /** propertiesToConsider */, + /** + * There are various properties: fesm2015, fesm5, es2015, esm2015, esm5, main, module, browser to choose from. + * Normally, Jest requires `umd`. If running Jest in ESM mode, Jest will require both `umd` + `esm2015`. + */ + ...['es2015', 'main'], + '--first-only' /** compileAllFormats */, + 'false', // make sure that `ngcc` runs on subfolders as well + '--async', + ]; + if (tsconfigPath) { + ngccBaseArgs.push(...['--tsconfig', tsconfigPath]); + } // We spawn instead of using the API because: // - NGCC Async uses clustering which is problematic when used via the API which means // that we cannot setup multiple cluster masters with different options. // - We will not be able to have concurrent builds otherwise Ex: App-Shell, // as NGCC will create a lock file for both builds and it will cause builds to fails. - const { status, error } = spawnSync( - process.execPath, - [ - ngccPath, - '--source' /** basePath */, - nodeModuleDirPath, - '--properties' /** propertiesToConsider */, - /** - * There are various properties: fesm2015, fesm5, es2015, esm2015, esm5, main, module, browser to choose from. - * Normally, Jest requires `umd`. If running Jest in ESM mode, Jest will require both `umd` + `esm2015`. - */ - ...['es2015', 'main'], - '--first-only' /** compileAllFormats */, - 'false', // make sure that `ngcc` runs on subfolders as well - '--async', - ], - { - stdio: ['inherit', process.stderr, process.stderr], - }, - ); + const { status, error } = spawnSync(process.execPath, ngccBaseArgs, { + stdio: ['inherit', process.stderr, process.stderr], + }); if (status !== 0) { const errorMessage: string = error?.message ?? '';