microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
eba0de58017cd198f69bffca9be3d8e0e4df4d6a

Branches

Tags

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

Clone

HTTPS

Download ZIP

test/extension/android/androidPlatform.test.ts

377lines · 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 Q from "q";
5import * as fs from "fs";
6import * as path from "path";
7import * as mockFs from "mock-fs";
8import * as assert from "assert";
9
10import {AndroidPlatform} from "../../../src/extension/android/androidPlatform";
11import {IAndroidRunOptions} from "../../../src/extension/launchArgs";
12import {FileSystem} from "../../../src/common/node/fileSystem";
13import {ReactNative022} from "../../resources/reactNative022";
14import * as adb from "../../../src/extension/android/adb";
15import {RecordingsHelper} from "../../resources/recordingsHelper";
16import {CommandExecutor} from "../../../src/common/commandExecutor";
17import * as rnHelper from "../../../src/common/reactNativeProjectHelper";
18
19import "should";
20import * as sinon from "sinon";
21import { SettingsHelper } from "../../../src/extension/settingsHelper";
22
23// TODO: Launch the extension server
24
25suite("androidPlatform", function () {
26 suite("extensionContext", function () {
27 const projectRoot = "C:/projects/SampleApplication_21/";
28 const androidProjectPath = path.join(projectRoot, "android");
29 const applicationName = "SampleApplication";
30 const androidPackageName = "com.sampleapplication";
31 const genericRunOptions: IAndroidRunOptions = { platform: "android", workspaceRoot: projectRoot, projectRoot: projectRoot };
32
33 const rnProjectContent = fs.readFileSync(ReactNative022.DEFAULT_PROJECT_FILE, "utf8");
34
35 let fileSystem: FileSystem;
36 let reactNative: ReactNative022;
37 let androidPlatform: AndroidPlatform;
38 let sandbox: Sinon.SinonSandbox;
39 let devices: any;
40 let adbHelper: adb.AdbHelper;
41
42 function createAndroidPlatform(runOptions: IAndroidRunOptions): AndroidPlatform {
43 return new AndroidPlatform(runOptions);
44 }
45
46 setup(() => {
47 mockFs();
48 sandbox = sinon.sandbox.create();
49
50 // Configure all the dependencies we'll use in our tests
51 fileSystem = new FileSystem();
52
53 adbHelper = new adb.AdbHelper(genericRunOptions.projectRoot);
54 sandbox.stub(adbHelper, "launchApp", function (projectRoot_: string, packageName: string, debugTarget?: string) {
55 devices = devices.map((device: any) => {
56 if (!debugTarget) {
57 device.installedApplications[androidPackageName] = { isInDebugMode: false };
58 }
59
60 if (debugTarget && debugTarget === device.id) {
61 device.installedApplications[androidPackageName] = { isInDebugMode: false };
62 }
63
64 return device;
65 });
66
67 return Q.resolve(void 0);
68 });
69 sandbox.stub(adbHelper, "getConnectedDevices", function () {
70 return Q.resolve(devices);
71 });
72 sandbox.stub(adbHelper, "getOnlineDevices", function () {
73 return Q.resolve(devices.filter((device: any) => {
74 return device.isOnline;
75 }));
76 });
77 sandbox.stub(adbHelper, "apiVersion", function () {
78 return Q.resolve(adb.AndroidAPILevel.LOLLIPOP);
79 });
80 sandbox.stub(adbHelper, "reverseAdb", function () {
81 return Q.resolve(void 0);
82 });
83
84 reactNative = new ReactNative022(fileSystem, adbHelper);
85
86 sandbox.stub(SettingsHelper, "getReactNativeProjectRoot", () => projectRoot);
87
88 androidPlatform = createAndroidPlatform(genericRunOptions);
89
90 sandbox.stub(CommandExecutor.prototype, "spawnReactCommand", function () {
91 return reactNative.runAndroid(genericRunOptions);
92 });
93
94 sandbox.stub(rnHelper.ReactNativeProjectHelper, "getReactNativeVersion", function () {
95 return Q.resolve("0.0.1");
96 });
97
98 androidPlatform.setAdbHelper(adbHelper);
99
100 sandbox.stub(reactNative, "installAppInDevice", function (deviceId: string) {
101 devices = devices.map((device: any) => {
102 if (deviceId && deviceId === device.id) {
103 device.installedApplications[androidPackageName] = {};
104 }
105
106 return device;
107 });
108 return Q.resolve(void 0);
109 });
110
111 // Create a React-Native project we'll use in our tests
112 return reactNative
113 .fromProjectFileContent(rnProjectContent)
114 .createProject(projectRoot, applicationName);
115 });
116
117 teardown(() => {
118 mockFs.restore();
119 sandbox.restore();
120 devices = [];
121 });
122
123 const testWithRecordings = new RecordingsHelper(() => reactNative).test;
124
125 testWithRecordings("runApp launches the app when a single emulator is connected",
126 [
127 "react-native/run-android/win10-rn0.21.0/succeedsWithOneVSEmulator",
128 "react-native/run-android/win10-rn0.22.2/succeedsWithOneVSEmulator",
129 "react-native/run-android/osx10.10-rn0.21.0/succeedsWithOneVSEmulator",
130 ], () => {
131 devices = fillDevices(["Nexus_5"]);
132
133 return Q({})
134 .then(() => {
135 return androidPlatform.runApp();
136 }).then(() => {
137 return devices[0].installedApplications[androidPackageName].isInDebugMode === false;
138 }).then(isRunning => {
139 isRunning.should.be.true();
140 });
141 });
142
143 testWithRecordings("runApp launches the app when two emulators are connected",
144 ["react-native/run-android/win10-rn0.21.0/succeedsWithTwoVSEmulators"], () => {
145 devices = fillDevices(["Nexus_5", "Nexus_6"]);
146
147 return Q({})
148 .then(() => {
149 return androidPlatform.runApp();
150 }).then(() => {
151 return Q.all([
152 Q.resolve(devices[0].installedApplications[androidPackageName].isInDebugMode === false),
153 Q.resolve(devices[1].installedApplications[androidPackageName].isInDebugMode === false),
154 ]);
155 }).spread((isRunningOnNexus5, isRunningOnNexus6) => {
156 // It should be running in exactly one of these two devices
157 isRunningOnNexus5.should.not.eql(isRunningOnNexus6);
158 });
159 });
160
161 testWithRecordings("runApp launches the app when three emulators are connected",
162 ["react-native/run-android/win10-rn0.21.0/succeedsWithThreeVSEmulators"], () => {
163 devices = fillDevices(["Nexus_5", "Nexus_6", "Nexus_7"]);
164 return Q({})
165 .then(() => {
166 return androidPlatform.runApp();
167 }).then(() => {
168 return Q.all([
169 Q.resolve(devices[0].installedApplications[androidPackageName].isInDebugMode === false),
170 Q.resolve(devices[1].installedApplications[androidPackageName].isInDebugMode === false),
171 Q.resolve(devices[2].installedApplications[androidPackageName].isInDebugMode === false),
172 ]);
173 }).then(isRunningList => {
174 // It should be running in exactly one of these three devices
175 isRunningList.filter(v => v).should.eql([true]);
176 });
177 });
178
179 testWithRecordings("runApp fails if no devices are connected",
180 ["react-native/run-android/win10-rn0.21.0/failsDueToNoDevicesConnected"], () => {
181 return Q({})
182 .then(() => {
183 return androidPlatform.runApp();
184 }).then(() => {
185 should.assert(false, "runApp should've exited with an error");
186 }, reason => {
187 reason.message.startsWith("Unknown error: not all success patterns were matched").should.be.true();
188 });
189 });
190
191 testWithRecordings("runApp launches the app in an online emulator only",
192 ["react-native/run-android/win10-rn0.21.0/succeedsWithFiveVSEmulators"], () => {
193 devices = fillDevices(["Nexus_5", "Nexus_6", "Nexus_7", "Nexus_8", "Nexus_9"]);
194 devices[4].isOnline = false;
195
196 return Q({})
197 .then(() => {
198 return androidPlatform.runApp();
199 }).then(() => {
200 return devices[4].installedApplications[androidPackageName].isInDebugMode === false;
201 }).then((isRunningOnOfflineDevice) => {
202 isRunningOnOfflineDevice.should.be.false();
203 });
204 });
205
206 testWithRecordings("runApp launches the app in the device specified as target",
207 ["react-native/run-android/win10-rn0.21.0/succeedsWithFiveVSEmulators"], () => {
208 devices = fillDevices(["Nexus_5", "Nexus_6", "Nexus_10", "Nexus_11", "Nexus_12"]);
209
210 return Q({})
211 .then(() => {
212 const runOptions: any = { platform: "android", workspaceRoot: projectRoot, projectRoot: projectRoot, target: "Nexus_12" };
213 const platform = createAndroidPlatform(runOptions);
214 platform.setAdbHelper(adbHelper);
215 return platform.runApp();
216 }).then(() => {
217 return devices[4].installedApplications[androidPackageName].isInDebugMode === false;
218 }).then((isRunningOnNexus12) => {
219 isRunningOnNexus12.should.be.true();
220 });
221 });
222
223 testWithRecordings("runApp launches the app in a random online device if the target is offline",
224 ["react-native/run-android/win10-rn0.21.0/succeedsWithTenVSEmulators"], () => {
225 const onlineDevicesIds = ["Nexus_11", "Nexus_13", "Nexus_14", "Nexus_15", "Nexus_16", "Nexus_17"];
226 const offineDevicesIds = ["Nexus_5", "Nexus_6", "Nexus_10", "Nexus_12"];
227 devices = fillDevices(offineDevicesIds.concat(onlineDevicesIds));
228 devices[0].isOnline = false;
229 devices[1].isOnline = false;
230 devices[2].isOnline = false;
231 devices[3].isOnline = false;
232
233 return Q({})
234 .then(() => {
235 const runOptions: any = { platform: "android", workspaceRoot: projectRoot, projectRoot: projectRoot, target: "Nexus_12" };
236 const platform = createAndroidPlatform(runOptions);
237 platform.setAdbHelper(adbHelper);
238 return platform.runApp();
239 }).then(() => {
240 return devices.filter((device: any) => device.installedApplications[androidPackageName].isInDebugMode === false);
241 }).then((devicesRunningAppId) => {
242 devicesRunningAppId.length.should.eql(1);
243 onlineDevicesIds.should.containEql(devicesRunningAppId[0].id);
244 });
245 });
246
247 testWithRecordings("runApp doesn't fail even if the call to start the LogCat does fail",
248 [
249 "react-native/run-android/win10-rn0.21.0/succeedsWithOneVSEmulator",
250 "react-native/run-android/win10-rn0.22.2/succeedsWithOneVSEmulator",
251 "react-native/run-android/osx10.10-rn0.21.0/succeedsWithOneVSEmulator",
252 ], () => {
253 devices = fillDevices(["Nexus_5"]);
254
255 return Q({})
256 .then(() => {
257 return androidPlatform.runApp();
258 }).then(() => {
259 return devices[0].installedApplications[androidPackageName].isInDebugMode === false;
260 }).then(isRunning => {
261 isRunning.should.be.true();
262 });
263 });
264
265 testWithRecordings("runApp fails when the android project doesn't exist, and shows a nice error message",
266 [
267 "react-native/run-android/win10-rn0.21.0/failsDueToAndroidFolderMissing",
268 "react-native/run-android/win10-rn0.22.2/failsDueToAndroidFolderMissing",
269 ], () => {
270 devices = fillDevices(["Nexus_5"]);
271
272 return Q({})
273 .then(() => {
274 return fileSystem.rmdir(androidProjectPath);
275 }).then(() => {
276 return androidPlatform.runApp();
277 }).then(() => {
278 should.assert(false, "Expected runApp to end up with an error");
279 return false;
280 }, reason => {
281 reason.message.should.eql("Android project not found.");
282 return !!devices[0].installedApplications[androidPackageName];
283 }).then(isRunning => {
284 isRunning.should.be.false();
285 });
286 });
287
288 testWithRecordings("runApp fails when the android emulator shell is unresponsive, and shows a nice error message",
289 ["react-native/run-android/osx10.10-rn0.21.0/failsDueToAdbCommandTimeout"], () => {
290 devices = fillDevices(["Nexus_5"]);
291
292 return Q({})
293 .then(() => {
294 return androidPlatform.runApp();
295 }).then(() => {
296 should.assert(false, "Expected runApp to end up with an error");
297 return false;
298 }, reason => {
299 "An Android shell command timed-out. Please retry the operation.".should.eql(reason.message);
300 return !!devices[0].installedApplications[androidPackageName];
301 }).then(isRunning => {
302 isRunning.should.be.false();
303 });
304 });
305
306 test("getRunArguments should return correct target", function() {
307 const runOptions: any = { platform: "android", workspaceRoot: projectRoot, projectRoot: projectRoot, target: "Nexus_12" };
308 const platform = createAndroidPlatform(runOptions);
309 const runArgs = platform.getRunArguments();
310
311 runArgs.should.be.an.Array();
312 runArgs.should.containDeepOrdered(["--deviceId", "Nexus_12"]);
313 });
314
315 test("getRunArguments should remove simulator target from args", function() {
316 const runOptions: any = { platform: "android", workspaceRoot: projectRoot, projectRoot: projectRoot, target: "simulator" };
317 const platform = createAndroidPlatform(runOptions);
318 const runArgs = platform.getRunArguments();
319
320 runArgs.should.be.an.Array();
321 runArgs.should.be.empty();
322 });
323
324 test("getRunArguments should remove device target from args", function() {
325 const runOptions: any = { platform: "android", workspaceRoot: projectRoot, projectRoot: projectRoot, target: "device" };
326 const platform = createAndroidPlatform(runOptions);
327 const runArgs = platform.getRunArguments();
328
329 runArgs.should.be.an.Array();
330 runArgs.should.be.empty();
331 });
332
333 test("getRunArguments should return correct args", function() {
334 const args = ["--deviceId", "device_id"];
335 const runOptions: any = { platform: "android", workspaceRoot: projectRoot, projectRoot: projectRoot, runArguments: args, target: "Nexus_12" };
336 const platform = createAndroidPlatform(runOptions);
337 const runArgs = platform.getRunArguments();
338
339 runArgs.should.be.an.Array();
340 runArgs.should.containDeepOrdered(args);
341 });
342
343 test("AdbHelper should correctly parse Android Sdk Location from local.properties file content", () => {
344 const adbHelper = new adb.AdbHelper("");
345 function testPaths(inputPath: string, expectedPath: string) {
346 const resultPath = adbHelper.parseSdkLocation(`sdk.dir=${inputPath}`);
347 assert.equal(resultPath, expectedPath);
348 }
349
350 const os = require("os");
351 function mockPlatform(platform: NodeJS.Platform) {
352 sandbox.restore();
353 sandbox.stub(os, "platform", function () {
354 return platform;
355 });
356 }
357
358 mockPlatform("win32");
359 testPaths(String.raw`C\:\\Users\\User1\\AndroidSdk`, String.raw`C:\Users\User1\AndroidSdk`);
360 testPaths(String.raw`\\\\Network\\Shared\\Folder`, String.raw`\\Network\Shared\Folder`);
361
362 mockPlatform("darwin");
363 testPaths(String.raw`/var/lib/some/path`, String.raw`/var/lib/some/path`);
364 testPaths(String.raw`~/Library`, String.raw`~/Library`);
365 testPaths(String.raw`/Users/User1/home/path`, String.raw`/Users/User1/home/path`);
366 });
367 });
368});
369
370function fillDevices(ids: string[]): any[] {
371 let devices: any[] = [];
372 ids.forEach(id => {
373 devices.push({ isOnline: true, installedApplications: {}, runningApplications: {}, type: adb.DeviceType.AndroidSdkEmulator, id: id });
374 });
375
376 return devices;
377}