microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
7b48f26eb8caae7ed9cc1a09249195dfed76fa76

Branches

Tags

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

Clone

HTTPS

Download ZIP

test/resources/reactNative065.ts

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