Skip to content

Commit

Permalink
fix(schematics): fix project schematics issues
Browse files Browse the repository at this point in the history
* fix broken schematics test specs
* use getAppModulePath util from '@schematics/angular' instead of defining our own
* use runSchematic instead of runSchematicAsync method becuase it is deprecated
* use runExternalSchematic instead of runExternalSchematicAsync method becuase it is deprecated
  • Loading branch information
Eslam-Gaber645 committed Jul 2, 2023
1 parent f644708 commit b32b83b
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 58 deletions.
82 changes: 38 additions & 44 deletions src/framework/theme/schematics/ng-add/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,19 @@

import {
addModuleImportToRootModule,
getProjectFromWorkspace,
getProjectTargetOptions,
getAppModulePath,
getProjectMainFile,
parseSourceFile,
getAppModulePath,
} from '@angular/cdk/schematics';
import { Tree } from '@angular-devkit/schematics';
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';

import { getFileContent } from '@schematics/angular/utility/test';
import { getWorkspace } from '@schematics/angular/utility/workspace';
import { Schema as WorkspaceOptions } from '@schematics/angular/workspace/schema';
import { Schema as ApplicationOptions, Style } from '@schematics/angular/application/schema';

import { Schema as NgAddOptions } from './schema';
import { getProject, readJSON, readText } from '../util';

