microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
3b6023b2c4497b5b8cf54373639977efc9e6e612

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/test/debugger/appWorker.test.ts

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