microsoft/vscode-react-native
Publicmirrored from https://github.com/microsoft/vscode-react-nativeAvailable
test/smoke/package/src/main.ts
275lines · 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 | |
| 4 | import * as fs from "fs"; |
| 5 | import * as path from "path"; |
| 6 | import * as cp from "child_process"; |
| 7 | import { Application, Quality, ApplicationOptions, MultiLogger, Logger, ConsoleLogger } from "../../automation"; |
| 8 | import { AppiumHelper } from "./helpers/appiumHelper"; |
| 9 | import { SmokeTestsConstants } from "./helpers/smokeTestsConstants"; |
| 10 | import { setup as setupReactNativeDebugAndroidTests } from "./debugAndroid.test"; |
| 11 | import { setup as setupReactNativeDebugiOSTests } from "./debugIos.test"; |
| 12 | import { AndroidEmulatorHelper } from "./helpers/androidEmulatorHelper"; |
| 13 | import { VSCodeHelper } from "./helpers/vsCodeHelper"; |
| 14 | import { SetupEnvironmentHelper } from "./helpers/setupEnvironmentHelper"; |
| 15 | import { TestConfigurator } from "./helpers/configHelper"; |
| 16 | import { findFile } from "./helpers/utilities"; |
| 17 | |
| 18 | // TODO Incapsulate main.ts (get rid of function(), local variables, etc) |
| 19 | console.log(`*** Setting up configuration variables`); |
| 20 | const envConfigFilePath = path.resolve(__dirname, "..", SmokeTestsConstants.EnvConfigFileName); |
| 21 | // Assume that config.dev.json are stored in the same folder as original config.json |
| 22 | const envConfigFilePathDev = path.resolve(__dirname, "..", SmokeTestsConstants.EnvDevConfigFileName); |
| 23 | |
| 24 | TestConfigurator.setUpEnvVariables(fs.existsSync(envConfigFilePathDev) ? envConfigFilePathDev : envConfigFilePath); |
| 25 | TestConfigurator.printEnvVariableConfiguration(); |
| 26 | |
| 27 | async function fail(errorMessage) { |
| 28 | console.error(errorMessage); |
| 29 | AndroidEmulatorHelper.terminateAndroidEmulator(); |
| 30 | if (process.platform === "darwin") { |
| 31 | try { |
| 32 | await SetupEnvironmentHelper.terminateIosSimulator(); |
| 33 | } catch (e) { |
| 34 | console.error(e); |
| 35 | } |
| 36 | } |
| 37 | AppiumHelper.terminateAppium(); |
| 38 | process.exit(1); |
| 39 | } |
| 40 | |
| 41 | if (parseInt(process.version.substr(1), 10) < 10) { |
| 42 | fail("Please update your Node version to greater than 10 to run the smoke test."); |
| 43 | } |
| 44 | |
| 45 | function getBuildElectronPath(root: string, isInsiders: boolean): string { |
| 46 | switch (process.platform) { |
| 47 | case "darwin": |
| 48 | return isInsiders |
| 49 | ? |
| 50 | path.join(root, "Visual Studio Code - Insiders.app") |
| 51 | : |
| 52 | path.join(root, "Visual Studio Code.app"); |
| 53 | case "linux": { |
| 54 | return path.join(root, "VSCode-linux-x64"); |
| 55 | } |
| 56 | case "win32": { |
| 57 | return root; |
| 58 | } |
| 59 | default: |
| 60 | throw new Error(`Platform ${process.platform} isn't supported`); |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | function getVSCodeExecutablePath(testVSCodeFolder: string, isInsiders: boolean) { |
| 65 | switch (process.platform) { |
| 66 | case "darwin": |
| 67 | return isInsiders |
| 68 | ? |
| 69 | path.join(testVSCodeFolder, "Visual Studio Code - Insiders.app", "Contents", "Resources", "app", "bin", "code") |
| 70 | : |
| 71 | path.join(testVSCodeFolder, "Visual Studio Code.app", "Contents", "Resources", "app", "bin", "code"); |
| 72 | case "win32": |
| 73 | return isInsiders |
| 74 | ? |
| 75 | path.join(testVSCodeFolder, "bin", "code-insiders.cmd") |
| 76 | : |
| 77 | path.join(testVSCodeFolder, "bin", "code.cmd"); |
| 78 | case "linux": |
| 79 | return isInsiders |
| 80 | ? |
| 81 | path.join(testVSCodeFolder, "VSCode-linux-x64", "bin", "code-insiders") |
| 82 | : |
| 83 | path.join(testVSCodeFolder, "VSCode-linux-x64", "bin", "code"); |
| 84 | default: |
| 85 | throw new Error(`Platform ${process.platform} isn't supported`); |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | // resolving path from VS Code smoke tests directory to repository root |
| 90 | const repoRoot = path.join(__dirname, "..", "..", "..", "..", "..", ".."); |
| 91 | const resourcesPath = path.join(__dirname, "..", "resources"); |
| 92 | const isInsiders = process.env.CODE_VERSION === "insiders"; |
| 93 | let testVSCodeDirectory; |
| 94 | if (!isInsiders) { |
| 95 | testVSCodeDirectory = path.join(resourcesPath, ".vscode-test", "stable"); |
| 96 | } else { |
| 97 | testVSCodeDirectory = path.join(resourcesPath, ".vscode-test", "insiders"); |
| 98 | } |
| 99 | |
| 100 | let electronExecutablePath: string; |
| 101 | |
| 102 | let quality: Quality; |
| 103 | if (isInsiders) { |
| 104 | quality = Quality.Insiders; |
| 105 | } else { |
| 106 | quality = Quality.Stable; |
| 107 | } |
| 108 | |
| 109 | export let winTaskKillCommands: string[] = []; |
| 110 | if (process.platform === "win32") { |
| 111 | const userName = cp.execSync("whoami").toString().trim(); |
| 112 | winTaskKillCommands = VSCodeHelper.getTaskKillCommands(testVSCodeDirectory, isInsiders, userName); |
| 113 | } |
| 114 | |
| 115 | export const RNworkspacePath = path.join(resourcesPath, SmokeTestsConstants.RNAppName); |
| 116 | const RNworkspaceFilePath = path.join(RNworkspacePath, SmokeTestsConstants.AppjsFileName); |
| 117 | export const ExpoWorkspacePath = path.join(resourcesPath, SmokeTestsConstants.ExpoAppName); |
| 118 | const ExpoWorkspaceFilePath = path.join(ExpoWorkspacePath, SmokeTestsConstants.AppjsFileName); |
| 119 | export const pureRNWorkspacePath = path.join(resourcesPath, SmokeTestsConstants.pureRNExpoApp); |
| 120 | const pureRNWorkspaceFilePath = path.join(pureRNWorkspacePath, SmokeTestsConstants.AppjsFileName); |
| 121 | |
| 122 | export const artifactsPath = path.join(repoRoot, SmokeTestsConstants.artifactsDir); |
| 123 | const userDataDir = path.join(repoRoot, SmokeTestsConstants.VSCodeUserDataDir); |
| 124 | |
| 125 | const extensionsPath = path.join(testVSCodeDirectory, "extensions"); |
| 126 | |
| 127 | function createOptions(quality: Quality, workspaceOrFolder: string, dataDirFolderName: string): ApplicationOptions | null { |
| 128 | if (!electronExecutablePath) { |
| 129 | return null; |
| 130 | } |
| 131 | |
| 132 | const logsDir = process.env.REACT_NATIVE_TOOLS_LOGS_DIR || artifactsPath; |
| 133 | const loggers: Logger[] = []; |
| 134 | |
| 135 | loggers.push(new ConsoleLogger()); |
| 136 | const codePath = getBuildElectronPath(testVSCodeDirectory, isInsiders); |
| 137 | console.log(`*** Executing ${codePath}`); |
| 138 | |
| 139 | return { |
| 140 | quality, |
| 141 | codePath: codePath, |
| 142 | workspacePath: workspaceOrFolder, |
| 143 | userDataDir: path.join(userDataDir, dataDirFolderName), |
| 144 | extensionsPath, |
| 145 | waitTime: SmokeTestsConstants.elementResponseTimeout, |
| 146 | logger: new MultiLogger(loggers), |
| 147 | verbose: true, |
| 148 | screenshotsPath: path.join(logsDir, "screenshots"), |
| 149 | }; |
| 150 | } |
| 151 | |
| 152 | export function prepareReactNativeProjectForHermesTesting() { |
| 153 | SetupEnvironmentHelper.prepareHermesReactNativeApplication(RNworkspaceFilePath, resourcesPath, RNworkspacePath, SmokeTestsConstants.RNAppName, "HermesReactNativeSample", process.env.RN_VERSION); |
| 154 | } |
| 155 | |
| 156 | const testParams = TestConfigurator.parseTestArguments(); |
| 157 | async function setup(): Promise<void> { |
| 158 | console.log("*** Test VS Code directory:", testVSCodeDirectory); |
| 159 | console.log("*** Preparing smoke tests setup..."); |
| 160 | |
| 161 | AppiumHelper.runAppium(); |
| 162 | |
| 163 | if (process.platform === "darwin") { |
| 164 | await SetupEnvironmentHelper.runIosSimulator(); |
| 165 | } |
| 166 | |
| 167 | await AndroidEmulatorHelper.runAndroidEmulator(); |
| 168 | |
| 169 | SetupEnvironmentHelper.prepareReactNativeApplication(RNworkspaceFilePath, resourcesPath, RNworkspacePath, SmokeTestsConstants.RNAppName, "ReactNativeSample", process.env.RN_VERSION); |
| 170 | if (!testParams.RunBasicTests) { |
| 171 | SetupEnvironmentHelper.prepareExpoApplication(ExpoWorkspaceFilePath, resourcesPath, ExpoWorkspacePath, SmokeTestsConstants.ExpoAppName); |
| 172 | const PureRNVersionExpo = process.env.PURE_RN_VERSION || await SetupEnvironmentHelper.getLatestSupportedRNVersionForExpo(); |
| 173 | SetupEnvironmentHelper.prepareReactNativeApplication(pureRNWorkspaceFilePath, resourcesPath, pureRNWorkspacePath, SmokeTestsConstants.pureRNExpoApp, "PureRNExpoSample", PureRNVersionExpo); |
| 174 | SetupEnvironmentHelper.addExpoDependencyToRNProject(pureRNWorkspacePath, process.env.PURE_EXPO_VERSION); |
| 175 | await SetupEnvironmentHelper.installExpoAppOnAndroid(); |
| 176 | SetupEnvironmentHelper.patchExpoSettingsFile(ExpoWorkspacePath); |
| 177 | if (process.platform === "darwin") { |
| 178 | await SetupEnvironmentHelper.installExpoAppOnIos(); |
| 179 | } |
| 180 | } |
| 181 | await VSCodeHelper.downloadVSCodeExecutable(resourcesPath); |
| 182 | |
| 183 | electronExecutablePath = getBuildElectronPath(testVSCodeDirectory, isInsiders); |
| 184 | if (!fs.existsSync(testVSCodeDirectory || "")) { |
| 185 | await fail(`Can't find VS Code executable at ${testVSCodeDirectory}.`); |
| 186 | } |
| 187 | const testVSCodeExecutablePath = getVSCodeExecutablePath(testVSCodeDirectory, isInsiders); |
| 188 | VSCodeHelper.installExtensionFromVSIX(extensionsPath, testVSCodeExecutablePath, resourcesPath, !testParams.DontDeleteVSIX); |
| 189 | |
| 190 | if (process.env.EXPO_XDL_VERSION) { |
| 191 | // msjsdiag.vscode-react-native-0.9.3 |
| 192 | const extensionDirName = findFile(extensionsPath, /msjsdiag\.vscode-react-native.*/); |
| 193 | if (!extensionDirName) { |
| 194 | throw new Error("Couldn't find extension directory"); |
| 195 | } |
| 196 | const extensionFullPath = path.join(extensionsPath, extensionDirName); |
| 197 | SetupEnvironmentHelper.installExpoXdlPackageToExtensionDir(extensionFullPath, process.env.EXPO_XDL_VERSION); |
| 198 | } else { |
| 199 | console.log(`*** EXPO_XDL_VERSION variable is not set, skipping installation of @expo/xdl package to the extension directory`); |
| 200 | } |
| 201 | |
| 202 | if (!fs.existsSync(userDataDir)) { |
| 203 | console.log(`*** Creating VS Code user data directory: ${userDataDir}`); |
| 204 | fs.mkdirSync(userDataDir); |
| 205 | } |
| 206 | console.log("*** Smoke tests setup done!\n"); |
| 207 | } |
| 208 | |
| 209 | let runName = 0; |
| 210 | export async function runVSCode(workspaceOrFolder: string): Promise<Application> { |
| 211 | runName++; |
| 212 | const extensionLogsDir = path.join(artifactsPath, runName.toString(), "extensionLogs"); |
| 213 | process.env.REACT_NATIVE_TOOLS_LOGS_DIR = extensionLogsDir; |
| 214 | const options = createOptions(quality, workspaceOrFolder, runName.toString()); |
| 215 | const app = new Application(options!); |
| 216 | console.log(`Options for run #${runName}: ${JSON.stringify(options, null, 2)}`); |
| 217 | await app!.start(); |
| 218 | return app!; |
| 219 | } |
| 220 | |
| 221 | before(async function () { |
| 222 | if (testParams.SkipSetup) { |
| 223 | console.log("*** --skip-setup parameter is set, skipping clean up and apps installation"); |
| 224 | // Assume that VS Code is already installed |
| 225 | electronExecutablePath = getBuildElectronPath(testVSCodeDirectory, isInsiders); |
| 226 | return; |
| 227 | } |
| 228 | this.timeout(SmokeTestsConstants.smokeTestSetupAwaitTimeout); |
| 229 | SetupEnvironmentHelper.cleanUp(path.join(testVSCodeDirectory, ".."), userDataDir, artifactsPath, [RNworkspacePath, ExpoWorkspacePath, pureRNWorkspacePath], SetupEnvironmentHelper.iOSExpoAppsCacheDir); |
| 230 | try { |
| 231 | await setup(); |
| 232 | } catch (err) { |
| 233 | await fail(err); |
| 234 | } |
| 235 | }); |
| 236 | |
| 237 | describe("Extension smoke tests", () => { |
| 238 | after(async function () { |
| 239 | AndroidEmulatorHelper.terminateAndroidEmulator(); |
| 240 | if (process.platform === "darwin") { |
| 241 | try { |
| 242 | await SetupEnvironmentHelper.terminateIosSimulator(); |
| 243 | } catch (e) { |
| 244 | console.error(e); |
| 245 | } |
| 246 | } |
| 247 | AppiumHelper.terminateAppium(); |
| 248 | }); |
| 249 | if (process.platform === "darwin") { |
| 250 | const noSelectArgs = !testParams.RunAndroidTests && !testParams.RunIosTests && !testParams.RunBasicTests; |
| 251 | if (noSelectArgs) { |
| 252 | console.log("*** Android and iOS tests will be run"); |
| 253 | setupReactNativeDebugAndroidTests(); |
| 254 | setupReactNativeDebugiOSTests(); |
| 255 | } else if (testParams.RunBasicTests) { |
| 256 | console.log("*** --basic-only parameter is set, basic Android and iOS tests will be run"); |
| 257 | setupReactNativeDebugAndroidTests(testParams); |
| 258 | setupReactNativeDebugiOSTests(testParams); |
| 259 | } else if (testParams.RunAndroidTests) { |
| 260 | console.log("*** --android parameter is set, Android tests will be run"); |
| 261 | setupReactNativeDebugAndroidTests(); |
| 262 | } else if (testParams.RunIosTests) { |
| 263 | console.log("*** --ios parameter is set, iOS tests will be run"); |
| 264 | setupReactNativeDebugiOSTests(); |
| 265 | } |
| 266 | } else { |
| 267 | if (testParams.RunBasicTests) { |
| 268 | console.log("*** --basic-only parameter is set, basic Android tests will be run"); |
| 269 | setupReactNativeDebugAndroidTests(testParams); |
| 270 | } else { |
| 271 | setupReactNativeDebugAndroidTests(); |
| 272 | } |
| 273 | |
| 274 | } |
| 275 | }); |
| 276 | |