diff --git a/packages/schematics/angular/application/files/src/assets/.gitkeep.template b/packages/schematics/angular/application/files/common-files/src/assets/.gitkeep.template similarity index 100% rename from packages/schematics/angular/application/files/src/assets/.gitkeep.template rename to packages/schematics/angular/application/files/common-files/src/assets/.gitkeep.template diff --git a/packages/schematics/angular/application/files/src/favicon.ico.template b/packages/schematics/angular/application/files/common-files/src/favicon.ico.template similarity index 100% rename from packages/schematics/angular/application/files/src/favicon.ico.template rename to packages/schematics/angular/application/files/common-files/src/favicon.ico.template diff --git a/packages/schematics/angular/application/files/src/index.html.template b/packages/schematics/angular/application/files/common-files/src/index.html.template similarity index 86% rename from packages/schematics/angular/application/files/src/index.html.template rename to packages/schematics/angular/application/files/common-files/src/index.html.template index 8a7c648e38c0..e2e52f15b22d 100644 --- a/packages/schematics/angular/application/files/src/index.html.template +++ b/packages/schematics/angular/application/files/common-files/src/index.html.template @@ -8,6 +8,6 @@ - <<%= prefix %>-root>-root> + <<%= selector %>>> diff --git a/packages/schematics/angular/application/files/src/styles.__style__.template b/packages/schematics/angular/application/files/common-files/src/styles.__style__.template similarity index 100% rename from packages/schematics/angular/application/files/src/styles.__style__.template rename to packages/schematics/angular/application/files/common-files/src/styles.__style__.template diff --git a/packages/schematics/angular/application/files/tsconfig.app.json.template b/packages/schematics/angular/application/files/common-files/tsconfig.app.json.template similarity index 100% rename from packages/schematics/angular/application/files/tsconfig.app.json.template rename to packages/schematics/angular/application/files/common-files/tsconfig.app.json.template diff --git a/packages/schematics/angular/application/files/tsconfig.spec.json.template b/packages/schematics/angular/application/files/common-files/tsconfig.spec.json.template similarity index 100% rename from packages/schematics/angular/application/files/tsconfig.spec.json.template rename to packages/schematics/angular/application/files/common-files/tsconfig.spec.json.template diff --git a/packages/schematics/angular/application/other-files/app.component.html.template b/packages/schematics/angular/application/files/common-other-files/app.component.html.template similarity index 100% rename from packages/schematics/angular/application/other-files/app.component.html.template rename to packages/schematics/angular/application/files/common-other-files/app.component.html.template diff --git a/packages/schematics/angular/application/files/src/main.ts.template b/packages/schematics/angular/application/files/module-files/src/main.ts.template similarity index 100% rename from packages/schematics/angular/application/files/src/main.ts.template rename to packages/schematics/angular/application/files/module-files/src/main.ts.template diff --git a/packages/schematics/angular/application/other-files/app.component.spec.ts.template b/packages/schematics/angular/application/files/other-module-files/app.component.spec.ts.template similarity index 100% rename from packages/schematics/angular/application/other-files/app.component.spec.ts.template rename to packages/schematics/angular/application/files/other-module-files/app.component.spec.ts.template diff --git a/packages/schematics/angular/application/other-files/app.component.ts.template b/packages/schematics/angular/application/files/other-module-files/app.component.ts.template similarity index 100% rename from packages/schematics/angular/application/other-files/app.component.ts.template rename to packages/schematics/angular/application/files/other-module-files/app.component.ts.template diff --git a/packages/schematics/angular/application/other-files/app.module.ts.template b/packages/schematics/angular/application/files/other-module-files/app.module.ts.template similarity index 100% rename from packages/schematics/angular/application/other-files/app.module.ts.template rename to packages/schematics/angular/application/files/other-module-files/app.module.ts.template diff --git a/packages/schematics/angular/application/files/other-standalone-files/app.component.spec.ts.template b/packages/schematics/angular/application/files/other-standalone-files/app.component.spec.ts.template new file mode 100644 index 000000000000..c1749005eccb --- /dev/null +++ b/packages/schematics/angular/application/files/other-standalone-files/app.component.spec.ts.template @@ -0,0 +1,29 @@ +import { TestBed } from '@angular/core/testing'; +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [AppComponent], + }).compileComponents(); + }); + + it('should create the app', () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.componentInstance; + expect(app).toBeTruthy(); + }); + + it(`should have the '<%= name %>' title`, () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.componentInstance; + expect(app.title).toEqual('<%= name %>'); + }); + + it('should render title', () => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.nativeElement as HTMLElement; + expect(compiled.querySelector('.content span')?.textContent).toContain('<%= name %> app is running!'); + }); +}); diff --git a/packages/schematics/angular/application/files/other-standalone-files/app.component.ts.template b/packages/schematics/angular/application/files/other-standalone-files/app.component.ts.template new file mode 100644 index 000000000000..756d6aac49af --- /dev/null +++ b/packages/schematics/angular/application/files/other-standalone-files/app.component.ts.template @@ -0,0 +1,40 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common';<% if(routing) { %> +import { RouterOutlet } from '@angular/router';<% } %> + +@Component({ + selector: '<%= selector %>', + standalone: true,<% if(inlineTemplate) { %> + template: ` + +
+

