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/smoke/package/src/helpers/setupEnvironmentHelper.ts

268lines · 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 * as utilities from "./utilities";
6import * as fs from "fs";
7import * as rimraf from "rimraf";
8import * as cp from "child_process";
9import * as semver from "semver";
10import * as os from "os";
11import { IosSimulatorHelper } from "./iosSimulatorHelper";
12import { sleep } from "./utilities";
13import { AndroidEmulatorHelper } from "./androidEmulatorHelper";
14
15const XDL = require("@expo/xdl");
16
17export class SetupEnvironmentHelper {
18
19 public static expoPackageName = "host.exp.exponent";
20 public static expoBundleId = "host.exp.Exponent";
21 public static iOSExpoAppsCacheDir = `${os.homedir()}/.expo/ios-simulator-app-cache`;
22
23 public static prepareReactNativeApplication(workspaceFilePath: string, resourcesPath: string, workspacePath: string, appName: string, customEntryPointFolder: string, version?: string) {
24 let command = `react-native init ${appName}`;
25 if (version) {
26 command += ` --version ${version}`;
27 }
28 console.log(`*** Creating RN app via '${command}' in ${workspacePath}...`);
29 cp.execSync(command, { cwd: resourcesPath, stdio: "inherit" });
30
31 const customEntryPointFile = path.join(resourcesPath, customEntryPointFolder, "App.js");
32 const launchConfigFile = path.join(resourcesPath, "launch.json");
33 const vsCodeConfigPath = path.join(workspacePath, ".vscode");
34
35 console.log(`*** Copying ${customEntryPointFile} into ${workspaceFilePath}...`);
36 fs.writeFileSync(workspaceFilePath, fs.readFileSync(customEntryPointFile));
37
38 if (!fs.existsSync(vsCodeConfigPath)) {
39 console.log(`*** Creating ${vsCodeConfigPath}...`);
40 fs.mkdirSync(vsCodeConfigPath);
41 }
42
43 console.log(`*** Copying ${launchConfigFile} into ${vsCodeConfigPath}...`);
44 fs.writeFileSync(path.join(vsCodeConfigPath, "launch.json"), fs.readFileSync(launchConfigFile));
45
46 SetupEnvironmentHelper.patchMetroConfig(workspacePath);
47 }
48
49 public static prepareHermesReactNativeApplication(workspaceFilePath: string, resourcesPath: string, workspacePath: string, appName: string, customEntryPointFolder: string, version?: string) {
50 const commandClean = path.join(workspacePath, "android", "gradlew") + " clean";
51
52 console.log(`*** Executing ${commandClean} ...`);
53 cp.execSync(commandClean, { cwd: path.join(workspacePath, "android"), stdio: "inherit" });
54
55 const customEntryPointFile = path.join(resourcesPath, customEntryPointFolder, "App.js");
56 const testButtonPath = path.join(resourcesPath, customEntryPointFolder, "AppTestButton.js");
57
58 console.log(`*** Copying ${customEntryPointFile} into ${workspaceFilePath}...`);
59 fs.writeFileSync(workspaceFilePath, fs.readFileSync(customEntryPointFile));
60
61 SetupEnvironmentHelper.copyGradleFilesToHermesApp(workspacePath, resourcesPath, customEntryPointFolder);
62
63 console.log(`*** Copying ${testButtonPath} into ${workspacePath}`);
64 fs.copyFileSync(testButtonPath, path.join(workspacePath, "AppTestButton.js"));
65 }
66
67 public static prepareExpoApplication(workspaceFilePath: string, resourcesPath: string, workspacePath: string, appName: string) {
68 const command = `echo -ne '\\n' | expo init -t tabs --name ${appName} ${appName}`;
69 console.log(`*** Creating Expo app via '${command}' in ${workspacePath}...`);
70 cp.execSync(command, { cwd: resourcesPath, stdio: "inherit" });
71
72 const customEntryPointFile = path.join(resourcesPath, "ExpoSample", "App.js");
73 const launchConfigFile = path.join(resourcesPath, "launch.json");
74 const vsCodeConfigPath = path.join(workspacePath, ".vscode");
75
76 console.log(`*** Copying ${customEntryPointFile} into ${workspaceFilePath}...`);
77 fs.writeFileSync(workspaceFilePath, fs.readFileSync(customEntryPointFile));
78
79 if (!fs.existsSync(vsCodeConfigPath)) {
80 console.log(`*** Creating ${vsCodeConfigPath}...`);
81 fs.mkdirSync(vsCodeConfigPath);
82 }
83
84 console.log(`*** Copying ${launchConfigFile} into ${vsCodeConfigPath}...`);
85 fs.writeFileSync(path.join(vsCodeConfigPath, "launch.json"), fs.readFileSync(launchConfigFile));
86
87 SetupEnvironmentHelper.patchMetroConfig(workspacePath);
88 }
89
90 public static addExpoDependencyToRNProject(workspacePath: string, version?: string) {
91 let npmCmd = "npm";
92 if (process.platform === "win32") {
93 npmCmd = "npm.cmd";
94 }
95
96 let expoPackage: string = version ? `expo@${version}` : "expo";
97 const command = `${npmCmd} install ${expoPackage} --save-dev`;
98
99 console.log(`*** Adding expo dependency to ${workspacePath} via '${command}' command...`);
100 cp.execSync(command, { cwd: workspacePath, stdio: "inherit" });
101 }
102
103 public static cleanUp(testVSCodeDirectory: string, userDataDir: string, testLogsDirectory: string, workspacePaths: string[], iOSExpoAppsCacheDirectory: string) {
104 console.log("\n*** Clean up...");
105 if (fs.existsSync(testVSCodeDirectory)) {
106 console.log(`*** Deleting test VS Code directory: ${testVSCodeDirectory}`);
107 rimraf.sync(testVSCodeDirectory);
108 }
109 if (fs.existsSync(userDataDir)) {
110 console.log(`*** Deleting VS Code temporary user data dir: ${userDataDir}`);
111 rimraf.sync(userDataDir);
112 }
113 if (fs.existsSync(testLogsDirectory)) {
114 console.log(`*** Deleting test logs directory: ${testLogsDirectory}`);
115 rimraf.sync(testLogsDirectory);
116 }
117 workspacePaths.forEach(testAppFolder => {
118 if (fs.existsSync(testAppFolder)) {
119 console.log(`*** Deleting test application: ${testAppFolder}`);
120 rimraf.sync(testAppFolder);
121 }
122 });
123 if (fs.existsSync(iOSExpoAppsCacheDirectory)) {
124 console.log(`*** Deleting iOS expo app cache directory: ${iOSExpoAppsCacheDirectory}`);
125 rimraf.sync(iOSExpoAppsCacheDirectory);
126 }
127 }
128
129 public static async getLatestSupportedRNVersionForExpo(): Promise<any> {
130 console.log("*** Getting latest React Native version supported by Expo...");
131 return new Promise((resolve, reject) => {
132 utilities.getContents("https://exp.host/--/api/v2/versions", null, null, function (error, versionsContent) {
133 if (error) {
134 reject(error);
135 }
136 try {
137 const content = JSON.parse(versionsContent);
138 if (content.sdkVersions) {
139 const maxSdkVersion = Object.keys(content.sdkVersions).sort((ver1, ver2) => {
140 if (semver.lt(ver1, ver2)) {
141 return 1;
142 } else if (semver.gt(ver1, ver2)) {
143 return -1;
144 }
145 return 0;
146 })[0];
147 if (content.sdkVersions[maxSdkVersion]) {
148 if (content.sdkVersions[maxSdkVersion].facebookReactNativeVersion) {
149 console.log(`*** Latest React Native version supported by Expo: ${content.sdkVersions[maxSdkVersion].facebookReactNativeVersion}`);
150 resolve(content.sdkVersions[maxSdkVersion].facebookReactNativeVersion as string);
151 }
152 }
153 }
154 reject("Received object is incorrect");
155 } catch (error) {
156 reject(error);
157 }
158 });
159 });
160 }
161
162 // Installs Expo app on Android device using XDL function
163 public static async installExpoAppOnAndroid() {
164 console.log(`*** Installing Expo app on Android emulator using Expo XDL function`);
165 await XDL.Android.installExpoAsync();
166 AndroidEmulatorHelper.enableDrawPermitForApp(this.expoPackageName);
167 }
168
169 // Installs Expo app on iOS device using XDL function
170 public static async installExpoAppOnIos() {
171 console.log(`*** Installing Expo app on iOS simulator using Expo XDL function`);
172 await XDL.Simulator._installExpoOnSimulatorAsync();
173 }
174
175 // Fix for https://github.com/expo/expo-cli/issues/951
176 // TODO: Delete when bug will be fixed
177 public static patchExpoSettingsFile(expoAppPath: string) {
178 const settingsJsonPath = path.join(expoAppPath, ".expo", "settings.json");
179 if (fs.existsSync(settingsJsonPath)) {
180 console.log(`*** Patching ${settingsJsonPath}...`);
181 let content = JSON.parse(fs.readFileSync(settingsJsonPath).toString());
182 if (content.https === false) {
183 console.log(`*** Deleting https: ${content.https} line...`);
184 delete content.https;
185 content = JSON.stringify(content, null, 2);
186 fs.writeFileSync(settingsJsonPath, content);
187 }
188 }
189 }
190
191 // TODO: refactor this function to make it capable to accept debug configuration as a parameter
192 public static addIosTargetToLaunchJson(workspacePath: string) {
193 let launchJsonPath = path.join(workspacePath, ".vscode", "launch.json");
194 console.log(`*** Implicitly adding target to "Debug iOS" config for ${launchJsonPath}`);
195 let content = JSON.parse(fs.readFileSync(launchJsonPath).toString());
196 let found = false;
197 for (let i = 0; i < content.configurations.length; i++) {
198 if (content.configurations[i].name === "Debug iOS") {
199 found = true;
200 content.configurations[i].target = IosSimulatorHelper.getDevice();
201 }
202 }
203 if (!found) {
204 throw new Error("Couldn't find \"Debug iOS\" configuration");
205 }
206 fs.writeFileSync(launchJsonPath, JSON.stringify(content, undefined, 4)); // Adds indentations
207 }
208
209 public static async runIosSimulator() {
210 const device = <string>IosSimulatorHelper.getDevice();
211 await this.terminateIosSimulator();
212 // Wipe data on simulator
213 await IosSimulatorHelper.eraseSimulator(device);
214 console.log(`*** Executing iOS simulator with 'xcrun simctl boot "${device}"' command...`);
215 await IosSimulatorHelper.bootSimulator(device);
216 await sleep(15 * 1000);
217 }
218
219 public static async terminateIosSimulator() {
220 const device = <string>IosSimulatorHelper.getDevice();
221 await IosSimulatorHelper.shutdownSimulator(device);
222 }
223
224 public static installExpoXdlPackageToExtensionDir(extensionDir: any, packageVersion: string) {
225 let npmCmd = "npm";
226 if (process.platform === "win32") {
227 npmCmd = "npm.cmd";
228 }
229 const command = `${npmCmd} install @expo/xdl@${packageVersion} --no-save`;
230
231 console.log(`*** Adding @expo/xdl dependency to ${extensionDir} via '${command}' command...`);
232 cp.execSync(command, { cwd: extensionDir, stdio: "inherit" });
233 }
234
235 public static async patchMetroConfig(appPath: string) {
236 const metroConfigPath = path.join(appPath, "metro.config.js");
237 console.log(`*** Patching ${metroConfigPath}`);
238 const patchContent = `
239// Sometimes on Windows Metro fails to resolve files located at .vscode\.react directory and throws EPERM errors
240// To avoid it this directory is added to black list for resolving by Metro
241if (process.platform === "win32") {
242 module.exports.resolver = {
243 blacklistRE: /.*\.vscode\\\.react.*/
244 };
245}
246
247// Redirect Metro cache
248module.exports.cacheStores = [
249 new (require('metro-cache')).FileStore({
250 root: require('path').join(".cache", 'metro-cache'),
251 }),
252];
253
254// Redirect Haste Map cache
255module.exports.hasteMapCacheDirectory = ".cache";`;
256 fs.appendFileSync(metroConfigPath, patchContent);
257 const contentAfterPatching = fs.readFileSync(metroConfigPath);
258 console.log(`*** Content of a metro.config.js after patching: ${contentAfterPatching}`);
259 }
260
261 private static copyGradleFilesToHermesApp(workspacePath: string, resourcesPath: string, customEntryPointFolder: string) {
262 const appGradleBuildFilePath = path.join(workspacePath, "android", "app", "build.gradle");
263 const resGradleBuildFilePath = path.join(resourcesPath, customEntryPointFolder, "build.gradle");
264
265 console.log(`*** Copying ${resGradleBuildFilePath} into ${appGradleBuildFilePath}...`);
266 fs.writeFileSync(appGradleBuildFilePath, fs.readFileSync(resGradleBuildFilePath));
267 }
268}
269