609 lines
18 KiB
TypeScript
609 lines
18 KiB
TypeScript
import { logger, ProjectGraph, Tree } from '@nrwl/devkit';
|
|
import {
|
|
addProjectConfiguration,
|
|
DependencyType,
|
|
readJson,
|
|
writeJson,
|
|
} from '@nrwl/devkit';
|
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
|
import updateTsConfigTarget from './update-tsconfig-target';
|
|
|
|
let projectGraph: ProjectGraph;
|
|
jest.mock('@nrwl/devkit', () => ({
|
|
...jest.requireActual<any>('@nrwl/devkit'),
|
|
createProjectGraphAsync: jest
|
|
.fn()
|
|
.mockImplementation(async () => projectGraph),
|
|
}));
|
|
|
|
describe('update-tsconfig-target migration', () => {
|
|
let tree: Tree;
|
|
|
|
beforeEach(() => {
|
|
tree = createTreeWithEmptyWorkspace(2);
|
|
});
|
|
|
|
it('should update target in "tsconfig.json" at the project root when it is an Angular project', async () => {
|
|
addProjectConfiguration(tree, 'app1', {
|
|
root: 'apps/app1',
|
|
sourceRoot: 'apps/app1/src',
|
|
projectType: 'application',
|
|
targets: {
|
|
build: {
|
|
executor: '@nrwl/angular:webpack-browser',
|
|
options: { tsConfig: 'apps/app1/tsconfig.app.json' },
|
|
},
|
|
},
|
|
});
|
|
projectGraph = {
|
|
dependencies: {
|
|
app1: [
|
|
{
|
|
type: DependencyType.static,
|
|
source: 'app1',
|
|
target: 'npm:@angular/core',
|
|
},
|
|
],
|
|
},
|
|
nodes: {},
|
|
};
|
|
writeJson(tree, 'apps/app1/tsconfig.json', {
|
|
compilerOptions: { target: 'es2017' },
|
|
});
|
|
writeJson(tree, 'apps/app1/tsconfig.app.json', {
|
|
compilerOptions: { target: 'es2017' },
|
|
});
|
|
|
|
await updateTsConfigTarget(tree);
|
|
|
|
const { compilerOptions } = readJson(tree, 'apps/app1/tsconfig.json');
|
|
expect(compilerOptions.target).toBe('es2020');
|
|
const optionTsConfig = readJson(tree, 'apps/app1/tsconfig.app.json');
|
|
expect(optionTsConfig.compilerOptions.target).toBe('es2020');
|
|
});
|
|
|
|
it('should not update target in a tsconfig file referenced by a target option when it does not have the target set and there is a "tsconfig.json" at the project root', async () => {
|
|
addProjectConfiguration(tree, 'app1', {
|
|
root: 'apps/app1',
|
|
sourceRoot: 'apps/app1/src',
|
|
projectType: 'application',
|
|
targets: {
|
|
build: {
|
|
executor: '@nrwl/angular:webpack-browser',
|
|
options: { tsConfig: 'apps/app1/tsconfig.app.json' },
|
|
},
|
|
},
|
|
});
|
|
projectGraph = {
|
|
dependencies: {
|
|
app1: [
|
|
{
|
|
type: DependencyType.static,
|
|
source: 'app1',
|
|
target: 'npm:@angular/core',
|
|
},
|
|
],
|
|
},
|
|
nodes: {},
|
|
};
|
|
writeJson(tree, 'apps/app1/tsconfig.json', {
|
|
compilerOptions: { target: 'es2017' },
|
|
});
|
|
writeJson(tree, 'apps/app1/tsconfig.app.json', {
|
|
compilerOptions: {},
|
|
});
|
|
|
|
await updateTsConfigTarget(tree);
|
|
|
|
const { compilerOptions } = readJson(tree, 'apps/app1/tsconfig.json');
|
|
expect(compilerOptions.target).toBe('es2020');
|
|
const optionTsConfig = readJson(tree, 'apps/app1/tsconfig.app.json');
|
|
expect(optionTsConfig.compilerOptions).toStrictEqual({});
|
|
});
|
|
|
|
it.each([
|
|
['@angular-devkit/build-angular:browser', 'tsconfig.app.json'],
|
|
['@angular-devkit/build-angular:karma', 'tsconfig.spec.json'],
|
|
['@nrwl/angular:webpack-browser', 'tsconfig.app.json'],
|
|
['@nrwl/angular:delegate-build', 'tsconfig.app.json'],
|
|
])(
|
|
'should update target in the tsconfig file referenced by the target configuration when using the "%s" executor and there is no "tsconfig.json" at the project root',
|
|
async (executor, tsConfig) => {
|
|
const tsConfigPath = `apps/app1/${tsConfig}`;
|
|
addProjectConfiguration(tree, 'app1', {
|
|
root: 'apps/app1',
|
|
sourceRoot: 'apps/app1/src',
|
|
projectType: 'application',
|
|
targets: {
|
|
build: { executor, options: { tsConfig: tsConfigPath } },
|
|
},
|
|
});
|
|
projectGraph = {
|
|
dependencies: {
|
|
app1: [
|
|
{
|
|
type: DependencyType.static,
|
|
source: 'app1',
|
|
target: 'npm:@angular/core',
|
|
},
|
|
],
|
|
},
|
|
nodes: {},
|
|
};
|
|
writeJson(tree, tsConfigPath, {
|
|
compilerOptions: { target: 'es2017' },
|
|
});
|
|
|
|
await updateTsConfigTarget(tree);
|
|
|
|
const { compilerOptions } = readJson(tree, tsConfigPath);
|
|
expect(compilerOptions.target).toBe('es2020');
|
|
}
|
|
);
|
|
|
|
it.each([
|
|
'@angular-devkit/build-angular:ng-packagr',
|
|
'@nrwl/angular:ng-packagr-lite',
|
|
'@nrwl/angular:package',
|
|
])(
|
|
'should update target in the tsconfig file referenced by the target configuration when using the "%s" executor and there is no "tsconfig.json" at the project root',
|
|
async (executor) => {
|
|
addProjectConfiguration(tree, 'lib1', {
|
|
root: 'libs/lib1',
|
|
sourceRoot: 'libs/lib1/src',
|
|
projectType: 'library',
|
|
targets: {
|
|
build: {
|
|
executor,
|
|
options: { tsConfig: 'libs/lib1/tsconfig.lib.json' },
|
|
configurations: {
|
|
production: { tsConfig: 'libs/lib1/tsconfig.lib.prod.json' },
|
|
},
|
|
},
|
|
},
|
|
});
|
|
projectGraph = {
|
|
dependencies: {
|
|
lib1: [
|
|
{
|
|
type: DependencyType.static,
|
|
source: 'lib1',
|
|
target: 'npm:@angular/core',
|
|
},
|
|
],
|
|
},
|
|
nodes: {},
|
|
};
|
|
writeJson(tree, 'libs/lib1/tsconfig.lib.json', {
|
|
compilerOptions: { target: 'es2017' },
|
|
});
|
|
writeJson(tree, 'libs/lib1/tsconfig.lib.prod.json', {});
|
|
|
|
await updateTsConfigTarget(tree);
|
|
|
|
const { compilerOptions } = readJson(tree, 'libs/lib1/tsconfig.lib.json');
|
|
expect(compilerOptions.target).toBe('es2020');
|
|
const tsConfigProd = readJson(tree, 'libs/lib1/tsconfig.lib.prod.json');
|
|
expect(tsConfigProd.compilerOptions.target).toBe('es2020');
|
|
}
|
|
);
|
|
|
|
it('should not error and log a warning when the tsconfig file specified in target does not exist', async () => {
|
|
jest.spyOn(logger, 'warn');
|
|
addProjectConfiguration(tree, 'lib1', {
|
|
root: 'libs/lib1',
|
|
sourceRoot: 'libs/lib1/src',
|
|
projectType: 'library',
|
|
targets: {
|
|
build: {
|
|
executor: '@nrwl/angular:package',
|
|
options: { tsConfig: 'libs/lib1/tsconfig.lib.json' },
|
|
},
|
|
},
|
|
});
|
|
projectGraph = {
|
|
dependencies: {
|
|
lib1: [
|
|
{
|
|
type: DependencyType.static,
|
|
source: 'lib1',
|
|
target: 'npm:@angular/core',
|
|
},
|
|
],
|
|
},
|
|
nodes: {},
|
|
};
|
|
|
|
await expect(updateTsConfigTarget(tree)).resolves.not.toThrow();
|
|
|
|
expect(logger.warn).toHaveBeenCalledWith(
|
|
expect.stringContaining(
|
|
`The "libs/lib1/tsconfig.lib.json" file specified in the "build" target of the "lib1" project could not be found.`
|
|
)
|
|
);
|
|
});
|
|
|
|
it('should update target in tsconfig file specified in the jest config when it is an Angular project', async () => {
|
|
addProjectConfiguration(tree, 'lib1', {
|
|
root: 'libs/lib1',
|
|
sourceRoot: 'libs/lib1/src',
|
|
projectType: 'library',
|
|
targets: {
|
|
build: {
|
|
executor: '@nrwl/jest:jest',
|
|
options: { jestConfig: 'libs/lib1/jest.config.ts' },
|
|
},
|
|
},
|
|
});
|
|
projectGraph = {
|
|
dependencies: {
|
|
lib1: [
|
|
{
|
|
type: DependencyType.static,
|
|
source: 'lib1',
|
|
target: 'npm:@angular/core',
|
|
},
|
|
],
|
|
},
|
|
nodes: {},
|
|
};
|
|
tree.write(
|
|
'libs/lib1/jest.config.ts',
|
|
`export default {
|
|
displayName: 'lib1',
|
|
preset: '../../jest.preset.js',
|
|
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
|
|
globals: {
|
|
'ts-jest': {
|
|
tsconfig: '<rootDir>/tsconfig.spec.json',
|
|
stringifyContentPathRegex: '\\.(html|svg)$',
|
|
},
|
|
},
|
|
coverageDirectory: '../../coverage/libs/lib1',
|
|
transform: {
|
|
'^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular',
|
|
},
|
|
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
|
|
snapshotSerializers: [
|
|
'jest-preset-angular/build/serializers/no-ng-attributes',
|
|
'jest-preset-angular/build/serializers/ng-snapshot',
|
|
'jest-preset-angular/build/serializers/html-comment',
|
|
],
|
|
};`
|
|
);
|
|
writeJson(tree, 'libs/lib1/tsconfig.spec.json', {
|
|
compilerOptions: { target: 'es2017' },
|
|
});
|
|
|
|
await updateTsConfigTarget(tree);
|
|
|
|
const { compilerOptions } = readJson(tree, 'libs/lib1/tsconfig.spec.json');
|
|
expect(compilerOptions.target).toBe('es2020');
|
|
});
|
|
|
|
it('should not error and log a warning when the tsconfig file specified in the jest configuration does not exist', async () => {
|
|
jest.spyOn(logger, 'warn');
|
|
addProjectConfiguration(tree, 'lib1', {
|
|
root: 'libs/lib1',
|
|
sourceRoot: 'libs/lib1/src',
|
|
projectType: 'library',
|
|
targets: {
|
|
test: {
|
|
executor: '@nrwl/jest:jest',
|
|
options: { jestConfig: 'libs/lib1/jest.config.ts' },
|
|
},
|
|
},
|
|
});
|
|
projectGraph = {
|
|
dependencies: {
|
|
lib1: [
|
|
{
|
|
type: DependencyType.static,
|
|
source: 'lib1',
|
|
target: 'npm:@angular/core',
|
|
},
|
|
],
|
|
},
|
|
nodes: {},
|
|
};
|
|
tree.write(
|
|
'libs/lib1/jest.config.ts',
|
|
`export default {
|
|
globals: {
|
|
'ts-jest': {
|
|
tsconfig: '<rootDir>/tsconfig.spec.json',
|
|
stringifyContentPathRegex: '\\.(html|svg)$',
|
|
},
|
|
},
|
|
};`
|
|
);
|
|
|
|
await expect(updateTsConfigTarget(tree)).resolves.not.toThrow();
|
|
|
|
expect(logger.warn).toHaveBeenCalledWith(
|
|
expect.stringContaining(
|
|
`The "<rootDir>/tsconfig.spec.json" file specified in the Jest configuration file "libs/lib1/jest.config.ts" of the "test" target of the "lib1" project could not be found.`
|
|
)
|
|
);
|
|
});
|
|
|
|
it('should not error and log a warning when the jest configuration does not specify the "tsconfig"', async () => {
|
|
jest.spyOn(logger, 'warn');
|
|
addProjectConfiguration(tree, 'lib1', {
|
|
root: 'libs/lib1',
|
|
sourceRoot: 'libs/lib1/src',
|
|
projectType: 'library',
|
|
targets: {
|
|
test: {
|
|
executor: '@nrwl/jest:jest',
|
|
options: { jestConfig: 'libs/lib1/jest.config.ts' },
|
|
},
|
|
},
|
|
});
|
|
projectGraph = {
|
|
dependencies: {
|
|
lib1: [
|
|
{
|
|
type: DependencyType.static,
|
|
source: 'lib1',
|
|
target: 'npm:@angular/core',
|
|
},
|
|
],
|
|
},
|
|
nodes: {},
|
|
};
|
|
tree.write('libs/lib1/jest.config.ts', `export default {};`);
|
|
|
|
await expect(updateTsConfigTarget(tree)).resolves.not.toThrow();
|
|
|
|
expect(logger.warn).toHaveBeenCalledWith(
|
|
expect.stringContaining(
|
|
`Couldn't find the "tsconfig" property for "ts-jest" in the Jest configuration file "libs/lib1/jest.config.ts" specified in the "test" target of the "lib1" project.`
|
|
)
|
|
);
|
|
});
|
|
|
|
it('should not error and log a warning when the jest configuration file does not exist', async () => {
|
|
jest.spyOn(logger, 'warn');
|
|
addProjectConfiguration(tree, 'lib1', {
|
|
root: 'libs/lib1',
|
|
sourceRoot: 'libs/lib1/src',
|
|
projectType: 'library',
|
|
targets: {
|
|
test: {
|
|
executor: '@nrwl/jest:jest',
|
|
options: { jestConfig: 'libs/lib1/jest.config.ts' },
|
|
},
|
|
},
|
|
});
|
|
projectGraph = {
|
|
dependencies: {
|
|
lib1: [
|
|
{
|
|
type: DependencyType.static,
|
|
source: 'lib1',
|
|
target: 'npm:@angular/core',
|
|
},
|
|
],
|
|
},
|
|
nodes: {},
|
|
};
|
|
|
|
await expect(updateTsConfigTarget(tree)).resolves.not.toThrow();
|
|
|
|
expect(logger.warn).toHaveBeenCalledWith(
|
|
expect.stringContaining(
|
|
`The "libs/lib1/jest.config.ts" file specified in the "test" target of the "lib1" project could not be found.`
|
|
)
|
|
);
|
|
});
|
|
|
|
it('should not error and log a warning when the jest configuration file is not specified', async () => {
|
|
jest.spyOn(logger, 'warn');
|
|
addProjectConfiguration(tree, 'lib1', {
|
|
root: 'libs/lib1',
|
|
sourceRoot: 'libs/lib1/src',
|
|
projectType: 'library',
|
|
targets: { test: { executor: '@nrwl/jest:jest', options: {} } },
|
|
});
|
|
projectGraph = {
|
|
dependencies: {
|
|
lib1: [
|
|
{
|
|
type: DependencyType.static,
|
|
source: 'lib1',
|
|
target: 'npm:@angular/core',
|
|
},
|
|
],
|
|
},
|
|
nodes: {},
|
|
};
|
|
|
|
await expect(updateTsConfigTarget(tree)).resolves.not.toThrow();
|
|
|
|
expect(logger.warn).toHaveBeenCalledWith(
|
|
expect.stringContaining(
|
|
`The "test" target of the "lib1" project is using the "@nrwl/jest:jest" executor but no "jestConfig" property was specified.`
|
|
)
|
|
);
|
|
});
|
|
|
|
it.each(['es2021', 'es2022', 'esnext'])(
|
|
'should not update target when it is already set to a target greater than es2020 ("%s")',
|
|
async (target) => {
|
|
addProjectConfiguration(tree, 'app1', {
|
|
root: 'apps/app1',
|
|
sourceRoot: 'apps/app1/src',
|
|
projectType: 'library',
|
|
targets: {
|
|
build: {
|
|
executor: '@angular-devkit/build-angular:browser',
|
|
options: { tsConfig: 'apps/app1/tsconfig.other.json' },
|
|
},
|
|
},
|
|
});
|
|
projectGraph = {
|
|
dependencies: {
|
|
app1: [
|
|
{
|
|
type: DependencyType.static,
|
|
source: 'app1',
|
|
target: 'npm:@angular/core',
|
|
},
|
|
],
|
|
},
|
|
nodes: {},
|
|
};
|
|
writeJson(tree, 'apps/app1/tsconfig.json', {
|
|
compilerOptions: { target },
|
|
});
|
|
|
|
await updateTsConfigTarget(tree);
|
|
|
|
const { compilerOptions } = readJson(tree, 'apps/app1/tsconfig.json');
|
|
expect(compilerOptions.target).toBe(target);
|
|
}
|
|
);
|
|
|
|
it('should not update target in "tsconfig.json" at the project root when it is not an angular project', async () => {
|
|
addProjectConfiguration(tree, 'lib1', {
|
|
root: 'libs/lib1',
|
|
sourceRoot: 'libs/lib1/src',
|
|
projectType: 'library',
|
|
});
|
|
projectGraph = {
|
|
dependencies: {
|
|
lib1: [
|
|
{
|
|
type: DependencyType.static,
|
|
source: 'lib1',
|
|
target: 'npm:lodash',
|
|
},
|
|
],
|
|
},
|
|
nodes: {},
|
|
};
|
|
writeJson(tree, 'libs/lib1/tsconfig.json', {
|
|
compilerOptions: { target: 'es2017' },
|
|
});
|
|
|
|
await updateTsConfigTarget(tree);
|
|
|
|
const { compilerOptions } = readJson(tree, 'libs/lib1/tsconfig.json');
|
|
expect(compilerOptions.target).toBe('es2017');
|
|
});
|
|
|
|
it('should not update target in a tsconfig file referenced by a target option when not using the relevant executors', async () => {
|
|
jest.spyOn(logger, 'warn');
|
|
addProjectConfiguration(tree, 'lib1', {
|
|
root: 'libs/lib1',
|
|
sourceRoot: 'libs/lib1/src',
|
|
projectType: 'library',
|
|
targets: {
|
|
build: {
|
|
executor: '@org/awesome-plugin:executor',
|
|
options: { tsConfig: 'libs/lib1/tsconfig.other.json' },
|
|
},
|
|
},
|
|
});
|
|
projectGraph = {
|
|
dependencies: {
|
|
lib1: [
|
|
{
|
|
type: DependencyType.static,
|
|
source: 'lib1',
|
|
target: 'npm:@angular/core',
|
|
},
|
|
],
|
|
},
|
|
nodes: {},
|
|
};
|
|
writeJson(tree, 'libs/lib1/tsconfig.other.json', {
|
|
compilerOptions: { target: 'es2017' },
|
|
});
|
|
|
|
await updateTsConfigTarget(tree);
|
|
|
|
const { compilerOptions } = readJson(tree, 'libs/lib1/tsconfig.other.json');
|
|
expect(compilerOptions.target).toBe('es2017');
|
|
expect(logger.warn).toHaveBeenCalledWith(
|
|
expect.stringContaining(
|
|
'The "build" target of the "lib1" project is using an executor not supported by the migration.'
|
|
)
|
|
);
|
|
});
|
|
|
|
it('should not update target in a tsconfig file referenced by a target configuration when not using the relevant executors', async () => {
|
|
addProjectConfiguration(tree, 'lib1', {
|
|
root: 'libs/lib1',
|
|
sourceRoot: 'libs/lib1/src',
|
|
projectType: 'library',
|
|
targets: {
|
|
build: {
|
|
executor: '@org/awesome-plugin:executor',
|
|
configurations: {
|
|
production: { tsConfig: 'libs/lib1/tsconfig.other.json' },
|
|
},
|
|
},
|
|
},
|
|
});
|
|
projectGraph = {
|
|
dependencies: {
|
|
lib1: [
|
|
{
|
|
type: DependencyType.static,
|
|
source: 'lib1',
|
|
target: 'npm:@angular/core',
|
|
},
|
|
],
|
|
},
|
|
nodes: {},
|
|
};
|
|
writeJson(tree, 'libs/lib1/tsconfig.other.json', {
|
|
compilerOptions: { target: 'es2017' },
|
|
});
|
|
|
|
await updateTsConfigTarget(tree);
|
|
|
|
const { compilerOptions } = readJson(tree, 'libs/lib1/tsconfig.other.json');
|
|
expect(compilerOptions.target).toBe('es2017');
|
|
});
|
|
|
|
it('should not update target in workspace "tsconfig.base.json"', async () => {
|
|
addProjectConfiguration(tree, 'app1', {
|
|
root: 'apps/app1',
|
|
sourceRoot: 'apps/app1/src',
|
|
projectType: 'application',
|
|
targets: {
|
|
build: {
|
|
executor: '@nrwl/angular:webpack-browser',
|
|
options: { tsConfig: 'apps/app1/tsconfig.json' },
|
|
},
|
|
},
|
|
});
|
|
projectGraph = {
|
|
dependencies: {
|
|
app1: [
|
|
{
|
|
type: DependencyType.static,
|
|
source: 'app1',
|
|
target: 'npm:@angular/core',
|
|
},
|
|
],
|
|
},
|
|
nodes: {},
|
|
};
|
|
writeJson(tree, 'apps/app1/tsconfig.json', {
|
|
compilerOptions: { target: 'es2017' },
|
|
});
|
|
writeJson(tree, 'tsconfig.base.json', {
|
|
compilerOptions: { target: 'es2017' },
|
|
});
|
|
|
|
await updateTsConfigTarget(tree);
|
|
|
|
const { compilerOptions } = readJson(tree, 'tsconfig.base.json');
|
|
expect(compilerOptions.target).toBe('es2017');
|
|
});
|
|
});
|