cleanup(angular): migrate karma-project generator to nx devkit (#5822)

This commit is contained in:
Leosvel Pérez Espinosa 2021-05-28 14:08:04 +01:00 committed by GitHub
parent 76a3092891
commit 1f93ebb47a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 368 additions and 347 deletions

View File

@ -1,6 +1,6 @@
# karma-project
Add karma testing to a project
Add karma testing to a project.
## Usage

View File

@ -1,6 +1,6 @@
# karma-project
Add karma testing to a project
Add karma testing to a project.
## Usage

View File

@ -1,6 +1,6 @@
# karma-project
Add karma testing to a project
Add karma testing to a project.
## Usage

View File

@ -32,9 +32,9 @@
},
"karma-project": {
"factory": "./src/schematics/karma-project/karma-project",
"schema": "./src/schematics/karma-project/schema.json",
"description": "Add karma testing to a project"
"factory": "./src/generators/karma-project/compat",
"schema": "./src/generators/karma-project/schema.json",
"description": "Add karma testing to a project."
},
"ngrx": {
@ -134,6 +134,11 @@
"schema": "./src/generators/karma/schema.json",
"description": "Add karma configuration to a workspace."
},
"karma-project": {
"factory": "./src/generators/karma-project/karmar-project",
"schema": "./src/generators/karma-project/schema.json",
"description": "Add karma testing to a project."
},
"move": {
"factory": "./src/generators/move/move#angularMoveGenerator",
"schema": "./src/generators/move/schema.json",

View File

@ -0,0 +1,71 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`karmaProject applications should create a test.ts 1`] = `
"// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: any;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\\\\.spec\\\\.ts$/);
// And load the modules.
context.keys().map(context);
"
`;
exports[`karmaProject library should create a test.ts 1`] = `
"// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone';
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: any;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\\\\.spec\\\\.ts$/);
// And load the modules.
context.keys().map(context);
"
`;
exports[`karmaProject should create a karma.conf.js 1`] = `
"// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
const { join } = require('path');
const getBaseKarmaConfig = require('../../karma.conf');
module.exports = function(config) {
const baseConfig = getBaseKarmaConfig();
config.set({
...baseConfig,
coverageIstanbulReporter: {
...baseConfig.coverageIstanbulReporter,
dir: join(__dirname, '../../coverage/libs/lib1')
}
});
};
"
`;

View File

@ -0,0 +1,4 @@
import { convertNxGenerator } from '@nrwl/devkit';
import { karmaProjectGenerator } from './karma-project';
export default convertNxGenerator(karmaProjectGenerator);

View File

