• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1describe("unittests:: Public APIs", () => {
2    function verifyApi(fileName: string) {
3        const builtFile = `built/local/${fileName}`;
4        const api = `api/${fileName}`;
5        let fileContent: string;
6        before(() => {
7            fileContent = Harness.IO.readFile(builtFile)!;
8            if (!fileContent) throw new Error(`File ${fileName} was not present in built/local`);
9            fileContent = fileContent.replace(/\r\n/g, "\n");
10        });
11
12        it("should be acknowledged when they change", () => {
13            Harness.Baseline.runBaseline(api, fileContent, { PrintDiff: true });
14        });
15
16        it("should compile", () => {
17            const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false);
18            fs.linkSync(`${vfs.builtFolder}/${fileName}`, `${vfs.srcFolder}/${fileName}`);
19            const sys = new fakes.System(fs);
20            const options: ts.CompilerOptions = {
21                ...ts.getDefaultCompilerOptions(),
22                strict: true,
23                exactOptionalPropertyTypes: true,
24            };
25            const host = new fakes.CompilerHost(sys, options);
26            const result = compiler.compileFiles(host, [`${vfs.srcFolder}/${fileName}`], options);
27            assert(!result.diagnostics || !result.diagnostics.length, Harness.Compiler.minimalDiagnosticsToString(result.diagnostics, /*pretty*/ true));
28        });
29    }
30
31    describe("for the language service and compiler", () => {
32        verifyApi("typescript.d.ts");
33    });
34
35    describe("for the language server", () => {
36        verifyApi("tsserverlibrary.d.ts");
37    });
38});
39
40describe("unittests:: Public APIs:: token to string", () => {
41    function assertDefinedTokenToString(initial: ts.SyntaxKind, last: ts.SyntaxKind) {
42        for (let t = initial; t <= last; t++) {
43            assert.isDefined(ts.tokenToString(t), `Expected tokenToString defined for ${ts.Debug.formatSyntaxKind(t)}`);
44        }
45    }
46
47    it("for punctuations", () => {
48        assertDefinedTokenToString(ts.SyntaxKind.FirstPunctuation, ts.SyntaxKind.LastPunctuation);
49    });
50    it("for keywords", () => {
51        assertDefinedTokenToString(ts.SyntaxKind.FirstKeyword, ts.SyntaxKind.LastKeyword);
52    });
53});
54
55describe("unittests:: Public APIs:: createPrivateIdentifier", () => {
56    it("throws when name doesn't start with #", () => {
57        assert.throw(() => ts.factory.createPrivateIdentifier("not"), "Debug Failure. First character of private identifier must be #: not");
58    });
59});
60
61describe("unittests:: Public APIs:: JSDoc newlines", () => {
62    it("are preserved verbatim", () => {
63        const testFilePath = "/file.ts";
64        const testFileText = `
65/**
66* @example
67* Some\n * text\r\n * with newlines.
68*/
69function test() {}`;
70
71        const testSourceFile = ts.createSourceFile(testFilePath, testFileText, ts.ScriptTarget.Latest, /*setParentNodes*/ true);
72        const funcDec = testSourceFile.statements.find(ts.isFunctionDeclaration)!;
73        const tags = ts.getJSDocTags(funcDec);
74        assert.isDefined(tags[0].comment);
75        assert.isDefined(tags[0].comment![0]);
76        assert.isString(tags[0].comment);
77        assert.equal(tags[0].comment as string, "Some\n text\r\n with newlines.");
78    });
79});
80
81describe("unittests:: Public APIs:: isPropertyName", () => {
82    it("checks if a PrivateIdentifier is a valid property name", () => {
83        const prop = ts.factory.createPrivateIdentifier("#foo");
84        assert.isTrue(ts.isPropertyName(prop), "PrivateIdentifier must be a valid property name.");
85    });
86});
87
88describe("unittests:: Public APIs:: getTypeAtLocation", () => {
89    it("works on PropertyAccessExpression in implements clause", () => {
90        const content = `namespace Test {
91            export interface Test {}
92        }
93        class Foo implements Test.Test {}`;
94
95        const host = new fakes.CompilerHost(vfs.createFromFileSystem(
96            Harness.IO,
97            /*ignoreCase*/ true,
98            { documents: [new documents.TextDocument("/file.ts", content)], cwd: "/" }));
99
100        const program = ts.createProgram({
101            host,
102            rootNames: ["/file.ts"],
103            options: { noLib: true }
104        });
105
106        const checker = program.getTypeChecker();
107        const file = program.getSourceFile("/file.ts")!;
108        const classDeclaration = file.statements.find(ts.isClassDeclaration)!;
109        const propertyAccess = classDeclaration.heritageClauses![0].types[0].expression as ts.PropertyAccessExpression;
110        const type = checker.getTypeAtLocation(propertyAccess);
111        assert.ok(!(type.flags & ts.TypeFlags.Any));
112        assert.equal(type, checker.getTypeAtLocation(propertyAccess.name));
113    });
114
115    it("works on SourceFile", () => {
116        const content = `const foo = 1;`;
117        const host = new fakes.CompilerHost(vfs.createFromFileSystem(
118            Harness.IO,
119            /*ignoreCase*/ true,
120            { documents: [new documents.TextDocument("/file.ts", content)], cwd: "/" }));
121
122        const program = ts.createProgram({
123            host,
124            rootNames: ["/file.ts"],
125            options: { noLib: true }
126        });
127
128        const checker = program.getTypeChecker();
129        const file = program.getSourceFile("/file.ts")!;
130        const type = checker.getTypeAtLocation(file);
131        assert.equal(type.flags, ts.TypeFlags.Any);
132    });
133
134    it("works on ExpressionWithTypeArguments", () => {
135        const content = `
136            function fn<T>(value: T) {
137                return { value };
138            }
139            const foo = fn<string>;
140        `;
141        const host = new fakes.CompilerHost(vfs.createFromFileSystem(
142            Harness.IO,
143            /*ignoreCase*/ true,
144            { documents: [new documents.TextDocument("/file.ts", content)], cwd: "/" }));
145
146        const program = ts.createProgram({
147            host,
148            rootNames: ["/file.ts"],
149            options: { noLib: true }
150        });
151
152        const checker = program.getTypeChecker();
153        const file = program.getSourceFile("/file.ts")!;
154        const [declaration] = (ts.findLast(file.statements, ts.isVariableStatement) as ts.VariableStatement).declarationList.declarations;
155        assert.equal(checker.getTypeAtLocation(declaration.initializer!).flags, ts.TypeFlags.Object);
156    });
157
158    it("returns an errorType for VariableDeclaration with BindingPattern name", () => {
159        const content = "const foo = [1];\n" + "const [a] = foo;";
160
161        const host = new fakes.CompilerHost(vfs.createFromFileSystem(
162            Harness.IO,
163            /*ignoreCase*/ true,
164            { documents: [new documents.TextDocument("/file.ts", content)], cwd: "/" }));
165
166        const program = ts.createProgram({
167            host,
168            rootNames: ["/file.ts"],
169            options: { noLib: true }
170        });
171
172        const checker = program.getTypeChecker();
173        const file = program.getSourceFile("/file.ts")!;
174        const [declaration] = (ts.findLast(file.statements, ts.isVariableStatement) as ts.VariableStatement).declarationList.declarations;
175        assert.equal(checker.getTypeAtLocation(declaration).flags, ts.TypeFlags.Any);
176    });
177});
178
179describe("unittests:: Public APIs:: validateLocaleAndSetLanguage", () => {
180    let savedUILocale: string | undefined;
181    beforeEach(() => savedUILocale = ts.getUILocale());
182    afterEach(() => ts.setUILocale(savedUILocale));
183
184    function verifyValidateLocale(locale: string, expectedToReadFile: boolean) {
185        it(`Verifying ${locale} ${expectedToReadFile ? "reads" : "does not read"} file`, () => {
186            const errors: ts.Diagnostic[] = [];
187            ts.validateLocaleAndSetLanguage(locale, {
188                getExecutingFilePath: () => "/tsc.js",
189                resolvePath: ts.identity,
190                fileExists: fileName => {
191                    assert.isTrue(expectedToReadFile, `Locale : ${locale} ${expectedToReadFile ? "should" : "should not"} check if ${fileName} exists.`);
192                    return expectedToReadFile;
193                },
194                readFile: fileName => {
195                    assert.isTrue(expectedToReadFile, `Locale : ${locale} ${expectedToReadFile ? "should" : "should not"} read ${fileName}.`);
196                    // Throw error here so that actual change to localized diagnostics messages doesnt take place
197                    throw new Error("cannot read file");
198                }
199            }, errors);
200        });
201    }
202    ts.supportedLocaleDirectories.forEach(locale => verifyValidateLocale(locale, /*expectedToReadFile*/ true));
203    ["en", "en-us"].forEach(locale => verifyValidateLocale(locale, /*expectedToReadFile*/ false));
204});
205
206describe("unittests:: Public APIs :: forEachChild of @param comments in JSDoc", () => {
207    it("finds correct children", () => {
208        const content = `
209/**
210 * @param The {@link TypeReferencesInAedoc}.
211 */
212var x
213`;
214        const sourceFile = ts.createSourceFile("/file.ts", content, ts.ScriptTarget.ESNext, /*setParentNodes*/ true);
215        const paramTag = sourceFile.getChildren()[0].getChildren()[0].getChildren()[0].getChildren()[0];
216        const kids = paramTag.getChildren();
217        const seen: Set<ts.Node> = new Set();
218        ts.forEachChild(paramTag, n => {
219            assert.strictEqual(/*actual*/ false, seen.has(n), "Found a duplicate-added child");
220            seen.add(n);
221        });
222        assert.equal(5, kids.length);
223    });
224});
225
226describe("unittests:: Public APIs:: getChild* methods on EndOfFileToken with JSDoc", () => {
227    it("finds correct children", () => {
228        const content = `
229/** jsdoc comment attached to EndOfFileToken */
230`;
231        const sourceFile = ts.createSourceFile("/file.ts", content, ts.ScriptTarget.ESNext, /*setParentNodes*/ true);
232        const endOfFileToken = sourceFile.getChildren()[1];
233        assert.equal(endOfFileToken.getChildren().length, 1);
234        assert.equal(endOfFileToken.getChildCount(), 1);
235        assert.notEqual(endOfFileToken.getChildAt(0), /*expected*/ undefined);
236    });
237});
238