devextreme-schematics 1.2.18 → 1.2.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. package/package.json +2 -2
  2. package/src/add-app-template/index.ts +30 -0
  3. package/src/add-app-template/index_spec.ts +73 -0
  4. package/src/add-layout/files/e2e/src/app.e2e-spec.ts +14 -14
  5. package/src/add-layout/files/e2e/src/app.po.ts +11 -11
  6. package/src/add-layout/files/src/app/app-navigation.ts +1 -1
  7. package/src/add-layout/files/src/app/layouts/index.ts +3 -3
  8. package/src/add-layout/files/src/app/shared/components/change-password-form/change-password-form.component.html +8 -6
  9. package/src/add-layout/files/src/app/shared/components/create-account-form/create-account-form.component.html +9 -7
  10. package/src/add-layout/files/src/app/shared/components/footer/footer.component.ts +19 -19
  11. package/src/add-layout/files/src/app/shared/components/login-form/login-form.component.html +8 -6
  12. package/src/add-layout/files/src/app/shared/components/reset-password-form/reset-password-form.component.html +8 -6
  13. package/src/add-layout/index.ts +386 -0
  14. package/src/add-layout/index_spec.ts +340 -0
  15. package/src/add-sample-views/files/pages/home/home.component.ts +10 -10
  16. package/src/add-sample-views/files/pages/profile/profile.component.ts +33 -33
  17. package/src/add-sample-views/index.ts +141 -0
  18. package/src/add-sample-views/index_spec.ts +74 -0
  19. package/src/add-view/index.ts +165 -0
  20. package/src/add-view/index_spec.ts +155 -0
  21. package/src/install/index.ts +86 -0
  22. package/src/install/index_spec.ts +106 -0
  23. package/src/install/schema.json +1 -1
  24. package/src/utility/array.ts +3 -0
  25. package/src/utility/change.js +1 -1
  26. package/src/utility/change.ts +66 -0
  27. package/src/utility/latest-versions.js +2 -2
  28. package/src/utility/latest-versions.ts +6 -0
  29. package/src/utility/modify-json-file.ts +13 -0
  30. package/src/utility/project.ts +25 -0
  31. package/src/utility/routing.js +4 -4
  32. package/src/utility/routing.ts +44 -0
  33. package/src/utility/source.ts +16 -0
  34. package/src/utility/string.ts +5 -0
  35. package/src/utility/styles.ts +33 -0
