@@ -18,36 +18,36 @@ describe('outputs', () => {
1818
1919 describe ( 'outputs migration' , ( ) => {
2020 describe ( 'EventEmitter declarations without problematic access patterns' , ( ) => {
21- it ( 'should migrate declaration with a primitive type hint' , ( ) => {
22- verifyDeclaration ( {
21+ it ( 'should migrate declaration with a primitive type hint' , async ( ) => {
22+ await verifyDeclaration ( {
2323 before : '@Output() readonly someChange = new EventEmitter<string>();' ,
2424 after : 'readonly someChange = output<string>();' ,
2525 } ) ;
2626 } ) ;
2727
28- it ( 'should migrate declaration with complex type hint' , ( ) => {
29- verifyDeclaration ( {
28+ it ( 'should migrate declaration with complex type hint' , async ( ) => {
29+ await verifyDeclaration ( {
3030 before : '@Output() readonly someChange = new EventEmitter<string | number>();' ,
3131 after : 'readonly someChange = output<string | number>();' ,
3232 } ) ;
3333 } ) ;
3434
35- it ( 'should migrate declaration without type hint' , ( ) => {
36- verifyDeclaration ( {
35+ it ( 'should migrate declaration without type hint' , async ( ) => {
36+ await verifyDeclaration ( {
3737 before : '@Output() readonly someChange = new EventEmitter();' ,
3838 after : 'readonly someChange = output();' ,
3939 } ) ;
4040 } ) ;
4141
42- it ( 'should take alias into account' , ( ) => {
43- verifyDeclaration ( {
42+ it ( 'should take alias into account' , async ( ) => {
43+ await verifyDeclaration ( {
4444 before : `@Output({alias: 'otherChange'}) readonly someChange = new EventEmitter();` ,
4545 after : `readonly someChange = output({ alias: 'otherChange' });` ,
4646 } ) ;
4747 } ) ;
4848
49- it ( 'should support alias as statically analyzable reference' , ( ) => {
50- verify ( {
49+ it ( 'should support alias as statically analyzable reference' , async ( ) => {
50+ await verify ( {
5151 before : `
5252 import {Directive, Output, EventEmitter} from '@angular/core';
5353
@@ -71,44 +71,128 @@ describe('outputs', () => {
7171 } ) ;
7272 } ) ;
7373
74- it ( 'should add readonly modifier' , ( ) => {
75- verifyDeclaration ( {
74+ it ( 'should add readonly modifier' , async ( ) => {
75+ await verifyDeclaration ( {
7676 before : '@Output() someChange = new EventEmitter();' ,
7777 after : 'readonly someChange = output();' ,
7878 } ) ;
7979 } ) ;
8080
81- it ( 'should respect visibility modifiers' , ( ) => {
82- verifyDeclaration ( {
81+ it ( 'should respect visibility modifiers' , async ( ) => {
82+ await verifyDeclaration ( {
8383 before : `@Output() protected someChange = new EventEmitter();` ,
8484 after : `protected readonly someChange = output();` ,
8585 } ) ;
8686 } ) ;
8787
88- it ( 'should migrate multiple outputs' , ( ) => {
89- // TODO: whitespace are messing up test verification
90- verifyDeclaration ( {
91- before : `@Output() someChange1 = new EventEmitter();
92- @Output() someChange2 = new EventEmitter();` ,
93- after : `readonly someChange1 = output();
94- readonly someChange2 = output();` ,
88+ it ( 'should preserve single line JSdoc comments when migrating outputs' , async ( ) => {
89+ await verify ( {
90+ before : `
91+ import {Directive, Output, EventEmitter} from '@angular/core';
92+
93+ @Directive()
94+ export class TestDir {
95+ /** Whenever there is change, emits an event. */
96+ @Output() someChange = new EventEmitter();
97+ }
98+ ` ,
99+ after : `
100+ import {Directive, output} from '@angular/core';
101+
102+ @Directive()
103+ export class TestDir {
104+ /** Whenever there is change, emits an event. */
105+ readonly someChange = output();
106+ }
107+ ` ,
108+ } ) ;
109+ } ) ;
110+
111+ it ( 'should preserve multiline JSdoc comments when migrating outputs' , async ( ) => {
112+ await verify ( {
113+ before : `
114+ import {Directive, Output, EventEmitter} from '@angular/core';
115+
116+ @Directive()
117+ export class TestDir {
118+ /**
119+ * Whenever there is change, emits an event.
120+ */
121+ @Output() someChange = new EventEmitter();
122+ }
123+ ` ,
124+ after : `
125+ import {Directive, output} from '@angular/core';
126+
127+ @Directive()
128+ export class TestDir {
129+ /**
130+ * Whenever there is change, emits an event.
131+ */
132+ readonly someChange = output();
133+ }
134+ ` ,
135+ } ) ;
136+ } ) ;
137+
138+ it ( 'should preserve multiline comments when migrating outputs' , async ( ) => {
139+ await verify ( {
140+ before : `
141+ import {Directive, Output, EventEmitter} from '@angular/core';
142+
143+ @Directive()
144+ export class TestDir {
145+ /* Whenever there is change,emits an event. */
146+ @Output() someChange = new EventEmitter();
147+ }
148+ ` ,
149+ after : `
150+ import {Directive, output} from '@angular/core';
151+
152+ @Directive()
153+ export class TestDir {
154+ /* Whenever there is change,emits an event. */
155+ readonly someChange = output();
156+ }
157+ ` ,
158+ } ) ;
159+ } ) ;
160+
161+ it ( 'should migrate multiple outputs' , async ( ) => {
162+ await verifyDeclaration ( {
163+ before :
164+ '@Output() someChange1 = new EventEmitter();\n@Output() someChange2 = new EventEmitter();' ,
165+ after : `readonly someChange1 = output();\nreadonly someChange2 = output();` ,
95166 } ) ;
96167 } ) ;
97168
98- it ( 'should migrate only EventEmitter outputs when multiple outputs exist' , ( ) => {
99- // TODO: whitespace are messing up test verification
100- verifyDeclaration ( {
101- before : `@Output() someChange1 = new EventEmitter();
102- @Output() someChange2 = new Subject();` ,
103- after : `readonly someChange1 = output();
104- @Output() someChange2 = new Subject();` ,
169+ it ( 'should migrate only EventEmitter outputs when multiple outputs exist' , async ( ) => {
170+ await verify ( {
171+ before : `
172+ import {Directive, Output, EventEmitter, Subject} from '@angular/core';
173+
174+ @Directive()
175+ export class TestDir {
176+ @Output() someChange1 = new EventEmitter();
177+ @Output() someChange2 = new Subject();
178+ }
179+ ` ,
180+ after : `
181+ import {Directive, Subject, output} from '@angular/core';
182+
183+ @Directive()
184+ export class TestDir {
185+ readonly someChange1 = output();
186+ @Output() someChange2 = new Subject();
187+ }
188+ ` ,
105189 } ) ;
106190 } ) ;
107191 } ) ;
108192
109193 describe ( '.next migration' , ( ) => {
110- it ( 'should migrate .next usages that should have been .emit' , ( ) => {
111- verify ( {
194+ it ( 'should migrate .next usages that should have been .emit' , async ( ) => {
195+ await verify ( {
112196 before : `
113197 import {Directive, Output, EventEmitter} from '@angular/core';
114198
@@ -136,8 +220,8 @@ describe('outputs', () => {
136220 } ) ;
137221 } ) ;
138222
139- it ( 'should _not_ migrate .next usages when problematic output usage is detected' , ( ) => {
140- verifyNoChange (
223+ it ( 'should _not_ migrate .next usages when problematic output usage is detected' , async ( ) => {
224+ await verifyNoChange (
141225 `
142226 import {Directive, Output, EventEmitter} from '@angular/core';
143227
@@ -159,8 +243,36 @@ describe('outputs', () => {
159243 } ) ;
160244
161245 describe ( '.complete migration' , ( ) => {
162- it ( 'should remove .complete usage for migrated outputs' , ( ) => {
163- verify ( {
246+ it ( 'should remove .complete usage for migrated outputs' , async ( ) => {
247+ await verify ( {
248+ before : `
249+ import {Directive, Output, EventEmitter} from '@angular/core';
250+
251+ @Directive()
252+ export class TestDir {
253+ @Output() someChange = new EventEmitter<string>();
254+
255+ ngOnDestroy() {
256+ this.someChange.complete();
257+ }
258+ }
259+ ` ,
260+ after : `
261+ import {Directive, output} from '@angular/core';
262+
263+ @Directive()
264+ export class TestDir {
265+ readonly someChange = output<string>();
266+
267+ ngOnDestroy() {
268+ }
269+ }
270+ ` ,
271+ } ) ;
272+ } ) ;
273+
274+ it ( 'should remove .complete usage with comments' , async ( ) => {
275+ await verify ( {
164276 before : `
165277 import {Directive, Output, EventEmitter} from '@angular/core';
166278
@@ -169,6 +281,7 @@ describe('outputs', () => {
169281 @Output() someChange = new EventEmitter<string>();
170282
171283 ngOnDestroy() {
284+ // maybe complete before the destroy?
172285 this.someChange.complete();
173286 }
174287 }
@@ -181,15 +294,14 @@ describe('outputs', () => {
181294 readonly someChange = output<string>();
182295
183296 ngOnDestroy() {
184-
185297 }
186298 }
187299 ` ,
188300 } ) ;
189301 } ) ;
190302
191- it ( 'should _not_ migrate .complete usage outside of expression statements' , ( ) => {
192- verifyNoChange (
303+ it ( 'should _not_ migrate .complete usage outside of expression statements' , async ( ) => {
304+ await verifyNoChange (
193305 `
194306 import {Directive, Output, EventEmitter} from '@angular/core';
195307
@@ -209,8 +321,8 @@ describe('outputs', () => {
209321 } ) ;
210322
211323 describe ( 'declarations _with_ problematic access patterns' , ( ) => {
212- it ( 'should _not_ migrate outputs that are used with .pipe' , ( ) => {
213- verifyNoChange ( `
324+ it ( 'should _not_ migrate outputs that are used with .pipe' , async ( ) => {
325+ await verifyNoChange ( `
214326 import {Directive, Output, EventEmitter} from '@angular/core';
215327
216328 @Directive()
@@ -224,8 +336,8 @@ describe('outputs', () => {
224336 ` ) ;
225337 } ) ;
226338
227- it ( 'should _not_ migrate outputs that are used with .pipe outside of a component class' , ( ) => {
228- verifyNoChange ( `
339+ it ( 'should _not_ migrate outputs that are used with .pipe outside of a component class' , async ( ) => {
340+ await verifyNoChange ( `
229341 import {Directive, Output, EventEmitter} from '@angular/core';
230342
231343 @Directive()
@@ -242,8 +354,8 @@ describe('outputs', () => {
242354 } ) ;
243355
244356 describe ( 'declarations other than EventEmitter' , ( ) => {
245- it ( 'should _not_ migrate outputs that are initialized with sth else than EventEmitter' , ( ) => {
246- verify ( {
357+ it ( 'should _not_ migrate outputs that are initialized with sth else than EventEmitter' , async ( ) => {
358+ await verify ( {
247359 before : populateDeclarationTestCase ( '@Output() protected someChange = new Subject();' ) ,
248360 after : populateDeclarationTestCase ( '@Output() protected someChange = new Subject();' ) ,
249361 } ) ;
@@ -252,14 +364,14 @@ describe('outputs', () => {
252364} ) ;
253365
254366async function verifyDeclaration ( testCase : { before : string ; after : string } ) {
255- verify ( {
367+ await verify ( {
256368 before : populateDeclarationTestCase ( testCase . before ) ,
257369 after : populateExpectedResult ( testCase . after ) ,
258370 } ) ;
259371}
260372
261373async function verifyNoChange ( beforeAndAfter : string ) {
262- verify ( { before : beforeAndAfter , after : beforeAndAfter } ) ;
374+ await verify ( { before : beforeAndAfter , after : beforeAndAfter } ) ;
263375}
264376
265377async function verify ( testCase : { before : string ; after : string } ) {
@@ -271,9 +383,10 @@ async function verify(testCase: {before: string; after: string}) {
271383 } ,
272384 ] ) ;
273385
274- let actual = fs . readFile ( absoluteFrom ( '/app.component.ts' ) ) ;
386+ const actual = fs . readFile ( absoluteFrom ( '/app.component.ts' ) ) . trim ( ) ;
387+ const expected = testCase . after . trim ( ) ;
275388
276- expect ( actual ) . toBe ( testCase . after ) ;
389+ expect ( actual ) . toBe ( expected ) ;
277390}
278391
279392function populateDeclarationTestCase ( declaration : string ) : string {
0 commit comments