55 * structure for each Angular version. The fixture files are actual angular.json
66 * files generated by `ng new` with each Angular CLI version.
77 *
8- * Key differences between versions:
9- *
10- * Angular 18-19:
11- * - builder: @angular-devkit/build-angular:application
12- * - outputPath: "dist/<project>" (string)
13- *
14- * Angular 20:
15- * - builder: @angular/build:application (new package!)
16- * - outputPath: MISSING (uses default dist/<project>)
17- * - index: MISSING (uses default src/index.html)
18- *
19- * Angular 21:
20- * - builder: @angular/build:application
21- * - outputPath: MISSING
22- * - polyfills: MISSING (zoneless by default)
23- * - test builder changed to @angular/build:unit-test
8+ * Key difference relevant to us:
9+ * - Angular 18-19: outputPath is a string like "dist/<project>"
10+ * - Angular 20-21: outputPath is MISSING (uses default dist/<project>)
2411 */
2512
2613import { SchematicContext , Tree } from '@angular-devkit/schematics' ;
@@ -36,24 +23,10 @@ const angular20Config = JSON.parse(fs.readFileSync(path.join(fixturesDir, 'angul
3623const angular21Config = JSON . parse ( fs . readFileSync ( path . join ( fixturesDir , 'angular-21.json' ) , 'utf-8' ) ) ;
3724
3825describe ( 'Angular Version Compatibility' , ( ) => {
39- /**
40- * Angular 18: Standard outputPath as string
41- */
4226 describe ( 'Angular 18' , ( ) => {
43- it ( 'has outputPath as string "dist/ng18" ' , ( ) => {
27+ it ( 'has outputPath as string' , ( ) => {
4428 const outputPath = angular18Config . projects . ng18 . architect . build . options . outputPath ;
4529 expect ( outputPath ) . toBe ( 'dist/ng18' ) ;
46- expect ( typeof outputPath ) . toBe ( 'string' ) ;
47- } ) ;
48-
49- it ( 'uses @angular-devkit/build-angular builder' , ( ) => {
50- const builder = angular18Config . projects . ng18 . architect . build . builder ;
51- expect ( builder ) . toBe ( '@angular-devkit/build-angular:application' ) ;
52- } ) ;
53-
54- it ( 'has index.html specified' , ( ) => {
55- const index = angular18Config . projects . ng18 . architect . build . options . index ;
56- expect ( index ) . toBe ( 'src/index.html' ) ;
5730 } ) ;
5831
5932 it ( 'ng add succeeds' , async ( ) => {
@@ -67,24 +40,10 @@ describe('Angular Version Compatibility', () => {
6740 } ) ;
6841 } ) ;
6942
70- /**
71- * Angular 19: Same structure as Angular 18
72- */
7343 describe ( 'Angular 19' , ( ) => {
74- it ( 'has outputPath as string "dist/ng19" ' , ( ) => {
44+ it ( 'has outputPath as string' , ( ) => {
7545 const outputPath = angular19Config . projects . ng19 . architect . build . options . outputPath ;
7646 expect ( outputPath ) . toBe ( 'dist/ng19' ) ;
77- expect ( typeof outputPath ) . toBe ( 'string' ) ;
78- } ) ;
79-
80- it ( 'uses @angular-devkit/build-angular builder' , ( ) => {
81- const builder = angular19Config . projects . ng19 . architect . build . builder ;
82- expect ( builder ) . toBe ( '@angular-devkit/build-angular:application' ) ;
83- } ) ;
84-
85- it ( 'has index.html specified' , ( ) => {
86- const index = angular19Config . projects . ng19 . architect . build . options . index ;
87- expect ( index ) . toBe ( 'src/index.html' ) ;
8847 } ) ;
8948
9049 it ( 'ng add succeeds' , async ( ) => {
@@ -98,30 +57,12 @@ describe('Angular Version Compatibility', () => {
9857 } ) ;
9958 } ) ;
10059
101- /**
102- * Angular 20: Breaking change - outputPath removed!
103- */
10460 describe ( 'Angular 20' , ( ) => {
10561 it ( 'has NO outputPath (uses default)' , ( ) => {
10662 const options = angular20Config . projects . ng20 . architect . build . options ;
10763 expect ( options . outputPath ) . toBeUndefined ( ) ;
10864 } ) ;
10965
110- it ( 'uses NEW @angular/build builder' , ( ) => {
111- const builder = angular20Config . projects . ng20 . architect . build . builder ;
112- expect ( builder ) . toBe ( '@angular/build:application' ) ;
113- } ) ;
114-
115- it ( 'has NO index property (uses default src/index.html)' , ( ) => {
116- const options = angular20Config . projects . ng20 . architect . build . options ;
117- expect ( options . index ) . toBeUndefined ( ) ;
118- } ) ;
119-
120- it ( 'still has polyfills with zone.js' , ( ) => {
121- const polyfills = angular20Config . projects . ng20 . architect . build . options . polyfills ;
122- expect ( polyfills ) . toContain ( 'zone.js' ) ;
123- } ) ;
124-
12566 it ( 'ng add succeeds despite missing outputPath' , async ( ) => {
12667 const tree = Tree . empty ( ) ;
12768 tree . create ( 'angular.json' , JSON . stringify ( angular20Config ) ) ;
@@ -133,41 +74,13 @@ describe('Angular Version Compatibility', () => {
13374 } ) ;
13475 } ) ;
13576
136- /**
137- * Angular 21: Even more minimal - polyfills removed (zoneless)
138- */
13977 describe ( 'Angular 21' , ( ) => {
14078 it ( 'has NO outputPath (uses default)' , ( ) => {
14179 const options = angular21Config . projects . ng21 . architect . build . options ;
14280 expect ( options . outputPath ) . toBeUndefined ( ) ;
14381 } ) ;
14482
145- it ( 'uses @angular/build builder' , ( ) => {
146- const builder = angular21Config . projects . ng21 . architect . build . builder ;
147- expect ( builder ) . toBe ( '@angular/build:application' ) ;
148- } ) ;
149-
150- it ( 'has NO polyfills (zoneless by default)' , ( ) => {
151- const options = angular21Config . projects . ng21 . architect . build . options ;
152- expect ( options . polyfills ) . toBeUndefined ( ) ;
153- } ) ;
154-
155- it ( 'has NO index property' , ( ) => {
156- const options = angular21Config . projects . ng21 . architect . build . options ;
157- expect ( options . index ) . toBeUndefined ( ) ;
158- } ) ;
159-
160- it ( 'uses new unit-test builder' , ( ) => {
161- const builder = angular21Config . projects . ng21 . architect . test . builder ;
162- expect ( builder ) . toBe ( '@angular/build:unit-test' ) ;
163- } ) ;
164-
165- it ( 'has NO extract-i18n target' , ( ) => {
166- const architect = angular21Config . projects . ng21 . architect ;
167- expect ( ( architect as Record < string , unknown > ) [ 'extract-i18n' ] ) . toBeUndefined ( ) ;
168- } ) ;
169-
170- it ( 'ng add succeeds despite minimal config' , async ( ) => {
83+ it ( 'ng add succeeds despite missing outputPath' , async ( ) => {
17184 const tree = Tree . empty ( ) ;
17285 tree . create ( 'angular.json' , JSON . stringify ( angular21Config ) ) ;
17386
@@ -178,9 +91,6 @@ describe('Angular Version Compatibility', () => {
17891 } ) ;
17992 } ) ;
18093
181- /**
182- * Cross-version compatibility summary
183- */
18494 describe ( 'Cross-version compatibility' , ( ) => {
18595 it ( 'all versions have projectType: application' , ( ) => {
18696 expect ( angular18Config . projects . ng18 . projectType ) . toBe ( 'application' ) ;
@@ -202,12 +112,5 @@ describe('Angular Version Compatibility', () => {
202112 expect ( angular20Config . projects . ng20 . architect . build . options . outputPath ) . toBeUndefined ( ) ;
203113 expect ( angular21Config . projects . ng21 . architect . build . options . outputPath ) . toBeUndefined ( ) ;
204114 } ) ;
205-
206- it ( 'builder evolution: @angular-devkit/build-angular → @angular/build' , ( ) => {
207- expect ( angular18Config . projects . ng18 . architect . build . builder ) . toContain ( '@angular-devkit/build-angular' ) ;
208- expect ( angular19Config . projects . ng19 . architect . build . builder ) . toContain ( '@angular-devkit/build-angular' ) ;
209- expect ( angular20Config . projects . ng20 . architect . build . builder ) . toContain ( '@angular/build' ) ;
210- expect ( angular21Config . projects . ng21 . architect . build . builder ) . toContain ( '@angular/build' ) ;
211- } ) ;
212115 } ) ;
213116} ) ;
0 commit comments