@@ -0,0 +1,340 @@
1
+ import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
2
+ import { Schema as WorkspaceOptions } from '@schematics/angular/workspace/schema';
3
+ import {
4
+ NodeDependencyType,
5
+ addPackageJsonDependency,
6
+ removePackageJsonDependency
7
+ } from '@schematics/angular/utility/dependencies';
8
+ import * as path from 'path';
9
+
10
+ import { modifyJSONFile } from '../utility/modify-json-file';
11
+
12
+ const collectionPath = path.join(__dirname, '../collection.json');
13
+
14
+ describe('layout', () => {
15
+ const appOptions: any = {
16
+ name: 'testApp',
17
+ projectRoot: '',
18
+ inlineStyle: false,
19
+ inlineTemplate: false,
20
+ routing: false,
21
+ style: 'scss',
22
+ skipTests: false,
23
+ skipPackageJson: false
24
+ };
25
+
26
+ const workspaceOptions: WorkspaceOptions = {
27
+ name: 'workspace',
28
+ version: '6.0.0'
29
+ };
30
+
31
+ const options: any = {
32
+ layout: 'side-nav-outer-toolbar',
33
+ resolveConflicts: 'override',
34
+ globalNgCliVersion: '^8.0.0'
35
+ };
36
+
37
+ const angularSchematicsCollection = require.resolve('../../node_modules/@schematics/angular/collection.json');
38
+ const schematicRunner = new SchematicTestRunner('@schematics/angular', angularSchematicsCollection);
39
+ let appTree: UnitTestTree;
40
+
41
+ beforeEach(async () => {
42
+ appTree = await schematicRunner.runSchematicAsync('workspace', workspaceOptions).toPromise();
43
+ appTree = await schematicRunner.runSchematicAsync('application', appOptions, appTree).toPromise();
44
+ });
45
+
46
+ it('should add layout with override', async () => {
47
+ const runner = new SchematicTestRunner('schematics', collectionPath);
48
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
49
+
50
+ expect(tree.files)
51
+ .toContain('/devextreme.json');
52
+ expect(tree.files)
53
+ .toContain('/src/app/app-navigation.ts');
54
+ expect(tree.files)
55
+ .toContain('/src/app/shared/components/header/header.component.ts');
56
+ expect(tree.files)
57
+ .toContain('/src/app/shared/components/login-form/login-form.component.ts');
58
+ expect(tree.files)
59
+ .toContain('/src/app/shared/components/side-navigation-menu/side-navigation-menu.component.ts');
60
+ expect(tree.files)
61
+ .toContain('/src/app/shared/services/app-info.service.ts');
62
+ expect(tree.files)
63
+ .toContain('/src/app/shared/services/auth.service.ts');
64
+ expect(tree.files)
65
+ .toContain('/src/app/shared/services/screen.service.ts');
66
+ expect(tree.files)
67
+ .toContain('/src/app/layouts/side-nav-outer-toolbar/side-nav-outer-toolbar.component.ts');
68
+ expect(tree.files)
69
+ .toContain('/src/app/layouts/side-nav-inner-toolbar/side-nav-inner-toolbar.component.ts');
70
+ expect(tree.files)
71
+ .toContain('/src/app/layouts/single-card/single-card.component.ts');
72
+ expect(tree.files)
73
+ .toContain('/src/themes/metadata.base.json');
74
+ expect(tree.files)
75
+ .toContain('/src/themes/metadata.additional.json');
76
+
77
+ const devextremeConfigContent = tree.readContent('/devextreme.json');
78
+ expect(devextremeConfigContent).toContain('"applicationEngine": "angular"');
79
+ expect(devextremeConfigContent).toContain('"inputFile": "src/themes/metadata.additional.json"');
80
+ expect(devextremeConfigContent).toMatch(/\n\s{2}\S/g);
81
+
82
+ const componentContent = tree.readContent('/src/app/app.component.html');
83
+ expect(componentContent).toContain('app-side-nav-outer-toolbar title="{{appInfo.title}}"');
84
+
85
+ const stylesContent = tree.readContent('/src/dx-styles.scss');
86
+ expect(stylesContent).toMatch(/html, body {/);
87
+
88
+ const indexContent = tree.readContent('/src/index.html');
89
+ expect(indexContent).toMatch(/<body class="dx-viewport">/);
90
+
91
+ const angularContent = JSON.parse(tree.readContent('/angular.json'));
92
+ const styles = angularContent.projects.testApp.architect.build.options.styles;
93
+
94
+ expect(styles[0]).toBe('node_modules/devextreme/dist/css/dx.common.css');
95
+ expect(styles[1]).toBe('src/themes/generated/theme.base.css');
96
+ expect(styles[2]).toBe('src/themes/generated/theme.additional.css');
97
+
98
+ const moduleContent = tree.readContent('/src/app/app.module.ts');
99
+ expect(moduleContent)
100
+ .toContain('import { SideNavOuterToolbarModule, SideNavInnerToolbarModule, SingleCardModule }');
101
+ expect(moduleContent)
102
+ .toContain(`import { AuthService, ScreenService, AppInfoService } from './shared/services';`);
103
+ expect(moduleContent).toContain('import { AppRoutingModule }');
104
+ expect(moduleContent)
105
+ .toContain('import { FooterModule, ' +
106
+ 'ResetPasswordFormModule, ' +
107
+ 'CreateAccountFormModule, ' +
108
+ 'ChangePasswordFormModule, ' +
109
+ 'LoginFormModule }');
110
+
111
+ const testContent = tree.readContent('/e2e/src/app.e2e-spec.ts');
112
+ expect(testContent).toMatch(/'Welcome to TestApp!'/);
113
+
114
+ const testUtilsContent = tree.readContent('/e2e/src/app.po.ts');
115
+ expect(testUtilsContent).toMatch(/'app-root .dx-drawer-content .dx-card p:nth-child\(2\)'/);
116
+
117
+ const appContent = tree.readContent('/src/app/app.component.ts');
118
+ expect(appContent).toContain('templateUrl: \'./app.component.html\',');
119
+ expect(appContent).toContain('styleUrls: [\'./app.component.scss\']');
120
+ expect(appContent).toContain('selector: \'app-root\',');
121
+ expect(appContent).toContain(`import { AuthService, ScreenService, AppInfoService } from './shared/services';`);
122
+
123
+ const navigationMenu = tree.readContent(
124
+ '/src/app/shared/components/side-navigation-menu/side-navigation-menu.component.ts');
125
+ expect(navigationMenu).toContain('@ViewChild(DxTreeViewComponent, { static: true })');
126
+ });
127
+
128
+ it('should add npm scripts', async () => {
129
+ const runner = new SchematicTestRunner('schematics', collectionPath);
130
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
131
+ const packageConfig = JSON.parse(tree.readContent('package.json'));
132
+ expect(packageConfig.scripts['build-themes']).toBe('devextreme build');
133
+ expect(packageConfig.scripts['postinstall']).toBe('npm run build-themes');
134
+ });
135
+
136
+ it('should set static flag', async () => {
137
+ removePackageJsonDependency(appTree, '@angular/core');
138
+ addPackageJsonDependency(appTree, {
139
+ type: NodeDependencyType.Default,
140
+ name: '@angular/core',
141
+ version: '7.0.0'
142
+ });
143
+
144
+ const runner = new SchematicTestRunner('schematics', collectionPath);
145
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
146
+ const navigationMenu = tree.readContent(
147
+ '/src/app/shared/components/side-navigation-menu/side-navigation-menu.component.ts');
148
+
149
+ expect(navigationMenu).toContain('@ViewChild(DxTreeViewComponent, { static: true })');
150
+ });
151
+
152
+ it('should add npm scripts safely', async () => {
153
+ modifyJSONFile(appTree, './package.json', config => {
154
+ const scripts = config['scripts'];
155
+
156
+ scripts['build-themes'] = 'prev value 1';
157
+ scripts['postinstall'] = 'prev value 2';
158
+
159
+ return config;
160
+ });
161
+
162
+ const runner = new SchematicTestRunner('schematics', collectionPath);
163
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
164
+ const packageConfig = JSON.parse(tree.readContent('package.json'));
165
+ expect(packageConfig.scripts['origin-build-themes']).toBe('prev value 1');
166
+ expect(packageConfig.scripts['origin-postinstall']).toBe('prev value 2');
167
+ expect(packageConfig.scripts['build-themes']).toBe('npm run origin-build-themes && devextreme build');
168
+ expect(packageConfig.scripts['postinstall']).toBe('npm run origin-postinstall && npm run build-themes');
169
+ });
170
+
171
+ it('should add angular/cdk dependency', async () => {
172
+ const runner = new SchematicTestRunner('schematics', collectionPath);
173
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
174
+ const packageConfig = JSON.parse(tree.readContent('package.json'));
175
+
176
+ expect(packageConfig.dependencies['@angular/cdk']).toBeDefined();
177
+ });
178
+
179
+ it('should choose angular/cdk version such as angular/cli', async () => {
180
+ const runner = new SchematicTestRunner('schematics', collectionPath);
181
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
182
+ const packageConfig = JSON.parse(tree.readContent('package.json'));
183
+
184
+ expect(packageConfig.dependencies['@angular/cdk']).toBe('^8.0.0');
185
+ });
186
+
187
+ it('should update budgets if updateBudgets option is true', async () => {
188
+ const runner = new SchematicTestRunner('schematics', collectionPath);
189
+ const tree = await runner.runSchematicAsync('add-layout', {
190
+ ...options,
191
+ updateBudgets: true
192
+ }, appTree).toPromise();
193
+
194
+ const angularContent = JSON.parse(tree.readContent('/angular.json'));
195
+ const budgets = angularContent.projects.testApp.architect.build.configurations.production.budgets;
196
+
197
+ expect(budgets.length).toBe(2);
198
+ expect(budgets[0]).toEqual({
199
+ type: 'initial',
200
+ maximumWarning: '4mb',
201
+ maximumError: '7mb'
202
+ });
203
+ });
204
+
205
+ it('should not update budgets if updateBudgets option is not defined or false', async () => {
206
+ const runner = new SchematicTestRunner('schematics', collectionPath);
207
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
208
+
209
+ const angularContent = JSON.parse(tree.readContent('/angular.json'));
210
+ const budgets = angularContent.projects.testApp.architect.build.configurations.production.budgets;
211
+ const defaultBudget = {
212
+ type: 'initial',
213
+ maximumWarning: '2mb',
214
+ maximumError: '5mb'
215
+ };
216
+
217
+ expect(budgets.length).toBe(2);
218
+ expect(budgets[0]).toEqual(defaultBudget);
219
+ });
220
+
221
+ it('should add layout without override', async () => {
222
+ const runner = new SchematicTestRunner('schematics', collectionPath);
223
+
224
+ options.resolveConflicts = 'createNew';
225
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
226
+
227
+ expect(tree.files).toContain('/src/app/app1.component.ts');
228
+
229
+ const componentContent = tree.readContent('/src/app/app1.component.html');
230
+ expect(componentContent).toContain('app-side-nav-outer-toolbar title="{{appInfo.title}}"');
231
+
232
+ const appContent = tree.readContent('/src/app/app.component.ts');
233
+ expect(appContent).toMatch(/templateUrl: '.\/app.component.html',/);
234
+ expect(appContent).toMatch(/styleUrls: \['.\/app.component.scss'\]/);
235
+
236
+ const newAppContent = tree.readContent('/src/app/app1.component.ts');
237
+ expect(newAppContent).toMatch(/templateUrl: '.\/app1.component.html',/);
238
+ expect(newAppContent).toMatch(/styleUrls: \['.\/app1.component.scss'\]/);
239
+ expect(newAppContent).toContain(`import { AuthService, ScreenService, AppInfoService } from './shared/services';`);
240
+
241
+ const appInfo = tree.readContent('/src/app/shared/services/app-info.service.ts');
242
+ expect(appInfo).toContain(`return 'TestApp';`);
243
+ });
244
+
245
+ it('should add routing to layout', async () => {
246
+ let newAppTree = await schematicRunner.runSchematicAsync('workspace', workspaceOptions).toPromise();
247
+
248
+ appOptions.routing = false;
249
+ newAppTree = await schematicRunner.runSchematicAsync(
250
+ 'application', appOptions, newAppTree).toPromise();
251
+
252
+ const runner = new SchematicTestRunner('schematics', collectionPath);
253
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
254
+
255
+ expect(tree.files).toContain('/src/app/app-routing.module.ts');
256
+ const moduleContent = tree.readContent('/src/app/app-routing.module.ts');
257
+ expect(moduleContent)
258
+ .toMatch(/imports:\s\[RouterModule\.forRoot\(routes, { useHash: true }\)\],/);
259
+
260
+ expect(moduleContent)
261
+ .toContain(`{
262
+ path: 'login-form',
263
+ component: LoginFormComponent,
264
+ canActivate: [ AuthGuardService ]
265
+ }`);
266
+ });
267
+
268
+ it('should use selected layout', async () => {
269
+ const runner = new SchematicTestRunner('schematics', collectionPath);
270
+ options.layout = 'side-nav-inner-toolbar';
271
+ options.resolveConflicts = 'override';
272
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
273
+ const content = tree.readContent('/src/app/app.component.html');
274
+
275
+ expect(content).toContain('app-side-nav-inner-toolbar title="{{appInfo.title}}"');
276
+ });
277
+
278
+ it('should consider the `project` option', async () => {
279
+ appTree = await schematicRunner.runSchematicAsync('application', {
280
+ ...appOptions,
281
+ name: 'testApp2',
282
+ projectRoot: 'projects/testApp2'
283
+ }, appTree).toPromise();
284
+
285
+ const runner = new SchematicTestRunner('schematics', collectionPath);
286
+ const tree = await runner.runSchematicAsync('add-layout', {
287
+ ...options,
288
+ project: 'testApp2'
289
+ }, appTree).toPromise();
290
+
291
+ expect(tree.files)
292
+ .toContain('/devextreme.json');
293
+ expect(tree.files)
294
+ .toContain('/projects/testApp2/src/themes/metadata.base.json');
295
+ });
296
+
297
+ it('should merge build commands in devextreme.json file', async () => {
298
+ appTree = await schematicRunner.runSchematicAsync('application', {
299
+ ...appOptions,
300
+ name: 'testApp2',
301
+ prefix: 'app2',
302
+ projectRoot: 'projects/testApp2'
303
+ }, appTree).toPromise();
304
+
305
+ const runner = new SchematicTestRunner('schematics', collectionPath);
306
+ let tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
307
+ tree = await runner.runSchematicAsync('add-layout', {
308
+ ...options,
309
+ project: 'testApp2'
310
+ }, appTree).toPromise();
311
+
312
+ const appContent = tree.readContent('projects/testApp2/src/app/app.component.ts');
313
+ expect(appContent).toContain('selector: \'app2-root\',');
314
+
315
+ const content = tree.readContent('/devextreme.json');
316
+ expect(content).toContain('"inputFile": "src/themes/metadata.base.json",');
317
+ expect(content).toContain('"inputFile": "projects/testApp2/src/themes/metadata.base.json",');
318
+ });
319
+
320
+ it('should add e2e tests only for default project', async () => {
321
+ appTree = await schematicRunner.runSchematicAsync('application', {
322
+ ...appOptions,
323
+ name: 'testApp2',
324
+ projectRoot: 'projects/testApp2'
325
+ }, appTree).toPromise();
326
+
327
+ const runner = new SchematicTestRunner('schematics', collectionPath);
328
+ let tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
329
+ tree = await runner.runSchematicAsync('add-layout', {
330
+ ...options,
331
+ project: 'testApp2'
332
+ }, appTree).toPromise();
333
+
334
+ const testContent = tree.readContent('/e2e/src/app.e2e-spec.ts');
335
+ expect(testContent).toContain('Welcome to TestApp!');
336
+
337
+ const testUtilsContent = tree.readContent('/e2e/src/app.po.ts');
338
+ expect(testUtilsContent).toMatch(/'app-root .dx-drawer-content .dx-card p:nth-child\(2\)'/);
339
+ });
340
+ });
@@ -1,10 +1,10 @@
1
- import { Component } from '@angular/core';
2
-
3
- @Component({
4
- templateUrl: 'home.component.html',
5
- styleUrls: [ './home.component.scss' ]
6
- })
7
-
8
- export class HomeComponent {
9
- constructor() {}
10
- }
1
+ import { Component } from '@angular/core';
2
+
3
+ @Component({
4
+ templateUrl: 'home.component.html',
5
+ styleUrls: [ './home.component.scss' ]
6
+ })
7
+
8
+ export class HomeComponent {
9
+ constructor() {}
10
+ }
@@ -1,33 +1,33 @@
1
- import { Component } from '@angular/core';
2
-
3
- @Component({
4
- templateUrl: 'profile.component.html',
5
- styleUrls: [ './profile.component.scss' ]
6
- })
7
-
8
- export class ProfileComponent {
9
- employee: any;
10
- colCountByScreen: object;
11
-
12
- constructor() {
13
- this.employee = {
14
- ID: 7,
15
- FirstName: 'Sandra',
16
- LastName: 'Johnson',
17
- Prefix: 'Mrs.',
18
- Position: 'Controller',
19
- Picture: 'images/employees/06.png',
20
- BirthDate: new Date('1974/11/15'),
21
- HireDate: new Date('2005/05/11'),
22
- /* tslint:disable-next-line:max-line-length */
23
- Notes: 'Sandra is a CPA and has been our controller since 2008. She loves to interact with staff so if you`ve not met her, be certain to say hi.\r\n\r\nSandra has 2 daughters both of whom are accomplished gymnasts.',
24
- Address: '4600 N Virginia Rd.'
25
- };
26
- this.colCountByScreen = {
27
- xs: 1,
28
- sm: 2,
29
- md: 3,
30
- lg: 4
31
- };
32
- }
33
- }
1
+ import { Component } from '@angular/core';
2
+
3
+ @Component({
4
+ templateUrl: 'profile.component.html',
5
+ styleUrls: [ './profile.component.scss' ]
6
+ })
7
+
8
+ export class ProfileComponent {
9
+ employee: any;
10
+ colCountByScreen: object;
11
+
12
+ constructor() {
13
+ this.employee = {
14
+ ID: 7,
15
+ FirstName: 'Sandra',
16
+ LastName: 'Johnson',
17
+ Prefix: 'Mrs.',
18
+ Position: 'Controller',
19
+ Picture: 'images/employees/06.png',
20
+ BirthDate: new Date('1974/11/15'),
21
+ HireDate: new Date('2005/05/11'),
22
+ /* tslint:disable-next-line:max-line-length */
23
+ Notes: 'Sandra is a CPA and has been our controller since 2008. She loves to interact with staff so if you`ve not met her, be certain to say hi.\r\n\r\nSandra has 2 daughters both of whom are accomplished gymnasts.',
24
+ Address: '4600 N Virginia Rd.'
25
+ };
26
+ this.colCountByScreen = {
27
+ xs: 1,
28
+ sm: 2,
29
+ md: 3,
30
+ lg: 4
31
+ };
32
+ }
33
+ }
@@ -0,0 +1,141 @@
1
+ import {
2
+ Rule,
3
+ Tree,
4
+ chain,
5
+ apply,
6
+ template,
7
+ move,
8
+ url,
9
+ mergeWith
10
+ } from '@angular-devkit/schematics';
11
+
12
+ import {
13
+ addDeclarationToModule,
14
+ addImportToModule
15
+ } from '@schematics/angular/utility/ast-utils';
16
+
17
+ import { addViewToRouting } from '../add-view';
18
+
19
+ import {
20
+ getApplicationPath,
21
+ getProjectName
22
+ } from '../utility/project';
23
+
24
+ import { humanize } from '../utility/string';
25
+
26
+ import {
27
+ applyChanges,
28
+ insertItemToArray
29
+ } from '../utility/change';
30
+
31
+ import { getSourceFile } from '../utility/source';
32
+
33
+ const sampleViewOptions = [
34
+ {
35
+ name: 'home',
36
+ componentName: 'HomeComponent',
37
+ relativePath: './pages/home/home.component'
38
+ }, {
39
+ name: 'profile',
40
+ componentName: 'ProfileComponent',
41
+ relativePath: './pages/profile/profile.component'
42
+ }, {
43
+ name: 'tasks',
44
+ componentName: 'TasksComponent',
45
+ relativePath: './pages/tasks/tasks.component'
46
+ }];
47
+
48
+ const devextremeOptions = [
49
+ {
50
+ componentName: 'DxDataGridModule',
51
+ relativePath: 'devextreme-angular'
52
+ }, {
53
+ componentName: 'DxFormModule',
54
+ relativePath: 'devextreme-angular'
55
+ }];
56
+
57
+ const navigations = [
58
+ ` {
59
+ text: 'Home',
60
+ path: '/home',
61
+ icon: 'home'
62
+ }`,
63
+ ` {
64
+ text: 'Examples',
65
+ icon: 'folder',
66
+ items: [
67
+ {
68
+ text: 'Profile',
69
+ path: '/profile'
70
+ },
71
+ {
72
+ text: 'Tasks',
73
+ path: '/tasks'
74
+ }
75
+ ]
76
+ }`
77
+ ];
78
+
79
+ function addImportsToRoutingModule(isView: boolean, routingPath: string, options: any) {
80
+ return (host: Tree) => {
81
+ const source = getSourceFile(host, routingPath);
82
+
83
+ if (!source) {
84
+ return host;
85
+ }
86
+
87
+ let changes;
88
+
89
+ if (isView) {
90
+ changes = addDeclarationToModule(source, routingPath, options.componentName, options.relativePath);
91
+ } else {
92
+ changes = addImportToModule(source, routingPath, options.componentName, options.relativePath);
93
+ }
94
+
95
+ return applyChanges(host, changes, routingPath);
96
+ };
97
+ }
98
+
99
+ function addDefaultNavigation(rootPath: string) {
100
+ return (host: Tree) => {
101
+ const navigationPath = rootPath + 'app-navigation.ts';
102
+
103
+ navigations.forEach((navigation) => {
104
+ const navigationSource = getSourceFile(host, navigationPath)!;
105
+ insertItemToArray(host, navigationPath, navigationSource, navigation, { location: 'end' });
106
+ });
107
+
108
+ return host;
109
+ };
110
+ }
111
+
112
+ export default function(options: any): Rule {
113
+ return (host: Tree) => {
114
+ const project = getProjectName(host, options.project);
115
+ const rootPath = getApplicationPath(host, project);
116
+ const routingPath = rootPath + 'app-routing.module.ts';
117
+ const rules: any[] = [];
118
+
119
+ const templateSource = apply(url('./files'), [
120
+ template({
121
+ project: humanize(project)
122
+ }),
123
+ move(rootPath)
124
+ ]);
125
+
126
+ rules.push(mergeWith(templateSource));
127
+
128
+ sampleViewOptions.forEach((viewOptions) => {
129
+ rules.push(addViewToRouting({ name: viewOptions.name, project, module: 'app-routing' }));
130
+ rules.push(addImportsToRoutingModule(true, routingPath, viewOptions));
131
+ });
132
+
133
+ devextremeOptions.forEach((moduleOptions) => {
134
+ rules.push(addImportsToRoutingModule(false, routingPath, moduleOptions));
135
+ });
136
+
137
+ rules.push(addDefaultNavigation(rootPath));
138
+
139
+ return chain(rules);
140
+ };
141
+ }
@@ -0,0 +1,74 @@
1
+ import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
2
+ import { Schema as WorkspaceOptions } from '@schematics/angular/workspace/schema';
3
+ import * as path from 'path';
4
+
5
+ const collectionPath = path.join(__dirname, '../collection.json');
6
+
7
+ describe('sample views', () => {
8
+ const appOptions: any = {
9
+ name: 'testApp',
10
+ projectRoot: '',
11
+ inlineStyle: false,
12
+ inlineTemplate: false,
13
+ routing: true,
14
+ style: 'css',
15
+ skipTests: false,
16
+ skipPackageJson: false
17
+ };
18
+
19
+ const workspaceOptions: WorkspaceOptions = {
20
+ name: 'workspace',
21
+ version: '6.0.0'
22
+ };
23
+
24
+ const sampleViewsOptions: any = {
25
+ project: 'testApp'
26
+ };
27
+
28
+ const angularSchematicsCollection = require.resolve('../../node_modules/@schematics/angular/collection.json');
29
+ const schematicRunner = new SchematicTestRunner('@schematics/angular', angularSchematicsCollection);
30
+ let appTree: UnitTestTree;
31
+
32
+ beforeEach(async () => {
33
+ appTree = await schematicRunner.runSchematicAsync('workspace', workspaceOptions).toPromise();
34
+ appTree = await schematicRunner.runSchematicAsync('application', appOptions, appTree).toPromise();
35
+ });
36
+
37
+ it('should add sample views', async () => {
38
+ const runner = new SchematicTestRunner('schematics', collectionPath);
39
+ let tree = await runner.runSchematicAsync('add-layout', { layout: 'side-nav-outer-toolbar' }, appTree).toPromise();
40
+ tree = await runner.runSchematicAsync('add-sample-views', sampleViewsOptions, tree).toPromise();
41
+
42
+ const moduleContent = tree.readContent('/src/app/app-routing.module.ts');
43
+
44
+ expect(moduleContent).toMatch(/component: HomeComponent/);
45
+ expect(moduleContent).toMatch(/path: 'home'/);
46
+
47
+ expect(moduleContent).toMatch(/import { HomeComponent } from /);
48
+ expect(moduleContent).toMatch(/declarations: \[HomeComponent/);
49
+
50
+ const navigationContent = tree.readContent('/src/app/app-navigation.ts');
51
+ expect(navigationContent).toMatch(/text: 'Home'/);
52
+ expect(navigationContent).toContain(`export const navigation = [
53
+ {
54
+ text: 'Home',
55
+ path: '/home',
56
+ icon: 'home'
57
+ },
58
+ {
59
+ text: 'Examples',
60
+ icon: 'folder',
61
+ items: [
62
+ {
63
+ text: 'Profile',
64
+ path: '/profile'
65
+ },
66
+ {
67
+ text: 'Tasks',
68
+ path: '/tasks'
69
+ }
70
+ ]
71
+ }
72
+ ];`);
73
+ });
74
+ });