@@ -53,6 +53,13 @@ interface Promise<T> {
53
53
* @returns A Promise for the completion of the callback.
54
54
*/
55
55
catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;
56
+ /**
57
+ * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The
58
+ * resolved value cannot be modified from the callback.
59
+ * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected).
60
+ * @returns A Promise for the completion of the callback.
61
+ */
62
+ finally(onfinally?: (() => void) | undefined | null): Promise<T>
56
63
}
57
64
interface PromiseConstructor {
58
65
/**
@@ -277,7 +284,30 @@ interface Array<T> {}`
277
284
}
278
285
}
279
286
280
- function testConvertToAsyncFunction ( it : Mocha . PendingTestFunction , caption : string , text : string , baselineFolder : string , includeLib ?: boolean , includeModule ?: boolean , expectFailure = false , onlyProvideAction = false ) {
287
+ const enum ConvertToAsyncTestFlags {
288
+ None ,
289
+ IncludeLib = 1 << 0 ,
290
+ IncludeModule = 1 << 1 ,
291
+ ExpectSuggestionDiagnostic = 1 << 2 ,
292
+ ExpectNoSuggestionDiagnostic = 1 << 3 ,
293
+ ExpectAction = 1 << 4 ,
294
+ ExpectNoAction = 1 << 5 ,
295
+
296
+ ExpectSuccess = ExpectSuggestionDiagnostic | ExpectAction ,
297
+ ExpectFailed = ExpectNoSuggestionDiagnostic | ExpectNoAction ,
298
+ }
299
+
300
+ function testConvertToAsyncFunction ( it : Mocha . PendingTestFunction , caption : string , text : string , baselineFolder : string , flags : ConvertToAsyncTestFlags ) {
301
+ const includeLib = ! ! ( flags & ConvertToAsyncTestFlags . IncludeLib ) ;
302
+ const includeModule = ! ! ( flags & ConvertToAsyncTestFlags . IncludeModule ) ;
303
+ const expectSuggestionDiagnostic = ! ! ( flags & ConvertToAsyncTestFlags . ExpectSuggestionDiagnostic ) ;
304
+ const expectNoSuggestionDiagnostic = ! ! ( flags & ConvertToAsyncTestFlags . ExpectNoSuggestionDiagnostic ) ;
305
+ const expectAction = ! ! ( flags & ConvertToAsyncTestFlags . ExpectAction ) ;
306
+ const expectNoAction = ! ! ( flags & ConvertToAsyncTestFlags . ExpectNoAction ) ;
307
+ const expectFailure = expectNoSuggestionDiagnostic || expectNoAction ;
308
+ Debug . assert ( ! ( expectSuggestionDiagnostic && expectNoSuggestionDiagnostic ) , "Cannot combine both 'ExpectSuggestionDiagnostic' and 'ExpectNoSuggestionDiagnostic'" ) ;
309
+ Debug . assert ( ! ( expectAction && expectNoAction ) , "Cannot combine both 'ExpectAction' and 'ExpectNoAction'" ) ;
310
+
281
311
const t = extractTest ( text ) ;
282
312
const selectionRange = t . ranges . get ( "selection" ) ! ;
283
313
if ( ! selectionRange ) {
@@ -320,35 +350,47 @@ interface Array<T> {}`
320
350
const diagnostics = languageService . getSuggestionDiagnostics ( f . path ) ;
321
351
const diagnostic = find ( diagnostics , diagnostic => diagnostic . messageText === Diagnostics . This_may_be_converted_to_an_async_function . message &&
322
352
diagnostic . start === context . span . start && diagnostic . length === context . span . length ) ;
323
- if ( expectFailure ) {
324
- assert . isUndefined ( diagnostic ) ;
325
- }
326
- else {
327
- assert . exists ( diagnostic ) ;
328
- }
329
-
330
353
const actions = codefix . getFixes ( context ) ;
331
354
const action = find ( actions , action => action . description === Diagnostics . Convert_to_async_function . message ) ;
332
- if ( expectFailure && ! onlyProvideAction ) {
333
- assert . isNotTrue ( action && action . changes . length > 0 ) ;
334
- return ;
335
- }
336
355
337
- assert . isTrue ( action && action . changes . length > 0 ) ;
356
+ let outputText : string | null ;
357
+ if ( action ?. changes . length ) {
358
+ const data : string [ ] = [ ] ;
359
+ data . push ( `// ==ORIGINAL==` ) ;
360
+ data . push ( text . replace ( "[#|" , "/*[#|*/" ) . replace ( "|]" , "/*|]*/" ) ) ;
361
+ const changes = action . changes ;
362
+ assert . lengthOf ( changes , 1 ) ;
363
+
364
+ data . push ( `// ==ASYNC FUNCTION::${ action . description } ==` ) ;
365
+ const newText = textChanges . applyChanges ( sourceFile . text , changes [ 0 ] . textChanges ) ;
366
+ data . push ( newText ) ;
367
+
368
+ const diagProgram = makeLanguageService ( { path, content : newText } , includeLib , includeModule ) . getProgram ( ) ! ;
369
+ assert . isFalse ( hasSyntacticDiagnostics ( diagProgram ) ) ;
370
+ outputText = data . join ( newLineCharacter ) ;
371
+ }
372
+ else {
373
+ // eslint-disable-next-line no-null/no-null
374
+ outputText = null ;
375
+ }
338
376
339
- const data : string [ ] = [ ] ;
340
- data . push ( `// ==ORIGINAL==` ) ;
341
- data . push ( text . replace ( "[#|" , "/*[#|*/" ) . replace ( "|]" , "/*|]*/" ) ) ;
342
- const changes = action ! . changes ;
343
- assert . lengthOf ( changes , 1 ) ;
377
+ Harness . Baseline . runBaseline ( `${ baselineFolder } /${ caption } ${ extension } ` , outputText ) ;
344
378
345
- data . push ( `// ==ASYNC FUNCTION::${ action ! . description } ==` ) ;
346
- const newText = textChanges . applyChanges ( sourceFile . text , changes [ 0 ] . textChanges ) ;
347
- data . push ( newText ) ;
379
+ if ( expectNoSuggestionDiagnostic ) {
380
+ assert . isUndefined ( diagnostic , "Expected code fix to not provide a suggestion diagnostic" ) ;
381
+ }
382
+ else if ( expectSuggestionDiagnostic ) {
383
+ assert . exists ( diagnostic , "Expected code fix to provide a suggestion diagnostic" ) ;
384
+ }
348
385
349
- const diagProgram = makeLanguageService ( { path, content : newText } , includeLib , includeModule ) . getProgram ( ) ! ;
350
- assert . isFalse ( hasSyntacticDiagnostics ( diagProgram ) ) ;
351
- Harness . Baseline . runBaseline ( `${ baselineFolder } /${ caption } ${ extension } ` , data . join ( newLineCharacter ) ) ;
386
+ if ( expectNoAction ) {
387
+ assert . isNotTrue ( ! ! action ?. changes . length , "Expected code fix to not provide an action" ) ;
388
+ assert . isNotTrue ( typeof outputText === "string" , "Expected code fix to not apply changes" ) ;
389
+ }
390
+ else if ( expectAction ) {
391
+ assert . isTrue ( ! ! action ?. changes . length , "Expected code fix to provide an action" ) ;
392
+ assert . isTrue ( typeof outputText === "string" , "Expected code fix to apply changes" ) ;
393
+ }
352
394
}
353
395
354
396
function makeLanguageService ( file : TestFSWithWatch . File , includeLib ?: boolean , includeModule ?: boolean ) {
@@ -372,19 +414,23 @@ interface Array<T> {}`
372
414
}
373
415
374
416
const _testConvertToAsyncFunction = createTestWrapper ( ( it , caption : string , text : string ) => {
375
- testConvertToAsyncFunction ( it , caption , text , "convertToAsyncFunction" , /*includeLib*/ true ) ;
417
+ testConvertToAsyncFunction ( it , caption , text , "convertToAsyncFunction" , ConvertToAsyncTestFlags . IncludeLib | ConvertToAsyncTestFlags . ExpectSuccess ) ;
376
418
} ) ;
377
419
378
420
const _testConvertToAsyncFunctionFailed = createTestWrapper ( ( it , caption : string , text : string ) => {
379
- testConvertToAsyncFunction ( it , caption , text , "convertToAsyncFunction" , /*includeLib*/ true , /*includeModule*/ false , /*expectFailure*/ true ) ;
421
+ testConvertToAsyncFunction ( it , caption , text , "convertToAsyncFunction" , ConvertToAsyncTestFlags . IncludeLib | ConvertToAsyncTestFlags . ExpectFailed ) ;
380
422
} ) ;
381
423
382
424
const _testConvertToAsyncFunctionFailedSuggestion = createTestWrapper ( ( it , caption : string , text : string ) => {
383
- testConvertToAsyncFunction ( it , caption , text , "convertToAsyncFunction" , /*includeLib*/ true , /*includeModule*/ false , /*expectFailure*/ true , /*onlyProvideAction*/ true ) ;
425
+ testConvertToAsyncFunction ( it , caption , text , "convertToAsyncFunction" , ConvertToAsyncTestFlags . IncludeLib | ConvertToAsyncTestFlags . ExpectNoSuggestionDiagnostic | ConvertToAsyncTestFlags . ExpectAction ) ;
426
+ } ) ;
427
+
428
+ const _testConvertToAsyncFunctionFailedAction = createTestWrapper ( ( it , caption : string , text : string ) => {
429
+ testConvertToAsyncFunction ( it , caption , text , "convertToAsyncFunction" , ConvertToAsyncTestFlags . IncludeLib | ConvertToAsyncTestFlags . ExpectSuggestionDiagnostic | ConvertToAsyncTestFlags . ExpectNoAction ) ;
384
430
} ) ;
385
431
386
432
const _testConvertToAsyncFunctionWithModule = createTestWrapper ( ( it , caption : string , text : string ) => {
387
- testConvertToAsyncFunction ( it , caption , text , "convertToAsyncFunction" , /*includeLib*/ true , /*includeModule*/ true ) ;
433
+ testConvertToAsyncFunction ( it , caption , text , "convertToAsyncFunction" , ConvertToAsyncTestFlags . IncludeLib | ConvertToAsyncTestFlags . IncludeModule | ConvertToAsyncTestFlags . ExpectSuccess ) ;
388
434
} ) ;
389
435
390
436
describe ( "unittests:: services:: convertToAsyncFunction" , ( ) => {
@@ -435,11 +481,11 @@ function [#|f|](): Promise<void>{
435
481
function [#|f|]():Promise<void> {
436
482
return fetch('https://typescriptlang.org').then(result => { console.log(result); }).catch(err => { console.log(err); });
437
483
}` ) ;
438
- _testConvertToAsyncFunction ( "convertToAsyncFunction_CatchAndRej" , `
484
+ _testConvertToAsyncFunctionFailed ( "convertToAsyncFunction_CatchAndRej" , `
439
485
function [#|f|]():Promise<void> {
440
486
return fetch('https://typescriptlang.org').then(result => { console.log(result); }, rejection => { console.log("rejected:", rejection); }).catch(err => { console.log(err) });
441
487
}` ) ;
442
- _testConvertToAsyncFunction ( "convertToAsyncFunction_CatchAndRejRef" , `
488
+ _testConvertToAsyncFunctionFailed ( "convertToAsyncFunction_CatchAndRejRef" , `
443
489
function [#|f|]():Promise<void> {
444
490
return fetch('https://typescriptlang.org').then(res, rej).catch(catch_err)
445
491
}
@@ -1718,5 +1764,76 @@ function [#|foo|](p: Promise<string[]>) {
1718
1764
}
1719
1765
` ) ;
1720
1766
1767
+ _testConvertToAsyncFunction ( "convertToAsyncFunction_thenNoArguments" , `
1768
+ declare function foo(): Promise<number>;
1769
+ function [#|f|](): Promise<number> {
1770
+ return foo().then();
1771
+ }` ) ;
1772
+ _testConvertToAsyncFunction ( "convertToAsyncFunction_catchNoArguments" , `
1773
+ declare function foo(): Promise<number>;
1774
+ function [#|f|](): Promise<number> {
1775
+ return foo().catch();
1776
+ }` ) ;
1777
+ _testConvertToAsyncFunction ( "convertToAsyncFunction_chainedThenCatchThen" , `
1778
+ declare function foo(): Promise<number>;
1779
+ function [#|f|](): Promise<number> {
1780
+ return foo().then(x => Promise.resolve(x + 1)).catch(() => 1).then(y => y + 2);
1781
+ }` ) ;
1782
+ _testConvertToAsyncFunction ( "convertToAsyncFunction_finally" , `
1783
+ declare function foo(): Promise<number>;
1784
+ function [#|f|](): Promise<number> {
1785
+ return foo().finally(() => console.log("done"));
1786
+ }` ) ;
1787
+ _testConvertToAsyncFunction ( "convertToAsyncFunction_finallyNoArguments" , `
1788
+ declare function foo(): Promise<number>;
1789
+ function [#|f|](): Promise<number> {
1790
+ return foo().finally();
1791
+ }` ) ;
1792
+ _testConvertToAsyncFunction ( "convertToAsyncFunction_finallyNull" , `
1793
+ declare function foo(): Promise<number>;
1794
+ function [#|f|](): Promise<number> {
1795
+ return foo().finally(null);
1796
+ }` ) ;
1797
+ _testConvertToAsyncFunction ( "convertToAsyncFunction_finallyUndefined" , `
1798
+ declare function foo(): Promise<number>;
1799
+ function [#|f|](): Promise<number> {
1800
+ return foo().finally(undefined);
1801
+ }` ) ;
1802
+ _testConvertToAsyncFunction ( "convertToAsyncFunction_thenFinally" , `
1803
+ declare function foo(): Promise<number>;
1804
+ function [#|f|](): Promise<number> {
1805
+ return foo().then(x => x + 1).finally(() => console.log("done"));
1806
+ }` ) ;
1807
+ _testConvertToAsyncFunction ( "convertToAsyncFunction_thenFinallyThen" , `
1808
+ declare function foo(): Promise<number>;
1809
+ function [#|f|](): Promise<number> {
1810
+ return foo().then(x => Promise.resolve(x + 1)).finally(() => console.log("done")).then(y => y + 2);
1811
+ }` ) ;
1812
+ _testConvertToAsyncFunctionFailedAction ( "convertToAsyncFunction_returnInBranch" , `
1813
+ declare function foo(): Promise<number>;
1814
+ function [#|f|](): Promise<number> {
1815
+ return foo().then(() => {
1816
+ if (Math.random()) {
1817
+ return 1;
1818
+ }
1819
+ return 2;
1820
+ }).then(a => {
1821
+ return a + 1;
1822
+ });
1823
+ }
1824
+ ` ) ;
1825
+ _testConvertToAsyncFunctionFailedAction ( "convertToAsyncFunction_partialReturnInBranch" , `
1826
+ declare function foo(): Promise<number>;
1827
+ function [#|f|](): Promise<number> {
1828
+ return foo().then(() => {
1829
+ if (Math.random()) {
1830
+ return 1;
1831
+ }
1832
+ console.log("foo");
1833
+ }).then(a => {
1834
+ return a + 1;
1835
+ });
1836
+ }
1837
+ ` ) ;
1721
1838
} ) ;
1722
1839
}
0 commit comments