• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts.projectSystem {
2    describe("unittests:: tsserver:: webServer", () => {
3        class TestWorkerSession extends server.WorkerSession {
4            constructor(host: server.ServerHost, webHost: server.HostWithWriteMessage, options: Partial<server.StartSessionOptions>, logger: server.Logger) {
5                super(
6                    host,
7                    webHost,
8                    {
9                        globalPlugins: undefined,
10                        pluginProbeLocations: undefined,
11                        allowLocalPluginLoads: undefined,
12                        useSingleInferredProject: true,
13                        useInferredProjectPerProjectRoot: false,
14                        suppressDiagnosticEvents: false,
15                        noGetErrOnBackgroundUpdate: true,
16                        syntaxOnly: undefined,
17                        serverMode: undefined,
18                        ...options
19                    },
20                    logger,
21                    server.nullCancellationToken,
22                    () => emptyArray
23                );
24            }
25
26            getProjectService() {
27                return this.projectService;
28            }
29        }
30        function setup(logLevel: server.LogLevel | undefined) {
31            const host = createServerHost([libFile], { windowsStyleRoot: "c:/" });
32            const messages: any[] = [];
33            const webHost: server.WebHost = {
34                readFile: s => host.readFile(s),
35                fileExists: s => host.fileExists(s),
36                writeMessage: s => messages.push(s),
37            };
38            const webSys = server.createWebSystem(webHost, emptyArray, () => host.getExecutingFilePath());
39            const logger = logLevel !== undefined ? new server.MainProcessLogger(logLevel, webHost) : nullLogger;
40            const session = new TestWorkerSession(webSys, webHost, { serverMode: LanguageServiceMode.PartialSemantic }, logger);
41            return { getMessages: () => messages, clearMessages: () => messages.length = 0, session };
42
43        }
44
45        describe("open files are added to inferred project and semantic operations succeed", () => {
46            function verify(logLevel: server.LogLevel | undefined) {
47                const { session, clearMessages, getMessages } = setup(logLevel);
48                const service = session.getProjectService();
49                const file: File = {
50                    path: "^memfs:/sample-folder/large.ts",
51                    content: "export const numberConst = 10; export const arrayConst: Array<string> = [];"
52                };
53                session.executeCommand({
54                    seq: 1,
55                    type: "request",
56                    command: protocol.CommandTypes.Open,
57                    arguments: {
58                        file: file.path,
59                        fileContent: file.content
60                    }
61                });
62                checkNumberOfProjects(service, { inferredProjects: 1 });
63                const project = service.inferredProjects[0];
64                checkProjectActualFiles(project, ["/lib.d.ts", file.path]); // Lib files are rooted
65                verifyQuickInfo();
66                verifyGotoDefInLib();
67
68                function verifyQuickInfo() {
69                    clearMessages();
70                    const start = protocolFileLocationFromSubstring(file, "numberConst");
71                    session.onMessage({
72                        seq: 2,
73                        type: "request",
74                        command: protocol.CommandTypes.Quickinfo,
75                        arguments: start
76                    });
77                    assert.deepEqual(last(getMessages()), {
78                        seq: 0,
79                        type: "response",
80                        command: protocol.CommandTypes.Quickinfo,
81                        request_seq: 2,
82                        success: true,
83                        performanceData: undefined,
84                        body: {
85                            kind: ScriptElementKind.constElement,
86                            kindModifiers: "export",
87                            start: { line: start.line, offset: start.offset },
88                            end: { line: start.line, offset: start.offset + "numberConst".length },
89                            displayString: "const numberConst: 10",
90                            documentation: "",
91                            tags: []
92                        }
93                    });
94                    verifyLogger();
95                }
96
97                function verifyGotoDefInLib() {
98                    clearMessages();
99                    const start = protocolFileLocationFromSubstring(file, "Array");
100                    session.onMessage({
101                        seq: 3,
102                        type: "request",
103                        command: protocol.CommandTypes.DefinitionAndBoundSpan,
104                        arguments: start
105                    });
106                    assert.deepEqual(last(getMessages()), {
107                        seq: 0,
108                        type: "response",
109                        command: protocol.CommandTypes.DefinitionAndBoundSpan,
110                        request_seq: 3,
111                        success: true,
112                        performanceData: undefined,
113                        body: {
114                            definitions: [{
115                                file: "/lib.d.ts",
116                                ...protocolTextSpanWithContextFromSubstring({
117                                    fileText: libFile.content,
118                                    text: "Array",
119                                    contextText: "interface Array<T> { length: number; [n: number]: T; }"
120                                })
121                            }],
122                            textSpan: {
123                                start: { line: start.line, offset: start.offset },
124                                end: { line: start.line, offset: start.offset + "Array".length },
125                            }
126                        }
127                    });
128                    verifyLogger();
129                }
130
131                function verifyLogger() {
132                    const messages = getMessages();
133                    assert.equal(messages.length, logLevel === server.LogLevel.verbose ? 4 : 1, `Expected ${JSON.stringify(messages)}`);
134                    if (logLevel === server.LogLevel.verbose) {
135                        verifyLogMessages(messages[0], "info");
136                        verifyLogMessages(messages[1], "perf");
137                        verifyLogMessages(messages[2], "info");
138                    }
139                    clearMessages();
140                }
141
142                function verifyLogMessages(actual: any, expectedLevel: server.MessageLogLevel) {
143                    assert.equal(actual.type, "log");
144                    assert.equal(actual.level, expectedLevel);
145                }
146            }
147
148            it("with logging enabled", () => {
149                verify(server.LogLevel.verbose);
150            });
151
152            it("with logging disabled", () => {
153                verify(/*logLevel*/ undefined);
154            });
155        });
156    });
157}
158