microsoft/vscode-react-native

Public

mirrored fromhttps://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
cc70057d4beada1315f86cbbf3246d5c065b9eda

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/test/debugger/appWorker.test.ts

284lines · modecode

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import * as assert from "assert";
5import * as WebSocket from "ws";
6import * as path from "path";
7import * as Q from "q";
8import * as sinon from "sinon";
9
10import * as AppWorker from "../../debugger/appWorker";
11import { ForkedAppWorker } from "../../debugger/forkedAppWorker";
12import * as ForkedAppWorkerModule from "../../debugger/forkedAppWorker";
13// import {ScriptImporter} from "../../debugger/scriptImporter";
14import {Packager} from "../../common/packager";
15
16suite("appWorker", function() {
17 suite("debuggerContext", function() {
18 const packagerPort = 8081;
19
20 // suite("SandboxedAppWorker", function() {
21 // const sourcesStoragePath = path.resolve(__dirname, "assets");
22 // const startScriptFileName = require.resolve(path.join(sourcesStoragePath, ScriptImporter.DEBUGGER_WORKER_FILE_BASENAME));
23
24 // let sandboxedWorker: AppWorker.SandboxedAppWorker;
25 // let downloadAppScriptStub = sinon.stub();
26 // let postReplyFunction = sinon.stub();
27 // let readFileStub = sinon.stub();
28
29 // setup(function() {
30 // const nodeFileSystemMock: any = {
31 // readFile: readFileStub,
32 // };
33
34 // const scriptImporterMock: any = {
35 // downloadAppScript: downloadAppScriptStub,
36 // };
37
38 // sandboxedWorker = new AppWorker.SandboxedAppWorker(packagerPort, sourcesStoragePath, postReplyFunction, {
39 // nodeFileSystem: nodeFileSystemMock,
40 // scriptImporter: scriptImporterMock,
41 // });
42 // });
43
44 // teardown(function() {
45 // // Reset everything
46 // sandboxedWorker = null;
47
48 // readFileStub = sinon.stub();
49 // downloadAppScriptStub = sinon.stub();
50 // postReplyFunction = sinon.stub();
51 // });
52
53
54 // test("should execute scripts correctly and be able to invoke the callback", function() {
55 // const expectedMessageResult = { success: true };
56 // const startScriptContents = `var testResponse = ${JSON.stringify(expectedMessageResult)}; postMessage(testResponse);`;
57
58 // readFileStub.withArgs(startScriptFileName).returns(Q.resolve(startScriptContents));
59
60 // return sandboxedWorker.start().then(() => {
61 // assert(postReplyFunction.calledWithExactly(expectedMessageResult));
62 // });
63 // });
64
65 // test("should be able to import scripts", function() {
66 // const scriptImportPath = "testScript.js";
67 // const startScriptContents = `importScripts("${scriptImportPath}"); postMessage("postImport");`;
68 // readFileStub.withArgs(startScriptFileName).returns(Q.resolve(startScriptContents));
69
70 // const testScriptContents = "postMessage('inImport')";
71 // const scriptImportDeferred = Q.defer<void>();
72 // downloadAppScriptStub.withArgs(scriptImportPath).returns(scriptImportDeferred.promise.then(() => {
73 // return {
74 // contents: testScriptContents,
75 // filepath: scriptImportPath,
76 // };
77 // }));
78
79 // return sandboxedWorker.start().then(() => {
80 // // We have not yet finished importing the script, we should not have posted a response yet
81 // assert(postReplyFunction.notCalled, "postReplyFuncton called before scripts imported");
82 // scriptImportDeferred.resolve(void 0);
83 // return Q.delay(1);
84 // }).then(() => {
85 // assert(postReplyFunction.calledWith("postImport"), "postMessage after import not handled");
86 // assert(postReplyFunction.calledWith("inImport"), "postMessage not registered from within import");
87 // });
88 // });
89
90 // test("should correctly pass postMessage to the loaded script", function() {
91 // const startScriptContents = `onmessage = postMessage;`;
92 // readFileStub.withArgs(startScriptFileName).returns(Q.resolve(startScriptContents));
93
94 // const testMessage = { method: "test", success: true };
95
96 // return sandboxedWorker.start().then(() => {
97 // assert(postReplyFunction.notCalled, "postRepyFunction called before message sent");
98 // sandboxedWorker.postMessage(testMessage);
99 // return Q.delay(1);
100 // }).then(() => {
101 // assert(postReplyFunction.calledWith({ data: testMessage }), "No echo back from app");
102 // });
103 // });
104
105 // test("should be able to require an installed node module via __debug__.require", function () {
106 // const expectedMessageResult = { qString: Q.toString() };
107 // const startScriptContents = `var Q = __debug__.require('q');
108 // var testResponse = { qString: Q.toString() };
109 // postMessage(testResponse);`;
110
111 // readFileStub.withArgs(startScriptFileName).returns(Q.resolve(startScriptContents));
112
113 // return sandboxedWorker.start().then(() => {
114 // assert(postReplyFunction.calledWithExactly(expectedMessageResult));
115 // });
116 // });
117 // });
118
119 suite("MultipleLifetimesAppWorker", function() {
120 const sourcesStoragePath = path.resolve(__dirname, "assets");
121
122 let multipleLifetimesWorker: AppWorker.MultipleLifetimesAppWorker;
123 let sandboxedAppWorkerStub: Sinon.SinonStub;
124 let appWorkerModuleStub: Sinon.SinonStub;
125 let webSocket: Sinon.SinonStub;
126 let webSocketConstructor: Sinon.SinonStub;
127 let packagerIsRunning: Sinon.SinonStub;
128
129 let sendMessage: (message: string) => void;
130
131 let clock: Sinon.SinonFakeTimers;
132
133 setup(function() {
134 webSocket = sinon.createStubInstance(WebSocket);
135
136 sandboxedAppWorkerStub = sinon.createStubInstance(ForkedAppWorker);
137 appWorkerModuleStub = sinon.stub(ForkedAppWorkerModule, "ForkedAppWorker").returns(sandboxedAppWorkerStub);
138
139 const messageInvocation: Sinon.SinonStub = (<any>webSocket).on.withArgs("message");
140 sendMessage = (message: string) => messageInvocation.callArgWith(1, message);
141
142 webSocketConstructor = sinon.stub();
143 webSocketConstructor.returns(webSocket);
144 packagerIsRunning = sinon.stub(Packager, "isPackagerRunning");
145 packagerIsRunning.returns(Q.resolve(true));
146
147 multipleLifetimesWorker = new AppWorker.MultipleLifetimesAppWorker(packagerPort, sourcesStoragePath, {
148 webSocketConstructor: webSocketConstructor,
149 });
150
151 sinon.stub(multipleLifetimesWorker, "downloadAndPatchDebuggerWorker").returns(Q.resolve({}));
152 });
153
154 teardown(function() {
155 // Reset everything
156 multipleLifetimesWorker.stop();
157 multipleLifetimesWorker = null;
158 appWorkerModuleStub.restore();
159 webSocket = null;
160 sandboxedAppWorkerStub = null;
161 webSocketConstructor = null;
162 sendMessage = null;
163 packagerIsRunning.restore();
164 packagerIsRunning = null;
165
166 if (clock) {
167 clock.restore();
168 clock = null;
169 }
170 });
171
172 test("with packager running should construct a websocket connection to the correct endpoint and listen for events", function() {
173 return multipleLifetimesWorker.start().then(() => {
174 const websocketRegex = new RegExp("ws://[^:]*:[0-9]*/debugger-proxy\\?role=debugger");
175 assert(webSocketConstructor.calledWithMatch(websocketRegex), "The web socket was not constructed to the correct url: " + webSocketConstructor.args[0][0]);
176
177 const expectedListeners = ["open", "close", "message", "error"];
178 expectedListeners.forEach((event) => {
179 assert((<any>webSocket).on.calledWithMatch(event), `Missing listener for ${event}`);
180 });
181 });
182 });
183
184 test("with packager running should attempt to reconnect after disconnecting", function() {
185 let startWorker = sinon.spy(multipleLifetimesWorker, "start");
186 return multipleLifetimesWorker.start().then(() => {
187 // Forget previous invocations
188 startWorker.reset();
189 packagerIsRunning.returns(Q.resolve(true));
190
191 clock = sinon.useFakeTimers();
192
193 const closeInvocation: Sinon.SinonStub = (<any>webSocket).on.withArgs("close");
194 closeInvocation.callArg(1);
195
196 // Ensure that the retry is 100ms after the disconnection
197 clock.tick(99);
198 assert(startWorker.notCalled, "Attempted to reconnect too quickly");
199
200 clock.tick(1);
201 }).then(() => {
202 assert(startWorker.called);
203 });
204 });
205
206 test("with packager running should respond correctly to prepareJSRuntime messages", function() {
207 return multipleLifetimesWorker.start().then(() => {
208 const messageId = 1;
209 const testMessage = JSON.stringify({ method: "prepareJSRuntime", id: messageId });
210 const expectedReply = JSON.stringify({ replyID: messageId });
211
212 const appWorkerDeferred = Q.defer<void>();
213
214 const appWorkerStart: Sinon.SinonStub = (<any>sandboxedAppWorkerStub).start;
215 const websocketSend: Sinon.SinonStub = (<any>webSocket).send;
216
217 appWorkerStart.returns(appWorkerDeferred.promise);
218
219 sendMessage(testMessage);
220
221 assert(appWorkerStart.called, "SandboxedAppWorker not started in respones to prepareJSRuntime");
222 assert(websocketSend.notCalled, "Response sent prior to configuring sandbox worker");
223
224 appWorkerDeferred.resolve(void 0);
225
226 return Q.delay(1).then(() => {
227 assert(websocketSend.calledWith(expectedReply), "Did not receive the expected response to prepareJSRuntime");
228 });
229 });
230 });
231
232 test("with packager running should pass unknown messages to the sandboxedAppWorker", function() {
233 return multipleLifetimesWorker.start().then(() => {
234 // Start up an app worker
235 const prepareJSMessage = JSON.stringify({ method: "prepareJSRuntime", id: 1 });
236 const appWorkerStart: Sinon.SinonStub = (<any>sandboxedAppWorkerStub).start;
237 appWorkerStart.returns(Q.resolve(void 0));
238
239 sendMessage(prepareJSMessage);
240
241 // Then attempt to message it
242
243 const testMessage = { method: "unknownMethod" };
244 const testMessageString = JSON.stringify(testMessage);
245
246 const postMessageStub: Sinon.SinonStub = (<any>sandboxedAppWorkerStub).postMessage;
247
248 assert(postMessageStub.notCalled, "sandboxedAppWorker.postMessage called prior to any message");
249 sendMessage(testMessageString);
250
251 assert(postMessageStub.calledWith(testMessage), "message was not passed to sandboxedAppWorker");
252 });
253 });
254
255 test("with packager running should close connection if there is another debugger connected to packager", () => {
256 return multipleLifetimesWorker.start().then(() => {
257 // Forget previous invocations
258 webSocketConstructor.reset();
259 clock = sinon.useFakeTimers(new Date().getTime());
260
261 const closeInvocation: Sinon.SinonStub = (<any>webSocket).on.withArgs("close");
262 (<any>webSocket)._closeMessage = "Another debugger is already connected";
263 closeInvocation.callArg(1);
264
265 // Ensure it doesn't try to reconnect
266 clock.tick(100);
267 assert(webSocketConstructor.notCalled, "socket attempted to reconnect");
268 });
269 });
270
271 test("without packager running should not start if there is no packager running", () => {
272 packagerIsRunning.returns(Q.resolve(false));
273
274 return multipleLifetimesWorker.start()
275 .done(() => {
276 assert(webSocketConstructor.notCalled, "socket should not be created");
277 }, reason => {
278 assert(reason.message === `Cannot attach to packager. Are you sure there is a packager and it is running in the port ${packagerPort}? If your packager is configured to run in another port make sure to add that to the setting.json.`);
279 });
280 });
281 });
282
283 });
284});
285