@ -0,0 +1,146 @@
import type { Tree } from '@nrwl/devkit';
import * as devkit from '@nrwl/devkit';
import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import { karmaProjectGenerator } from './karma-project';
describe('karmaProject', () => {
let tree: Tree;
beforeEach(async () => {
tree = createTreeWithEmptyWorkspace();
const libGenerator = wrapAngularDevkitSchematic('@nrwl/angular', 'lib');
await libGenerator(tree, {
name: 'lib1',
unitTestRunner: 'none',
});
const appGenerator = wrapAngularDevkitSchematic('@nrwl/angular', 'app');
await appGenerator(tree, {
name: 'app1',
unitTestRunner: 'none',
});
});
it('should throw when there is already a test target', async () => {
devkit.updateJson(tree, 'workspace.json', (json) => {
json.projects['lib1'].architect.test = {};
return json;
});
await expect(
karmaProjectGenerator(tree, { project: 'lib1' })
).rejects.toThrow('"lib1" already has a test target.');
});
it('should generate files', async () => {
await karmaProjectGenerator(tree, { project: 'lib1' });
expect(tree.exists('/libs/lib1/karma.conf.js')).toBeTruthy();
expect(tree.exists('/libs/lib1/tsconfig.spec.json')).toBeTruthy();
expect(tree.exists('/libs/lib1/src/test.ts')).toBeTruthy();
});
it('should create a karma.conf.js', async () => {
await karmaProjectGenerator(tree, { project: 'lib1' });
const karmaConf = tree.read('libs/lib1/karma.conf.js').toString();
expect(karmaConf).toMatchSnapshot();
});
it('should update the project tsconfig.json to reference the tsconfig.spec.json', async () => {
await karmaProjectGenerator(tree, { project: 'lib1' });
const tsConfig = devkit.readJson(tree, 'libs/lib1/tsconfig.json');
expect(tsConfig.references).toContainEqual({
path: './tsconfig.spec.json',
});
});
it('should format files', async () => {
jest.spyOn(devkit, 'formatFiles');
await karmaProjectGenerator(tree, { project: 'lib1' });
expect(devkit.formatFiles).toHaveBeenCalled();
});
describe('library', () => {
it('should update the workspace config correctly', async () => {
await karmaProjectGenerator(tree, { project: 'lib1' });
const workspaceJson = devkit.readJson(tree, 'workspace.json');
expect(workspaceJson.projects.lib1.architect.test).toEqual({
builder: '@angular-devkit/build-angular:karma',
options: {
main: 'libs/lib1/src/test.ts',
tsConfig: 'libs/lib1/tsconfig.spec.json',
karmaConfig: 'libs/lib1/karma.conf.js',
},
});
});
it('should create a tsconfig.spec.json', async () => {
await karmaProjectGenerator(tree, { project: 'lib1' });
const tsConfig = devkit.readJson(tree, 'libs/lib1/tsconfig.spec.json');
expect(tsConfig).toEqual({
extends: './tsconfig.json',
compilerOptions: {
outDir: '../../dist/out-tsc',
types: ['jasmine', 'node'],
},
files: ['src/test.ts'],
include: ['**/*.spec.ts', '**/*.d.ts'],
});
});
it('should create a test.ts', async () => {
await karmaProjectGenerator(tree, { project: 'lib1' });
const testTs = tree.read('libs/lib1/src/test.ts').toString();
expect(testTs).toMatchSnapshot();
});
});
describe('applications', () => {
it('should update the workspace config correctly', async () => {
await karmaProjectGenerator(tree, { project: 'app1' });
const workspaceJson = devkit.readJson(tree, 'workspace.json');
expect(workspaceJson.projects.app1.architect.test).toEqual({
builder: '@angular-devkit/build-angular:karma',
options: {
main: 'apps/app1/src/test.ts',
polyfills: 'apps/app1/src/polyfills.ts',
tsConfig: 'apps/app1/tsconfig.spec.json',
karmaConfig: 'apps/app1/karma.conf.js',
styles: [],
scripts: [],
assets: [],
},
});
});
it('should create a tsconfig.spec.json', async () => {
await karmaProjectGenerator(tree, { project: 'app1' });
const tsConfig = devkit.readJson(tree, 'apps/app1/tsconfig.spec.json');
expect(tsConfig).toEqual({
extends: './tsconfig.json',
compilerOptions: {
outDir: '../../dist/out-tsc',
types: ['jasmine', 'node'],
},
files: ['src/test.ts', 'src/polyfills.ts'],
include: ['**/*.spec.ts', '**/*.d.ts'],
});
});
it('should create a test.ts', async () => {
await karmaProjectGenerator(tree, { project: 'app1' });
const testTs = tree.read('apps/app1/src/test.ts').toString();
expect(testTs).toMatchSnapshot();
});
});
});

View File

@ -0,0 +1,20 @@
import type { Tree } from '@nrwl/devkit';
import { formatFiles } from '@nrwl/devkit';
import { checkProjectTestTarget } from './lib/check-test-target';
import { generateKarmaProjectFiles } from './lib/generate-karma-project-files';
import { updateTsConfigs } from './lib/update-tsconfig';
import { updateWorkspaceConfig } from './lib/update-workspace-config';
import type { KarmaProjectOptions } from './schema';
export async function karmaProjectGenerator(
tree: Tree,
options: KarmaProjectOptions
) {
checkProjectTestTarget(tree, options.project);
generateKarmaProjectFiles(tree, options.project);
updateTsConfigs(tree, options.project);
updateWorkspaceConfig(tree, options.project);
await formatFiles(tree);
}
export default karmaProjectGenerator;