+ Welcome to {{title}}! +

+ {{ title }} app is running! + Angular Logo +
+

Here are some links to help you start:

+ + <% if (routing) { + %><% + } %> + `,<% } else { %> + templateUrl: './app.component.html',<% } if(inlineStyle) { %> + styles: [],<% } else { %> + styleUrls: ['./app.component.<%= style %>'], <% } %> + imports: [CommonModule<% if(routing) { %>, RouterOutlet<% } %>] +}) +export class AppComponent { + title = '<%= name %>'; +} diff --git a/packages/schematics/angular/application/files/standalone-files/src/app/app.config.ts.template b/packages/schematics/angular/application/files/standalone-files/src/app/app.config.ts.template new file mode 100644 index 000000000000..b5fe1c155f51 --- /dev/null +++ b/packages/schematics/angular/application/files/standalone-files/src/app/app.config.ts.template @@ -0,0 +1,8 @@ +import { ApplicationConfig } from '@angular/core';<% if (routing) { %> +import { provideRouter } from '@angular/router'; + +import { routes } from './app.routes';<% } %> + +export const appConfig: ApplicationConfig = { + providers: [<% if (routing) { %>provideRouter(routes) <% } %>], +}; \ No newline at end of file diff --git a/packages/schematics/angular/application/files/standalone-files/src/app/app.routes.ts.template b/packages/schematics/angular/application/files/standalone-files/src/app/app.routes.ts.template new file mode 100644 index 000000000000..dc39edb5f23a --- /dev/null +++ b/packages/schematics/angular/application/files/standalone-files/src/app/app.routes.ts.template @@ -0,0 +1,3 @@ +import { Routes } from '@angular/router'; + +export const routes: Routes = []; diff --git a/packages/schematics/angular/application/files/standalone-files/src/main.ts.template b/packages/schematics/angular/application/files/standalone-files/src/main.ts.template new file mode 100644 index 000000000000..35b00f346331 --- /dev/null +++ b/packages/schematics/angular/application/files/standalone-files/src/main.ts.template @@ -0,0 +1,6 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { appConfig } from './app/app.config'; +import { AppComponent } from './app/app.component'; + +bootstrapApplication(AppComponent, appConfig) + .catch((err) => console.error(err)); diff --git a/packages/schematics/angular/application/index.ts b/packages/schematics/angular/application/index.ts index fdf7ae347c2a..b3580cc315c5 100644 --- a/packages/schematics/angular/application/index.ts +++ b/packages/schematics/angular/application/index.ts @@ -32,6 +32,187 @@ import { getWorkspace, updateWorkspace } from '../utility/workspace'; import { Builders, ProjectType } from '../utility/workspace-models'; import { Schema as ApplicationOptions, Style } from './schema'; +export default function (options: ApplicationOptions): Rule { + return async (host: Tree) => { + const { appDir, appRootSelector, componentOptions, folderName, sourceDir } = + await getAppOptions(host, options); + + const appTypeRules = options.standalone + ? getStandaloneAppRules( + options, + appDir, + folderName, + sourceDir, + appRootSelector, + componentOptions, + ) + : getModuleAppRules( + options, + appDir, + folderName, + sourceDir, + appRootSelector, + componentOptions, + ); + + return chain([ + addAppToWorkspaceFile(options, appDir, folderName), + mergeWith( + apply(url('./files/common-files'), [ + options.minimal ? filter(minimalPathFilter) : noop(), + applyTemplates({ + utils: strings, + ...options, + selector: appRootSelector, + relativePathToWorkspaceRoot: relativePathToWorkspaceRoot(appDir), + appName: options.name, + folderName, + }), + move(appDir), + ]), + MergeStrategy.Overwrite, + ), + ...appTypeRules, + mergeWith( + apply(url('./files/common-other-files'), [ + options.strict ? noop() : filter((path) => path !== '/package.json.template'), + componentOptions.inlineTemplate + ? filter((path) => !path.endsWith('.html.template')) + : noop(), + componentOptions.skipTests + ? filter((path) => !path.endsWith('.spec.ts.template')) + : noop(), + applyTemplates({ + utils: strings, + ...options, + selector: appRootSelector, + ...componentOptions, + }), + move(sourceDir), + ]), + MergeStrategy.Overwrite, + ), + options.skipPackageJson ? noop() : addDependenciesToPackageJson(options), + ]); + }; +} + +function getModuleAppRules( + options: ApplicationOptions, + appDir: string, + folderName: string, + sourceDir: string, + appRootSelector: string, + componentOptions: Partial, +): Rule[] { + return [ + mergeWith( + apply(url('./files/module-files'), [ + options.minimal ? filter(minimalPathFilter) : noop(), + applyTemplates({ + utils: strings, + ...options, + relativePathToWorkspaceRoot: relativePathToWorkspaceRoot(appDir), + appName: options.name, + folderName, + }), + move(appDir), + ]), + MergeStrategy.Overwrite, + ), + schematic('module', { + name: 'app', + commonModule: false, + flat: true, + routing: options.routing, + routingScope: 'Root', + path: sourceDir, + project: options.name, + }), + schematic('component', { + name: 'app', + selector: appRootSelector, + flat: true, + path: sourceDir, + skipImport: true, + project: options.name, + ...componentOptions, + }), + mergeWith( + apply(url('./files/other-module-files'), [ + options.strict ? noop() : filter((path) => path !== '/package.json.template'), + componentOptions.inlineTemplate + ? filter((path) => !path.endsWith('.html.template')) + : noop(), + componentOptions.skipTests ? filter((path) => !path.endsWith('.spec.ts.template')) : noop(), + applyTemplates({ + utils: strings, + ...options, + selector: appRootSelector, + ...componentOptions, + }), + move(sourceDir), + ]), + MergeStrategy.Overwrite, + ), + ]; +} + +function getStandaloneAppRules( + options: ApplicationOptions, + appDir: string, + folderName: string, + sourceDir: string, + appRootSelector: string, + componentOptions: Partial, +): Rule[] { + return [ + mergeWith( + apply(url('./files/standalone-files'), [ + options.minimal ? filter(minimalPathFilter) : noop(), + options.routing ? noop() : filter((path) => !path.endsWith('app.routes.ts.template')), + applyTemplates({ + utils: strings, + ...options, + selector: appRootSelector, + relativePathToWorkspaceRoot: relativePathToWorkspaceRoot(appDir), + appName: options.name, + folderName, + }), + move(appDir), + ]), + MergeStrategy.Overwrite, + ), + schematic('component', { + name: 'app', + selector: appRootSelector, + flat: true, + path: sourceDir, + skipImport: true, + project: options.name, + standalone: true, + ...componentOptions, + }), + mergeWith( + apply(url('./files/other-standalone-files'), [ + options.strict ? noop() : filter((path) => path !== '/package.json.template'), + componentOptions.inlineTemplate + ? filter((path) => !path.endsWith('.html.template')) + : noop(), + componentOptions.skipTests ? filter((path) => !path.endsWith('.spec.ts.template')) : noop(), + applyTemplates({ + utils: strings, + ...options, + selector: appRootSelector, + ...componentOptions, + }), + move(sourceDir), + ]), + MergeStrategy.Overwrite, + ), + ]; +} + function addDependenciesToPackageJson(options: ApplicationOptions) { return (host: Tree, context: SchematicContext) => { [ @@ -112,6 +293,16 @@ function addAppToWorkspaceFile( }); } + if (options.standalone) { + const schematicsWithStandalone = ['component', 'directive', 'pipe']; + schematicsWithStandalone.forEach((type) => { + if (!(`@schematics/angular:${type}` in schematics)) { + schematics[`@schematics/angular:${type}`] = {}; + } + (schematics[`@schematics/angular:${type}`] as JsonObject).standalone = true; + }); + } + const sourceRoot = join(normalize(projectRoot), 'src'); let budgets = []; if (options.strict) { @@ -222,99 +413,65 @@ function addAppToWorkspaceFile( }); }); } + function minimalPathFilter(path: string): boolean { return !path.endsWith('tsconfig.spec.json.template'); } -export default function (options: ApplicationOptions): Rule { - return async (host: Tree) => { - const appRootSelector = `${options.prefix}-root`; - const componentOptions: Partial = !options.minimal - ? { - inlineStyle: options.inlineStyle, - inlineTemplate: options.inlineTemplate, - skipTests: options.skipTests, - style: options.style, - viewEncapsulation: options.viewEncapsulation, - } - : { - inlineStyle: options.inlineStyle ?? true, - inlineTemplate: options.inlineTemplate ?? true, - skipTests: true, - style: options.style, - viewEncapsulation: options.viewEncapsulation, - }; +async function getAppOptions( + host: Tree, + options: ApplicationOptions, +): Promise<{ + appDir: string; + appRootSelector: string; + componentOptions: Partial; + folderName: string; + sourceDir: string; +}> { + const appRootSelector = `${options.prefix}-root`; + const componentOptions = getComponentOptions(options); - const workspace = await getWorkspace(host); - const newProjectRoot = (workspace.extensions.newProjectRoot as string | undefined) || ''; + const workspace = await getWorkspace(host); + const newProjectRoot = (workspace.extensions.newProjectRoot as string | undefined) || ''; - // If scoped project (i.e. "@foo/bar"), convert dir to "foo/bar". - let folderName = options.name.startsWith('@') ? options.name.slice(1) : options.name; - if (/[A-Z]/.test(folderName)) { - folderName = strings.dasherize(folderName); - } + // If scoped project (i.e. "@foo/bar"), convert dir to "foo/bar". + let folderName = options.name.startsWith('@') ? options.name.slice(1) : options.name; + if (/[A-Z]/.test(folderName)) { + folderName = strings.dasherize(folderName); + } - const appDir = - options.projectRoot === undefined - ? join(normalize(newProjectRoot), folderName) - : normalize(options.projectRoot); + const appDir = + options.projectRoot === undefined + ? join(normalize(newProjectRoot), folderName) + : normalize(options.projectRoot); - const sourceDir = `${appDir}/src/app`; + const sourceDir = `${appDir}/src/app`; - return chain([ - addAppToWorkspaceFile(options, appDir, folderName), - mergeWith( - apply(url('./files'), [ - options.minimal ? filter(minimalPathFilter) : noop(), - applyTemplates({ - utils: strings, - ...options, - relativePathToWorkspaceRoot: relativePathToWorkspaceRoot(appDir), - appName: options.name, - folderName, - }), - move(appDir), - ]), - MergeStrategy.Overwrite, - ), - schematic('module', { - name: 'app', - commonModule: false, - flat: true, - routing: options.routing, - routingScope: 'Root', - path: sourceDir, - project: options.name, - }), - schematic('component', { - name: 'app', - selector: appRootSelector, - flat: true, - path: sourceDir, - skipImport: true, - project: options.name, - ...componentOptions, - }), - mergeWith( - apply(url('./other-files'), [ - options.strict ? noop() : filter((path) => path !== '/package.json.template'), - componentOptions.inlineTemplate - ? filter((path) => !path.endsWith('.html.template')) - : noop(), - componentOptions.skipTests - ? filter((path) => !path.endsWith('.spec.ts.template')) - : noop(), - applyTemplates({ - utils: strings, - ...options, - selector: appRootSelector, - ...componentOptions, - }), - move(sourceDir), - ]), - MergeStrategy.Overwrite, - ), - options.skipPackageJson ? noop() : addDependenciesToPackageJson(options), - ]); + return { + appDir, + appRootSelector, + componentOptions, + folderName, + sourceDir, }; } + +function getComponentOptions(options: ApplicationOptions): Partial { + const componentOptions: Partial = !options.minimal + ? { + inlineStyle: options.inlineStyle, + inlineTemplate: options.inlineTemplate, + skipTests: options.skipTests, + style: options.style, + viewEncapsulation: options.viewEncapsulation, + } + : { + inlineStyle: options.inlineStyle ?? true, + inlineTemplate: options.inlineTemplate ?? true, + skipTests: true, + style: options.style, + viewEncapsulation: options.viewEncapsulation, + }; + + return componentOptions; +} diff --git a/packages/schematics/angular/application/index_spec.ts b/packages/schematics/angular/application/index_spec.ts index dfe649393bb9..41d431f37e8c 100644 --- a/packages/schematics/angular/application/index_spec.ts +++ b/packages/schematics/angular/application/index_spec.ts @@ -524,4 +524,85 @@ describe('Application Schematic', () => { const cfg = JSON.parse(tree.readContent('/angular.json')); expect(cfg.projects['@myscope/myapp']).toBeDefined(); }); + + describe('standalone', () => { + it('should create all files of a standalone application', async () => { + const options = { ...defaultOptions, standalone: true }; + + const tree = await schematicRunner.runSchematic('application', options, workspaceTree); + + const files = tree.files; + expect(files).toEqual( + jasmine.arrayContaining([ + '/projects/foo/tsconfig.app.json', + '/projects/foo/tsconfig.spec.json', + '/projects/foo/src/favicon.ico', + '/projects/foo/src/index.html', + '/projects/foo/src/main.ts', + '/projects/foo/src/styles.css', + '/projects/foo/src/app/app.config.ts', + '/projects/foo/src/app/app.component.css', + '/projects/foo/src/app/app.component.html', + '/projects/foo/src/app/app.component.spec.ts', + '/projects/foo/src/app/app.component.ts', + ]), + ); + }); + + it('should not create any module files', async () => { + const options = { ...defaultOptions, standalone: true }; + + const tree = await schematicRunner.runSchematic('application', options, workspaceTree); + const moduleFiles = tree.files.filter((file) => file.endsWith('.module.ts')); + expect(moduleFiles.length).toEqual(0); + }); + + it('should create a standalone component', async () => { + const options = { ...defaultOptions, standalone: true }; + + const tree = await schematicRunner.runSchematic('application', options, workspaceTree); + + const component = tree.readContent('/projects/foo/src/app/app.component.ts'); + expect(component).toMatch(/standalone: true/); + }); + + it('should create routing information when routing is true', async () => { + const options = { ...defaultOptions, standalone: true, routing: true }; + + const tree = await schematicRunner.runSchematic('application', options, workspaceTree); + + expect(tree.files).toContain('/projects/foo/src/app/app.routes.ts'); + + const component = tree.readContent('/projects/foo/src/app/app.component.ts'); + expect(component).toContain(`import { RouterOutlet } from '@angular/router';`); + expect(component).toContain(`imports: [CommonModule, RouterOutlet]`); + + const config = tree.readContent('/projects/foo/src/app/app.config.ts'); + expect(config).toContain(`import { provideRouter } from '@angular/router';`); + expect(config).toContain(`import { routes } from './app.routes';`); + expect(config).toContain('provideRouter(routes)'); + }); + + it('should create a main.ts', async () => { + const options = { ...defaultOptions, standalone: true }; + const tree = await schematicRunner.runSchematic('application', options, workspaceTree); + + const main = tree.readContent('/projects/foo/src/main.ts'); + expect(main).toContain('bootstrapApplication'); + }); + + it('should set the default schematic options to be standalone', async () => { + const options = { ...defaultOptions, standalone: true }; + const tree = await schematicRunner.runSchematic('application', options, workspaceTree); + + const workspace = JSON.parse(tree.readContent('/angular.json')); + expect(workspace.projects.foo.schematics).toEqual( + jasmine.objectContaining({ + '@schematics/angular:component': { standalone: true }, + '@schematics/angular:directive': { standalone: true }, + '@schematics/angular:pipe': { standalone: true }, + }), + ); + }); + }); }); diff --git a/packages/schematics/angular/application/schema.json b/packages/schematics/angular/application/schema.json index 42cf17920d5f..1ef4cc1e5317 100644 --- a/packages/schematics/angular/application/schema.json +++ b/packages/schematics/angular/application/schema.json @@ -102,6 +102,12 @@ "description": "Creates an application with stricter bundle budgets settings.", "type": "boolean", "default": true + }, + "standalone": { + "description": "Creates an application based upon the standalone API, without NgModules.", + "type": "boolean", + "default": false, + "x-user-analytics": "ep.ng_standalone" } }, "required": ["name"] diff --git a/packages/schematics/angular/ng-new/index.ts b/packages/schematics/angular/ng-new/index.ts index 55ee3174a72b..868f47c18918 100644 --- a/packages/schematics/angular/ng-new/index.ts +++ b/packages/schematics/angular/ng-new/index.ts @@ -56,6 +56,7 @@ export default function (options: NgNewOptions): Rule { skipInstall: true, strict: options.strict, minimal: options.minimal, + standalone: options.standalone, }; return chain([ diff --git a/packages/schematics/angular/ng-new/index_spec.ts b/packages/schematics/angular/ng-new/index_spec.ts index e26bf5948647..8d80fdd15f6f 100644 --- a/packages/schematics/angular/ng-new/index_spec.ts +++ b/packages/schematics/angular/ng-new/index_spec.ts @@ -42,6 +42,21 @@ describe('Ng New Schematic', () => { ); }); + it('should create files of a standalone application', async () => { + const options = { ...defaultOptions, standalone: true }; + + const tree = await schematicRunner.runSchematic('ng-new', options); + const files = tree.files; + expect(files).toEqual( + jasmine.arrayContaining([ + '/bar/tsconfig.app.json', + '/bar/src/main.ts', + '/bar/src/app/app.config.ts', + ]), + ); + expect(files).not.toEqual(jasmine.arrayContaining(['/bar/src/app/app.module.ts'])); + }); + it('should should set the prefix in angular.json and in app.component.ts', async () => { const options = { ...defaultOptions, prefix: 'pre' }; diff --git a/packages/schematics/angular/ng-new/schema.json b/packages/schematics/angular/ng-new/schema.json index 4e069a3ce2af..ddc63cf6eec5 100644 --- a/packages/schematics/angular/ng-new/schema.json +++ b/packages/schematics/angular/ng-new/schema.json @@ -133,6 +133,12 @@ "description": "The package manager used to install dependencies.", "type": "string", "enum": ["npm", "yarn", "pnpm", "cnpm"] + }, + "standalone": { + "description": "Creates an application based upon the standalone API, without NgModules.", + "type": "boolean", + "default": false, + "x-user-analytics": "ep.ng_standalone" } }, "required": ["name", "version"] diff --git a/tests/legacy-cli/e2e/tests/generate/application/application-standalone-routing.ts b/tests/legacy-cli/e2e/tests/generate/application/application-standalone-routing.ts new file mode 100644 index 000000000000..3506f39092aa --- /dev/null +++ b/tests/legacy-cli/e2e/tests/generate/application/application-standalone-routing.ts @@ -0,0 +1,13 @@ +import { expectFileNotToExist, expectFileToMatch } from '../../../utils/fs'; +import { ng } from '../../../utils/process'; +import { useCIChrome } from '../../../utils/project'; + +export default async function () { + await ng('generate', 'application', 'app2', '--standalone', '--routing'); + await expectFileToMatch('angular.json', /\"app2\":/); + await expectFileToMatch('projects/app2/src/main.ts', /bootstrapApplication/); + await expectFileNotToExist('projects/app2/src/app/app.module.ts'); + await expectFileToMatch('projects/app2/src/app/app.routes.ts', /export const routes: Routes/); + await useCIChrome('app2', 'projects/app2'); + return ng('test', 'app2', '--watch=false'); +} diff --git a/tests/legacy-cli/e2e/tests/generate/application/application-standalone.ts b/tests/legacy-cli/e2e/tests/generate/application/application-standalone.ts new file mode 100644 index 000000000000..9ed1fc24501e --- /dev/null +++ b/tests/legacy-cli/e2e/tests/generate/application/application-standalone.ts @@ -0,0 +1,12 @@ +import { expectFileNotToExist, expectFileToMatch } from '../../../utils/fs'; +import { ng } from '../../../utils/process'; +import { useCIChrome } from '../../../utils/project'; + +export default async function () { + await ng('generate', 'application', 'app2', '--standalone'); + await expectFileToMatch('angular.json', /\"app2\":/); + await expectFileToMatch('projects/app2/src/main.ts', /bootstrapApplication/); + await expectFileNotToExist('projects/app2/src/app/app.module.ts'); + await useCIChrome('app2', 'projects/app2'); + return ng('test', 'app2', '--watch=false'); +}