Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/api/test/browser/extHostWebview.test.ts
3296 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 assert from 'assert';
7
import { DisposableStore } from '../../../../base/common/lifecycle.js';
8
import { Schemas } from '../../../../base/common/network.js';
9
import { URI } from '../../../../base/common/uri.js';
10
import { mock } from '../../../../base/test/common/mock.js';
11
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
12
import { IExtensionDescription } from '../../../../platform/extensions/common/extensions.js';
13
import { NullLogService } from '../../../../platform/log/common/log.js';
14
import { MainThreadWebviewManager } from '../../browser/mainThreadWebviewManager.js';
15
import { NullApiDeprecationService } from '../../common/extHostApiDeprecationService.js';
16
import { IExtHostRpcService } from '../../common/extHostRpcService.js';
17
import { ExtHostWebviews } from '../../common/extHostWebview.js';
18
import { ExtHostWebviewPanels } from '../../common/extHostWebviewPanels.js';
19
import { SingleProxyRPCProtocol } from '../common/testRPCProtocol.js';
20
import { decodeAuthority, webviewResourceBaseHost } from '../../../contrib/webview/common/webview.js';
21
import { EditorGroupColumn } from '../../../services/editor/common/editorGroupColumn.js';
22
import { IExtHostContext } from '../../../services/extensions/common/extHostCustomers.js';
23
import type * as vscode from 'vscode';
24
25
suite('ExtHostWebview', () => {
26
let disposables: DisposableStore;
27
let rpcProtocol: (IExtHostRpcService & IExtHostContext) | undefined;
28
29
setup(() => {
30
disposables = new DisposableStore();
31
32
const shape = createNoopMainThreadWebviews();
33
rpcProtocol = SingleProxyRPCProtocol(shape);
34
});
35
36
teardown(() => {
37
disposables.dispose();
38
});
39
40
ensureNoDisposablesAreLeakedInTestSuite();
41
42
function createWebview(rpcProtocol: (IExtHostRpcService & IExtHostContext) | undefined, remoteAuthority: string | undefined) {
43
const extHostWebviews = disposables.add(new ExtHostWebviews(rpcProtocol!, {
44
authority: remoteAuthority,
45
isRemote: !!remoteAuthority,
46
}, undefined, new NullLogService(), NullApiDeprecationService));
47
48
const extHostWebviewPanels = disposables.add(new ExtHostWebviewPanels(rpcProtocol!, extHostWebviews, undefined));
49
50
return disposables.add(extHostWebviewPanels.createWebviewPanel({
51
extensionLocation: URI.from({
52
scheme: remoteAuthority ? Schemas.vscodeRemote : Schemas.file,
53
authority: remoteAuthority,
54
path: '/ext/path',
55
})
56
} as IExtensionDescription, 'type', 'title', 1, {}));
57
}
58
59
test('Cannot register multiple serializers for the same view type', async () => {
60
const viewType = 'view.type';
61
62
const extHostWebviews = disposables.add(new ExtHostWebviews(rpcProtocol!, { authority: undefined, isRemote: false }, undefined, new NullLogService(), NullApiDeprecationService));
63
64
const extHostWebviewPanels = disposables.add(new ExtHostWebviewPanels(rpcProtocol!, extHostWebviews, undefined));
65
66
let lastInvokedDeserializer: vscode.WebviewPanelSerializer | undefined = undefined;
67
68
class NoopSerializer implements vscode.WebviewPanelSerializer {
69
async deserializeWebviewPanel(webview: vscode.WebviewPanel, _state: any): Promise<void> {
70
lastInvokedDeserializer = this;
71
disposables.add(webview);
72
}
73
}
74
75
const extension = {} as IExtensionDescription;
76
77
const serializerA = new NoopSerializer();
78
const serializerB = new NoopSerializer();
79
80
const serializerARegistration = extHostWebviewPanels.registerWebviewPanelSerializer(extension, viewType, serializerA);
81
82
await extHostWebviewPanels.$deserializeWebviewPanel('x', viewType, {
83
title: 'title',
84
state: {},
85
panelOptions: {},
86
webviewOptions: {},
87
active: true,
88
}, 0 as EditorGroupColumn);
89
assert.strictEqual(lastInvokedDeserializer, serializerA);
90
91
assert.throws(
92
() => disposables.add(extHostWebviewPanels.registerWebviewPanelSerializer(extension, viewType, serializerB)),
93
'Should throw when registering two serializers for the same view');
94
95
serializerARegistration.dispose();
96
97
disposables.add(extHostWebviewPanels.registerWebviewPanelSerializer(extension, viewType, serializerB));
98
99
await extHostWebviewPanels.$deserializeWebviewPanel('x', viewType, {
100
title: 'title',
101
state: {},
102
panelOptions: {},
103
webviewOptions: {},
104
active: true,
105
}, 0 as EditorGroupColumn);
106
assert.strictEqual(lastInvokedDeserializer, serializerB);
107
});
108
109
test('asWebviewUri for local file paths', () => {
110
const webview = createWebview(rpcProtocol, /* remoteAuthority */undefined);
111
112
assert.strictEqual(
113
(webview.webview.asWebviewUri(URI.parse('file:///Users/codey/file.html')).toString()),
114
`https://file%2B.vscode-resource.${webviewResourceBaseHost}/Users/codey/file.html`,
115
'Unix basic'
116
);
117
118
assert.strictEqual(
119
(webview.webview.asWebviewUri(URI.parse('file:///Users/codey/file.html#frag')).toString()),
120
`https://file%2B.vscode-resource.${webviewResourceBaseHost}/Users/codey/file.html#frag`,
121
'Unix should preserve fragment'
122
);
123
124
assert.strictEqual(
125
(webview.webview.asWebviewUri(URI.parse('file:///Users/codey/f%20ile.html')).toString()),
126
`https://file%2B.vscode-resource.${webviewResourceBaseHost}/Users/codey/f%20ile.html`,
127
'Unix with encoding'
128
);
129
130
assert.strictEqual(
131
(webview.webview.asWebviewUri(URI.parse('file://localhost/Users/codey/file.html')).toString()),
132
`https://file%2Blocalhost.vscode-resource.${webviewResourceBaseHost}/Users/codey/file.html`,
133
'Unix should preserve authority'
134
);
135
136
assert.strictEqual(
137
(webview.webview.asWebviewUri(URI.parse('file:///c:/codey/file.txt')).toString()),
138
`https://file%2B.vscode-resource.${webviewResourceBaseHost}/c%3A/codey/file.txt`,
139
'Windows C drive'
140
);
141
});
142
143
test('asWebviewUri for remote file paths', () => {
144
const webview = createWebview(rpcProtocol, /* remoteAuthority */ 'remote');
145
146
assert.strictEqual(
147
(webview.webview.asWebviewUri(URI.parse('file:///Users/codey/file.html')).toString()),
148
`https://vscode-remote%2Bremote.vscode-resource.${webviewResourceBaseHost}/Users/codey/file.html`,
149
'Unix basic'
150
);
151
});
152
153
test('asWebviewUri for remote with / and + in name', () => {
154
const webview = createWebview(rpcProtocol, /* remoteAuthority */ 'remote');
155
const authority = 'ssh-remote+localhost=foo/bar';
156
157
const sourceUri = URI.from({
158
scheme: 'vscode-remote',
159
authority: authority,
160
path: '/Users/cody/x.png'
161
});
162
163
const webviewUri = webview.webview.asWebviewUri(sourceUri);
164
assert.strictEqual(
165
webviewUri.toString(),
166
`https://vscode-remote%2Bssh-002dremote-002blocalhost-003dfoo-002fbar.vscode-resource.vscode-cdn.net/Users/cody/x.png`,
167
'Check transform');
168
169
assert.strictEqual(
170
decodeAuthority(webviewUri.authority),
171
`vscode-remote+${authority}.vscode-resource.vscode-cdn.net`,
172
'Check decoded authority'
173
);
174
});
175
176
test('asWebviewUri for remote with port in name', () => {
177
const webview = createWebview(rpcProtocol, /* remoteAuthority */ 'remote');
178
const authority = 'localhost:8080';
179
180
const sourceUri = URI.from({
181
scheme: 'vscode-remote',
182
authority: authority,
183
path: '/Users/cody/x.png'
184
});
185
186
const webviewUri = webview.webview.asWebviewUri(sourceUri);
187
assert.strictEqual(
188
webviewUri.toString(),
189
`https://vscode-remote%2Blocalhost-003a8080.vscode-resource.vscode-cdn.net/Users/cody/x.png`,
190
'Check transform');
191
192
assert.strictEqual(
193
decodeAuthority(webviewUri.authority),
194
`vscode-remote+${authority}.vscode-resource.vscode-cdn.net`,
195
'Check decoded authority'
196
);
197
});
198
});
199
200
201
function createNoopMainThreadWebviews() {
202
return new class extends mock<MainThreadWebviewManager>() {
203
$disposeWebview() { /* noop */ }
204
$createWebviewPanel() { /* noop */ }
205
$registerSerializer() { /* noop */ }
206
$unregisterSerializer() { /* noop */ }
207
};
208
}
209
210