View File

@ -0,0 +1,9 @@
import type { Tree } from '@nrwl/devkit';
import { readProjectConfiguration } from '@nrwl/devkit';
export function checkProjectTestTarget(tree: Tree, project: string): void {
const projectConfig = readProjectConfiguration(tree, project);
if (projectConfig.targets.test) {
throw new Error(`"${project}" already has a test target.`);
}
}

View File

@ -0,0 +1,22 @@
import type { Tree } from '@nrwl/devkit';
import {
generateFiles,
joinPathFragments,
offsetFromRoot,
readProjectConfiguration,
} from '@nrwl/devkit';
export function generateKarmaProjectFiles(tree: Tree, project: string): void {
const projectConfig = readProjectConfiguration(tree, project);
generateFiles(
tree,
joinPathFragments(__dirname, '..', 'files'),
projectConfig.root,
{
tmpl: '',
projectRoot: projectConfig.root,
isLibrary: projectConfig.projectType === 'library',
offsetFromRoot: offsetFromRoot(projectConfig.root),
}
);
}

View File

@ -0,0 +1,39 @@
import type { Tree } from '@nrwl/devkit';
import {
joinPathFragments,
readProjectConfiguration,
updateJson,
} from '@nrwl/devkit';
export function updateTsConfigs(tree: Tree, project: string): void {
const projectConfig = readProjectConfiguration(tree, project);
updateJson(
tree,
joinPathFragments(projectConfig.root, 'tsconfig.json'),
(json) => {
return {
...json,
references: [
...(json.references || []),
{
path: './tsconfig.spec.json',
},
],
};
}
);
const extraFiles =
projectConfig.projectType === 'library' ? [] : ['src/polyfills.ts'];
return updateJson(
tree,
joinPathFragments(projectConfig.root, 'tsconfig.spec.json'),
(json) => {
return {
...json,
files: [...json.files, ...extraFiles],
};
}
);
}

View File

@ -0,0 +1,41 @@
import type { Tree } from '@nrwl/devkit';
import {
joinPathFragments,
readProjectConfiguration,
updateProjectConfiguration,
} from '@nrwl/devkit';
export function updateWorkspaceConfig(tree: Tree, project: string): void {
const projectConfig = readProjectConfiguration(tree, project);
projectConfig.targets.test = {
executor: '@angular-devkit/build-angular:karma',
options: {
main: joinPathFragments(projectConfig.sourceRoot, 'test.ts'),
tsConfig: joinPathFragments(projectConfig.root, 'tsconfig.spec.json'),
karmaConfig: joinPathFragments(projectConfig.root, 'karma.conf.js'),
},
};
if (projectConfig.projectType === 'application') {
projectConfig.targets.test.options = {
...projectConfig.targets.test.options,
polyfills: joinPathFragments(projectConfig.sourceRoot, 'polyfills.ts'),
styles: [],
scripts: [],
assets: [],
};
}
if (
projectConfig.targets.lint &&
projectConfig.targets.lint.executor ===
'@angular-devkit/build-angular:tslint'
) {
projectConfig.targets.lint.options.tsConfig = [
...projectConfig.targets.lint.options.tsConfig,
joinPathFragments(projectConfig.root, 'tsconfig.spec.json'),
];
}
updateProjectConfiguration(tree, project, projectConfig);
}

View File

@ -0,0 +1,3 @@
export interface KarmaProjectOptions {
project: string;
}

View File

