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