const workspaceOptions: WorkspaceOptions = {
name: 'workspace',
Expand Down Expand Up @@ -69,32 +67,38 @@ $nb-themes: nb-register-theme((
`;

async function createTestWorkspace(runner: SchematicTestRunner, appOptions: Partial<ApplicationOptions> = {}) {
const workspace: UnitTestTree = await runner
.runExternalSchematicAsync('@schematics/angular', 'workspace', workspaceOptions)
.toPromise();
const workspace: UnitTestTree = await runner.runExternalSchematic(
'@schematics/angular',
'workspace',
workspaceOptions,
);

const options = { ...defaultAppOptions, ...appOptions };
return runner.runExternalSchematicAsync('@schematics/angular', 'application', options, workspace).toPromise();
return runner.runExternalSchematic('@schematics/angular', 'application', options, workspace);
}

function getPackageDependencies(tree: Tree): any {
const packageJson = JSON.parse(getFileContent(tree, '/package.json'));
const packageJson = readJSON(tree, '/package.json');
return packageJson.dependencies;
}

describe('ng-add', () => {
let runner: SchematicTestRunner;
let appTree: Tree;

function addOptionsDefaults(options: Partial<NgAddOptions>): NgAddOptions {
return { animations: true, customization: true, layout: true, theme: 'default', project: 'nebular', ...options };
}
function runNgAddSchematic(options: Partial<NgAddOptions> = {}) {
return runner.runSchematicAsync('ng-add', options, appTree);
return runner.runSchematic('ng-add', addOptionsDefaults(options), appTree);
}

function runSetupSchematic(options: Partial<NgAddOptions> = {}) {
return runner.runSchematicAsync('setup', options, appTree);
return runner.runSchematic('setup', addOptionsDefaults(options), appTree);
}

function runPostInstallSchematic(options: Partial<NgAddOptions> = {}) {
return runner.runSchematicAsync('post-install', options, appTree);
return runner.runSchematic('post-install', addOptionsDefaults(options), appTree);
}

beforeEach(async () => {
Expand All @@ -107,11 +111,8 @@ describe('ng-add', () => {
describe('ng-add', () => {
let tree: UnitTestTree;

beforeEach((done) => {
runNgAddSchematic().subscribe((applicationTree: UnitTestTree) => {
tree = applicationTree;
done();
});
beforeEach(async () => {
tree = await runNgAddSchematic();
});

it('should add @angular/cdk in package.json', () => {
Expand Down Expand Up @@ -145,7 +146,7 @@ describe('ng-add', () => {
expect(dependencies['@nebular/eva-icons']).toBeDefined();
expect(dependencies['@nebular/eva-icons']).toBe(nebularEvaIconsVersion);

runPostInstallSchematic().subscribe((updatedTree) => {
runPostInstallSchematic().then((updatedTree) => {
dependencies = getPackageDependencies(updatedTree);

const evaIconsVersion = require('../../../eva-icons/package.json').peerDependencies['eva-icons'];
Expand All @@ -156,16 +157,14 @@ describe('ng-add', () => {
});
});

it('should register NbThemeModule.forRoot()', (done) => {
runSetupSchematic().subscribe((tree) => {
const appModuleContent = tree.readContent('/projects/nebular/src/app/app.module.ts');
expect(appModuleContent).toContain(`NbThemeModule.forRoot({ name: 'default' })`);
done();
});
it('should register NbThemeModule.forRoot()', async () => {
const tree = await runSetupSchematic();
const appModuleContent = tree.readContent('/projects/nebular/src/app/app.module.ts');
expect(appModuleContent).toContain(`NbThemeModule.forRoot({ name: 'default' })`);
});

it('should register NbThemeModule with specified theme', (done) => {
runSetupSchematic({ theme: 'cosmic' }).subscribe((tree) => {
runSetupSchematic({ theme: 'cosmic' }).then((tree) => {
const appModuleContent = tree.readContent('/projects/nebular/src/app/app.module.ts');

expect(appModuleContent).toContain(`NbThemeModule.forRoot({ name: 'cosmic' })`);
Expand All @@ -174,7 +173,7 @@ describe('ng-add', () => {
});

it('should register NbLayoutModule', (done) => {
runSetupSchematic().subscribe((tree) => {
runSetupSchematic().then((tree) => {
const appModuleContent = tree.readContent('/projects/nebular/src/app/app.module.ts');

expect(appModuleContent).toContain(`NbLayoutModule`);
Expand All @@ -183,7 +182,7 @@ describe('ng-add', () => {
});

it('should create AppRoutingModule if no Router already registered', (done) => {
runSetupSchematic().subscribe((tree) => {
runSetupSchematic().then((tree) => {
const appModuleContent = tree.readContent('/projects/nebular/src/app/app.module.ts');

expect(appModuleContent).toContain(`AppRoutingModule`);
Expand All @@ -193,9 +192,8 @@ describe('ng-add', () => {
});

it('should register inline theme if no theme already registered', (done) => {
runSetupSchematic({ customization: false }).subscribe(async (tree) => {
const workspace = await getWorkspace(tree);
const project = getProjectFromWorkspace(workspace);
runSetupSchematic({ customization: false }).then(async (tree) => {
const project = await getProject(tree, 'nebular');
const styles = getProjectTargetOptions(project, 'build').styles;

expect(styles).toContain('./node_modules/@nebular/theme/styles/prebuilt/default.css');
Expand All @@ -205,9 +203,9 @@ describe('ng-add', () => {

it('should create theme.scss and plug it into the project', async () => {
appTree = await createTestWorkspace(runner, { style: Style.Scss });
const tree = await runSetupSchematic({ customization: true }).toPromise();
const styles = tree.readContent('/projects/nebular/src/styles.scss');
const themes = tree.readContent('/projects/nebular/src/themes.scss');
const tree = await runSetupSchematic({ customization: true });
const styles = tree?.readContent('/projects/nebular/src/styles.scss');
const themes = tree?.readContent('/projects/nebular/src/themes.scss');

expect(styles).toContain(EXPECTED_STYLES_SCSS);
expect(themes).toContain(EXPECTED_THEME_SCSS);
Expand All @@ -216,15 +214,12 @@ describe('ng-add', () => {
it('should throw error if adding scss themes in css project', async (done) => {
appTree = await createTestWorkspace(runner, { style: Style.Css });

runSetupSchematic({ customization: true }).subscribe({
next: () => done.fail(new Error(`Doesn't throw`)),
error: done,
});
runSetupSchematic({ customization: true }).then(() => done.fail(new Error(`Doesn't throw`)), done);
});

