microsoft/vscode-react-native

Public

mirrored from https://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
f0161ba5b4933b844917e01f74fc7dfb17d2f862

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/test/debugger/appWorker.test.ts

281lines · modeblame

3b6023b2Jimmy Thomson10 years ago1// 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";
299b0557Patricio Beltran10 years ago12import {Packager} from "../../common/packager";
3b6023b2Jimmy Thomson10 years ago13
14suite("appWorker", function() {
15suite("debuggerContext", function() {
5e651f3edigeff10 years ago16const packagerPort = 8081;
3b6023b2Jimmy Thomson10 years ago17
5e651f3edigeff10 years ago18suite("SandboxedAppWorker", function() {
3b6023b2Jimmy Thomson10 years ago19const sourcesStoragePath = path.resolve(__dirname, "assets");
20const startScriptFileName = require.resolve(path.join(sourcesStoragePath, ScriptImporter.DEBUGGER_WORKER_FILE_BASENAME));
21const debugAdapterPort = 9090;
22
23let sandboxedWorker: AppWorker.SandboxedAppWorker;
24let downloadAppScriptStub = sinon.stub();
25let postReplyFunction = sinon.stub();
26let readFileStub = sinon.stub();
27
28setup(function() {
29const nodeFileSystemMock: any = {
cdf34447digeff10 years ago30readFile: readFileStub,
3b6023b2Jimmy Thomson10 years ago31};
32
33const scriptImporterMock: any = {
cdf34447digeff10 years ago34downloadAppScript: downloadAppScriptStub,
3b6023b2Jimmy Thomson10 years ago35};
36
5e651f3edigeff10 years ago37sandboxedWorker = new AppWorker.SandboxedAppWorker(packagerPort, sourcesStoragePath, debugAdapterPort, postReplyFunction, {
3b6023b2Jimmy Thomson10 years ago38nodeFileSystem: nodeFileSystemMock,
cdf34447digeff10 years ago39scriptImporter: scriptImporterMock,
3b6023b2Jimmy Thomson10 years ago40});
41});
42
43teardown(function() {
44// Reset everything
45sandboxedWorker = null;
46
47readFileStub = sinon.stub();
48downloadAppScriptStub = sinon.stub();
49postReplyFunction = sinon.stub();
50});
51
52
53test("should execute scripts correctly and be able to invoke the callback", function() {
54const expectedMessageResult = { success: true };
55const startScriptContents = `var testResponse = ${JSON.stringify(expectedMessageResult)}; postMessage(testResponse);`;
56
57readFileStub.withArgs(startScriptFileName).returns(Q.resolve(startScriptContents));
58
59return sandboxedWorker.start().then(() => {
60assert(postReplyFunction.calledWithExactly(expectedMessageResult));
61});
62});
63
64test("should be able to import scripts", function() {
65const scriptImportPath = "testScript.js";
66const startScriptContents = `importScripts("${scriptImportPath}"); postMessage("postImport");`;
67readFileStub.withArgs(startScriptFileName).returns(Q.resolve(startScriptContents));
68
69const testScriptContents = "postMessage('inImport')";
70const scriptImportDeferred = Q.defer<void>();
71downloadAppScriptStub.withArgs(scriptImportPath, debugAdapterPort).returns(scriptImportDeferred.promise.then(() => {
72return {
73contents: testScriptContents,
cdf34447digeff10 years ago74filepath: scriptImportPath,
3b6023b2Jimmy Thomson10 years ago75};
76}));
77
78return sandboxedWorker.start().then(() => {
79// We have not yet finished importing the script, we should not have posted a response yet
80assert(postReplyFunction.notCalled, "postReplyFuncton called before scripts imported");
81scriptImportDeferred.resolve(void 0);
82return Q.delay(1);
83}).then(() => {
84assert(postReplyFunction.calledWith("postImport"), "postMessage after import not handled");
85assert(postReplyFunction.calledWith("inImport"), "postMessage not registered from within import");
86});
87});
88
89test("should correctly pass postMessage to the loaded script", function() {
90const startScriptContents = `onmessage = postMessage;`;
91readFileStub.withArgs(startScriptFileName).returns(Q.resolve(startScriptContents));
92
93const testMessage = { method: "test", success: true };
94
95return sandboxedWorker.start().then(() => {
96assert(postReplyFunction.notCalled, "postRepyFunction called before message sent");
97sandboxedWorker.postMessage(testMessage);
98return Q.delay(1);
99}).then(() => {
100assert(postReplyFunction.calledWith({ data: testMessage }), "No echo back from app");
101});
102});
a39f743aJimmy Thomson10 years ago103
7e9f0db0Jimmy Thomson10 years ago104test("should be able to require an installed node module via __debug__.require", function () {
105const expectedMessageResult = { qString: Q.toString() };
106const startScriptContents = `var Q = __debug__.require('q');
107var testResponse = { qString: Q.toString() };
a39f743aJimmy Thomson10 years ago108postMessage(testResponse);`;
109
110readFileStub.withArgs(startScriptFileName).returns(Q.resolve(startScriptContents));
111
112return sandboxedWorker.start().then(() => {
113assert(postReplyFunction.calledWithExactly(expectedMessageResult));
114});
115});
3b6023b2Jimmy Thomson10 years ago116});
117
118suite("MultipleLifetimesAppWorker", function() {
119const sourcesStoragePath = path.resolve(__dirname, "assets");
120const debugAdapterPort = 9090;
121
122let multipleLifetimesWorker: AppWorker.MultipleLifetimesAppWorker;
123let sandboxedAppWorkerStub: Sinon.SinonStub;
124let webSocket: Sinon.SinonStub;
125let sandboxedAppConstructor: Sinon.SinonStub;
126let webSocketConstructor: Sinon.SinonStub;
299b0557Patricio Beltran10 years ago127let packagerIsRunning: Sinon.SinonStub;
3b6023b2Jimmy Thomson10 years ago128
ac841b61Jimmy Thomson10 years ago129let sendMessage: (message: string) => void;
130
3b6023b2Jimmy Thomson10 years ago131let clock: Sinon.SinonFakeTimers;
132
133setup(function() {
134webSocket = sinon.createStubInstance(WebSocket);
135sandboxedAppWorkerStub = sinon.createStubInstance(AppWorker.SandboxedAppWorker);
136
ac841b61Jimmy Thomson10 years ago137const messageInvocation: Sinon.SinonStub = (<any>webSocket).on.withArgs("message");
138sendMessage = (message: string) => messageInvocation.callArgWith(1, message);
139
3b6023b2Jimmy Thomson10 years ago140sandboxedAppConstructor = sinon.stub();
141sandboxedAppConstructor.returns(sandboxedAppWorkerStub);
142webSocketConstructor = sinon.stub();
143webSocketConstructor.returns(webSocket);
299b0557Patricio Beltran10 years ago144packagerIsRunning = sinon.stub(Packager, "isPackagerRunning");
145packagerIsRunning.returns(Q.resolve(true));
3b6023b2Jimmy Thomson10 years ago146
5e651f3edigeff10 years ago147multipleLifetimesWorker = new AppWorker.MultipleLifetimesAppWorker(packagerPort, sourcesStoragePath, debugAdapterPort, {
3b6023b2Jimmy Thomson10 years ago148sandboxedAppConstructor: sandboxedAppConstructor,
cdf34447digeff10 years ago149webSocketConstructor: webSocketConstructor,
3b6023b2Jimmy Thomson10 years ago150});
151});
152
153teardown(function() {
154// Reset everything
155multipleLifetimesWorker = null;
156webSocket = null;
157sandboxedAppWorkerStub = null;
158sandboxedAppConstructor = null;
159webSocketConstructor = null;
ac841b61Jimmy Thomson10 years ago160sendMessage = null;
299b0557Patricio Beltran10 years ago161packagerIsRunning.restore();
162packagerIsRunning = null;
3b6023b2Jimmy Thomson10 years ago163
164if (clock) {
165clock.restore();
166clock = null;
167}
168});
169
299b0557Patricio Beltran10 years ago170test("with packager running should construct a websocket connection to the correct endpoint and listen for events", function() {
3b6023b2Jimmy Thomson10 years ago171return multipleLifetimesWorker.start().then(() => {
172const websocketRegex = new RegExp("ws://[^:]*:[0-9]*/debugger-proxy\\?role=debugger");
173assert(webSocketConstructor.calledWithMatch(websocketRegex), "The web socket was not constructed to the correct url: " + webSocketConstructor.args[0][0]);
174
175const expectedListeners = ["open", "close", "message", "error"];
176expectedListeners.forEach((event) => {
177assert((<any>webSocket).on.calledWithMatch(event), `Missing listener for ${event}`);
178});
179});
180});
181
299b0557Patricio Beltran10 years ago182test("with packager running should attempt to reconnect after disconnecting", function() {
3b6023b2Jimmy Thomson10 years ago183return multipleLifetimesWorker.start().then(() => {
184// Forget previous invocations
185webSocketConstructor.reset();
299b0557Patricio Beltran10 years ago186packagerIsRunning.returns(Q.resolve(true));
3b6023b2Jimmy Thomson10 years ago187
6e731058Jimmy Thomson10 years ago188clock = sinon.useFakeTimers();
189
3b6023b2Jimmy Thomson10 years ago190const closeInvocation: Sinon.SinonStub = (<any>webSocket).on.withArgs("close");
191closeInvocation.callArg(1);
192
193// Ensure that the retry is 100ms after the disconnection
194clock.tick(99);
195assert(webSocketConstructor.notCalled, "Attempted to reconnect too quickly");
196
197clock.tick(1);
299b0557Patricio Beltran10 years ago198}).then(() => {
3b6023b2Jimmy Thomson10 years ago199assert(webSocketConstructor.called);
200});
201});
202
299b0557Patricio Beltran10 years ago203test("with packager running should respond correctly to prepareJSRuntime messages", function() {
3b6023b2Jimmy Thomson10 years ago204return multipleLifetimesWorker.start().then(() => {
205const messageId = 1;
206const testMessage = JSON.stringify({ method: "prepareJSRuntime", id: messageId });
207const expectedReply = JSON.stringify({ replyID: messageId });
208
209const appWorkerDeferred = Q.defer<void>();
210
211const appWorkerStart: Sinon.SinonStub = (<any>sandboxedAppWorkerStub).start;
212const websocketSend: Sinon.SinonStub = (<any>webSocket).send;
213
214appWorkerStart.returns(appWorkerDeferred.promise);
215
216sendMessage(testMessage);
217
218assert(appWorkerStart.called, "SandboxedAppWorker not started in respones to prepareJSRuntime");
219assert(websocketSend.notCalled, "Response sent prior to configuring sandbox worker");
220
221appWorkerDeferred.resolve(void 0);
222
223return Q.delay(1).then(() => {
224assert(websocketSend.calledWith(expectedReply), "Did not receive the expected response to prepareJSRuntime");
225});
226});
227});
ac841b61Jimmy Thomson10 years ago228
299b0557Patricio Beltran10 years ago229test("with packager running should pass unknown messages to the sandboxedAppWorker", function() {
ac841b61Jimmy Thomson10 years ago230return multipleLifetimesWorker.start().then(() => {
231// Start up an app worker
232const prepareJSMessage = JSON.stringify({ method: "prepareJSRuntime", id: 1 });
233const appWorkerStart: Sinon.SinonStub = (<any>sandboxedAppWorkerStub).start;
234appWorkerStart.returns(Q.resolve(void 0));
235
236sendMessage(prepareJSMessage);
237
238// Then attempt to message it
239
240const testMessage = { method: "unknownMethod" };
241const testMessageString = JSON.stringify(testMessage);
242
243const postMessageStub: Sinon.SinonStub = (<any>sandboxedAppWorkerStub).postMessage;
244
245assert(postMessageStub.notCalled, "sandboxedAppWorker.postMessage called prior to any message");
246sendMessage(testMessageString);
247
248assert(postMessageStub.calledWith(testMessage), "message was not passed to sandboxedAppWorker");
249});
250});
299b0557Patricio Beltran10 years ago251
252test("with packager running should close connection if there is another debugger connected to packager", () => {
253return multipleLifetimesWorker.start().then(() => {
254// Forget previous invocations
255webSocketConstructor.reset();
256clock = sinon.useFakeTimers(new Date().getTime());
257
258const closeInvocation: Sinon.SinonStub = (<any>webSocket).on.withArgs("close");
259(<any>webSocket)._closeMessage = "Another debugger is already connected";
260closeInvocation.callArg(1);
261
262// Ensure it doesn't try to reconnect
263clock.tick(100);
264assert(webSocketConstructor.notCalled, "socket attempted to reconnect");
265});
266});
267
268test("without packager running should not start if there is no packager running", () => {
269packagerIsRunning.returns(Q.resolve(false));
270
271return multipleLifetimesWorker.start()
272.done(() => {
273assert(webSocketConstructor.notCalled, "socket should not be created");
274}, reason => {
275assert(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.`);
276});
277});
3b6023b2Jimmy Thomson10 years ago278});
299b0557Patricio Beltran10 years ago279
3b6023b2Jimmy Thomson10 years ago280});
7e9f0db0Jimmy Thomson10 years ago281});