Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/test/automation/src/application.ts
5221 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Workbench } from './workbench';
7
import { Code, launch, LaunchOptions } from './code';
8
import { Logger, measureAndLog } from './logger';
9
import { Profiler } from './profiler';
10
11
export const enum Quality {
12
Dev,
13
Insiders,
14
Stable,
15
Exploration,
16
OSS
17
}
18
19
export interface ApplicationOptions extends LaunchOptions {
20
quality: Quality;
21
}
22
23
export class Application {
24
25
constructor(private options: ApplicationOptions) {
26
this._userDataPath = options.userDataDir;
27
this._workspacePathOrFolder = options.workspacePath;
28
}
29
30
private _code: Code | undefined;
31
get code(): Code { return this._code!; }
32
33
private _workbench: Workbench | undefined;
34
get workbench(): Workbench { return this._workbench!; }
35
36
get quality(): Quality {
37
return this.options.quality;
38
}
39
40
get logger(): Logger {
41
return this.options.logger;
42
}
43
44
get remote(): boolean {
45
return !!this.options.remote;
46
}
47
48
get web(): boolean {
49
return !!this.options.web;
50
}
51
52
private _workspacePathOrFolder: string | undefined;
53
get workspacePathOrFolder(): string {
54
if (!this._workspacePathOrFolder) {
55
throw new Error('This test requires a workspace to be open');
56
}
57
return this._workspacePathOrFolder;
58
}
59
60
get extensionsPath(): string | undefined {
61
return this.options.extensionsPath;
62
}
63
64
private _userDataPath: string | undefined;
65
get userDataPath(): string | undefined {
66
return this._userDataPath;
67
}
68
69
private _profiler: Profiler | undefined;
70
71
get profiler(): Profiler { return this._profiler!; }
72
73
async start(): Promise<void> {
74
await this._start();
75
}
76
77
async restart(options?: { workspaceOrFolder?: string; extraArgs?: string[] }): Promise<void> {
78
await measureAndLog(() => (async () => {
79
await this.stop();
80
await this._start(options?.workspaceOrFolder, options?.extraArgs);
81
})(), 'Application#restart()', this.logger);
82
}
83
84
private async _start(workspaceOrFolder = this._workspacePathOrFolder, extraArgs: string[] = []): Promise<void> {
85
this._workspacePathOrFolder = workspaceOrFolder;
86
87
// Launch Code...
88
const code = await this.startApplication(extraArgs);
89
90
// ...and make sure the window is ready to interact
91
await measureAndLog(() => this.checkWindowReady(code), 'Application#checkWindowReady()', this.logger);
92
}
93
94
async stop(): Promise<void> {
95
if (this._code) {
96
try {
97
await this._code.exit();
98
} finally {
99
this._code = undefined;
100
}
101
}
102
}
103
104
async startTracing(name?: string): Promise<void> {
105
await this._code?.startTracing(name);
106
}
107
108
async stopTracing(name?: string, persist: boolean = false): Promise<void> {
109
await this._code?.stopTracing(name, persist);
110
}
111
112
private async startApplication(extraArgs: string[] = []): Promise<Code> {
113
const code = this._code = await launch({
114
...this.options,
115
workspacePath: this._workspacePathOrFolder,
116
extraArgs: [...(this.options.extraArgs || []), ...extraArgs],
117
});
118
119
this._workbench = new Workbench(this._code);
120
this._profiler = new Profiler(this.code);
121
122
return code;
123
}
124
125
private async checkWindowReady(code: Code): Promise<void> {
126
127
// We need a rendered workbench
128
await measureAndLog(() => code.didFinishLoad(), 'Application#checkWindowReady: wait for navigation to be committed', this.logger);
129
await measureAndLog(() => code.waitForElement('.monaco-workbench'), 'Application#checkWindowReady: wait for .monaco-workbench element', this.logger);
130
await measureAndLog(() => code.whenWorkbenchRestored(), 'Application#checkWorkbenchRestored', this.logger);
131
132
// Remote but not web: wait for a remote connection state change
133
if (this.remote) {
134
await measureAndLog(() => code.waitForTextContent('.monaco-workbench .statusbar-item[id="status.host"]', undefined, statusHostLabel => {
135
this.logger.log(`checkWindowReady: remote indicator text is ${statusHostLabel}`);
136
137
// The absence of "Opening Remote" is not a strict
138
// indicator for a successful connection, but we
139
// want to avoid hanging here until timeout because
140
// this method is potentially called from a location
141
// that has no tracing enabled making it hard to
142
// diagnose this. As such, as soon as the connection
143
// state changes away from the "Opening Remote..." one
144
// we return.
145
return !statusHostLabel.includes('Opening Remote');
146
}, 300 /* = 30s of retry */), 'Application#checkWindowReady: wait for remote indicator', this.logger);
147
}
148
}
149
}
150
151