microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
514df4f4ef8788dfab32c26fd9d9c889f50a55ed

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/test/debugger/appWorker.test.ts

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