• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts {
2    describe("unittests:: services:: Transpile", () => {
3
4        interface TranspileTestSettings {
5            options?: TranspileOptions;
6            noSetFileName?: boolean;
7        }
8
9        function transpilesCorrectly(name: string, input: string, testSettings: TranspileTestSettings) {
10            describe(name, () => {
11                let transpileResult: TranspileOutput;
12                let oldTranspileResult: string;
13                let oldTranspileDiagnostics: Diagnostic[];
14
15                const transpileOptions: TranspileOptions = testSettings.options || {};
16                if (!transpileOptions.compilerOptions) {
17                    transpileOptions.compilerOptions = { };
18                }
19                if (transpileOptions.compilerOptions.target === undefined) {
20                    transpileOptions.compilerOptions.target = ScriptTarget.ES3;
21                }
22
23                if (transpileOptions.compilerOptions.newLine === undefined) {
24                    // use \r\n as default new line
25                    transpileOptions.compilerOptions.newLine = NewLineKind.CarriageReturnLineFeed;
26                }
27
28                transpileOptions.compilerOptions.sourceMap = true;
29
30                let unitName = transpileOptions.fileName;
31                if (!unitName) {
32                    unitName = transpileOptions.compilerOptions.jsx ? "file.tsx" : "file.ts";
33                    if (!testSettings.noSetFileName) {
34                        transpileOptions.fileName = unitName;
35                    }
36                }
37
38                transpileOptions.reportDiagnostics = true;
39
40                const justName = "transpile/" + name.replace(/[^a-z0-9\-. ]/ig, "") + (transpileOptions.compilerOptions.jsx ? Extension.Tsx : Extension.Ts);
41                const toBeCompiled = [{
42                    unitName,
43                    content: input
44                }];
45                const canUseOldTranspile = !transpileOptions.renamedDependencies;
46
47                before(() => {
48                    transpileResult = transpileModule(input, transpileOptions);
49
50                    if (canUseOldTranspile) {
51                        oldTranspileDiagnostics = [];
52                        oldTranspileResult = transpile(input, transpileOptions.compilerOptions, transpileOptions.fileName, oldTranspileDiagnostics, transpileOptions.moduleName);
53                    }
54                });
55
56                after(() => {
57                    transpileResult = undefined!;
58                    oldTranspileResult = undefined!;
59                    oldTranspileDiagnostics = undefined!;
60                });
61
62                /* eslint-disable no-null/no-null */
63                it("Correct errors for " + justName, () => {
64                    Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".errors.txt"),
65                        transpileResult.diagnostics!.length === 0 ? null : Harness.Compiler.getErrorBaseline(toBeCompiled, transpileResult.diagnostics!));
66                });
67
68                if (canUseOldTranspile) {
69                    it("Correct errors (old transpile) for " + justName, () => {
70                        Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".oldTranspile.errors.txt"),
71                            oldTranspileDiagnostics.length === 0 ? null : Harness.Compiler.getErrorBaseline(toBeCompiled, oldTranspileDiagnostics));
72                    });
73                }
74                /* eslint-enable no-null/no-null */
75
76                it("Correct output for " + justName, () => {
77                    Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, Extension.Js), transpileResult.outputText);
78                });
79
80                if (canUseOldTranspile) {
81                    it("Correct output (old transpile) for " + justName, () => {
82                        Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".oldTranspile.js"), oldTranspileResult);
83                    });
84                }
85            });
86        }
87
88        transpilesCorrectly("Generates no diagnostics with valid inputs", `var x = 0;`, {
89            options: { compilerOptions: { module: ModuleKind.CommonJS } }
90        });
91
92        transpilesCorrectly("Generates no diagnostics for missing file references", `/// <reference path="file2.ts" />
93var x = 0;`, {
94            options: { compilerOptions: { module: ModuleKind.CommonJS } }
95        });
96
97        transpilesCorrectly("Generates no diagnostics for missing module imports", `import {a} from "module2";`, {
98            options: { compilerOptions: { module: ModuleKind.CommonJS } }
99        });
100
101        transpilesCorrectly("Generates expected syntactic diagnostics", `a b`, {
102            options: { compilerOptions: { module: ModuleKind.CommonJS } }
103        });
104
105        transpilesCorrectly("Does not generate semantic diagnostics", `var x: string = 0;`, {
106            options: { compilerOptions: { module: ModuleKind.CommonJS } }
107        });
108
109        transpilesCorrectly("Generates module output", `var x = 0;`, {
110            options: { compilerOptions: { module: ModuleKind.AMD } }
111        });
112
113        transpilesCorrectly("Uses correct newLine character", `var x = 0;`, {
114            options: { compilerOptions: { module: ModuleKind.CommonJS, newLine: NewLineKind.LineFeed } }
115        });
116
117        transpilesCorrectly("Sets module name", "var x = 1;", {
118            options: { compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, moduleName: "NamedModule" }
119        });
120
121        transpilesCorrectly("No extra errors for file without extension", `"use strict";\r\nvar x = 0;`, {
122            options: { compilerOptions: { module: ModuleKind.CommonJS }, fileName: "file" }
123        });
124
125        transpilesCorrectly("Rename dependencies - System",
126            `import {foo} from "SomeName";\n` +
127            `declare function use(a: any);\n` +
128            `use(foo);`, {
129                options: { compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, renamedDependencies: { SomeName: "SomeOtherName" } }
130            });
131
132        transpilesCorrectly("Rename dependencies - AMD",
133            `import {foo} from "SomeName";\n` +
134            `declare function use(a: any);\n` +
135            `use(foo);`, {
136                options: { compilerOptions: { module: ModuleKind.AMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { SomeName: "SomeOtherName" } }
137            });
138
139        transpilesCorrectly("Rename dependencies - UMD",
140            `import {foo} from "SomeName";\n` +
141            `declare function use(a: any);\n` +
142            `use(foo);`, {
143                options: { compilerOptions: { module: ModuleKind.UMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { SomeName: "SomeOtherName" } }
144            });
145
146        transpilesCorrectly("Transpile with emit decorators and emit metadata",
147            `import {db} from './db';\n` +
148            `function someDecorator(target) {\n` +
149            `    return target;\n` +
150            `} \n` +
151            `@someDecorator\n` +
152            `class MyClass {\n` +
153            `    db: db;\n` +
154            `    constructor(db: db) {\n` +
155            `        this.db = db;\n` +
156            `        this.db.doSomething(); \n` +
157            `    }\n` +
158            `}\n` +
159            `export {MyClass}; \n`, {
160                options: {
161                    compilerOptions: {
162                        module: ModuleKind.CommonJS,
163                        newLine: NewLineKind.LineFeed,
164                        noEmitHelpers: true,
165                        emitDecoratorMetadata: true,
166                        experimentalDecorators: true,
167                        target: ScriptTarget.ES5,
168                    }
169                }
170            });
171
172        transpilesCorrectly("Supports backslashes in file name", "var x", {
173            options: { fileName: "a\\b.ts" }
174        });
175
176        transpilesCorrectly("transpile file as 'tsx' if 'jsx' is specified", `var x = <div/>`, {
177            options: { compilerOptions: { jsx: JsxEmit.React, newLine: NewLineKind.LineFeed } }
178        });
179
180        transpilesCorrectly("transpile .js files", "const a = 10;", {
181            options: { compilerOptions: { newLine: NewLineKind.LineFeed, module: ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true }
182        });
183
184        transpilesCorrectly("Supports urls in file name", "var x", {
185            options: { fileName: "http://somewhere/directory//directory2/file.ts" }
186        });
187
188        transpilesCorrectly("Accepts string as enum values for compile-options", "export const x = 0", {
189            options: {
190                compilerOptions: {
191                    module: "es6" as any as ModuleKind,
192                    // Capitalization and spaces ignored
193                    target: " Es6 " as any as ScriptTarget
194                }
195            }
196        });
197
198        transpilesCorrectly("Report an error when compiler-options module-kind is out-of-range", "", {
199            options: { compilerOptions: { module: 123 as any as ModuleKind } }
200        });
201
202        transpilesCorrectly("Report an error when compiler-options target-script is out-of-range", "", {
203            options: { compilerOptions: { module: 123 as any as ModuleKind } }
204        });
205
206        transpilesCorrectly("Support options with lib values", "const a = 10;", {
207            options: { compilerOptions: { lib: ["es6", "dom"], module: ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true }
208        });
209
210        transpilesCorrectly("Support options with types values", "const a = 10;", {
211            options: { compilerOptions: { types: ["jquery", "typescript"], module: ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true }
212        });
213
214        transpilesCorrectly("Supports setting 'allowJs'", "x;", {
215            options: { compilerOptions: { allowJs: true }, fileName: "input.js", reportDiagnostics: true }
216        });
217
218        transpilesCorrectly("Supports setting 'allowSyntheticDefaultImports'", "x;", {
219            options: { compilerOptions: { allowSyntheticDefaultImports: true }, fileName: "input.js", reportDiagnostics: true }
220        });
221
222        transpilesCorrectly("Supports setting 'allowUnreachableCode'", "x;", {
223            options: { compilerOptions: { allowUnreachableCode: true }, fileName: "input.js", reportDiagnostics: true }
224        });
225
226        transpilesCorrectly("Supports setting 'allowUnusedLabels'", "x;", {
227            options: { compilerOptions: { allowUnusedLabels: true }, fileName: "input.js", reportDiagnostics: true }
228        });
229
230        transpilesCorrectly("Supports setting 'alwaysStrict'", "x;", {
231            options: { compilerOptions: { alwaysStrict: true }, fileName: "input.js", reportDiagnostics: true }
232        });
233
234        transpilesCorrectly("Supports setting 'baseUrl'", "x;", {
235            options: { compilerOptions: { baseUrl: "./folder/baseUrl" }, fileName: "input.js", reportDiagnostics: true }
236        });
237
238        transpilesCorrectly("Supports setting 'charset'", "x;", {
239            options: { compilerOptions: { charset: "en-us" }, fileName: "input.js", reportDiagnostics: true }
240        });
241
242        transpilesCorrectly("Supports setting 'declaration'", "x;", {
243            options: { compilerOptions: { declaration: true }, fileName: "input.js", reportDiagnostics: true }
244        });
245
246        transpilesCorrectly("Supports setting 'declarationDir'", "x;", {
247            options: { compilerOptions: { declarationDir: "out/declarations" }, fileName: "input.js", reportDiagnostics: true }
248        });
249
250        transpilesCorrectly("Supports setting 'emitBOM'", "x;", {
251            options: { compilerOptions: { emitBOM: true }, fileName: "input.js", reportDiagnostics: true }
252        });
253
254        transpilesCorrectly("Supports setting 'emitDecoratorMetadata'", "x;", {
255            options: { compilerOptions: { emitDecoratorMetadata: true, experimentalDecorators: true }, fileName: "input.js", reportDiagnostics: true }
256        });
257
258        transpilesCorrectly("Supports setting 'experimentalDecorators'", "x;", {
259            options: { compilerOptions: { experimentalDecorators: true }, fileName: "input.js", reportDiagnostics: true }
260        });
261
262        transpilesCorrectly("Supports setting 'forceConsistentCasingInFileNames'", "x;", {
263            options: { compilerOptions: { forceConsistentCasingInFileNames: true }, fileName: "input.js", reportDiagnostics: true }
264        });
265
266        transpilesCorrectly("Supports setting 'isolatedModules'", "x;", {
267            options: { compilerOptions: { isolatedModules: true }, fileName: "input.js", reportDiagnostics: true }
268        });
269
270        transpilesCorrectly("Supports setting 'jsx'", "x;", {
271            options: { compilerOptions: { jsx: 1 }, fileName: "input.js", reportDiagnostics: true }
272        });
273
274        transpilesCorrectly("Supports setting 'lib'", "x;", {
275            options: { compilerOptions: { lib: ["es2015", "dom"] }, fileName: "input.js", reportDiagnostics: true }
276        });
277
278        transpilesCorrectly("Supports setting 'locale'", "x;", {
279            options: { compilerOptions: { locale: "en-us" }, fileName: "input.js", reportDiagnostics: true }
280        });
281
282        transpilesCorrectly("Supports setting 'module'", "x;", {
283            options: { compilerOptions: { module: ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true }
284        });
285
286        transpilesCorrectly("Supports setting 'moduleResolution'", "x;", {
287            options: { compilerOptions: { moduleResolution: ModuleResolutionKind.NodeJs }, fileName: "input.js", reportDiagnostics: true }
288        });
289
290        transpilesCorrectly("Supports setting 'newLine'", "x;", {
291            options: { compilerOptions: { newLine: NewLineKind.CarriageReturnLineFeed }, fileName: "input.js", reportDiagnostics: true }
292        });
293
294        transpilesCorrectly("Supports setting 'noEmit'", "x;", {
295            options: { compilerOptions: { noEmit: true }, fileName: "input.js", reportDiagnostics: true }
296        });
297
298        transpilesCorrectly("Supports setting 'noEmitHelpers'", "x;", {
299            options: { compilerOptions: { noEmitHelpers: true }, fileName: "input.js", reportDiagnostics: true }
300        });
301
302        transpilesCorrectly("Supports setting 'noEmitOnError'", "x;", {
303            options: { compilerOptions: { noEmitOnError: true }, fileName: "input.js", reportDiagnostics: true }
304        });
305
306        transpilesCorrectly("Supports setting 'noErrorTruncation'", "x;", {
307            options: { compilerOptions: { noErrorTruncation: true }, fileName: "input.js", reportDiagnostics: true }
308        });
309
310        transpilesCorrectly("Supports setting 'noFallthroughCasesInSwitch'", "x;", {
311            options: { compilerOptions: { noFallthroughCasesInSwitch: true }, fileName: "input.js", reportDiagnostics: true }
312        });
313
314        transpilesCorrectly("Supports setting 'noImplicitAny'", "x;", {
315            options: { compilerOptions: { noImplicitAny: true }, fileName: "input.js", reportDiagnostics: true }
316        });
317
318        transpilesCorrectly("Supports setting 'noImplicitReturns'", "x;", {
319            options: { compilerOptions: { noImplicitReturns: true }, fileName: "input.js", reportDiagnostics: true }
320        });
321
322        transpilesCorrectly("Supports setting 'noImplicitThis'", "x;", {
323            options: { compilerOptions: { noImplicitThis: true }, fileName: "input.js", reportDiagnostics: true }
324        });
325
326        transpilesCorrectly("Supports setting 'noImplicitUseStrict'", "x;", {
327            options: { compilerOptions: { noImplicitUseStrict: true }, fileName: "input.js", reportDiagnostics: true }
328        });
329
330        transpilesCorrectly("Supports setting 'noLib'", "x;", {
331            options: { compilerOptions: { noLib: true }, fileName: "input.js", reportDiagnostics: true }
332        });
333
334        transpilesCorrectly("Supports setting 'noResolve'", "x;", {
335            options: { compilerOptions: { noResolve: true }, fileName: "input.js", reportDiagnostics: true }
336        });
337
338        transpilesCorrectly("Supports setting 'out'", "x;", {
339            options: { compilerOptions: { out: "./out" }, fileName: "input.js", reportDiagnostics: true }
340        });
341
342        transpilesCorrectly("Supports setting 'outDir'", "x;", {
343            options: { compilerOptions: { outDir: "./outDir" }, fileName: "input.js", reportDiagnostics: true }
344        });
345
346        transpilesCorrectly("Supports setting 'outFile'", "x;", {
347            options: { compilerOptions: { outFile: "./outFile" }, fileName: "input.js", reportDiagnostics: true }
348        });
349
350        transpilesCorrectly("Supports setting 'paths'", "x;", {
351            options: { compilerOptions: { paths: { "*": ["./generated*"] } }, fileName: "input.js", reportDiagnostics: true }
352        });
353
354        transpilesCorrectly("Supports setting 'preserveConstEnums'", "x;", {
355            options: { compilerOptions: { preserveConstEnums: true }, fileName: "input.js", reportDiagnostics: true }
356        });
357
358        transpilesCorrectly("Supports setting 'reactNamespace'", "x;", {
359            options: { compilerOptions: { reactNamespace: "react" }, fileName: "input.js", reportDiagnostics: true }
360        });
361
362        transpilesCorrectly("Supports setting 'jsxFactory'", "x;", {
363            options: { compilerOptions: { jsxFactory: "createElement" }, fileName: "input.js", reportDiagnostics: true }
364        });
365
366        transpilesCorrectly("Supports setting 'jsxFragmentFactory'", "x;", {
367            options: { compilerOptions: { jsxFactory: "x", jsxFragmentFactory: "frag" }, fileName: "input.js", reportDiagnostics: true }
368        });
369
370        transpilesCorrectly("Supports setting 'removeComments'", "x;", {
371            options: { compilerOptions: { removeComments: true }, fileName: "input.js", reportDiagnostics: true }
372        });
373
374        transpilesCorrectly("Supports setting 'rootDir'", "x;", {
375            options: { compilerOptions: { rootDir: "./rootDir" }, fileName: "./rootDir/input.js", reportDiagnostics: true }
376        });
377
378        transpilesCorrectly("Supports setting 'rootDirs'", "x;", {
379            options: { compilerOptions: { rootDirs: ["./a", "./b"] }, fileName: "input.js", reportDiagnostics: true }
380        });
381
382        transpilesCorrectly("Supports setting 'skipLibCheck'", "x;", {
383            options: { compilerOptions: { skipLibCheck: true }, fileName: "input.js", reportDiagnostics: true }
384        });
385
386        transpilesCorrectly("Supports setting 'skipDefaultLibCheck'", "x;", {
387            options: { compilerOptions: { skipDefaultLibCheck: true }, fileName: "input.js", reportDiagnostics: true }
388        });
389
390        transpilesCorrectly("Supports setting 'strictNullChecks'", "x;", {
391            options: { compilerOptions: { strictNullChecks: true }, fileName: "input.js", reportDiagnostics: true }
392        });
393
394        transpilesCorrectly("Supports setting 'stripInternal'", "x;", {
395            options: { compilerOptions: { stripInternal: true }, fileName: "input.js", reportDiagnostics: true }
396        });
397
398        transpilesCorrectly("Supports setting 'suppressExcessPropertyErrors'", "x;", {
399            options: { compilerOptions: { suppressExcessPropertyErrors: true }, fileName: "input.js", reportDiagnostics: true }
400        });
401
402        transpilesCorrectly("Supports setting 'suppressImplicitAnyIndexErrors'", "x;", {
403            options: { compilerOptions: { suppressImplicitAnyIndexErrors: true }, fileName: "input.js", reportDiagnostics: true }
404        });
405
406        transpilesCorrectly("Supports setting 'target'", "x;", {
407            options: { compilerOptions: { target: 2 }, fileName: "input.js", reportDiagnostics: true }
408        });
409
410        transpilesCorrectly("Supports setting 'types'", "x;", {
411            options: { compilerOptions: { types: ["jquery", "jasmine"] }, fileName: "input.js", reportDiagnostics: true }
412        });
413
414        transpilesCorrectly("Supports setting 'typeRoots'", "x;", {
415            options: { compilerOptions: { typeRoots: ["./folder"] }, fileName: "input.js", reportDiagnostics: true }
416        });
417
418        transpilesCorrectly("Supports setting 'incremental'", "x;", {
419            options: { compilerOptions: { incremental: true }, fileName: "input.js", reportDiagnostics: true }
420        });
421
422        transpilesCorrectly("Supports setting 'composite'", "x;", {
423            options: { compilerOptions: { composite: true }, fileName: "input.js", reportDiagnostics: true }
424        });
425
426        transpilesCorrectly("Supports setting 'tsbuildinfo'", "x;", {
427            options: { compilerOptions: { incremental: true, tsBuildInfoFile: "./folder/config.tsbuildinfo" }, fileName: "input.js", reportDiagnostics: true }
428        });
429
430        transpilesCorrectly("Correctly serialize metadata when transpile with CommonJS option",
431            `import * as ng from "angular2/core";` +
432            `declare function foo(...args: any[]);` +
433            `@foo` +
434            `export class MyClass1 {` +
435            `    constructor(private _elementRef: ng.ElementRef){}` +
436            `}`, {
437                options: {
438                    compilerOptions: {
439                        target: ScriptTarget.ES5,
440                        module: ModuleKind.CommonJS,
441                        moduleResolution: ModuleResolutionKind.NodeJs,
442                        emitDecoratorMetadata: true,
443                        experimentalDecorators: true,
444                        isolatedModules: true,
445                    }
446                }
447            }
448        );
449
450        transpilesCorrectly("Correctly serialize metadata when transpile with System option",
451            `import * as ng from "angular2/core";` +
452            `declare function foo(...args: any[]);` +
453            `@foo` +
454            `export class MyClass1 {` +
455            `    constructor(private _elementRef: ng.ElementRef){}` +
456            `}`, {
457                options: {
458                    compilerOptions: {
459                        target: ScriptTarget.ES5,
460                        module: ModuleKind.System,
461                        moduleResolution: ModuleResolutionKind.NodeJs,
462                        emitDecoratorMetadata: true,
463                        experimentalDecorators: true,
464                        isolatedModules: true,
465                    }
466                }
467            }
468        );
469
470        transpilesCorrectly("Supports readonly keyword for arrays", "let x: readonly string[];", {
471            options: { compilerOptions: { module: ModuleKind.CommonJS } }
472        });
473
474        transpilesCorrectly("Supports 'as const' arrays", `([] as const).forEach(k => console.log(k));`, {
475            options: { compilerOptions: { module: ModuleKind.CommonJS } }
476        });
477
478        transpilesCorrectly("Infer correct file extension", `const fn = <T>(a: T) => a`, {
479            noSetFileName: true
480        });
481
482        transpilesCorrectly("Export star as ns conflict does not crash", `
483var a;
484export { a as alias };
485export * as alias from './file';`, {
486            noSetFileName: true
487        });
488
489        transpilesCorrectly("Elides import equals referenced only by export type",
490            `import IFoo = Namespace.IFoo;` +
491            `export type { IFoo };`, {
492                options: { compilerOptions: { module: ModuleKind.CommonJS } }
493            }
494        );
495
496        transpilesCorrectly("Elides import equals referenced only by type only export specifier",
497            `import IFoo = Namespace.IFoo;` +
498            `export { type IFoo };`, {
499                options: { compilerOptions: { module: ModuleKind.CommonJS } }
500            }
501        );
502    });
503}
504