• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import * as ts from "../../_namespaces/ts";
2import * as Harness from "../../_namespaces/Harness";
3
4const libFile: ts.TestFSWithWatch.File = {
5    path: "/a/lib/lib.d.ts",
6    content: `/// <reference no-default-lib="true"/>
7interface Boolean {}
8interface Function {}
9interface IArguments {}
10interface Number { toExponential: any; }
11interface Object {}
12declare function fetch(input?, init?): Promise<Response>;
13interface Response extends Body {
14    readonly headers: Headers;
15    readonly ok: boolean;
16    readonly redirected: boolean;
17    readonly status: number;
18    readonly statusText: string;
19    readonly trailer: Promise<Headers>;
20    readonly type: ResponseType;
21    readonly url: string;
22    clone(): Response;
23}
24interface Body {
25    readonly body: ReadableStream | null;
26    readonly bodyUsed: boolean;
27    arrayBuffer(): Promise<ArrayBuffer>;
28    blob(): Promise<Blob>;
29    formData(): Promise<FormData>;
30    json(): Promise<any>;
31    text(): Promise<string>;
32}
33declare type PromiseConstructorLike = new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void) => PromiseLike<T>;
34interface PromiseLike<T> {
35    /**
36     * Attaches callbacks for the resolution and/or rejection of the Promise.
37     * @param onfulfilled The callback to execute when the Promise is resolved.
38     * @param onrejected The callback to execute when the Promise is rejected.
39     * @returns A Promise for the completion of which ever callback is executed.
40     */
41    then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): PromiseLike<TResult1 | TResult2>;
42}
43interface Promise<T> {
44    /**
45     * Attaches callbacks for the resolution and/or rejection of the Promise.
46     * @param onfulfilled The callback to execute when the Promise is resolved.
47     * @param onrejected The callback to execute when the Promise is rejected.
48     * @returns A Promise for the completion of which ever callback is executed.
49     */
50    then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;
51
52    /**
53     * Attaches a callback for only the rejection of the Promise.
54     * @param onrejected The callback to execute when the Promise is rejected.
55     * @returns A Promise for the completion of the callback.
56     */
57    catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;
58    /**
59     * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The
60     * resolved value cannot be modified from the callback.
61     * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected).
62     * @returns A Promise for the completion of the callback.
63     */
64    finally(onfinally?: (() => void) | undefined | null): Promise<T>
65}
66interface PromiseConstructor {
67    /**
68     * A reference to the prototype.
69     */
70    readonly prototype: Promise<any>;
71
72    /**
73     * Creates a new Promise.
74     * @param executor A callback used to initialize the promise. This callback is passed two arguments:
75     * a resolve callback used resolve the promise with a value or the result of another promise,
76     * and a reject callback used to reject the promise with a provided reason or error.
77     */
78    new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;
79
80    /**
81     * Creates a Promise that is resolved with an array of results when all of the provided Promises
82     * resolve, or rejected when any Promise is rejected.
83     * @param values An array of Promises.
84     * @returns A new Promise.
85     */
86    all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>, T10 | PromiseLike<T10>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;
87
88    /**
89     * Creates a Promise that is resolved with an array of results when all of the provided Promises
90     * resolve, or rejected when any Promise is rejected.
91     * @param values An array of Promises.
92     * @returns A new Promise.
93     */
94    all<T1, T2, T3, T4, T5, T6, T7, T8, T9>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;
95
96    /**
97     * Creates a Promise that is resolved with an array of results when all of the provided Promises
98     * resolve, or rejected when any Promise is rejected.
99     * @param values An array of Promises.
100     * @returns A new Promise.
101     */
102    all<T1, T2, T3, T4, T5, T6, T7, T8>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>;
103
104    /**
105     * Creates a Promise that is resolved with an array of results when all of the provided Promises
106     * resolve, or rejected when any Promise is rejected.
107     * @param values An array of Promises.
108     * @returns A new Promise.
109     */
110    all<T1, T2, T3, T4, T5, T6, T7>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>]): Promise<[T1, T2, T3, T4, T5, T6, T7]>;
111
112    /**
113     * Creates a Promise that is resolved with an array of results when all of the provided Promises
114     * resolve, or rejected when any Promise is rejected.
115     * @param values An array of Promises.
116     * @returns A new Promise.
117     */
118    all<T1, T2, T3, T4, T5, T6>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>]): Promise<[T1, T2, T3, T4, T5, T6]>;
119
120    /**
121     * Creates a Promise that is resolved with an array of results when all of the provided Promises
122     * resolve, or rejected when any Promise is rejected.
123     * @param values An array of Promises.
124     * @returns A new Promise.
125     */
126    all<T1, T2, T3, T4, T5>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>]): Promise<[T1, T2, T3, T4, T5]>;
127
128    /**
129     * Creates a Promise that is resolved with an array of results when all of the provided Promises
130     * resolve, or rejected when any Promise is rejected.
131     * @param values An array of Promises.
132     * @returns A new Promise.
133     */
134    all<T1, T2, T3, T4>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>]): Promise<[T1, T2, T3, T4]>;
135
136    /**
137     * Creates a Promise that is resolved with an array of results when all of the provided Promises
138     * resolve, or rejected when any Promise is rejected.
139     * @param values An array of Promises.
140     * @returns A new Promise.
141     */
142    all<T1, T2, T3>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>]): Promise<[T1, T2, T3]>;
143
144    /**
145     * Creates a Promise that is resolved with an array of results when all of the provided Promises
146     * resolve, or rejected when any Promise is rejected.
147     * @param values An array of Promises.
148     * @returns A new Promise.
149     */
150    all<T1, T2>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<[T1, T2]>;
151
152    /**
153     * Creates a Promise that is resolved with an array of results when all of the provided Promises
154     * resolve, or rejected when any Promise is rejected.
155     * @param values An array of Promises.
156     * @returns A new Promise.
157     */
158    all<T>(values: (T | PromiseLike<T>)[]): Promise<T[]>;
159
160    /**
161     * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved
162     * or rejected.
163     * @param values An array of Promises.
164     * @returns A new Promise.
165     */
166    race<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike<T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>, T10 | PromiseLike<T10>]): Promise<T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8 | T9 | T10>;
167
168    /**
169     * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved
170     * or rejected.
171     * @param values An array of Promises.
172     * @returns A new Promise.
173     */
174    race<T1, T2, T3, T4, T5, T6, T7, T8, T9>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike<T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>]): Promise<T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8 | T9>;
175
176    /**
177     * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved
178     * or rejected.
179     * @param values An array of Promises.
180     * @returns A new Promise.
181     */
182    race<T1, T2, T3, T4, T5, T6, T7, T8>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike<T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>]): Promise<T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8>;
183
184    /**
185     * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved
186     * or rejected.
187     * @param values An array of Promises.
188     * @returns A new Promise.
189     */
190    race<T1, T2, T3, T4, T5, T6, T7>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike<T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>]): Promise<T1 | T2 | T3 | T4 | T5 | T6 | T7>;
191
192    /**
193     * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved
194     * or rejected.
195     * @param values An array of Promises.
196     * @returns A new Promise.
197     */
198    race<T1, T2, T3, T4, T5, T6>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike<T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>]): Promise<T1 | T2 | T3 | T4 | T5 | T6>;
199
200    /**
201     * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved
202     * or rejected.
203     * @param values An array of Promises.
204     * @returns A new Promise.
205     */
206    race<T1, T2, T3, T4, T5>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike<T4>, T5 | PromiseLike<T5>]): Promise<T1 | T2 | T3 | T4 | T5>;
207
208    /**
209     * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved
210     * or rejected.
211     * @param values An array of Promises.
212     * @returns A new Promise.
213     */
214    race<T1, T2, T3, T4>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike<T4>]): Promise<T1 | T2 | T3 | T4>;
215
216    /**
217     * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved
218     * or rejected.
219     * @param values An array of Promises.
220     * @returns A new Promise.
221     */
222    race<T1, T2, T3>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>]): Promise<T1 | T2 | T3>;
223
224    /**
225     * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved
226     * or rejected.
227     * @param values An array of Promises.
228     * @returns A new Promise.
229     */
230    race<T1, T2>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<T1 | T2>;
231
232    /**
233     * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved
234     * or rejected.
235     * @param values An array of Promises.
236     * @returns A new Promise.
237     */
238    race<T>(values: (T | PromiseLike<T>)[]): Promise<T>;
239
240    /**
241     * Creates a new rejected promise for the provided reason.
242     * @param reason The reason the promise was rejected.
243     * @returns A new rejected Promise.
244     */
245    reject<T = never>(reason?: any): Promise<T>;
246
247    /**
248     * Creates a new resolved promise for the provided value.
249     * @param value A promise.
250     * @returns A promise whose internal state matches the provided promise.
251     */
252    resolve<T>(value: T | PromiseLike<T>): Promise<T>;
253
254    /**
255     * Creates a new resolved promise .
256     * @returns A resolved promise.
257     */
258    resolve(): Promise<void>;
259}
260
261declare var Promise: PromiseConstructor;
262interface RegExp {}
263interface String { charAt: any; }
264interface Array<T> {}`
265};
266
267const moduleFile: ts.TestFSWithWatch.File = {
268    path: "/module.ts",
269    content:
270`export function fn(res: any): any {
271    return res;
272}`
273};
274
275type WithSkipAndOnly<T extends any[]> = ((...args: T) => void) & {
276    skip: (...args: T) => void;
277    only: (...args: T) => void;
278};
279
280function createTestWrapper<T extends any[]>(fn: (it: Mocha.PendingTestFunction, ...args: T) => void): WithSkipAndOnly<T> {
281    wrapped.skip = (...args: T) => fn(it.skip, ...args);
282    wrapped.only = (...args: T) => fn(it.only, ...args);
283    return wrapped;
284    function wrapped(...args: T) {
285        return fn(it, ...args);
286    }
287}
288
289const enum ConvertToAsyncTestFlags {
290    None,
291    IncludeLib = 1 << 0,
292    IncludeModule = 1 << 1,
293    ExpectSuggestionDiagnostic = 1 << 2,
294    ExpectNoSuggestionDiagnostic = 1 << 3,
295    ExpectAction = 1 << 4,
296    ExpectNoAction = 1 << 5,
297
298    ExpectSuccess = ExpectSuggestionDiagnostic | ExpectAction,
299    ExpectFailed = ExpectNoSuggestionDiagnostic | ExpectNoAction,
300}
301
302function testConvertToAsyncFunction(it: Mocha.PendingTestFunction, caption: string, text: string, baselineFolder: string, flags: ConvertToAsyncTestFlags) {
303    const includeLib = !!(flags & ConvertToAsyncTestFlags.IncludeLib);
304    const includeModule = !!(flags & ConvertToAsyncTestFlags.IncludeModule);
305    const expectSuggestionDiagnostic = !!(flags & ConvertToAsyncTestFlags.ExpectSuggestionDiagnostic);
306    const expectNoSuggestionDiagnostic = !!(flags & ConvertToAsyncTestFlags.ExpectNoSuggestionDiagnostic);
307    const expectAction = !!(flags & ConvertToAsyncTestFlags.ExpectAction);
308    const expectNoAction = !!(flags & ConvertToAsyncTestFlags.ExpectNoAction);
309    const expectFailure = expectNoSuggestionDiagnostic || expectNoAction;
310    ts.Debug.assert(!(expectSuggestionDiagnostic && expectNoSuggestionDiagnostic), "Cannot combine both 'ExpectSuggestionDiagnostic' and 'ExpectNoSuggestionDiagnostic'");
311    ts.Debug.assert(!(expectAction && expectNoAction), "Cannot combine both 'ExpectAction' and 'ExpectNoAction'");
312
313    const t = ts.extractTest(text);
314    const selectionRange = t.ranges.get("selection")!;
315    if (!selectionRange) {
316        throw new Error(`Test ${caption} does not specify selection range`);
317    }
318
319    const extensions = expectFailure ? [ts.Extension.Ts] : [ts.Extension.Ts, ts.Extension.Js];
320
321    extensions.forEach(extension =>
322        it(`${caption} [${extension}]`, () => runBaseline(extension)));
323
324    function runBaseline(extension: ts.Extension) {
325        const path = "/a" + extension;
326        const languageService = makeLanguageService({ path, content: t.source }, includeLib, includeModule);
327        const program = languageService.getProgram()!;
328
329        if (hasSyntacticDiagnostics(program)) {
330            // Don't bother generating JS baselines for inputs that aren't valid JS.
331            assert.equal(ts.Extension.Js, extension, "Syntactic diagnostics found in non-JS file");
332            return;
333        }
334
335        const f = {
336            path,
337            content: t.source
338        };
339
340        const sourceFile = program.getSourceFile(path)!;
341        const context: ts.CodeFixContext = {
342            errorCode: 80006,
343            span: { start: selectionRange.pos, length: selectionRange.end - selectionRange.pos },
344            sourceFile,
345            program,
346            cancellationToken: { throwIfCancellationRequested: ts.noop, isCancellationRequested: ts.returnFalse },
347            preferences: ts.emptyOptions,
348            host: ts.notImplementedHost,
349            formatContext: ts.formatting.getFormatContext(ts.testFormatSettings, ts.notImplementedHost)
350        };
351
352        const diagnostics = languageService.getSuggestionDiagnostics(f.path);
353        const diagnostic = ts.find(diagnostics, diagnostic => diagnostic.messageText === ts.Diagnostics.This_may_be_converted_to_an_async_function.message &&
354            diagnostic.start === context.span.start && diagnostic.length === context.span.length);
355        const actions = ts.codefix.getFixes(context);
356        const action = ts.find(actions, action => action.description === ts.Diagnostics.Convert_to_async_function.message);
357
358        let outputText: string | null;
359        if (action?.changes.length) {
360            const data: string[] = [];
361            data.push(`// ==ORIGINAL==`);
362            data.push(text.replace("[#|", "/*[#|*/").replace("|]", "/*|]*/"));
363            const changes = action.changes;
364            assert.lengthOf(changes, 1);
365
366            data.push(`// ==ASYNC FUNCTION::${action.description}==`);
367            const newText = ts.textChanges.applyChanges(sourceFile.text, changes[0].textChanges);
368            data.push(newText);
369
370            const diagProgram = makeLanguageService({ path, content: newText }, includeLib, includeModule).getProgram()!;
371            assert.isFalse(hasSyntacticDiagnostics(diagProgram));
372            outputText = data.join(ts.newLineCharacter);
373        }
374        else {
375            // eslint-disable-next-line no-null/no-null
376            outputText = null;
377        }
378
379        Harness.Baseline.runBaseline(`${baselineFolder}/${caption}${extension}`, outputText);
380
381        if (expectNoSuggestionDiagnostic) {
382            assert.isUndefined(diagnostic, "Expected code fix to not provide a suggestion diagnostic");
383        }
384        else if (expectSuggestionDiagnostic) {
385            assert.exists(diagnostic, "Expected code fix to provide a suggestion diagnostic");
386        }
387
388        if (expectNoAction) {
389            assert.isNotTrue(!!action?.changes.length, "Expected code fix to not provide an action");
390            assert.isNotTrue(typeof outputText === "string", "Expected code fix to not apply changes");
391        }
392        else if (expectAction) {
393            assert.isTrue(!!action?.changes.length, "Expected code fix to provide an action");
394            assert.isTrue(typeof outputText === "string", "Expected code fix to apply changes");
395        }
396    }
397
398    function makeLanguageService(file: ts.TestFSWithWatch.File, includeLib?: boolean, includeModule?: boolean) {
399        const files = [file];
400        if (includeLib) {
401            files.push(libFile); // libFile is expensive to parse repeatedly - only test when required
402        }
403        if (includeModule) {
404            files.push(moduleFile);
405        }
406        const host = ts.projectSystem.createServerHost(files);
407        const projectService = ts.projectSystem.createProjectService(host);
408        projectService.openClientFile(file.path);
409        return ts.first(projectService.inferredProjects).getLanguageService();
410    }
411
412    function hasSyntacticDiagnostics(program: ts.Program) {
413        const diags = program.getSyntacticDiagnostics();
414        return ts.length(diags) > 0;
415    }
416}
417
418const _testConvertToAsyncFunction = createTestWrapper((it, caption: string, text: string) => {
419    testConvertToAsyncFunction(it, caption, text, "convertToAsyncFunction", ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectSuccess);
420});
421
422const _testConvertToAsyncFunctionFailed = createTestWrapper((it, caption: string, text: string) => {
423    testConvertToAsyncFunction(it, caption, text, "convertToAsyncFunction", ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectFailed);
424});
425
426const _testConvertToAsyncFunctionFailedSuggestion = createTestWrapper((it, caption: string, text: string) => {
427    testConvertToAsyncFunction(it, caption, text, "convertToAsyncFunction", ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectNoSuggestionDiagnostic | ConvertToAsyncTestFlags.ExpectAction);
428});
429
430const _testConvertToAsyncFunctionFailedAction = createTestWrapper((it, caption: string, text: string) => {
431    testConvertToAsyncFunction(it, caption, text, "convertToAsyncFunction", ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectSuggestionDiagnostic | ConvertToAsyncTestFlags.ExpectNoAction);
432});
433
434const _testConvertToAsyncFunctionWithModule = createTestWrapper((it, caption: string, text: string) => {
435    testConvertToAsyncFunction(it, caption, text, "convertToAsyncFunction", ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.IncludeModule | ConvertToAsyncTestFlags.ExpectSuccess);
436});
437
438describe("unittests:: services:: convertToAsyncFunction", () => {
439    _testConvertToAsyncFunction("convertToAsyncFunction_basic", `
440function [#|f|](): Promise<void>{
441    return fetch('https://typescriptlang.org').then(result => { console.log(result) });
442}`);
443    _testConvertToAsyncFunction("convertToAsyncFunction_arrayBindingPattern", `
444function [#|f|](): Promise<void>{
445    return fetch('https://typescriptlang.org').then(([result]) => { console.log(result) });
446}`);
447    _testConvertToAsyncFunction("convertToAsyncFunction_objectBindingPattern", `
448function [#|f|](): Promise<void>{
449    return fetch('https://typescriptlang.org').then(({ result }) => { console.log(result) });
450}`);
451    _testConvertToAsyncFunction("convertToAsyncFunction_arrayBindingPatternRename", `
452function [#|f|](): Promise<void>{
453    const result = getResult();
454    return fetch('https://typescriptlang.org').then(([result]) => { console.log(result) });
455}`);
456    _testConvertToAsyncFunction("convertToAsyncFunction_objectBindingPatternRename", `
457function [#|f|](): Promise<void>{
458    const result = getResult();
459    return fetch('https://typescriptlang.org').then(({ result }) => { console.log(result) });
460}`);
461    _testConvertToAsyncFunction("convertToAsyncFunction_basicNoReturnTypeAnnotation", `
462function [#|f|]() {
463    return fetch('https://typescriptlang.org').then(result => { console.log(result) });
464}`);
465    _testConvertToAsyncFunction("convertToAsyncFunction_basicWithComments", `
466function [#|f|](): Promise<void>{
467    /* Note - some of these comments are removed during the refactor. This is not ideal. */
468
469    // a
470    /*b*/ return /*c*/ fetch( /*d*/ 'https://typescriptlang.org' /*e*/).then( /*f*/ result /*g*/ => { /*h*/ console.log(/*i*/ result /*j*/) /*k*/}/*l*/);
471    // m
472}`);
473
474    _testConvertToAsyncFunction("convertToAsyncFunction_ArrowFunction", `
475[#|():Promise<void> => {|]
476    return fetch('https://typescriptlang.org').then(result => console.log(result));
477}`);
478    _testConvertToAsyncFunction("convertToAsyncFunction_ArrowFunctionNoAnnotation", `
479[#|() => {|]
480    return fetch('https://typescriptlang.org').then(result => console.log(result));
481}`);
482    _testConvertToAsyncFunction("convertToAsyncFunction_Catch", `
483function [#|f|]():Promise<void> {
484    return fetch('https://typescriptlang.org').then(result => { console.log(result); }).catch(err => { console.log(err); });
485}`);
486    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_CatchAndRej", `
487function [#|f|]():Promise<void> {
488    return fetch('https://typescriptlang.org').then(result => { console.log(result); }, rejection => { console.log("rejected:", rejection); }).catch(err => { console.log(err) });
489}`);
490    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_CatchAndRejRef", `
491function [#|f|]():Promise<void> {
492    return fetch('https://typescriptlang.org').then(res, rej).catch(catch_err)
493}
494function res(result){
495    console.log(result);
496}
497function rej(rejection){
498    return rejection.ok;
499}
500function catch_err(err){
501    console.log(err);
502}`);
503    _testConvertToAsyncFunction("convertToAsyncFunction_CatchRef", `
504function [#|f|]():Promise<void> {
505    return fetch('https://typescriptlang.org').then(res).catch(catch_err)
506}
507function res(result){
508    console.log(result);
509}
510function catch_err(err){
511    console.log(err);
512}
513`);
514    _testConvertToAsyncFunction("convertToAsyncFunction_CatchNoBrackets", `
515function [#|f|]():Promise<void> {
516    return fetch('https://typescriptlang.org').then(result => console.log(result)).catch(err => console.log(err));
517}`
518    );
519    _testConvertToAsyncFunction("convertToAsyncFunction_IgnoreArgs1", `
520function [#|f|](): Promise<void> {
521    return fetch('https://typescriptlang.org').then( _ => { console.log("done"); });
522}`
523    );
524    _testConvertToAsyncFunction("convertToAsyncFunction_IgnoreArgs2", `
525function [#|f|](): Promise<void> {
526    return fetch('https://typescriptlang.org').then( () => console.log("done") );
527}`
528    );
529    _testConvertToAsyncFunction("convertToAsyncFunction_IgnoreArgs3", `
530function [#|f|](): Promise<void> {
531    return fetch('https://typescriptlang.org').then( () => console.log("almost done") ).then( () => console.log("done") );
532}`
533    );
534    _testConvertToAsyncFunction("convertToAsyncFunction_IgnoreArgs4", `
535function [#|f|]() {
536    return fetch('https://typescriptlang.org').then(res);
537}
538function res(){
539    console.log("done");
540}`
541    );
542
543    _testConvertToAsyncFunction("convertToAsyncFunction_Method", `
544class Parser {
545    [#|f|]():Promise<void> {
546        return fetch('https://typescriptlang.org').then(result => console.log(result));
547    }
548}`
549    );
550    _testConvertToAsyncFunction("convertToAsyncFunction_MultipleCatches", `
551function [#|f|](): Promise<void> {
552    return fetch('https://typescriptlang.org').then(res => console.log(res)).catch(err => console.log("err", err)).catch(err2 => console.log("err2", err2));
553}`
554    );
555    _testConvertToAsyncFunction("convertToAsyncFunction_MultipleThens", `
556function [#|f|]():Promise<void> {
557    return fetch('https://typescriptlang.org').then(res).then(res2);
558}
559function res(result){
560    return result.ok;
561}
562function res2(result2){
563    console.log(result2);
564}`
565    );
566    _testConvertToAsyncFunction("convertToAsyncFunction_MultipleThensSameVarName", `
567function [#|f|]():Promise<void> {
568    return fetch('https://typescriptlang.org').then(res).then(res2);
569}
570function res(result){
571    return result.ok;
572}
573function res2(result){
574    return result.bodyUsed;
575}
576`
577    );
578    _testConvertToAsyncFunction("convertToAsyncFunction_NoRes", `
579function [#|f|]():Promise<void | Response> {
580    return fetch('https://typescriptlang.org').then(null, rejection => console.log("rejected:", rejection));
581}
582`
583    );
584    _testConvertToAsyncFunction("convertToAsyncFunction_NoRes2", `
585function [#|f|]():Promise<void | Response> {
586    return fetch('https://typescriptlang.org').then(undefined).catch(rej => console.log(rej));
587}
588`
589    );
590
591    _testConvertToAsyncFunction("convertToAsyncFunction_NoRes3", `
592function [#|f|]():Promise<void | Response> {
593    return fetch('https://typescriptlang.org').catch(rej => console.log(rej));
594}
595`
596    );
597    _testConvertToAsyncFunction("convertToAsyncFunction_NoRes4", `
598function [#|f|]() {
599    return fetch('https://typescriptlang.org').then(undefined, rejection => console.log("rejected:", rejection));
600}
601`
602    );
603    _testConvertToAsyncFunction("convertToAsyncFunction_NoCatchHandler", `
604function [#|f|]() {
605    return fetch('https://typescriptlang.org').then(x => x.statusText).catch(undefined);
606}
607`
608    );
609    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_NoSuggestion", `
610function [#|f|]():Promise<Response> {
611    return fetch('https://typescriptlang.org');
612}
613`
614    );
615    _testConvertToAsyncFunction("convertToAsyncFunction_PromiseDotAll", `
616function [#|f|]():Promise<void>{
617    return Promise.all([fetch('https://typescriptlang.org'), fetch('https://microsoft.com'), fetch('https://youtube.com')]).then(function(vals){
618        vals.forEach(console.log);
619    });
620}
621`
622    );
623    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_NoSuggestionNoPromise", `
624function [#|f|]():void{
625}
626`
627    );
628    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_Rej", `
629function [#|f|]():Promise<void> {
630    return fetch('https://typescriptlang.org').then(result => { console.log(result); }, rejection => { console.log("rejected:", rejection); });
631}
632`
633    );
634    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_RejRef", `
635function [#|f|]():Promise<void> {
636    return fetch('https://typescriptlang.org').then(res, rej);
637}
638function res(result){
639    console.log(result);
640}
641function rej(err){
642    console.log(err);
643}
644`
645    );
646    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_RejNoBrackets", `
647function [#|f|]():Promise<void> {
648    return fetch('https://typescriptlang.org').then(result => console.log(result), rejection => console.log("rejected:", rejection));
649}
650`
651    );
652
653    _testConvertToAsyncFunction("convertToAsyncFunction_ResRef", `
654function [#|f|]():Promise<boolean> {
655    return fetch('https://typescriptlang.org').then(res);
656}
657function res(result){
658    return result.ok;
659}
660`
661    );
662
663    _testConvertToAsyncFunction("convertToAsyncFunction_ResRef1", `
664class Foo {
665    public [#|method|](): Promise<boolean> {
666        return fetch('a').then(this.foo);
667    }
668
669    private foo(res) {
670        return res.ok;
671    }
672}
673        `);
674
675    _testConvertToAsyncFunction("convertToAsyncFunction_ResRef2", `
676class Foo {
677    public [#|method|](): Promise<Response> {
678        return fetch('a').then(this.foo);
679    }
680
681    private foo = res => res;
682}
683        `);
684
685    _testConvertToAsyncFunction("convertToAsyncFunction_ResRef3", `
686const res = (result) => {
687    return result.ok;
688}
689function [#|f|](): Promise<boolean> {
690    return fetch('https://typescriptlang.org').then(res);
691}
692        `
693    );
694
695    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_NoSuggestionResRef1", `
696const res = 1;
697function [#|f|]() {
698    return fetch('https://typescriptlang.org').then(res);
699}
700`
701    );
702
703    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_NoSuggestionResRef2", `
704class Foo {
705    private foo = 1;
706    public [#|method|](): Promise<boolean> {
707        return fetch('a').then(this.foo);
708    }
709}
710`
711    );
712
713    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_NoSuggestionResRef3", `
714const res = undefined;
715function [#|f|]() {
716    return fetch('https://typescriptlang.org').then(res);
717}
718`
719    );
720
721    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_NoSuggestionResRef4", `
722class Foo {
723    private foo = undefined;
724    public [#|method|](): Promise<boolean> {
725        return fetch('a').then(this.foo);
726    }
727}
728`
729    );
730
731    _testConvertToAsyncFunction("convertToAsyncFunction_ResRefNoReturnVal", `
732function [#|f|]():Promise<void> {
733    return fetch('https://typescriptlang.org').then(res);
734}
735function res(result){
736    console.log(result);
737}
738`
739    );
740
741    _testConvertToAsyncFunction("convertToAsyncFunction_ResRefNoReturnVal1", `
742class Foo {
743    public [#|method|](): Promise<void> {
744        return fetch('a').then(this.foo);
745    }
746
747    private foo(res) {
748        console.log(res);
749    }
750}
751        `);
752
753    _testConvertToAsyncFunction("convertToAsyncFunction_NoBrackets", `
754function [#|f|]():Promise<void> {
755    return fetch('https://typescriptlang.org').then(result => console.log(result));
756}
757`
758    );
759    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_Finally1", `
760function [#|finallyTest|](): Promise<void> {
761    return fetch("https://typescriptlang.org").then(res => console.log(res)).catch(rej => console.log("error", rej)).finally(console.log("finally!"));
762}
763`
764    );
765
766    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_Finally2", `
767function [#|finallyTest|](): Promise<void> {
768    return fetch("https://typescriptlang.org").then(res => console.log(res)).finally(console.log("finally!"));
769}
770`
771    );
772
773    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_Finally3", `
774function [#|finallyTest|](): Promise<void> {
775    return fetch("https://typescriptlang.org").finally(console.log("finally!"));
776}
777`
778    );
779    _testConvertToAsyncFunction("convertToAsyncFunction_InnerPromise", `
780function [#|innerPromise|](): Promise<string> {
781    return fetch("https://typescriptlang.org").then(resp => {
782        var blob2 = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error');
783        return blob2;
784    }).then(blob => {
785        return blob.toString();
786    });
787}
788`
789    );
790    _testConvertToAsyncFunction("convertToAsyncFunction_InnerPromiseRet", `
791function [#|innerPromise|](): Promise<string> {
792    return fetch("https://typescriptlang.org").then(resp => {
793        return resp.blob().then(blob => blob.byteOffset).catch(err => 'Error');
794    }).then(blob => {
795        return blob.toString();
796    });
797}
798`
799    );
800
801    _testConvertToAsyncFunction("convertToAsyncFunction_InnerPromiseRetBinding1", `
802function [#|innerPromise|](): Promise<string> {
803    return fetch("https://typescriptlang.org").then(resp => {
804        return resp.blob().then(({ blob }) => blob.byteOffset).catch(({ message }) => 'Error ' + message);
805    }).then(blob => {
806        return blob.toString();
807    });
808}
809`
810    );
811
812    _testConvertToAsyncFunction("convertToAsyncFunction_InnerPromiseRetBinding2", `
813function [#|innerPromise|](): Promise<string> {
814    return fetch("https://typescriptlang.org").then(resp => {
815        return resp.blob().then(blob => blob.byteOffset).catch(err => 'Error');
816    }).then(({ x }) => {
817        return x.toString();
818    });
819}
820`
821    );
822
823    _testConvertToAsyncFunction("convertToAsyncFunction_InnerPromiseRetBinding3", `
824function [#|innerPromise|](): Promise<string> {
825    return fetch("https://typescriptlang.org").then(resp => {
826        return resp.blob().then(({ blob }) => blob.byteOffset).catch(({ message }) => 'Error ' + message);
827    }).then(([x, y]) => {
828        return (x || y).toString();
829    });
830}
831`
832    );
833
834    _testConvertToAsyncFunction("convertToAsyncFunction_InnerPromiseRetBinding4", `
835function [#|innerPromise|](): Promise<string> {
836    return fetch("https://typescriptlang.org").then(resp => {
837        return resp.blob().then(({ blob }: { blob: { byteOffset: number } }) => [0, blob.byteOffset]).catch(({ message }: Error) => ['Error ', message]);
838    }).then(([x, y]) => {
839        return (x || y).toString();
840    });
841}
842`
843    );
844
845    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn01", `
846function [#|f|]() {
847    let blob = fetch("https://typescriptlang.org").then(resp => console.log(resp));
848    return blob;
849}
850`
851    );
852    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn02", `
853function [#|f|]() {
854    let blob = fetch("https://typescriptlang.org");
855    blob.then(resp => console.log(resp));
856    return blob;
857}
858`
859    );
860    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn03", `
861function [#|f|]() {
862    let blob = fetch("https://typescriptlang.org")
863    let blob2 = blob.then(resp => console.log(resp));
864    blob2.catch(err);
865    return blob;
866}
867
868function err (rej) {
869    console.log(rej)
870}
871`
872    );
873    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn04", `
874function [#|f|]() {
875    var blob = fetch("https://typescriptlang.org").then(res => console.log(res)), blob2 = fetch("https://microsoft.com").then(res => res.ok).catch(err);
876    return blob;
877}
878function err (rej) {
879    console.log(rej)
880}
881`
882    );
883
884    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn05", `
885function [#|f|]() {
886    var blob = fetch("https://typescriptlang.org").then(res => console.log(res));
887    blob.then(x => x);
888    return blob;
889}
890`
891    );
892
893    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn06", `
894function [#|f|]() {
895    var blob = fetch("https://typescriptlang.org");
896    return blob;
897}
898`
899    );
900
901    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn07", `
902function [#|f|]() {
903    let blob = fetch("https://typescriptlang.org");
904    let blob2 = fetch("https://microsoft.com");
905    blob2.then(res => console.log("res:", res));
906    blob.then(resp => console.log(resp));
907    return blob;
908}
909`
910    );
911
912    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn08", `
913function [#|f|]() {
914    let blob = fetch("https://typescriptlang.org");
915    if (!blob.ok){
916        return blob;
917    }
918    blob.then(resp => console.log(resp));
919    return blob;
920}
921`
922    );
923
924    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn09", `
925function [#|f|]() {
926    let blob3;
927    let blob = fetch("https://typescriptlang.org");
928    let blob2 = fetch("https://microsoft.com");
929    blob2.then(res => console.log("res:", res));
930    blob.then(resp => console.log(resp));
931    blob3 = blob2.catch(rej => rej.ok);
932    return blob;
933}
934`
935    );
936
937
938    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn10", `
939function [#|f|]() {
940    let blob3;
941    let blob = fetch("https://typescriptlang.org");
942    let blob2 = fetch("https://microsoft.com");
943    blob2.then(res => console.log("res:", res));
944    blob.then(resp => console.log(resp));
945    blob3 = fetch("test.com");
946    blob3 = blob2;
947    return blob;
948}
949`
950    );
951
952    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn11", `
953function [#|f|]() {
954    let blob;
955    return blob;
956}
957`
958    );
959
960
961
962    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_Param1", `
963function [#|f|]() {
964    return my_print(fetch("https://typescriptlang.org").then(res => console.log(res)));
965}
966function my_print (resp) {
967    if (resp.ok) {
968        console.log(resp.buffer);
969    }
970    return resp;
971}
972
973`
974    );
975
976    _testConvertToAsyncFunction("convertToAsyncFunction_Param2", `
977function [#|f|]() {
978    return my_print(fetch("https://typescriptlang.org").then(res => console.log(res))).catch(err => console.log("Error!", err));
979}
980function my_print (resp): Promise<void> {
981    if (resp.ok) {
982        console.log(resp.buffer);
983    }
984    return resp;
985}
986
987
988`
989    );
990
991    _testConvertToAsyncFunction("convertToAsyncFunction_MultipleReturns1", `
992function [#|f|](): Promise<void> {
993    let x = fetch("https://microsoft.com").then(res => console.log("Microsoft:", res));
994    if (x.ok) {
995        return fetch("https://typescriptlang.org").then(res => console.log(res));
996    }
997    return x.then(resp => {
998        var blob = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error');
999    });
1000}
1001`
1002    );
1003
1004    _testConvertToAsyncFunction("convertToAsyncFunction_MultipleReturns2", `
1005function [#|f|](): Promise<void> {
1006    let x = fetch("https://microsoft.com").then(res => console.log("Microsoft:", res));
1007    if (x.ok) {
1008        return fetch("https://typescriptlang.org").then(res => console.log(res));
1009    }
1010    return x.then(resp => {
1011        var blob = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error');
1012        return fetch("https://microsoft.com").then(res => console.log("Another one!"));
1013    });
1014}
1015`
1016    );
1017
1018
1019    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_SeperateLines", `
1020function [#|f|](): Promise<string> {
1021    var blob = fetch("https://typescriptlang.org")
1022    blob.then(resp => {
1023        var blob = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error');
1024    });
1025    blob.then(blob => {
1026        return blob.toString();
1027    });
1028
1029    return blob;
1030}
1031`
1032    );
1033
1034
1035    _testConvertToAsyncFunction("convertToAsyncFunction_InnerVarNameConflict", `
1036function [#|f|](): Promise<string> {
1037    return fetch("https://typescriptlang.org").then(resp => {
1038        var blob = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error');
1039    }).then(blob => {
1040        return blob.toString();
1041    });
1042}
1043`
1044    );
1045    _testConvertToAsyncFunction("convertToAsyncFunction_InnerPromiseSimple", `
1046function [#|f|](): Promise<string> {
1047    return fetch("https://typescriptlang.org").then(resp => {
1048        return resp.blob().then(blob => blob.byteOffset);
1049    }).then(blob => {
1050        return blob.toString();
1051    });
1052}
1053`
1054    );
1055    _testConvertToAsyncFunction("convertToAsyncFunction_PromiseAllAndThen1", `
1056function [#|f|]() {
1057    return Promise.resolve().then(function () {
1058        return Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function () {
1059                return fetch("https://github.com");
1060              }).then(res => res.toString())]);
1061    });
1062}
1063`
1064    );
1065
1066    _testConvertToAsyncFunction("convertToAsyncFunction_PromiseAllAndThen2", `
1067function [#|f|]() {
1068    return Promise.resolve().then(function () {
1069        return Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function () {
1070                return fetch("https://github.com");
1071              })]).then(res => res.toString());
1072    });
1073}
1074`
1075    );
1076
1077    _testConvertToAsyncFunction("convertToAsyncFunction_PromiseAllAndThen3", `
1078function [#|f|]() {
1079    return Promise.resolve().then(() =>
1080        Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function () {
1081            return fetch("https://github.com");
1082        }).then(res => res.toString())]));
1083}
1084`
1085    );
1086
1087    _testConvertToAsyncFunction("convertToAsyncFunction_PromiseAllAndThen4", `
1088function [#|f|]() {
1089    return Promise.resolve().then(() =>
1090        Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function () {
1091            return fetch("https://github.com");
1092        })]).then(res => res.toString()));
1093}
1094`
1095    );
1096    _testConvertToAsyncFunction("convertToAsyncFunction_Scope1", `
1097function [#|f|]() {
1098    var var1: Response, var2;
1099    return fetch('https://typescriptlang.org').then( _ =>
1100      Promise.resolve().then( res => {
1101        var2 = "test";
1102        return fetch("https://microsoft.com");
1103      }).then(res =>
1104         var1 === res
1105      )
1106    ).then(res);
1107  }
1108  function res(response){
1109      console.log(response);
1110  }
1111`);
1112
1113    _testConvertToAsyncFunction("convertToAsyncFunction_Conditionals", `
1114function [#|f|](){
1115    return fetch("https://typescriptlang.org").then(res => {
1116      if (res.ok) {
1117        return fetch("https://microsoft.com");
1118      }
1119      else {
1120        if (res.buffer.length > 5) {
1121          return res;
1122        }
1123        else {
1124            return fetch("https://github.com");
1125        }
1126      }
1127    });
1128}
1129`
1130    );
1131
1132    _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThen", `
1133function [#|f|](){
1134    return fetch("https://typescriptlang.org").then(res).catch(rej).then(res);
1135}
1136
1137function res(result){
1138    return result;
1139}
1140
1141function rej(reject){
1142    return reject;
1143}
1144`
1145    );
1146
1147    _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMatchingTypes01", `
1148function [#|f|](){
1149    return fetch("https://typescriptlang.org").then(res).catch(rej).then(res);
1150}
1151
1152function res(result): number {
1153    return 5;
1154}
1155
1156function rej(reject): number {
1157    return 3;
1158}
1159`
1160    );
1161
1162    _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMatchingTypes01NoAnnotations", `
1163function [#|f|](){
1164    return fetch("https://typescriptlang.org").then(res).catch(rej).then(res);
1165}
1166
1167function res(result){
1168    return 5;
1169}
1170
1171function rej(reject){
1172    return 3;
1173}
1174`
1175    );
1176
1177
1178    _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMatchingTypes02", `
1179function [#|f|](){
1180    return fetch("https://typescriptlang.org").then(res => 0).catch(rej => 1).then(res);
1181}
1182
1183function res(result): number {
1184    return 5;
1185}
1186`
1187    );
1188
1189    _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMatchingTypes02NoAnnotations", `
1190function [#|f|](){
1191    return fetch("https://typescriptlang.org").then(res => 0).catch(rej => 1).then(res);
1192}
1193
1194function res(result){
1195    return 5;
1196}
1197`
1198    );
1199
1200    _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMismatchTypes01", `
1201function [#|f|](){
1202    return fetch("https://typescriptlang.org").then(res).catch(rej).then(res);
1203}
1204
1205function res(result){
1206    return 5;
1207}
1208
1209function rej(reject){
1210    return "Error";
1211}
1212`
1213    );
1214
1215    _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMismatchTypes02", `
1216function [#|f|](){
1217    return fetch("https://typescriptlang.org").then(res).catch(rej).then(res);
1218}
1219
1220function res(result){
1221    return 5;
1222}
1223
1224function rej(reject): Response{
1225    return reject;
1226}
1227`
1228    );
1229
1230    _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMismatchTypes02NoAnnotations", `
1231function [#|f|](){
1232    return fetch("https://typescriptlang.org").then(res).catch(rej).then(res);
1233}
1234
1235function res(result){
1236    return 5;
1237}
1238
1239function rej(reject){
1240    return reject;
1241}
1242`
1243    );
1244
1245
1246    _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMismatchTypes03", `
1247function [#|f|](){
1248    return fetch("https://typescriptlang.org").then(res).catch(rej).then(res);
1249}
1250
1251function res(result){
1252    return 5;
1253}
1254
1255function rej(reject){
1256    return Promise.resolve(1);
1257}
1258`
1259    );
1260
1261    _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMismatchTypes04", `
1262interface a {
1263    name: string;
1264    age: number;
1265}
1266
1267interface b extends a {
1268    color: string;
1269}
1270
1271
1272function [#|f|](){
1273    return fetch("https://typescriptlang.org").then(res).catch(rej).then(res);
1274}
1275
1276function res(result): b{
1277    return {name: "myName", age: 22, color: "red"};
1278}
1279
1280function rej(reject): a{
1281    return {name: "myName", age: 27};
1282}
1283`
1284    );
1285
1286    _testConvertToAsyncFunction("convertToAsyncFunction_ParameterNameCollision", `
1287async function foo<T>(x: T): Promise<T> {
1288    return x;
1289}
1290
1291function [#|bar|]<T>(x: T): Promise<T> {
1292    return foo(x).then(foo)
1293}
1294`
1295    );
1296
1297    _testConvertToAsyncFunction("convertToAsyncFunction_Return1", `
1298function [#|f|](p: Promise<unknown>) {
1299    return p.catch((error: Error) => {
1300        return Promise.reject(error);
1301    });
1302}`
1303    );
1304
1305    _testConvertToAsyncFunction("convertToAsyncFunction_Return2", `
1306function [#|f|](p: Promise<unknown>) {
1307    return p.catch((error: Error) => Promise.reject(error));
1308}`
1309    );
1310
1311    _testConvertToAsyncFunction("convertToAsyncFunction_Return3", `
1312function [#|f|](p: Promise<unknown>) {
1313    return p.catch(function (error: Error) {
1314        return Promise.reject(error);
1315    });
1316}`
1317    );
1318
1319    _testConvertToAsyncFunction("convertToAsyncFunction_LocalReturn", `
1320function [#|f|]() {
1321    let x = fetch("https://typescriptlang.org").then(res => console.log(res));
1322    return x.catch(err => console.log("Error!", err));
1323}
1324
1325`);
1326    _testConvertToAsyncFunction("convertToAsyncFunction_PromiseCallInner", `
1327function [#|f|]() {
1328    return fetch(Promise.resolve(1).then(res => "https://typescriptlang.org")).catch(err => console.log(err));
1329}
1330
1331`);
1332    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_CatchFollowedByCall", `
1333function [#|f|](){
1334    return fetch("https://typescriptlang.org").then(res).catch(rej).toString();
1335}
1336
1337function res(result){
1338    return result;
1339}
1340
1341function rej(reject){
1342    return reject;
1343}
1344`
1345    );
1346
1347    _testConvertToAsyncFunction("convertToAsyncFunction_Scope2", `
1348function [#|f|](){
1349    var i:number;
1350    return fetch("https://typescriptlang.org").then(i => i.ok).then(res => i+1).catch(err => i-1)
1351}
1352`
1353    );
1354
1355    _testConvertToAsyncFunction("convertToAsyncFunction_Loop", `
1356function [#|f|](){
1357    return fetch("https://typescriptlang.org").then(res => { for(let i=0; i<10; i++){
1358        console.log(res);
1359    }})
1360}
1361`
1362    );
1363
1364    _testConvertToAsyncFunction("convertToAsyncFunction_Conditional2", `
1365function [#|f|](){
1366    var res = 100;
1367    if (res > 50) {
1368        return fetch("https://typescriptlang.org").then(res => console.log(res));
1369    }
1370    else {
1371        return fetch("https://typescriptlang.org").then(res_func);
1372    }
1373}
1374
1375function res_func(result){
1376    console.log(result);
1377}
1378`
1379    );
1380
1381    _testConvertToAsyncFunction("convertToAsyncFunction_Scope3", `
1382function [#|f|]() {
1383  var obj;
1384  return fetch("https://typescriptlang.org").then(function (res) {
1385    obj = {
1386      func: function f() {
1387        console.log(res);
1388      }
1389    };
1390  });
1391}
1392`
1393    );
1394
1395    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_NestedFunctionWrongLocation", `
1396function [#|f|]() {
1397    function fn2(){
1398        function fn3(){
1399            return fetch("https://typescriptlang.org").then(res => console.log(res));
1400        }
1401        return fn3();
1402    }
1403    return fn2();
1404}
1405`);
1406
1407    _testConvertToAsyncFunction("convertToAsyncFunction_NestedFunctionRightLocation", `
1408function f() {
1409    function fn2(){
1410        function [#|fn3|](){
1411            return fetch("https://typescriptlang.org").then(res => console.log(res));
1412        }
1413        return fn3();
1414    }
1415    return fn2();
1416}
1417`);
1418
1419    _testConvertToAsyncFunction("convertToAsyncFunction_UntypedFunction", `
1420function [#|f|]() {
1421    return Promise.resolve().then(res => console.log(res));
1422}
1423`);
1424
1425    _testConvertToAsyncFunction("convertToAsyncFunction_TernaryConditional", `
1426function [#|f|]() {
1427    let i;
1428    return Promise.resolve().then(res => res ? i = res : i = 100);
1429}
1430`);
1431
1432    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_ResRejNoArgsArrow", `
1433    function [#|f|]() {
1434        return Promise.resolve().then(() => 1, () => "a");
1435    }
1436`);
1437
1438    _testConvertToAsyncFunction("convertToAsyncFunction_simpleFunctionExpression", `
1439const [#|foo|] = function () {
1440    return fetch('https://typescriptlang.org').then(result => { console.log(result) });
1441}
1442`);
1443
1444    _testConvertToAsyncFunction("convertToAsyncFunction_simpleFunctionExpressionWithName", `
1445const foo = function [#|f|]() {
1446    return fetch('https://typescriptlang.org').then(result => { console.log(result) });
1447}
1448`);
1449
1450    _testConvertToAsyncFunction("convertToAsyncFunction_simpleFunctionExpressionAssignedToBindingPattern", `
1451const { length } = [#|function|] () {
1452    return fetch('https://typescriptlang.org').then(result => { console.log(result) });
1453}
1454`);
1455
1456    _testConvertToAsyncFunction("convertToAsyncFunction_catchBlockUniqueParams", `
1457function [#|f|]() {
1458    return Promise.resolve().then(x => 1).catch(x => "a").then(x => !!x);
1459}
1460`);
1461
1462    _testConvertToAsyncFunction("convertToAsyncFunction_catchBlockUniqueParamsBindingPattern", `
1463function [#|f|]() {
1464    return Promise.resolve().then(() => ({ x: 3 })).catch(() => ({ x: "a" })).then(({ x }) => !!x);
1465}
1466`);
1467
1468    _testConvertToAsyncFunction("convertToAsyncFunction_bindingPattern", `
1469function [#|f|]() {
1470    return fetch('https://typescriptlang.org').then(res);
1471}
1472function res({ status, trailer }){
1473    console.log(status);
1474}
1475`);
1476
1477    _testConvertToAsyncFunction("convertToAsyncFunction_bindingPatternNameCollision", `
1478function [#|f|]() {
1479    const result = 'https://typescriptlang.org';
1480    return fetch(result).then(res);
1481}
1482function res({ status, trailer }){
1483    console.log(status);
1484}
1485`);
1486
1487    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_thenArgumentNotFunction", `
1488function [#|f|]() {
1489    return Promise.resolve().then(f ? (x => x) : (y => y));
1490}
1491`);
1492
1493    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_thenArgumentNotFunctionNotLastInChain", `
1494function [#|f|]() {
1495    return Promise.resolve().then(f ? (x => x) : (y => y)).then(q => q);
1496}
1497`);
1498
1499    _testConvertToAsyncFunction("convertToAsyncFunction_runEffectfulContinuation", `
1500function [#|f|]() {
1501    return fetch('https://typescriptlang.org').then(res).then(_ => console.log("done"));
1502}
1503function res(result) {
1504    return Promise.resolve().then(x => console.log(result));
1505}
1506`);
1507
1508    _testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsPromise", `
1509function [#|f|]() {
1510    return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText.length)).then(x => console.log(x + 5));
1511}
1512`);
1513
1514    _testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsPromiseInBlock", `
1515function [#|f|]() {
1516    return fetch('https://typescriptlang.org').then(s => { return Promise.resolve(s.statusText.length) }).then(x => x + 5);
1517}
1518`);
1519
1520    _testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsFixablePromise", `
1521function [#|f|]() {
1522    return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText).then(st => st.length)).then(x => console.log(x + 5));
1523}
1524`);
1525
1526    _testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsPromiseLastInChain", `
1527function [#|f|]() {
1528    return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText.length));
1529}
1530`);
1531
1532    _testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsRejectedPromiseInTryBlock", `
1533function [#|f|]() {
1534    return Promise.resolve(1)
1535        .then(x => Promise.reject(x))
1536        .catch(err => console.log(err));
1537}
1538`);
1539
1540    _testConvertToAsyncFunction("convertToAsyncFunction_nestedPromises", `
1541function [#|f|]() {
1542    return fetch('https://typescriptlang.org').then(x => Promise.resolve(3).then(y => Promise.resolve(x.statusText.length + y)));
1543}
1544`);
1545
1546    _testConvertToAsyncFunction("convertToAsyncFunction_noArgs1", `
1547function delay(millis: number): Promise<void> {
1548    throw "no"
1549}
1550
1551function [#|main2|]() {
1552    console.log("Please wait. Loading.");
1553    return delay(500)
1554        .then(() => { console.log("."); return delay(500); })
1555        .then(() => { console.log("."); return delay(500); })
1556        .then(() => { console.log("."); return delay(500); })
1557}
1558        `);
1559
1560    _testConvertToAsyncFunction("convertToAsyncFunction_noArgs2", `
1561function delay(millis: number): Promise<void> {
1562    throw "no"
1563}
1564
1565function [#|main2|]() {
1566    console.log("Please wait. Loading.");
1567    return delay(500)
1568        .then(() => delay(500))
1569        .then(() => delay(500))
1570        .then(() => delay(500))
1571}
1572        `);
1573
1574    _testConvertToAsyncFunction("convertToAsyncFunction_exportModifier", `
1575export function [#|foo|]() {
1576    return fetch('https://typescriptlang.org').then(s => console.log(s));
1577}
1578`);
1579
1580    _testConvertToAsyncFunction("convertToAsyncFunction_OutermostOnlySuccess", `
1581function [#|foo|]() {
1582    return fetch('a').then(() => {
1583        return fetch('b').then(() => 'c');
1584    })
1585}
1586`);
1587    _testConvertToAsyncFunction("convertToAsyncFunction_decoratedMethod", `
1588function decorator() {
1589    return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor;
1590}
1591class Foo {
1592    @decorator()
1593    [#|method|]() {
1594        return fetch('a').then(x => x);
1595    }
1596}
1597`);
1598
1599    _testConvertToAsyncFunction("convertToAsyncFunction_decoratedMethodWithSingleLineComment", `
1600function decorator() {
1601    return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor;
1602}
1603class Foo {
1604    @decorator()
1605    // comment
1606    [#|method|]() {
1607        return fetch('a').then(x => x);
1608    }
1609}
1610`);
1611
1612    _testConvertToAsyncFunction("convertToAsyncFunction_decoratedMethodWithMultipleLineComment", `
1613function decorator() {
1614    return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor;
1615}
1616class Foo {
1617    @decorator()
1618    /**
1619     * comment
1620     */
1621    [#|method|]() {
1622        return fetch('a').then(x => x);
1623    }
1624}
1625`);
1626
1627    _testConvertToAsyncFunction("convertToAsyncFunction_decoratedMethodWithModifier", `
1628function decorator() {
1629    return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor;
1630}
1631class Foo {
1632    @decorator()
1633    public [#|method|]() {
1634        return fetch('a').then(x => x);
1635    }
1636}
1637`);
1638
1639    _testConvertToAsyncFunctionFailedSuggestion("convertToAsyncFunction_OutermostOnlyFailure", `
1640function foo() {
1641    return fetch('a').then([#|() => {|]
1642        return fetch('b').then(() => 'c');
1643    })
1644}
1645`);
1646
1647    _testConvertToAsyncFunction("convertToAsyncFunction_thenTypeArgument1", `
1648type APIResponse<T> = { success: true, data: T } | { success: false };
1649
1650function wrapResponse<T>(response: T): APIResponse<T> {
1651    return { success: true, data: response };
1652}
1653
1654function [#|get|]() {
1655    return Promise.resolve(undefined!).then<APIResponse<{ email: string }>>(wrapResponse);
1656}
1657`);
1658
1659    _testConvertToAsyncFunction("convertToAsyncFunction_thenTypeArgument2", `
1660type APIResponse<T> = { success: true, data: T } | { success: false };
1661
1662function wrapResponse<T>(response: T): APIResponse<T> {
1663    return { success: true, data: response };
1664}
1665
1666function [#|get|]() {
1667    return Promise.resolve(undefined!).then<APIResponse<{ email: string }>>(d => wrapResponse(d));
1668}
1669`);
1670
1671    _testConvertToAsyncFunction("convertToAsyncFunction_thenTypeArgument3", `
1672type APIResponse<T> = { success: true, data: T } | { success: false };
1673
1674function wrapResponse<T>(response: T): APIResponse<T> {
1675    return { success: true, data: response };
1676}
1677
1678function [#|get|]() {
1679    return Promise.resolve(undefined!).then<APIResponse<{ email: string }>>(d => {
1680        console.log(d);
1681        return wrapResponse(d);
1682    });
1683}
1684`);
1685
1686    _testConvertToAsyncFunction("convertToAsyncFunction_catchTypeArgument1", `
1687type APIResponse<T> = { success: true, data: T } | { success: false };
1688
1689function [#|get|]() {
1690    return Promise
1691        .resolve<APIResponse<{ email: string }>>({ success: true, data: { email: "" } })
1692        .catch<APIResponse<{ email: string }>>(() => ({ success: false }));
1693}
1694`);
1695
1696    _testConvertToAsyncFunctionFailed("convertToAsyncFunction_threeArguments", `
1697function [#|f|]() {
1698    return Promise.resolve().then(undefined, undefined, () => 1);
1699}`);
1700
1701    _testConvertToAsyncFunction("convertToAsyncFunction_callbackArgument", `
1702function foo(props: any): void {
1703    return props;
1704}
1705
1706const fn = (): Promise<(message: string) => void> =>
1707    new Promise(resolve => resolve((message: string) => foo(message)));
1708
1709function [#|f|]() {
1710    return fn().then(res => res("test"));
1711}
1712`);
1713
1714    _testConvertToAsyncFunction("convertToAsyncFunction_emptyCatch1", `
1715function [#|f|]() {
1716    return Promise.resolve().catch();
1717}
1718`);
1719
1720    _testConvertToAsyncFunction("convertToAsyncFunction_emptyCatch2", `
1721function [#|f|]() {
1722    return Promise.resolve(0).then(x => x).catch();
1723}
1724`);
1725
1726    _testConvertToAsyncFunctionWithModule("convertToAsyncFunction_importedFunction", `
1727import { fn } from "./module";
1728function [#|f|]() {
1729    return Promise.resolve(0).then(fn);
1730}
1731`);
1732
1733    _testConvertToAsyncFunctionFailed("convertToAsyncFunction__NoSuggestionInFunctionsWithNonFixableReturnStatements1", `
1734function f(x: number): Promise<void>;
1735function f(): void;
1736function [#|f|](x?: number): Promise<void> | void {
1737    if (!x) return;
1738    return fetch('').then(() => {});
1739}
1740`);
1741
1742    _testConvertToAsyncFunctionFailed("convertToAsyncFunction__NoSuggestionInFunctionsWithNonFixableReturnStatements2", `
1743function f(x: number): Promise<void>;
1744function f(): number;
1745function [#|f|](x?: number): Promise<void> | number {
1746    if (x) return x;
1747    return fetch('').then(() => {});
1748}
1749`);
1750
1751    _testConvertToAsyncFunctionFailed("convertToAsyncFunction__NoSuggestionInGetters", `
1752class Foo {
1753    get [#|m|](): Promise<number> {
1754        return Promise.resolve(1).then(n => n);
1755    }
1756}
1757`);
1758
1759    _testConvertToAsyncFunctionFailed("convertToAsyncFunction__NoSuggestionForGeneratorCallbacks", `
1760function [#|foo|](p: Promise<string[]>) {
1761    return p.then(function* (strings) {
1762        for (const s of strings) {
1763            yield s.toUpperCase();
1764        }
1765    });
1766}
1767`);
1768
1769    _testConvertToAsyncFunction("convertToAsyncFunction_thenNoArguments", `
1770declare function foo(): Promise<number>;
1771function [#|f|](): Promise<number> {
1772    return foo().then();
1773}`);
1774    _testConvertToAsyncFunction("convertToAsyncFunction_catchNoArguments", `
1775declare function foo(): Promise<number>;
1776function [#|f|](): Promise<number> {
1777    return foo().catch();
1778}`);
1779    _testConvertToAsyncFunction("convertToAsyncFunction_chainedThenCatchThen", `
1780declare function foo(): Promise<number>;
1781function [#|f|](): Promise<number> {
1782    return foo().then(x => Promise.resolve(x + 1)).catch(() => 1).then(y => y + 2);
1783}`);
1784    _testConvertToAsyncFunction("convertToAsyncFunction_finally", `
1785declare function foo(): Promise<number>;
1786function [#|f|](): Promise<number> {
1787    return foo().finally(() => console.log("done"));
1788}`);
1789    _testConvertToAsyncFunction("convertToAsyncFunction_finallyNoArguments", `
1790declare function foo(): Promise<number>;
1791function [#|f|](): Promise<number> {
1792    return foo().finally();
1793}`);
1794    _testConvertToAsyncFunction("convertToAsyncFunction_finallyNull", `
1795declare function foo(): Promise<number>;
1796function [#|f|](): Promise<number> {
1797    return foo().finally(null);
1798}`);
1799    _testConvertToAsyncFunction("convertToAsyncFunction_finallyUndefined", `
1800declare function foo(): Promise<number>;
1801function [#|f|](): Promise<number> {
1802    return foo().finally(undefined);
1803}`);
1804    _testConvertToAsyncFunction("convertToAsyncFunction_thenFinally", `
1805declare function foo(): Promise<number>;
1806function [#|f|](): Promise<number> {
1807    return foo().then(x => x + 1).finally(() => console.log("done"));
1808}`);
1809    _testConvertToAsyncFunction("convertToAsyncFunction_thenFinallyThen", `
1810declare function foo(): Promise<number>;
1811function [#|f|](): Promise<number> {
1812    return foo().then(x => Promise.resolve(x + 1)).finally(() => console.log("done")).then(y => y + 2);
1813}`);
1814    _testConvertToAsyncFunctionFailedAction("convertToAsyncFunction_returnInBranch", `
1815declare function foo(): Promise<number>;
1816function [#|f|](): Promise<number> {
1817    return foo().then(() => {
1818        if (Math.random()) {
1819            return 1;
1820        }
1821        return 2;
1822    }).then(a => {
1823        return a + 1;
1824    });
1825}
1826`);
1827    _testConvertToAsyncFunctionFailedAction("convertToAsyncFunction_partialReturnInBranch", `
1828declare function foo(): Promise<number>;
1829function [#|f|](): Promise<number> {
1830    return foo().then(() => {
1831        if (Math.random()) {
1832            return 1;
1833        }
1834        console.log("foo");
1835    }).then(a => {
1836        return a + 1;
1837    });
1838}
1839`);
1840});
1841