microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
3c172a056576b34ff7bb5d777cbd9b47ff97cd7f

Branches

Tags

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

Clone

HTTPS

Download ZIP

test/resources/reactNative022.ts

194lines · 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 path from "path";
6import * as assert from "assert";
7
8import {PromiseUtil} from "../../src/common/node/promise";
9
10import * as reactNative from "../../src/common/reactNative";
11import {IAndroidRunOptions} from "../../src/common/launchArgs";
12import {ISpawnResult} from "../../src/common/node/childProcess";
13import {FileSystem} from "../../src/common/node/fileSystem";
14import {Package} from "../../src/common/node/package";
15import {Recording, Simulator} from "./processExecution/simulator";
16import {AdbSimulator} from "./simulators/adbSimulator";
17import {APKSerializer} from "./simulators/apkSerializer";
18
19const resourcesPath = path.join(__dirname, "../../../test/resources/");
20const sampleRNProjectPath = path.join(resourcesPath, "sampleReactNative022Project");
21const processExecutionsRecordingsPath = path.join(resourcesPath, "processExecutionsRecordings");
22
23export type IReactNative = reactNative.IReactNative;
24
25/* This class simulates calling the React-Native CLI v0.22. It currently supports react-native init
26 and react-native run-android. */
27export class ReactNative022 implements IReactNative {
28
29 public static DEFAULT_PROJECT_FILE = path.join(sampleRNProjectPath, "package.json");
30
31 private static ANDROID_APK_RELATIVE_PATH = "android/app/build/outputs/apk/app-debug.apk";
32
33 private projectFileContent: string;
34
35 private simulator: Simulator = new Simulator({
36 beforeStart: () => this.readAndroidPackageName(), // 1. We read the package.json to verify this is a RN project
37 outputBased: [
38 {
39 eventPattern: /:app:assembleDebug/,
40 action: () => this.createAPK(), // 2. We compile the application.
41 },
42 {
43 eventPattern: /Installed on [0-9]+ devices*\./,
44 action: () => this.installAppInAllDevices(), // 3. We install it on all available devices.
45 },
46 ],
47 beforeSuccess: (stdout: string, stderr: string) => // 4. If we didn't had any errors after starting to launch the app,
48 this.launchApp(stdout, stderr), // it means we were succesful
49 });
50
51 private recording: Recording;
52
53 private androidPackageName: string;
54 private projectRoot: string;
55 private androidAPKPath: string;
56
57 constructor(private adb: AdbSimulator, private fileSystem: FileSystem) {
58 assert(this.adb, "adb shouldn't be null");
59 assert(this.fileSystem, "fileSystem shouldn't be null");
60 }
61
62 public fromProjectFileContent(content: string): this {
63 this.projectFileContent = content;
64 return this;
65 }
66
67 public loadRecordingFromName(recordingName: string): Q.Promise<void> {
68 return this.loadRecordingFromFile(path.join(processExecutionsRecordingsPath, `${recordingName}.json`));
69 }
70
71 public loadRecordingFromString(recordingContent: string): Q.Promise<void> {
72 return Q.when(this.loadRecording(JSON.parse(recordingContent)));
73 }
74
75 public loadRecordingFromFile(recordingPath: string): Q.Promise<void> {
76 return Q({})
77 .then(() => {
78 return new FileSystem().readFile(recordingPath);
79 }).then(fileContents => {
80 this.loadRecording(JSON.parse(fileContents));
81 });
82 }
83
84 public loadRecording(recording: Recording): void {
85 assert(recording, "recording shouldn't be null");
86 this.recording = recording;
87 }
88
89 public createProject(projectRoot: string, projectName: string): Q.Promise<void> {
90 return Q({})
91 .then(() => {
92 this.fileSystem.makeDirectoryRecursiveSync(projectRoot);
93 return this.projectFileContent !== undefined ?
94 this.projectFileContent :
95 this.readDefaultProjectFile();
96 }).then(defaultContents => {
97 const reactNativeConfiguration = JSON.parse(defaultContents);
98 reactNativeConfiguration.name = projectName;
99 const reactNativeConfigurationFormatted = JSON.stringify(reactNativeConfiguration);
100 return this.fileSystem.writeFile(this.getPackageJsonPath(projectRoot), reactNativeConfigurationFormatted);
101 }).then(() => {
102 return this.fileSystem.mkDir(this.getAndroidProjectPath(projectRoot));
103 });
104 }
105
106 public runAndroid(runOptions: IAndroidRunOptions): ISpawnResult {
107 this.projectRoot = runOptions.projectRoot;
108 this.simulator.simulate(this.recording).done();
109 return this.simulator.spawn();
110 }
111
112 private getAndroidProjectPath(projectRoot = this.projectRoot): string {
113 return path.join(projectRoot, "android");
114 }
115
116 private getPackageJsonPath(projectRoot: string): string {
117 return new Package(projectRoot, { fileSystem: this.fileSystem }).informationJsonFilePath();
118 }
119
120 private readAndroidPackageName(): Q.Promise<void> {
121 return new Package(this.projectRoot, { fileSystem: this.fileSystem }).name().then(name => {
122 this.androidPackageName = `com.${name.toLowerCase()}`;
123 });
124 }
125
126 private createAPK(): Q.Promise<void> {
127 return this.isAndroidProjectPresent().then(isPresent => {
128 return isPresent ? void 0 : Q.reject<void>(new Error("The recording expects the Android project to be present, but it's not"));
129 }).then(() => {
130 this.androidAPKPath = path.join(this.projectRoot, ReactNative022.ANDROID_APK_RELATIVE_PATH);
131 return new APKSerializer(this.fileSystem).writeApk(this.androidAPKPath, { packageName: this.androidPackageName });
132 });
133 }
134
135 private isAndroidProjectPresent(): Q.Promise<boolean> {
136 // TODO: Make more checks as neccesary for the tests
137 return this.fileSystem.directoryExists(this.getAndroidProjectPath());
138 }
139
140 private installAppInAllDevices(): Q.Promise<void> {
141 return new PromiseUtil().reduce(this.adb.getConnectedDevices(), device => this.installAppInDevice(device.id));
142 }
143
144 private installAppInDevice(deviceId: string): Q.Promise<void> {
145 return this.adb.isDeviceOnline(deviceId).then(isOnline => {
146 if (isOnline) {
147 return this.adb.installApp(this.androidAPKPath, deviceId);
148 } else {
149 // TODO: Figure out what's the right thing to do here, if we ever need this for the tests
150 return void 0;
151 }
152 });
153 }
154
155 private launchApp(stdout: string, stderr: string): Q.Promise<void> {
156 /*
157 Sample output we want to accept:
158 BUILD SUCCESSFUL
159
160 Total time: 9.052 secs
161 Starting the app (C:\Program Files (x86)\Android\android-sdk/platform-tools/adb shell am start -n com.sampleapplication/.MainActivity)...
162 Starting: Intent { cmp=com.sampleapplication/.MainActivity }
163
164
165 Sample output we don't to accept:
166 BUILD SUCCESSFUL
167
168 Total time: 9.052 secs
169 Starting the app (C:\Program Files (x86)\Android\android-sdk/platform-tools/adb shell am start -n com.sampleapplication/.MainActivity)...
170 Starting: Intent { cmp=com.sampleapplication/.MainActivity }
171 Error: some error happened
172 **/
173 const succesfulOutputEnd = `Starting the app \\(.*adb shell am start -n ([^ /]+)\/\\.MainActivity\\)\\.\\.\\.\\s+`
174 + `Starting: Intent { cmp=([^ /]+)\/\\.MainActivity }\\s+$`;
175 const matches = stdout.match(new RegExp(succesfulOutputEnd));
176 if (matches) {
177 if (matches.length === 3 && matches[1] === this.androidPackageName && matches[2] === this.androidPackageName) {
178 return this.adb.launchApp(this.projectRoot, this.androidPackageName);
179 } else {
180 return Q.reject<void>(new Error("There was an error while trying to match the Starting the app messages."
181 + "Expected to match the pattern and recognize the expected android package name, but it failed."
182 + `Expected android package name: ${this.androidPackageName}. Actual matches: ${JSON.stringify(matches)}`));
183 }
184 } else {
185 // The record doesn't indicate that the app was launched, so we don't do anything
186 return Q.resolve(void 0);
187 }
188 }
189
190 private readDefaultProjectFile(): Q.Promise<string> {
191 const realFileSystem = new FileSystem(); // We always use the real file system (not the mock one) to read the sample project
192 return realFileSystem.readFile(ReactNative022.DEFAULT_PROJECT_FILE);
193 }
194}
195