feat(schematics): add schematics for jest
This commit is contained in:
parent
e608211f46
commit
5a547ccadd
@ -1,3 +1,4 @@
|
|||||||
tmp
|
tmp
|
||||||
build
|
build
|
||||||
node_modules
|
node_modules
|
||||||
|
packages/schematics/src/collection/**/files/*.json
|
||||||
41
e2e/schematics/jest.test.ts
Normal file
41
e2e/schematics/jest.test.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import {
|
||||||
|
newProject,
|
||||||
|
runCLI,
|
||||||
|
newLib,
|
||||||
|
copyMissingPackages,
|
||||||
|
updateFile,
|
||||||
|
readJson,
|
||||||
|
runCommand,
|
||||||
|
runCLIAsync
|
||||||
|
} from '../utils';
|
||||||
|
|
||||||
|
describe('Jest', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
newProject();
|
||||||
|
runCLI('generate jest', {
|
||||||
|
silenceError: true
|
||||||
|
});
|
||||||
|
// TODO: remove this hack after there's a version of @nrwl/builders published
|
||||||
|
const packageJson = readJson('package.json');
|
||||||
|
packageJson.devDependencies['@nrwl/builders'] =
|
||||||
|
'../../build/packages/builders';
|
||||||
|
updateFile('package.json', JSON.stringify(packageJson));
|
||||||
|
runCommand('npm install');
|
||||||
|
copyMissingPackages();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(
|
||||||
|
'should be able to generate a testable library using jest',
|
||||||
|
async done => {
|
||||||
|
newLib('jestlib --unit-test-runner jest');
|
||||||
|
await Promise.all([
|
||||||
|
runCLIAsync('generate service test --project jestlib'),
|
||||||
|
runCLIAsync('generate component test --project jestlib')
|
||||||
|
]);
|
||||||
|
const jestResult = await runCLIAsync('test jestlib');
|
||||||
|
expect(jestResult.stderr).toContain('Test Suites: 3 passed, 3 total');
|
||||||
|
done();
|
||||||
|
},
|
||||||
|
10000
|
||||||
|
);
|
||||||
|
});
|
||||||
33
e2e/utils.ts
33
e2e/utils.ts
@ -1,4 +1,4 @@
|
|||||||
import { execSync } from 'child_process';
|
import { execSync, exec } from 'child_process';
|
||||||
import { readFileSync, statSync, writeFileSync } from 'fs';
|
import { readFileSync, statSync, writeFileSync } from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
@ -84,6 +84,37 @@ function copyNodeModule(path: string, name: string) {
|
|||||||
execSync(`cp -a node_modules/${name} tmp/${path}/node_modules/${name}`);
|
execSync(`cp -a node_modules/${name} tmp/${path}/node_modules/${name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function runCommandAsync(
|
||||||
|
command: string,
|
||||||
|
opts = {
|
||||||
|
silenceError: false
|
||||||
|
}
|
||||||
|
): Promise<{ stdout: string; stderr: string }> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
exec(
|
||||||
|
command,
|
||||||
|
{
|
||||||
|
cwd: `./tmp/proj`
|
||||||
|
},
|
||||||
|
(err, stdout, stderr) => {
|
||||||
|
if (!opts.silenceError && err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
resolve({ stdout, stderr });
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runCLIAsync(
|
||||||
|
command: string,
|
||||||
|
opts = {
|
||||||
|
silenceError: false
|
||||||
|
}
|
||||||
|
): Promise<{ stdout: string; stderr: string }> {
|
||||||
|
return runCommandAsync(`./node_modules/.bin/ng ${command}`, opts);
|
||||||
|
}
|
||||||
|
|
||||||
export function runCLI(
|
export function runCLI(
|
||||||
command?: string,
|
command?: string,
|
||||||
opts = {
|
opts = {
|
||||||
|
|||||||
@ -36,6 +36,19 @@
|
|||||||
"description": "Add NgRx support to a module"
|
"description": "Add NgRx support to a module"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"jest": {
|
||||||
|
"factory": "./collection/jest",
|
||||||
|
"schema": "./collection/jest/schema.json",
|
||||||
|
"description": "Add Jest configuration to the workspace"
|
||||||
|
},
|
||||||
|
|
||||||
|
"jest-project": {
|
||||||
|
"factory": "./collection/jest-project",
|
||||||
|
"schema": "./collection/jest-project/schema.json",
|
||||||
|
"description": "Add Jest configuration to a project",
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
|
|
||||||
"upgrade-module": {
|
"upgrade-module": {
|
||||||
"factory": "./collection/upgrade-module",
|
"factory": "./collection/upgrade-module",
|
||||||
"schema": "./collection/upgrade-module/schema.json",
|
"schema": "./collection/upgrade-module/schema.json",
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
name: '<%= project %>',
|
||||||
|
preset: '<%= offsetFromRoot %>jest.config.js',
|
||||||
|
coverageDirectory: '<%= offsetFromRoot %>coverage/<%= projectRoot %>'
|
||||||
|
};
|
||||||
@ -0,0 +1 @@
|
|||||||
|
import 'jest-preset-angular';
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"extends": "<%= offsetFromRoot %>tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "<%= offsetFromRoot %>dist/out-tsc/<%= projectRoot %>",
|
||||||
|
"module": "commonjs",
|
||||||
|
"types": ["jest", "node"]
|
||||||
|
},
|
||||||
|
"files": [<% if(!skipSetupFile) { %>"src/test-setup.ts", <% } %>"src/polyfills.ts"],
|
||||||
|
"include": ["**/*.spec.ts", "**/*.d.ts"]
|
||||||
|
}
|
||||||
96
packages/schematics/src/collection/jest-project/index.ts
Normal file
96
packages/schematics/src/collection/jest-project/index.ts
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
import {
|
||||||
|
Rule,
|
||||||
|
Tree,
|
||||||
|
mergeWith,
|
||||||
|
chain,
|
||||||
|
url,
|
||||||
|
apply,
|
||||||
|
SchematicContext,
|
||||||
|
move,
|
||||||
|
template,
|
||||||
|
noop,
|
||||||
|
filter
|
||||||
|
} from '@angular-devkit/schematics';
|
||||||
|
import {
|
||||||
|
getProjectConfig,
|
||||||
|
readJsonInTree,
|
||||||
|
updateJsonInTree
|
||||||
|
} from '../../utils/ast-utils';
|
||||||
|
import { offsetFromRoot } from '../../utils/common';
|
||||||
|
import { join, normalize } from '@angular-devkit/core';
|
||||||
|
|
||||||
|
export interface JestProjectSchema {
|
||||||
|
project: string;
|
||||||
|
skipSetupFile: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateFiles(options: JestProjectSchema): Rule {
|
||||||
|
return (host, context) => {
|
||||||
|
const projectConfig = getProjectConfig(host, options.project);
|
||||||
|
return mergeWith(
|
||||||
|
apply(url('./files'), [
|
||||||
|
template({
|
||||||
|
tmpl: '',
|
||||||
|
...options,
|
||||||
|
projectRoot: projectConfig.root,
|
||||||
|
offsetFromRoot: offsetFromRoot(projectConfig.root)
|
||||||
|
}),
|
||||||
|
options.skipSetupFile
|
||||||
|
? filter(file => file !== '/src/test-setup.ts')
|
||||||
|
: noop(),
|
||||||
|
move(projectConfig.root)
|
||||||
|
])
|
||||||
|
)(host, context);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateAngularJson(options: JestProjectSchema): Rule {
|
||||||
|
return updateJsonInTree('angular.json', json => {
|
||||||
|
const projectConfig = json.projects[options.project];
|
||||||
|
projectConfig.architect.test = {
|
||||||
|
builder: '@nrwl/builders:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: join(normalize(projectConfig.root), 'jest.config.js'),
|
||||||
|
tsConfig: join(normalize(projectConfig.root), 'tsconfig.spec.json')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (!options.skipSetupFile) {
|
||||||
|
projectConfig.architect.test.options.setupFile = join(
|
||||||
|
normalize(projectConfig.root),
|
||||||
|
'src/test-setup.ts'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (projectConfig.architect.lint) {
|
||||||
|
projectConfig.architect.lint.options.tsConfig = [
|
||||||
|
...projectConfig.architect.lint.options.tsConfig,
|
||||||
|
join(normalize(projectConfig.root), 'tsconfig.spec.json')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function check(options: JestProjectSchema) {
|
||||||
|
return (host: Tree, context: SchematicContext) => {
|
||||||
|
const projectConfig = getProjectConfig(host, options.project);
|
||||||
|
if (projectConfig.architect.test) {
|
||||||
|
throw new Error(
|
||||||
|
`${options.project} already has a test architect option.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const packageJson = readJsonInTree(host, 'package.json');
|
||||||
|
if (!packageJson.devDependencies.jest) {
|
||||||
|
throw new Error(
|
||||||
|
`Your workspace does not have jest installed. Please run "ng generate jest" to setup your workspace to run tests with jest.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function(options: JestProjectSchema): Rule {
|
||||||
|
return chain([
|
||||||
|
check(options),
|
||||||
|
generateFiles(options),
|
||||||
|
updateAngularJson(options)
|
||||||
|
]);
|
||||||
|
}
|
||||||
@ -0,0 +1,169 @@
|
|||||||
|
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
|
||||||
|
import * as path from 'path';
|
||||||
|
import { Tree, VirtualTree } from '@angular-devkit/schematics';
|
||||||
|
import { createEmptyWorkspace } from '../../utils/testing-utils';
|
||||||
|
import { readJsonInTree } from '@nrwl/schematics/src/utils/ast-utils';
|
||||||
|
|
||||||
|
describe('lib', () => {
|
||||||
|
const schematicRunner = new SchematicTestRunner(
|
||||||
|
'@nrwl/schematics',
|
||||||
|
path.join(__dirname, '../../collection.json')
|
||||||
|
);
|
||||||
|
|
||||||
|
let appTree: Tree;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
appTree = new VirtualTree();
|
||||||
|
appTree = createEmptyWorkspace(appTree);
|
||||||
|
appTree = schematicRunner.runSchematic('jest', {}, appTree);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate files', () => {
|
||||||
|
appTree = schematicRunner.runSchematic(
|
||||||
|
'lib',
|
||||||
|
{
|
||||||
|
name: 'lib1',
|
||||||
|
unitTestRunner: 'none'
|
||||||
|
},
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
const resultTree = schematicRunner.runSchematic(
|
||||||
|
'jest-project',
|
||||||
|
{
|
||||||
|
project: 'lib1'
|
||||||
|
},
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
expect(resultTree.exists('/libs/lib1/src/test-setup.ts')).toBeTruthy();
|
||||||
|
expect(resultTree.exists('/libs/lib1/jest.config.js')).toBeTruthy();
|
||||||
|
expect(resultTree.exists('/libs/lib1/tsconfig.spec.json')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should alter angular.json', () => {
|
||||||
|
appTree = schematicRunner.runSchematic(
|
||||||
|
'lib',
|
||||||
|
{
|
||||||
|
name: 'lib1',
|
||||||
|
unitTestRunner: 'none'
|
||||||
|
},
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
const resultTree = schematicRunner.runSchematic(
|
||||||
|
'jest-project',
|
||||||
|
{
|
||||||
|
project: 'lib1'
|
||||||
|
},
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
||||||
|
expect(angularJson.projects.lib1.architect.test).toEqual({
|
||||||
|
builder: '@nrwl/builders:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'libs/lib1/jest.config.js',
|
||||||
|
setupFile: 'libs/lib1/src/test-setup.ts',
|
||||||
|
tsConfig: 'libs/lib1/tsconfig.spec.json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(angularJson.projects.lib1.architect.lint.options.tsConfig).toContain(
|
||||||
|
'libs/lib1/tsconfig.spec.json'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a tsconfig.spec.json', () => {
|
||||||
|
appTree = schematicRunner.runSchematic(
|
||||||
|
'lib',
|
||||||
|
{
|
||||||
|
name: 'lib1',
|
||||||
|
unitTestRunner: 'none'
|
||||||
|
},
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
const resultTree = schematicRunner.runSchematic(
|
||||||
|
'jest-project',
|
||||||
|
{
|
||||||
|
project: 'lib1'
|
||||||
|
},
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
const tsConfig = readJsonInTree(resultTree, 'libs/lib1/tsconfig.spec.json');
|
||||||
|
expect(tsConfig).toEqual({
|
||||||
|
extends: '../../tsconfig.json',
|
||||||
|
compilerOptions: {
|
||||||
|
module: 'commonjs',
|
||||||
|
outDir: '../../dist/out-tsc/libs/lib1',
|
||||||
|
types: ['jest', 'node']
|
||||||
|
},
|
||||||
|
files: ['src/test-setup.ts', 'src/polyfills.ts'],
|
||||||
|
include: ['**/*.spec.ts', '**/*.d.ts']
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('--skip-setup-file', () => {
|
||||||
|
it('should generate src/test-setup.ts', () => {
|
||||||
|
appTree = schematicRunner.runSchematic(
|
||||||
|
'lib',
|
||||||
|
{
|
||||||
|
name: 'lib1',
|
||||||
|
unitTestRunner: 'none'
|
||||||
|
},
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
const resultTree = schematicRunner.runSchematic(
|
||||||
|
'jest-project',
|
||||||
|
{
|
||||||
|
project: 'lib1',
|
||||||
|
skipSetupFile: true
|
||||||
|
},
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
expect(resultTree.exists('src/test-setup.ts')).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not list the setup file in angular.json', () => {
|
||||||
|
appTree = schematicRunner.runSchematic(
|
||||||
|
'lib',
|
||||||
|
{
|
||||||
|
name: 'lib1',
|
||||||
|
unitTestRunner: 'none'
|
||||||
|
},
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
const resultTree = schematicRunner.runSchematic(
|
||||||
|
'jest-project',
|
||||||
|
{
|
||||||
|
project: 'lib1',
|
||||||
|
skipSetupFile: true
|
||||||
|
},
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
||||||
|
expect(
|
||||||
|
angularJson.projects.lib1.architect.test.options.setupFile
|
||||||
|
).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not list the setup file in tsconfig.spec.json', () => {
|
||||||
|
appTree = schematicRunner.runSchematic(
|
||||||
|
'lib',
|
||||||
|
{
|
||||||
|
name: 'lib1',
|
||||||
|
unitTestRunner: 'none'
|
||||||
|
},
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
const resultTree = schematicRunner.runSchematic(
|
||||||
|
'jest-project',
|
||||||
|
{
|
||||||
|
project: 'lib1',
|
||||||
|
skipSetupFile: true
|
||||||
|
},
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
const tsConfig = readJsonInTree(
|
||||||
|
resultTree,
|
||||||
|
'libs/lib1/tsconfig.spec.json'
|
||||||
|
);
|
||||||
|
expect(tsConfig.files).not.toContain('src/test-setup.ts');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
21
packages/schematics/src/collection/jest-project/schema.json
Normal file
21
packages/schematics/src/collection/jest-project/schema.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/schema",
|
||||||
|
"id": "Nx Jest Project Schematics Schema",
|
||||||
|
"title": "Create Jest Configuration for the workspace",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"project": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The name of the project.",
|
||||||
|
"$default": {
|
||||||
|
"$source": "projectName"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"skipSetupFile": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Skips the setup file required for angular",
|
||||||
|
"default": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": []
|
||||||
|
}
|
||||||
10
packages/schematics/src/collection/jest/files/jest.config.js
Normal file
10
packages/schematics/src/collection/jest/files/jest.config.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
module.exports = {
|
||||||
|
testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'],
|
||||||
|
transform: {
|
||||||
|
'^.+\\.(ts|js|html)$': 'jest-preset-angular/preprocessor.js'
|
||||||
|
},
|
||||||
|
resolver: '@nrwl/builders/plugins/jest/resolver',
|
||||||
|
moduleFileExtensions: ['ts', 'js', 'html'],
|
||||||
|
collectCoverage: true,
|
||||||
|
coverageReporters: ['html']
|
||||||
|
};
|
||||||
29
packages/schematics/src/collection/jest/index.ts
Normal file
29
packages/schematics/src/collection/jest/index.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import {
|
||||||
|
mergeWith,
|
||||||
|
SchematicContext,
|
||||||
|
chain,
|
||||||
|
url
|
||||||
|
} from '@angular-devkit/schematics';
|
||||||
|
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
|
||||||
|
import { updateJsonInTree } from '../../utils/ast-utils';
|
||||||
|
import { jestVersion, nxVersion } from '../../lib-versions';
|
||||||
|
import { Rule } from '@angular-devkit/schematics';
|
||||||
|
|
||||||
|
const updatePackageJson = updateJsonInTree('package.json', json => {
|
||||||
|
json.devDependencies = {
|
||||||
|
...json.devDependencies,
|
||||||
|
'@nrwl/builders': nxVersion,
|
||||||
|
jest: jestVersion,
|
||||||
|
'@types/jest': jestVersion,
|
||||||
|
'jest-preset-angular': '6.0.0'
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
function addInstall(_, context: SchematicContext) {
|
||||||
|
context.addTask(new NodePackageInstallTask());
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function(): Rule {
|
||||||
|
return chain([mergeWith(url('./files')), updatePackageJson, addInstall]);
|
||||||
|
}
|
||||||
33
packages/schematics/src/collection/jest/jest.spec.ts
Normal file
33
packages/schematics/src/collection/jest/jest.spec.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
|
||||||
|
import * as path from 'path';
|
||||||
|
import { Tree, VirtualTree } from '@angular-devkit/schematics';
|
||||||
|
import { createEmptyWorkspace, createLib } from '../../utils/testing-utils';
|
||||||
|
import { readJsonInTree } from '@nrwl/schematics/src/utils/ast-utils';
|
||||||
|
|
||||||
|
describe('lib', () => {
|
||||||
|
const schematicRunner = new SchematicTestRunner(
|
||||||
|
'@nrwl/schematics',
|
||||||
|
path.join(__dirname, '../../collection.json')
|
||||||
|
);
|
||||||
|
|
||||||
|
let appTree: Tree;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
appTree = new VirtualTree();
|
||||||
|
appTree = createEmptyWorkspace(appTree);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate files', () => {
|
||||||
|
const resultTree = schematicRunner.runSchematic('jest', {}, appTree);
|
||||||
|
expect(resultTree.exists('jest.config.js')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add dependencies', () => {
|
||||||
|
const resultTree = schematicRunner.runSchematic('jest', {}, appTree);
|
||||||
|
const packageJson = readJsonInTree(resultTree, 'package.json');
|
||||||
|
expect(packageJson.devDependencies.jest).toBeDefined();
|
||||||
|
expect(packageJson.devDependencies['@nrwl/builders']).toBeDefined();
|
||||||
|
expect(packageJson.devDependencies['@types/jest']).toBeDefined();
|
||||||
|
expect(packageJson.devDependencies['jest-preset-angular']).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
8
packages/schematics/src/collection/jest/schema.json
Normal file
8
packages/schematics/src/collection/jest/schema.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/schema",
|
||||||
|
"id": "Nx Jest Schematics Schema",
|
||||||
|
"title": "Create Jest Configuration for the workspace",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {},
|
||||||
|
"required": []
|
||||||
|
}
|
||||||
@ -5,7 +5,8 @@ import {
|
|||||||
noop,
|
noop,
|
||||||
Rule,
|
Rule,
|
||||||
Tree,
|
Tree,
|
||||||
SchematicContext
|
SchematicContext,
|
||||||
|
schematic
|
||||||
} from '@angular-devkit/schematics';
|
} from '@angular-devkit/schematics';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
@ -33,6 +34,7 @@ import {
|
|||||||
import { formatFiles } from '../../utils/rules/format-files';
|
import { formatFiles } from '../../utils/rules/format-files';
|
||||||
import { updateKarmaConf } from '../../utils/rules/update-karma-conf';
|
import { updateKarmaConf } from '../../utils/rules/update-karma-conf';
|
||||||
import { excludeUnnecessaryFiles } from '@nrwl/schematics/src/utils/rules/filter-tree';
|
import { excludeUnnecessaryFiles } from '@nrwl/schematics/src/utils/rules/filter-tree';
|
||||||
|
import { join, normalize } from '@angular-devkit/core';
|
||||||
|
|
||||||
interface NormalizedSchema extends Schema {
|
interface NormalizedSchema extends Schema {
|
||||||
name: string;
|
name: string;
|
||||||
@ -240,6 +242,12 @@ function updateProject(options: NormalizedSchema): Rule {
|
|||||||
host.delete(path.join(options.projectRoot, 'package.json'));
|
host.delete(path.join(options.projectRoot, 'package.json'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.unitTestRunner !== 'karma') {
|
||||||
|
host.delete(path.join(options.projectRoot, 'karma.conf.js'));
|
||||||
|
host.delete(path.join(options.projectRoot, 'src/test.ts'));
|
||||||
|
host.delete(path.join(options.projectRoot, 'tsconfig.spec.json'));
|
||||||
|
}
|
||||||
|
|
||||||
host.overwrite(
|
host.overwrite(
|
||||||
path.join(libRoot, `${options.name}.module.ts`),
|
path.join(libRoot, `${options.name}.module.ts`),
|
||||||
`
|
`
|
||||||
@ -253,26 +261,29 @@ function updateProject(options: NormalizedSchema): Rule {
|
|||||||
export class ${options.moduleName} { }
|
export class ${options.moduleName} { }
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
host.create(
|
|
||||||
path.join(libRoot, `${options.name}.module.spec.ts`),
|
|
||||||
`
|
|
||||||
import { async, TestBed } from '@angular/core/testing';
|
|
||||||
import { ${options.moduleName} } from './${options.name}.module';
|
|
||||||
|
|
||||||
describe('${options.moduleName}', () => {
|
if (options.unitTestRunner !== 'none') {
|
||||||
beforeEach(async(() => {
|
host.create(
|
||||||
TestBed.configureTestingModule({
|
path.join(libRoot, `${options.name}.module.spec.ts`),
|
||||||
imports: [ ${options.moduleName} ]
|
`
|
||||||
})
|
import { async, TestBed } from '@angular/core/testing';
|
||||||
.compileComponents();
|
import { ${options.moduleName} } from './${options.name}.module';
|
||||||
}));
|
|
||||||
|
describe('${options.moduleName}', () => {
|
||||||
it('should create', () => {
|
beforeEach(async(() => {
|
||||||
expect(${options.moduleName}).toBeDefined();
|
TestBed.configureTestingModule({
|
||||||
|
imports: [ ${options.moduleName} ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(${options.moduleName}).toBeDefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
`
|
||||||
`
|
);
|
||||||
);
|
}
|
||||||
host.overwrite(
|
host.overwrite(
|
||||||
`${options.projectRoot}/src/index.ts`,
|
`${options.projectRoot}/src/index.ts`,
|
||||||
`
|
`
|
||||||
@ -293,6 +304,16 @@ describe('${options.moduleName}', () => {
|
|||||||
delete fixedProject.architect.build;
|
delete fixedProject.architect.build;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.unitTestRunner !== 'karma') {
|
||||||
|
delete fixedProject.architect.test;
|
||||||
|
|
||||||
|
fixedProject.architect.lint.options.tsConfig = fixedProject.architect.lint.options.tsConfig.filter(
|
||||||
|
path =>
|
||||||
|
path !==
|
||||||
|
join(normalize(options.projectRoot), 'tsconfig.spec.json')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
json.projects[options.name] = fixedProject;
|
json.projects[options.name] = fixedProject;
|
||||||
return json;
|
return json;
|
||||||
}),
|
}),
|
||||||
@ -309,18 +330,6 @@ describe('${options.moduleName}', () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
updateJsonInTree(`${options.projectRoot}/tsconfig.spec.json`, json => {
|
|
||||||
return {
|
|
||||||
...json,
|
|
||||||
extends: `${offsetFromRoot(options.projectRoot)}tsconfig.json`,
|
|
||||||
compilerOptions: {
|
|
||||||
...json.compilerOptions,
|
|
||||||
outDir: `${offsetFromRoot(options.projectRoot)}dist/out-tsc/${
|
|
||||||
options.projectRoot
|
|
||||||
}`
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
updateJsonInTree(`${options.projectRoot}/tslint.json`, json => {
|
updateJsonInTree(`${options.projectRoot}/tslint.json`, json => {
|
||||||
return {
|
return {
|
||||||
...json,
|
...json,
|
||||||
@ -337,22 +346,43 @@ describe('${options.moduleName}', () => {
|
|||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
updateNgPackage(options),
|
updateNgPackage(options),
|
||||||
host => {
|
options.unitTestRunner === 'karma' ? updateKarmaConfig(options) : noop()
|
||||||
const karma = host
|
|
||||||
.read(`${options.projectRoot}/karma.conf.js`)
|
|
||||||
.toString();
|
|
||||||
host.overwrite(
|
|
||||||
`${options.projectRoot}/karma.conf.js`,
|
|
||||||
karma.replace(
|
|
||||||
`'../../coverage${options.projectRoot}'`,
|
|
||||||
`'${offsetFromRoot(options.projectRoot)}coverage'`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
])(host, null);
|
])(host, null);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateKarmaConfig(options: NormalizedSchema) {
|
||||||
|
return chain([
|
||||||
|
host => {
|
||||||
|
const karma = host
|
||||||
|
.read(`${options.projectRoot}/karma.conf.js`)
|
||||||
|
.toString();
|
||||||
|
host.overwrite(
|
||||||
|
`${options.projectRoot}/karma.conf.js`,
|
||||||
|
karma.replace(
|
||||||
|
`'../../coverage${options.projectRoot}'`,
|
||||||
|
`'${offsetFromRoot(options.projectRoot)}coverage'`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
updateJsonInTree(`${options.projectRoot}/tsconfig.spec.json`, json => {
|
||||||
|
return {
|
||||||
|
...json,
|
||||||
|
extends: `${offsetFromRoot(options.projectRoot)}tsconfig.json`,
|
||||||
|
compilerOptions: {
|
||||||
|
...json.compilerOptions,
|
||||||
|
outDir: `${offsetFromRoot(options.projectRoot)}dist/out-tsc/${
|
||||||
|
options.projectRoot
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
updateKarmaConf({
|
||||||
|
projectName: options.name
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
function updateTsConfig(options: NormalizedSchema): Rule {
|
function updateTsConfig(options: NormalizedSchema): Rule {
|
||||||
return chain([
|
return chain([
|
||||||
(host: Tree, context: SchematicContext) => {
|
(host: Tree, context: SchematicContext) => {
|
||||||
@ -396,10 +426,12 @@ export default function(schema: Schema): Rule {
|
|||||||
|
|
||||||
move(options.name, options.projectRoot),
|
move(options.name, options.projectRoot),
|
||||||
updateProject(options),
|
updateProject(options),
|
||||||
updateKarmaConf({
|
|
||||||
projectName: options.name
|
|
||||||
}),
|
|
||||||
updateTsConfig(options),
|
updateTsConfig(options),
|
||||||
|
options.unitTestRunner === 'jest'
|
||||||
|
? schematic('jest-project', {
|
||||||
|
project: options.name
|
||||||
|
})
|
||||||
|
: noop(),
|
||||||
|
|
||||||
options.publishable ? updateLibPackageNpmScope(options) : noop(),
|
options.publishable ? updateLibPackageNpmScope(options) : noop(),
|
||||||
options.routing && options.lazy
|
options.routing && options.lazy
|
||||||
|
|||||||
@ -47,7 +47,7 @@ describe('lib', () => {
|
|||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const packageJson = readJsonInTree(tree, '/package.json');
|
const packageJson = readJsonInTree(tree, '/package.json');
|
||||||
expect(packageJson.devDependencies).toBeUndefined();
|
expect(packageJson.devDependencies['ng-packagr']).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update package.json when publishable', () => {
|
it('should update package.json when publishable', () => {
|
||||||
@ -392,4 +392,42 @@ describe('lib', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('--unit-test-runner jest', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
appTree = schematicRunner.runSchematic('jest', {}, appTree);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate jest configuration', () => {
|
||||||
|
const resultTree = schematicRunner.runSchematic(
|
||||||
|
'lib',
|
||||||
|
{ name: 'myLib', unitTestRunner: 'jest' },
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
expect(resultTree.exists('libs/my-lib/src/test-setup.ts')).toBeTruthy();
|
||||||
|
expect(resultTree.exists('libs/my-lib/jest.config.js')).toBeTruthy();
|
||||||
|
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
||||||
|
expect(angularJson.projects['my-lib'].architect.test.builder).toEqual(
|
||||||
|
'@nrwl/builders:jest'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('--unit-test-runner none', () => {
|
||||||
|
it('should not generate test configuration', () => {
|
||||||
|
const resultTree = schematicRunner.runSchematic(
|
||||||
|
'lib',
|
||||||
|
{ name: 'myLib', unitTestRunner: 'none' },
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
resultTree.exists('libs/my-lib/src/lib/my-lib.module.spec.ts')
|
||||||
|
).toBeFalsy();
|
||||||
|
expect(resultTree.exists('libs/my-lib/tsconfig.spec.json')).toBeFalsy();
|
||||||
|
expect(resultTree.exists('libs/my-lib/jest.config.js')).toBeFalsy();
|
||||||
|
expect(resultTree.exists('libs/my-lib/karma.config.js')).toBeFalsy();
|
||||||
|
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
||||||
|
expect(angularJson.projects['my-lib'].architect.test).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { UnitTestRunner } from '../../utils/test-runners';
|
||||||
|
|
||||||
export interface Schema {
|
export interface Schema {
|
||||||
name: string;
|
name: string;
|
||||||
skipFormat: boolean;
|
skipFormat: boolean;
|
||||||
@ -14,4 +16,6 @@ export interface Schema {
|
|||||||
lazy?: boolean;
|
lazy?: boolean;
|
||||||
parentModule?: string;
|
parentModule?: string;
|
||||||
tags?: string;
|
tags?: string;
|
||||||
|
|
||||||
|
unitTestRunner: UnitTestRunner;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,6 +61,12 @@
|
|||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Add tags to the library (used for linting)"
|
"description": "Add tags to the library (used for linting)"
|
||||||
|
},
|
||||||
|
"unitTestRunner": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["karma", "jest", "none"],
|
||||||
|
"description": "Test runner to use for unit tests",
|
||||||
|
"default": "karma"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": []
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { UnitTestRunner } from '../../utils/test-runners';
|
||||||
|
|
||||||
export interface Schema {
|
export interface Schema {
|
||||||
directory: string;
|
directory: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
@ -12,6 +12,7 @@ export const latestMigration = '20180507-create-nx-json';
|
|||||||
export const prettierVersion = '1.13.7';
|
export const prettierVersion = '1.13.7';
|
||||||
export const typescriptVersion = '~2.7.2';
|
export const typescriptVersion = '~2.7.2';
|
||||||
export const rxjsVersion = '^6.0.0';
|
export const rxjsVersion = '^6.0.0';
|
||||||
|
export const jestVersion = '^23.0.0';
|
||||||
export const jasmineMarblesVersion = '0.3.1';
|
export const jasmineMarblesVersion = '0.3.1';
|
||||||
|
|
||||||
export const libVersions = {
|
export const libVersions = {
|
||||||
|
|||||||
1
packages/schematics/src/utils/test-runners.ts
Normal file
1
packages/schematics/src/utils/test-runners.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export type UnitTestRunner = 'karma' | 'jest' | 'none';
|
||||||
@ -26,7 +26,13 @@ export function createEmptyWorkspace(tree: Tree): Tree {
|
|||||||
'/angular.json',
|
'/angular.json',
|
||||||
JSON.stringify({ projects: {}, newProjectRoot: '' })
|
JSON.stringify({ projects: {}, newProjectRoot: '' })
|
||||||
);
|
);
|
||||||
tree.create('/package.json', JSON.stringify({}));
|
tree.create(
|
||||||
|
'/package.json',
|
||||||
|
JSON.stringify({
|
||||||
|
dependencies: {},
|
||||||
|
devDependencies: {}
|
||||||
|
})
|
||||||
|
);
|
||||||
tree.create('/nx.json', JSON.stringify({ npmScope: 'proj', projects: {} }));
|
tree.create('/nx.json', JSON.stringify({ npmScope: 'proj', projects: {} }));
|
||||||
tree.create(
|
tree.create(
|
||||||
'/tsconfig.json',
|
'/tsconfig.json',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user