-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Expand file tree
/
Copy pathclient-global-api.test.ts
More file actions
138 lines (122 loc) · 5.18 KB
/
Copy pathclient-global-api.test.ts
File metadata and controls
138 lines (122 loc) · 5.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright (c) Microsoft Corporation. All rights reserved.
import { PassThrough } from "node:stream";
import { describe, expect, it, onTestFinished, vi } from "vitest";
import {
createMessageConnection,
StreamMessageReader,
StreamMessageWriter,
} from "vscode-jsonrpc/node.js";
import {
registerClientGlobalApiHandlers,
type ClientGlobalApiHandlers,
type ExtensionLaunchProviderResolveRequest,
type ExtensionLaunchProviderResolveResult,
} from "../src/generated/rpc.js";
function connect(handlers: ClientGlobalApiHandlers) {
const outbound = new PassThrough();
const inbound = new PassThrough();
const client = createMessageConnection(
new StreamMessageReader(inbound),
new StreamMessageWriter(outbound)
);
const server = createMessageConnection(
new StreamMessageReader(outbound),
new StreamMessageWriter(inbound)
);
onTestFinished(() => {
client.dispose();
server.dispose();
inbound.destroy();
outbound.destroy();
});
registerClientGlobalApiHandlers(client, handlers);
client.listen();
server.listen();
return server;
}
const request: ExtensionLaunchProviderResolveRequest = {
id: "project:extension",
modulePath: "/extensions/example/index.js",
name: "Example",
source: "project",
};
describe("client-global API transport", () => {
it("awaits a handler and returns its result without a session", async () => {
let release!: (result: ExtensionLaunchProviderResolveResult) => void;
const result = new Promise<ExtensionLaunchProviderResolveResult>((resolve) => {
release = resolve;
});
const handler = vi.fn(async () => result);
const server = connect({ extensionLaunchProvider: { resolve: handler } });
const response = server.sendRequest("extensionLaunchProvider.resolve", request);
const completed = vi.fn();
void response.then(completed);
await vi.waitFor(() => expect(handler).toHaveBeenCalledWith(request));
expect(completed).not.toHaveBeenCalled();
const launch = { executable: "/app/extension-host", args: ["example"], env: {} };
release({ launch });
await expect(response).resolves.toEqual({ launch });
expect(handler).toHaveBeenCalledTimes(1);
});
it("keeps global handlers and responses on their original connection", async () => {
const firstHandler = vi.fn(async () => ({
launch: { executable: "/first/host", args: [], env: {} },
}));
const secondHandler = vi.fn(async () => ({
launch: { executable: "/second/host", args: [], env: {} },
}));
const first = connect({ extensionLaunchProvider: { resolve: firstHandler } });
const second = connect({ extensionLaunchProvider: { resolve: secondHandler } });
const responses = await Promise.all([
first.sendRequest("extensionLaunchProvider.resolve", request),
second.sendRequest("extensionLaunchProvider.resolve", request),
]);
expect(responses).toEqual([
{ launch: { executable: "/first/host", args: [], env: {} } },
{ launch: { executable: "/second/host", args: [], env: {} } },
]);
expect(firstHandler).toHaveBeenCalledTimes(1);
expect(secondHandler).toHaveBeenCalledTimes(1);
});
it("continues dispatching requests while a global handler is pending", async () => {
let release!: (result: ExtensionLaunchProviderResolveResult) => void;
const result = new Promise<ExtensionLaunchProviderResolveResult>((resolve) => {
release = resolve;
});
const handler = vi.fn(async () => result);
const tokenHandler = vi.fn(async () => ({ kind: "cancelled" as const }));
const server = connect({
extensionLaunchProvider: { resolve: handler },
gitHubToken: { getToken: tokenHandler },
});
const pending = server.sendRequest("extensionLaunchProvider.resolve", request);
await vi.waitFor(() => expect(handler).toHaveBeenCalledOnce());
await expect(
server.sendRequest("gitHubToken.getToken", {
registrationId: "registration",
host: "github.com",
reason: "initial",
})
).resolves.toEqual({ kind: "cancelled" });
release({});
await expect(pending).resolves.toEqual({});
});
it("returns an error when no global handler is registered", async () => {
const server = connect({});
await expect(
server.sendRequest("extensionLaunchProvider.resolve", request)
).rejects.toThrow("No extensionLaunchProvider client-global handler registered");
});
it("propagates handler failure without substituting a successful result", async () => {
const server = connect({
extensionLaunchProvider: {
resolve: async () => {
throw new Error("Host review unavailable");
},
},
});
await expect(
server.sendRequest("extensionLaunchProvider.resolve", request)
).rejects.toThrow("Host review unavailable");
});
});