mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-18 03:23:57 +08:00
Updates for all angular.io links to the new angular.dev domain. Additionally, adjustment to new resources where the equivalent does not exist on the new site (e.g. Tour of Heroes tutorial)
330 lines
12 KiB
TypeScript
330 lines
12 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.dev/license
|
|
*/
|
|
|
|
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
|
|
import { Schema as ApplicationOptions } from '../application/schema';
|
|
import { Schema as WorkspaceOptions } from '../workspace/schema';
|
|
import { Schema as ModuleOptions } from './schema';
|
|
|
|
describe('Module Schematic', () => {
|
|
const schematicRunner = new SchematicTestRunner(
|
|
'@schematics/angular',
|
|
require.resolve('../collection.json'),
|
|
);
|
|
const defaultOptions: ModuleOptions = {
|
|
name: 'foo',
|
|
module: undefined,
|
|
flat: false,
|
|
project: 'bar',
|
|
};
|
|
|
|
const workspaceOptions: WorkspaceOptions = {
|
|
name: 'workspace',
|
|
newProjectRoot: 'projects',
|
|
version: '6.0.0',
|
|
};
|
|
|
|
const appOptions: ApplicationOptions = {
|
|
name: 'bar',
|
|
inlineStyle: false,
|
|
inlineTemplate: false,
|
|
standalone: false,
|
|
routing: true,
|
|
skipTests: false,
|
|
skipPackageJson: false,
|
|
};
|
|
let appTree: UnitTestTree;
|
|
beforeEach(async () => {
|
|
appTree = await schematicRunner.runSchematic('workspace', workspaceOptions);
|
|
appTree = await schematicRunner.runSchematic('application', appOptions, appTree);
|
|
});
|
|
|
|
it('should create a module', async () => {
|
|
const options = { ...defaultOptions };
|
|
|
|
const tree = await schematicRunner.runSchematic('module', options, appTree);
|
|
const files = tree.files;
|
|
expect(files).toContain('/projects/bar/src/app/foo/foo.module.ts');
|
|
});
|
|
|
|
it('should import into another module', async () => {
|
|
const options = { ...defaultOptions, module: 'app.module.ts' };
|
|
|
|
const tree = await schematicRunner.runSchematic('module', options, appTree);
|
|
const content = tree.readContent('/projects/bar/src/app/app.module.ts');
|
|
expect(content).toMatch(/import { FooModule } from '.\/foo\/foo.module'/);
|
|
expect(content).toMatch(/imports: \[[^\]]*FooModule[^\]]*\]/m);
|
|
});
|
|
|
|
it('should import into another module when using flat', async () => {
|
|
const options = { ...defaultOptions, flat: true, module: 'app.module.ts' };
|
|
|
|
const tree = await schematicRunner.runSchematic('module', options, appTree);
|
|
const content = tree.readContent('/projects/bar/src/app/app.module.ts');
|
|
expect(content).toMatch(/import { FooModule } from '.\/foo.module'/);
|
|
expect(content).toMatch(/imports: \[[^\]]*FooModule[^\]]*\]/m);
|
|
});
|
|
|
|
it('should import into another module when using flat', async () => {
|
|
const options = { ...defaultOptions, flat: true, module: 'app.module.ts' };
|
|
|
|
const tree = await schematicRunner.runSchematic('module', options, appTree);
|
|
const content = tree.readContent('/projects/bar/src/app/app.module.ts');
|
|
expect(content).toMatch(/import { FooModule } from '.\/foo.module'/);
|
|
expect(content).toMatch(/imports: \[[^\]]*FooModule[^\]]*\]/m);
|
|
});
|
|
|
|
it('should import into another module (deep)', async () => {
|
|
let tree = appTree;
|
|
|
|
tree = await schematicRunner.runSchematic(
|
|
'module',
|
|
{
|
|
...defaultOptions,
|
|
path: 'projects/bar/src/app/sub1',
|
|
name: 'test1',
|
|
},
|
|
tree,
|
|
);
|
|
tree = await schematicRunner.runSchematic(
|
|
'module',
|
|
{
|
|
...defaultOptions,
|
|
path: 'projects/bar/src/app/sub2',
|
|
name: 'test2',
|
|
module: '../sub1/test1',
|
|
},
|
|
tree,
|
|
);
|
|
|
|
const content = tree.readContent('/projects/bar/src/app/sub1/test1/test1.module.ts');
|
|
expect(content).toMatch(/import { Test2Module } from '..\/..\/sub2\/test2\/test2.module'/);
|
|
});
|
|
|
|
it('should create a routing module', async () => {
|
|
const options = { ...defaultOptions, routing: true };
|
|
|
|
const tree = await schematicRunner.runSchematic('module', options, appTree);
|
|
const files = tree.files;
|
|
expect(files).toContain('/projects/bar/src/app/foo/foo.module.ts');
|
|
expect(files).toContain('/projects/bar/src/app/foo/foo-routing.module.ts');
|
|
const moduleContent = tree.readContent('/projects/bar/src/app/foo/foo.module.ts');
|
|
expect(moduleContent).toMatch(/import { FooRoutingModule } from '.\/foo-routing.module'/);
|
|
const routingModuleContent = tree.readContent(
|
|
'/projects/bar/src/app/foo/foo-routing.module.ts',
|
|
);
|
|
expect(routingModuleContent).toMatch(/RouterModule.forChild\(routes\)/);
|
|
});
|
|
|
|
it('should dasherize a name', async () => {
|
|
const options = { ...defaultOptions, name: 'TwoWord' };
|
|
|
|
const tree = await schematicRunner.runSchematic('module', options, appTree);
|
|
const files = tree.files;
|
|
expect(files).toContain('/projects/bar/src/app/two-word/two-word.module.ts');
|
|
});
|
|
|
|
it('should respect the sourceRoot value', async () => {
|
|
const config = JSON.parse(appTree.readContent('/angular.json'));
|
|
config.projects.bar.sourceRoot = 'projects/bar/custom';
|
|
appTree.overwrite('/angular.json', JSON.stringify(config, null, 2));
|
|
appTree = await schematicRunner.runSchematic('module', defaultOptions, appTree);
|
|
expect(appTree.files).toContain('/projects/bar/custom/app/foo/foo.module.ts');
|
|
});
|
|
|
|
describe('lazy route generator', () => {
|
|
const options = {
|
|
...defaultOptions,
|
|
route: '/new-route',
|
|
module: 'app',
|
|
};
|
|
|
|
it('should generate a lazy loaded module with a routing module', async () => {
|
|
const tree = await schematicRunner.runSchematic('module', options, appTree);
|
|
const files = tree.files;
|
|
|
|
expect(files).toEqual(
|
|
jasmine.arrayContaining([
|
|
'/projects/bar/src/app/foo/foo.module.ts',
|
|
'/projects/bar/src/app/foo/foo-routing.module.ts',
|
|
'/projects/bar/src/app/foo/foo.component.ts',
|
|
'/projects/bar/src/app/foo/foo.component.html',
|
|
'/projects/bar/src/app/foo/foo.component.css',
|
|
]),
|
|
);
|
|
|
|
const appRoutingModuleContent = tree.readContent(
|
|
'/projects/bar/src/app/app-routing.module.ts',
|
|
);
|
|
expect(appRoutingModuleContent).toMatch(
|
|
/path: '\/new-route', loadChildren: \(\) => import\('.\/foo\/foo.module'\).then\(m => m.FooModule\)/,
|
|
);
|
|
|
|
const fooRoutingModuleContent = tree.readContent(
|
|
'/projects/bar/src/app/foo/foo-routing.module.ts',
|
|
);
|
|
expect(fooRoutingModuleContent).toMatch(/RouterModule.forChild\(routes\)/);
|
|
expect(fooRoutingModuleContent).toMatch(
|
|
/const routes: Routes = \[\r?\n?\s*{ path: '', component: FooComponent }\r?\n?\s*\];/,
|
|
);
|
|
});
|
|
|
|
it('should generate a lazy loaded module with embedded route declarations', async () => {
|
|
appTree.overwrite(
|
|
'/projects/bar/src/app/app.module.ts',
|
|
`
|
|
import { NgModule } from '@angular/core';
|
|
import { AppComponent } from './app.component';
|
|
|
|
@NgModule({
|
|
declarations: [
|
|
AppComponent
|
|
],
|
|
imports: [
|
|
BrowserModule,
|
|
RouterModule.forRoot([])
|
|
],
|
|
providers: [],
|
|
bootstrap: [AppComponent]
|
|
})
|
|
export class AppModule { }
|
|
`,
|
|
);
|
|
appTree.delete('/projects/bar/src/app/app-routing.module.ts');
|
|
|
|
const tree = await schematicRunner.runSchematic('module', options, appTree);
|
|
const files = tree.files;
|
|
|
|
expect(files).toContain('/projects/bar/src/app/foo/foo.module.ts');
|
|
expect(files).not.toContain('/projects/bar/src/app/foo/foo-routing.module.ts');
|
|
expect(files).toContain('/projects/bar/src/app/foo/foo.component.ts');
|
|
expect(files).toContain('/projects/bar/src/app/foo/foo.component.html');
|
|
expect(files).toContain('/projects/bar/src/app/foo/foo.component.css');
|
|
|
|
const appModuleContent = tree.readContent('/projects/bar/src/app/app.module.ts');
|
|
expect(appModuleContent).toMatch(
|
|
/path: '\/new-route', loadChildren: \(\) => import\('.\/foo\/foo.module'\).then\(m => m.FooModule\)/,
|
|
);
|
|
|
|
const fooModuleContent = tree.readContent('/projects/bar/src/app/foo/foo.module.ts');
|
|
expect(fooModuleContent).toMatch(/RouterModule.forChild\(routes\)/);
|
|
expect(fooModuleContent).toMatch(
|
|
/const routes: Routes = \[\r?\n?\s*{ path: '', component: FooComponent }\r?\n?\s*\];/,
|
|
);
|
|
});
|
|
|
|
it('should generate a lazy loaded module when "flat" flag is true', async () => {
|
|
const tree = await schematicRunner.runSchematic(
|
|
'module',
|
|
{ ...options, flat: true },
|
|
appTree,
|
|
);
|
|
const files = tree.files;
|
|
|
|
expect(files).toEqual(
|
|
jasmine.arrayContaining([
|
|
'/projects/bar/src/app/foo.module.ts',
|
|
'/projects/bar/src/app/foo-routing.module.ts',
|
|
'/projects/bar/src/app/foo.component.ts',
|
|
'/projects/bar/src/app/foo.component.html',
|
|
'/projects/bar/src/app/foo.component.css',
|
|
]),
|
|
);
|
|
|
|
const appRoutingModuleContent = tree.readContent(
|
|
'/projects/bar/src/app/app-routing.module.ts',
|
|
);
|
|
expect(appRoutingModuleContent).toMatch(
|
|
/path: '\/new-route', loadChildren: \(\) => import\('.\/foo.module'\).then\(m => m.FooModule\)/,
|
|
);
|
|
});
|
|
|
|
it('should generate a lazy loaded module and add route in another parallel routing module', async () => {
|
|
await schematicRunner.runSchematic(
|
|
'module',
|
|
{
|
|
...defaultOptions,
|
|
name: 'foo',
|
|
routing: true,
|
|
},
|
|
appTree,
|
|
);
|
|
|
|
const tree = await schematicRunner.runSchematic(
|
|
'module',
|
|
{
|
|
...defaultOptions,
|
|
name: 'bar',
|
|
module: 'foo',
|
|
route: 'new-route',
|
|
},
|
|
appTree,
|
|
);
|
|
expect(tree.files).toEqual(
|
|
jasmine.arrayContaining([
|
|
'/projects/bar/src/app/foo/foo-routing.module.ts',
|
|
'/projects/bar/src/app/foo/foo.module.ts',
|
|
'/projects/bar/src/app/bar/bar-routing.module.ts',
|
|
'/projects/bar/src/app/bar/bar.module.ts',
|
|
'/projects/bar/src/app/bar/bar.component.ts',
|
|
]),
|
|
);
|
|
|
|
const barRoutingModuleContent = tree.readContent(
|
|
'/projects/bar/src/app/bar/bar-routing.module.ts',
|
|
);
|
|
expect(barRoutingModuleContent).toContain(`path: '', component: BarComponent `);
|
|
|
|
const fooRoutingModuleContent = tree.readContent(
|
|
'/projects/bar/src/app/foo/foo-routing.module.ts',
|
|
);
|
|
expect(fooRoutingModuleContent).toContain(
|
|
`loadChildren: () => import('../bar/bar.module').then(m => m.BarModule)`,
|
|
);
|
|
});
|
|
|
|
it('should not add reference to RouterModule when referencing lazy routing module', async () => {
|
|
// Delete routing module
|
|
appTree.delete('/projects/bar/src/app/app-routing.module.ts');
|
|
|
|
// Update app.module to contain the route config.
|
|
appTree.overwrite(
|
|
'projects/bar/src/app/app.module.ts',
|
|
`
|
|
import { NgModule } from '@angular/core';
|
|
import { RouterModule } from '@angular/router';
|
|
import { BrowserModule } from '@angular/platform-browser';
|
|
import { AppComponent } from './app.component';
|
|
|
|
|
|
@NgModule({
|
|
imports: [BrowserModule, RouterModule.forRoot([])],
|
|
declarations: [AppComponent],
|
|
})
|
|
export class AppModule {}
|
|
`,
|
|
);
|
|
|
|
const tree = await schematicRunner.runSchematic(
|
|
'module',
|
|
{
|
|
...defaultOptions,
|
|
name: 'bar',
|
|
route: 'bar',
|
|
routing: true,
|
|
module: 'app.module.ts',
|
|
},
|
|
appTree,
|
|
);
|
|
const content = tree.readContent('/projects/bar/src/app/bar/bar.module.ts');
|
|
expect(content).toContain('RouterModule.forChild(routes)');
|
|
expect(content).not.toContain('BarRoutingModule');
|
|
});
|
|
});
|
|
});
|