@ -1,7 +1,8 @@
{
"$schema": "http://json-schema.org/schema",
"$id": "SchematicsNxKarmaProject",
"$id": "NxKarmaProjectGenerator",
"title": "Create Karma Configuration for a project",
"cli": "nx",
"type": "object",
"properties": {
"project": {

View File

@ -1,199 +0,0 @@
import { Tree } from '@angular-devkit/schematics';
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
import { runSchematic } from '../../utils/testing';
import { readJsonInTree } from '@nrwl/workspace';
describe('karmaProject', () => {
let appTree: Tree;
beforeEach(async () => {
appTree = Tree.empty();
appTree = createEmptyWorkspace(appTree);
appTree = await runSchematic(
'lib',
{
name: 'lib1',
unitTestRunner: 'none',
},
appTree
);
appTree = await runSchematic(
'app',
{
name: 'app1',
unitTestRunner: 'none',
},
appTree
);
});
it('should generate files', async () => {
const resultTree = await runSchematic(
'karma-project',
{
project: 'lib1',
},
appTree
);
expect(resultTree.exists('/libs/lib1/karma.conf.js')).toBeTruthy();
expect(resultTree.exists('/libs/lib1/tsconfig.spec.json')).toBeTruthy();
});
it('should create a karma.conf.js', async () => {
const resultTree = await runSchematic(
'karma-project',
{
project: 'lib1',
},
appTree
);
expect(resultTree.readContent('libs/lib1/karma.conf.js'))
.toBe(`// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
const { join } = require('path');
const getBaseKarmaConfig = require('../../karma.conf');
module.exports = function(config) {
const baseConfig = getBaseKarmaConfig();
config.set({
...baseConfig,
coverageIstanbulReporter: {
...baseConfig.coverageIstanbulReporter,
dir: join(__dirname, '../../coverage/libs/lib1')
}
});
};
`);
});
it('should update the local tsconfig.json', async () => {
const resultTree = await runSchematic(
'karma-project',
{
project: 'lib1',
},
appTree
);
const tsConfig = readJsonInTree(resultTree, 'libs/lib1/tsconfig.json');
expect(tsConfig.references).toContainEqual({
path: './tsconfig.spec.json',
});
});
describe('library', () => {
it('should alter workspace.json', async () => {
const resultTree = await runSchematic(
'karma-project',
{
project: 'lib1',
},
appTree
);
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
expect(workspaceJson.projects.lib1.architect.test).toEqual({
builder: '@angular-devkit/build-angular:karma',
options: {
main: 'libs/lib1/src/test.ts',
tsConfig: 'libs/lib1/tsconfig.spec.json',
karmaConfig: 'libs/lib1/karma.conf.js',
},
});
});
it('should create a tsconfig.spec.json', async () => {
const resultTree = await runSchematic(
'karma-project',
{
project: 'lib1',
},
appTree
);
const tsConfig = readJsonInTree(
resultTree,
'libs/lib1/tsconfig.spec.json'
);
expect(tsConfig).toEqual({
extends: './tsconfig.json',
compilerOptions: {
outDir: '../../dist/out-tsc',
types: ['jasmine', 'node'],
},
files: ['src/test.ts'],
include: ['**/*.spec.ts', '**/*.d.ts'],
});
});
it('should create test.ts', async () => {
const resultTree = await runSchematic(
'karma-project',
{
project: 'lib1',
},
appTree
);
const testTs = resultTree.read('libs/lib1/src/test.ts').toString();
expect(testTs).toContain("import 'zone.js/dist/zone';");
});
});
describe('applications', () => {
it('should alter workspace.json', async () => {
const resultTree = await runSchematic(
'karma-project',
{
project: 'app1',
},
appTree
);
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
expect(workspaceJson.projects.app1.architect.test).toEqual({
builder: '@angular-devkit/build-angular:karma',
options: {
main: 'apps/app1/src/test.ts',
polyfills: 'apps/app1/src/polyfills.ts',
tsConfig: 'apps/app1/tsconfig.spec.json',
karmaConfig: 'apps/app1/karma.conf.js',
styles: [],
scripts: [],
assets: [],
},
});
});
it('should create a tsconfig.spec.json', async () => {
const resultTree = await runSchematic(
'karma-project',
{
project: 'app1',
},
appTree
);
const tsConfig = readJsonInTree(
resultTree,
'apps/app1/tsconfig.spec.json'
);
expect(tsConfig).toEqual({
extends: './tsconfig.json',
compilerOptions: {
outDir: '../../dist/out-tsc',
types: ['jasmine', 'node'],
},
files: ['src/test.ts', 'src/polyfills.ts'],
include: ['**/*.spec.ts', '**/*.d.ts'],
});
});
it('should create test.ts', async () => {
const resultTree = await runSchematic(
'karma-project',
{
project: 'app1',
},
appTree
);
const testTs = resultTree.read('apps/app1/src/test.ts').toString();
expect(testTs).not.toContain("import 'zone.js/dist/zone';");
});
});
});

View File

@ -1,141 +0,0 @@
import {
apply,
chain,
mergeWith,
move,
Rule,
template,
Tree,
url,
} from '@angular-devkit/schematics';
import {
getProjectConfig,
updateJsonInTree,
updateWorkspaceInTree,
} from '@nrwl/workspace';
import { join, normalize } from '@angular-devkit/core';
import { offsetFromRoot } from '@nrwl/devkit';
import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter';
export interface KarmaProjectSchema {
project: string;
}
// TODO: @jjean implement skipSetupFile
function generateFiles(options: KarmaProjectSchema): Rule {
return (host, context) => {
const projectConfig = getProjectConfig(host, options.project);
return mergeWith(
apply(url('./files'), [
template({
tmpl: '',
...options,
projectRoot: projectConfig.root,
isLibrary: projectConfig.projectType === 'library',
offsetFromRoot: offsetFromRoot(projectConfig.root),
}),
move(projectConfig.root),
])
)(host, context);
};
}
function updateTsConfig(options: KarmaProjectSchema): Rule {
return (host: Tree) => {
const projectConfig = getProjectConfig(host, options.project);
return updateJsonInTree(
join(projectConfig.root, 'tsconfig.json'),
(json) => {
return {
...json,
references: [
...(json.references || []),
{
path: './tsconfig.spec.json',
},
],
};
}
);
};
}
function updateTsSpecConfig(options: KarmaProjectSchema): Rule {
return (host: Tree) => {
const projectConfig = getProjectConfig(host, options.project);
const extraFiles =
projectConfig.projectType === 'library' ? [] : ['src/polyfills.ts'];
return updateJsonInTree(
join(projectConfig.root, 'tsconfig.spec.json'),
(json) => {
return {
...json,
files: [...json.files, ...extraFiles],
};
}
);
};
}
function updateworkspaceJson(options: KarmaProjectSchema): Rule {
return updateWorkspaceInTree((json) => {
const projectConfig = json.projects[options.project];
projectConfig.architect.test = {
builder: '@angular-devkit/build-angular:karma',
options: {
main: join(normalize(projectConfig.sourceRoot), 'test.ts'),
tsConfig: join(normalize(projectConfig.root), 'tsconfig.spec.json'),
karmaConfig: join(normalize(projectConfig.root), 'karma.conf.js'),
},
};
if (projectConfig.projectType === 'application') {
projectConfig.architect.test.options = {
...projectConfig.architect.test.options,
polyfills: join(normalize(projectConfig.sourceRoot), 'polyfills.ts'),
styles: [],
scripts: [],
assets: [],
};
}
if (
projectConfig.architect.lint &&
projectConfig.architect.lint.builder ===
'@angular-devkit/build-angular:tslint'
) {
projectConfig.architect.lint.options.tsConfig = [
...projectConfig.architect.lint.options.tsConfig,
join(normalize(projectConfig.root), 'tsconfig.spec.json'),
];
}
return json;
});
}
function check(options: KarmaProjectSchema): Rule {
return (host: Tree) => {
const projectConfig = getProjectConfig(host, options.project);
if (projectConfig.architect.test) {
throw new Error(
`${options.project} already has a test architect option.`
);
}
};
}
export default function (options: KarmaProjectSchema): Rule {
return chain([
check(options),
generateFiles(options),
updateTsConfig(options),
updateTsSpecConfig(options),
updateworkspaceJson(options),
]);
}
export const karmaProjectGenerator = wrapAngularDevkitSchematic(
'@nrwl/angular',
'karma-project'
);