microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
e50dadc05b664d9b6f5bac64bbc5739db07304cf

Branches

Tags

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

Clone

HTTPS

Download ZIP

test/extension/android/androidPlatform.test.ts

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