it('should add the BrowserAnimationsModule to the project module', (done) => {
runSetupSchematic({ animations: true }).subscribe((tree) => {
const fileContent = getFileContent(tree, '/projects/nebular/src/app/app.module.ts');
runSetupSchematic({ animations: true }).then((tree) => {
const fileContent = readText(tree, '/projects/nebular/src/app/app.module.ts');

expect(fileContent).toContain(
'BrowserAnimationsModule',
Expand All @@ -235,8 +230,8 @@ describe('ng-add', () => {
});

it('should add the NoopAnimationsModule to the project module', (done) => {
runSetupSchematic({ animations: false }).subscribe((tree) => {
const fileContent = getFileContent(tree, '/projects/nebular/src/app/app.module.ts');
runSetupSchematic({ animations: false }).then((tree) => {
const fileContent = readText(tree, '/projects/nebular/src/app/app.module.ts');

expect(fileContent).toContain(
'NoopAnimationsModule',
Expand All @@ -247,15 +242,14 @@ describe('ng-add', () => {
});

it('should not add NoopAnimationsModule if BrowserAnimationsModule is set up', async () => {
const workspace = await getWorkspace(appTree);
const project = getProjectFromWorkspace(workspace);
const project = await getProject(appTree, 'nebular');

// Simulate the case where a developer uses `ng-add` on an Angular CLI project which already
// explicitly uses the `BrowserAnimationsModule`. It would be wrong to forcibly change
// to noop animations.
addModuleImportToRootModule(appTree, 'BrowserAnimationsModule', '@angular/platform-browser/animations', project);

runSetupSchematic({ animations: false }).subscribe((tree) => {
runSetupSchematic({ animations: false }).then((tree) => {
const appModulePath = getAppModulePath(tree, getProjectMainFile(project));
const fileContent = parseSourceFile(tree, appModulePath);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { chain, Rule, SchematicContext, Tree } from '@angular-devkit/schematics'
import { getRouterModuleDeclaration } from '@schematics/angular/utility/ast-utils';
import {
addModuleImportToRootModule,
getAppModulePath,
getProjectMainFile,
hasNgModuleImport,
parseSourceFile,
Expand All @@ -16,7 +17,7 @@ import { ProjectDefinition } from '@angular-devkit/core/src/workspace';
import { normalize } from '@angular-devkit/core';

import { Schema } from '../schema';
import { getAppModulePath, getProject, isImportedInMainModule } from '../../util';
import { getProject, isImportedInMainModule } from '../../util';
import { appRoutingModuleContent } from './app-routing-module-content';

export function registerModules(options: Schema): Rule {
Expand Down
10 changes: 1 addition & 9 deletions src/framework/theme/schematics/util/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,12 @@
*/

import { Tree } from '@angular-devkit/schematics';
import { dirname, normalize, Path } from '@angular-devkit/core';
import { getProjectMainFile, hasNgModuleImport } from '@angular/cdk/schematics';
import { ProjectDefinition } from '@angular-devkit/core/src/workspace';
import { findBootstrapModulePath } from '@schematics/angular/utility/ng-ast-utils';
import { getAppModulePath } from '@schematics/angular/utility/ng-ast-utils';

export function isImportedInMainModule(tree: Tree, project: ProjectDefinition, moduleName: string): boolean {
const appModulePath = getAppModulePath(tree, getProjectMainFile(project));

return hasNgModuleImport(tree, appModulePath, moduleName);
}

export function getAppModulePath(host: Tree, mainPath: string): string {
const moduleRelativePath = findBootstrapModulePath(host, mainPath);
const mainDir = dirname(mainPath as Path);

return normalize(`/${mainDir}/${moduleRelativePath}.ts`);
}
4 changes: 2 additions & 2 deletions src/framework/theme/schematics/util/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ function getMetadataProperty(metadata: ts.Node, propertyName: string): ts.Proper
const properties = (metadata as ts.ObjectLiteralExpression).properties;
const property = properties
.filter((prop) => prop.kind === ts.SyntaxKind.PropertyAssignment)
.filter((prop: ts.PropertyAssignment) => {
.filter((prop: ts.ObjectLiteralElementLike) => {
const name = prop.name;
switch (name.kind) {
switch (name?.kind) {
case ts.SyntaxKind.Identifier:
return (name as ts.Identifier).getText() === propertyName;
case ts.SyntaxKind.StringLiteral:
Expand Down
2 changes: 1 addition & 1 deletion src/framework/theme/tsconfig.schematics.spec.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"extends": "./tsconfig.schematics.json",
"compilerOptions": {
"types": ["jasmine"]
"types": ["jasmine", "node"]
},
"exclude": ["schematics/*/files/**/*"]
}
2 changes: 1 addition & 1 deletion tools/dev-schematics/new-component/index_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const collectionPath = path.join(__dirname, '../collection.json');
describe('new-component', () => {
it('works', (done) => {
const runner = new SchematicTestRunner('schematics', collectionPath);
runner.runSchematicAsync('new-component', {}, Tree.empty()).subscribe((tree: UnitTestTree) => {
runner.runSchematic('new-component', {}, Tree.empty()).then((tree: UnitTestTree) => {
expect(tree.files).toEqual([]);
done();
});
Expand Down

0 comments on commit b32b83b

Please sign in to comment.