microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
5759f79cea6d220d75c4589a028aec52100953d6

Branches

Tags

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

Clone

HTTPS

Download ZIP

test/smoke/package/src/debugAndroid.test.ts

272lines · 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 assert from "assert";
5import * as path from "path";
6import { AppiumHelper, Platform, AppiumClient } from "./helpers/appiumHelper";
7import { AndroidEmulatorHelper } from "./helpers/androidEmulatorHelper";
8import { sleep, waitUntilLaunchScenarioTargetUpdate, ExpoLaunch, findExpoSuccessAndFailurePatterns, findExpoURLInLogFile, findStringInFile } from "./helpers/utilities";
9import { SmokeTestsConstants } from "./helpers/smokeTestsConstants";
10import { pureRNWorkspacePath, RNworkspacePath, runVSCode, prepareReactNativeProjectForHermesTesting, ExpoWorkspacePath } from "./main";
11import { SetupEnvironmentHelper } from "./helpers/setupEnvironmentHelper";
12import { TestRunArguments } from "./helpers/configHelper";
13import { Application } from "../../automation";
14
15const RN_APP_PACKAGE_NAME = "com.latestrnapp";
16const RN_APP_ACTIVITY_NAME = "com.latestrnapp.MainActivity";
17const EXPO_APP_PACKAGE_NAME = SetupEnvironmentHelper.expoPackageName;
18const EXPO_APP_ACTIVITY_NAME = `${EXPO_APP_PACKAGE_NAME}.experience.HomeActivity`;
19const RNDebugConfigName = "Debug Android";
20const RNHermesDebugConfigName = "Debug Android (Hermes) - Experimental";
21const RNHermesAttachConfigName = "Attach to Hermes application - Experimental";
22const ExpoDebugConfigName = "Debug in Exponent";
23const ExpoLanDebugConfigName = "Debug in Exponent (LAN)";
24const ExpoLocalDebugConfigName = "Debug in Exponent (Local)";
25
26const RNSetBreakpointOnLine = 1;
27const RNHermesSetBreakpointOnLine = 11;
28const ExpoSetBreakpointOnLine = 1;
29// Time for Android Debug Test before it reaches timeout
30const debugAndroidTestTime = SmokeTestsConstants.androidAppBuildAndInstallTimeout + 100 * 1000;
31// Time for Android Expo Debug Test before it reaches timeout
32const debugExpoTestTime = SmokeTestsConstants.expoAppBuildAndInstallTimeout + 400 * 1000;
33
34export function setup(testParameters?: TestRunArguments): void {
35
36 describe("Debugging Android", () => {
37 let app: Application;
38 let client: AppiumClient;
39 console.log(testParameters);
40
41 async function disposeAll() {
42 if (app) {
43 await app.stop();
44 }
45 if (client) {
46 client.closeApp();
47 client.deleteSession();
48 }
49 }
50
51 afterEach(disposeAll);
52
53 async function runExpoDebugScenario(logFilePath: string, testName: string, workspacePath: string, debugConfigName: string, triesToLaunchApp: number) {
54 console.log(`${testName}: Starting debugging`);
55 // Scan logs only if launch retries provided (Expo Tunnel scenarios)
56 if (triesToLaunchApp <= 1) {
57 await app.workbench.quickaccess.runDebugScenario(debugConfigName);
58 } else {
59 for (let retry = 1; retry <= triesToLaunchApp; retry++) {
60 let expoLaunchStatus: ExpoLaunch;
61 await app.workbench.quickaccess.runDebugScenario(debugConfigName);
62 expoLaunchStatus = await findExpoSuccessAndFailurePatterns(logFilePath, SmokeTestsConstants.ExpoSuccessPattern, SmokeTestsConstants.ExpoFailurePattern);
63 if (expoLaunchStatus.successful) {
64 break;
65 } else {
66 if (retry === triesToLaunchApp) {
67 assert.fail(`App start has failed after ${retry} retries`);
68 }
69 console.log(`Attempt to start #${retry} failed, retrying...`);
70 }
71 }
72 }
73 }
74
75 async function expoTest(appFileName: string, testName: string, workspacePath: string, debugConfigName: string, triesToLaunchApp: number) {
76 let logFilePath = "";
77 app = await runVSCode(workspacePath);
78 console.log(`${testName}: ${workspacePath} directory is opened in VS Code`);
79 await app.workbench.quickaccess.openFile(appFileName);
80 await app.workbench.editors.scrollTop();
81 console.log(`${testName}: ${appFileName} file is opened`);
82 await app.workbench.debug.setBreakpointOnLine(ExpoSetBreakpointOnLine);
83 console.log(`${testName}: Breakpoint is set on line ${ExpoSetBreakpointOnLine}`);
84 console.log(`${testName}: Chosen debug configuration: ${debugConfigName}`);
85 if (process.env.REACT_NATIVE_TOOLS_LOGS_DIR) {
86 logFilePath = path.join(process.env.REACT_NATIVE_TOOLS_LOGS_DIR, SmokeTestsConstants.ReactNativeLogFileName);
87 } else {
88 assert.fail("REACT_NATIVE_TOOLS_LOGS_DIR is not defined");
89 }
90 await runExpoDebugScenario(logFilePath, testName, workspacePath, debugConfigName, triesToLaunchApp);
91
92 await app.workbench.editors.waitForTab("Expo QR Code readonly");
93 await app.workbench.editors.waitForActiveTab("Expo QR Code readonly");
94 console.log(`${testName}: 'Expo QR Code' tab found`);
95
96 let expoURL;
97 if (process.env.REACT_NATIVE_TOOLS_LOGS_DIR) {
98 expoURL = findExpoURLInLogFile(path.join(process.env.REACT_NATIVE_TOOLS_LOGS_DIR, SmokeTestsConstants.ReactNativeRunExpoLogFileName));
99 }
100 assert.notStrictEqual(expoURL, null, "Expo URL pattern is not found");
101 expoURL = expoURL as string;
102 const opts = AppiumHelper.prepareAttachOptsForAndroidActivity(EXPO_APP_PACKAGE_NAME, EXPO_APP_ACTIVITY_NAME, AndroidEmulatorHelper.androidEmulatorName);
103 client = await AppiumHelper.webdriverAttach(opts);
104 // TODO Add listener to trigger that main expo app has been ran
105 await AppiumHelper.openExpoApplication(Platform.Android, client, expoURL, workspacePath);
106 // TODO Add listener to trigger that child expo app has been ran instead of using timeout
107 console.log(`${testName}: Waiting ${SmokeTestsConstants.expoAppBuildAndInstallTimeout}ms until Expo app is ready...`);
108 await sleep(SmokeTestsConstants.expoAppBuildAndInstallTimeout);
109 await AppiumHelper.disableDevMenuInformationalMsg(client, Platform.AndroidExpo);
110 await sleep(2 * 1000);
111 await AppiumHelper.enableRemoteDebugJS(client, Platform.AndroidExpo);
112 await app.workbench.debug.waitForDebuggingToStart();
113 console.log(`${testName}: Debugging started`);
114 await app.workbench.debug.waitForStackFrame(sf => sf.name === appFileName && sf.lineNumber === ExpoSetBreakpointOnLine, `looking for ${appFileName} and line ${ExpoSetBreakpointOnLine}`);
115 console.log(`${testName}: Stack frame found`);
116 await app.workbench.debug.stepOver();
117 // Wait for debug string to be rendered in debug console
118 await sleep(SmokeTestsConstants.debugConsoleSearchTimeout);
119 console.log(`${testName}: Searching for \"Test output from debuggee\" string in console`);
120 let found = await app.workbench.debug.waitForOutput(output => output.some(line => line.indexOf("Test output from debuggee") >= 0));
121 assert.notStrictEqual(found, false, "\"Test output from debuggee\" string is missing in debug console");
122 console.log(`${testName}: \"Test output from debuggee\" string is found`);
123 await app.workbench.debug.disconnectFromDebugger();
124 console.log(`${testName}: Debugging is stopped`);
125 }
126
127 it("RN app Debug test", async function () {
128 this.timeout(debugAndroidTestTime);
129 app = await runVSCode(RNworkspacePath);
130 await app.workbench.quickaccess.openFile("App.js");
131 await app.workbench.editors.scrollTop();
132 console.log("Android Debug test: App.js file is opened");
133 await app.workbench.debug.setBreakpointOnLine(RNSetBreakpointOnLine);
134 console.log(`Android Debug test: Breakpoint is set on line ${RNSetBreakpointOnLine}`);
135 console.log(`Android Debug test: Chosen debug configuration: ${RNDebugConfigName}`);
136 console.log("Android Debug test: Starting debugging");
137 await app.workbench.quickaccess.runDebugScenario(RNDebugConfigName);
138 const opts = AppiumHelper.prepareAttachOptsForAndroidActivity(RN_APP_PACKAGE_NAME, RN_APP_ACTIVITY_NAME, AndroidEmulatorHelper.androidEmulatorName);
139 await AndroidEmulatorHelper.checkIfAppIsInstalled(RN_APP_PACKAGE_NAME, SmokeTestsConstants.androidAppBuildAndInstallTimeout);
140 client = await AppiumHelper.webdriverAttach(opts);
141 await AppiumHelper.enableRemoteDebugJS(client, Platform.Android);
142 await app.workbench.debug.waitForDebuggingToStart();
143 console.log("Android Debug test: Debugging started");
144 await app.workbench.debug.waitForStackFrame(sf => sf.name === "App.js" && sf.lineNumber === RNSetBreakpointOnLine, `looking for App.js and line ${RNSetBreakpointOnLine}`);
145 console.log("Android Debug test: Stack frame found");
146 await app.workbench.debug.stepOver();
147 // await for our debug string renders in debug console
148 await sleep(SmokeTestsConstants.debugConsoleSearchTimeout);
149 console.log("Android Debug test: Searching for \"Test output from debuggee\" string in console");
150 let found = await app.workbench.debug.waitForOutput(output => output.some(line => line.indexOf("Test output from debuggee") >= 0));
151 console.log(found);
152 assert.notStrictEqual(found, false, "\"Test output from debuggee\" string is missing in debug console");
153 console.log("Android Debug test: \"Test output from debuggee\" string is found");
154 await app.workbench.debug.disconnectFromDebugger();
155 console.log("Android Debug test: Debugging is stopped");
156 });
157
158 it("Hermes RN app Debug test", async function () {
159 try {
160 this.timeout(debugAndroidTestTime);
161 prepareReactNativeProjectForHermesTesting();
162 AndroidEmulatorHelper.uninstallTestAppFromEmulator(RN_APP_PACKAGE_NAME);
163 app = await runVSCode(RNworkspacePath);
164 await app.workbench.quickaccess.openFile("AppTestButton.js");
165 await app.workbench.editors.scrollTop();
166 console.log("Android Debug Hermes test: AppTestButton.js file is opened");
167 await app.workbench.debug.setBreakpointOnLine(RNHermesSetBreakpointOnLine);
168 console.log(`Android Debug Hermes test: Breakpoint is set on line ${RNHermesSetBreakpointOnLine}`);
169 console.log(`Android Debug Hermes test: Chosen debug configuration: ${RNHermesDebugConfigName}`);
170 console.log("Android Debug Hermes test: Starting debugging");
171 await app.workbench.quickaccess.runDebugScenario(RNHermesDebugConfigName);
172 const opts = AppiumHelper.prepareAttachOptsForAndroidActivity(RN_APP_PACKAGE_NAME, RN_APP_ACTIVITY_NAME, AndroidEmulatorHelper.androidEmulatorName);
173 await AndroidEmulatorHelper.checkIfAppIsInstalled(RN_APP_PACKAGE_NAME, SmokeTestsConstants.androidAppBuildAndInstallTimeout);
174 client = await AppiumHelper.webdriverAttach(opts);
175 await app.workbench.debug.waitForDebuggingToStart();
176 console.log("Android Debug Hermes test: Debugging started");
177 console.log("Android Debug Hermes test: Checking for Hermes mark");
178 let isHermesWorking = await AppiumHelper.isHermesWorking(client);
179 assert.strictEqual(isHermesWorking, true);
180 console.log("Android Debug Hermes test: Reattaching to Hermes app");
181 await app.workbench.debug.disconnectFromDebugger();
182 await app.workbench.quickaccess.runDebugScenario(RNHermesAttachConfigName);
183 console.log("Android Debug Hermes test: Reattached successfully");
184 await sleep(7000);
185 console.log("Android Debug Hermes test: Click Test Button");
186 await AppiumHelper.clickTestButtonHermes(client);
187 await app.workbench.debug.waitForStackFrame(sf => sf.name === "AppTestButton.js" && sf.lineNumber === RNHermesSetBreakpointOnLine, `looking for AppTestButton.js and line ${RNHermesSetBreakpointOnLine}`);
188 console.log("Android Debug Hermes test: Stack frame found");
189 await app.workbench.debug.continue();
190 // await for our debug string renders in debug console
191 await sleep(SmokeTestsConstants.debugConsoleSearchTimeout);
192 if (process.env.REACT_NATIVE_TOOLS_LOGS_DIR) {
193 console.log("Android Debug Hermes test: Searching for \"Test output from Hermes debuggee\" string in output file");
194 let found = findStringInFile(path.join(process.env.REACT_NATIVE_TOOLS_LOGS_DIR, SmokeTestsConstants.ReactNativeLogFileName), "Test output from Hermes debuggee");
195 assert.notStrictEqual(found, false, "\"Test output from Hermes debuggee\" string is missing in output file");
196 console.log("Android Debug test: \"Test output from Hermes debuggee\" string is found");
197 }
198 await app.workbench.debug.disconnectFromDebugger();
199 console.log("Android Debug Hermes test: Debugging is stopped");
200 } catch (e) {
201 console.log("Android Debug Hermes test failed: " + e);
202 return this.skip();
203 }
204 });
205
206 it("Expo app Debug test(Tunnel)", async function () {
207 if (testParameters && testParameters.RunBasicTests) {
208 this.skip();
209 }
210 this.timeout(debugExpoTestTime);
211 await expoTest("App.tsx", "Android Expo Debug test(Tunnel)", ExpoWorkspacePath, ExpoDebugConfigName, 5);
212 });
213
214 it("Pure RN app Expo test(LAN)", async function () {
215 if (testParameters && testParameters.RunBasicTests) {
216 this.skip();
217 }
218 this.timeout(debugExpoTestTime);
219 await expoTest("App.js", "Android pure RN Expo test(LAN)", pureRNWorkspacePath, ExpoLanDebugConfigName, 1);
220 });
221
222 it("Expo app Debug test(LAN)", async function () {
223 if (testParameters && testParameters.RunBasicTests) {
224 this.skip();
225 }
226 this.timeout(debugExpoTestTime);
227 await expoTest("App.tsx", "Android Expo Debug test(LAN)", ExpoWorkspacePath, ExpoLanDebugConfigName, 1);
228 });
229
230 it("Expo app Debug test(localhost)", async function () {
231 if (testParameters && testParameters.RunBasicTests) {
232 this.skip();
233 }
234 this.timeout(debugExpoTestTime);
235 await expoTest("App.tsx", "Android Expo Debug test(localhost)", ExpoWorkspacePath, ExpoLocalDebugConfigName, 1);
236 });
237
238 it("Save Android emulator test", async function () {
239 // Theres is a problem with starting an emulator by the VS Code process on Windows testing machine.
240 // The issue will be investigated
241 if (process.platform === "win32") {
242 console.log(`Android emulator save test: Theres is a problem with starting an emulator by the VS Code process on Windows testing machine, so we skip this test.`);
243 return this.skip();
244 }
245 this.timeout(debugAndroidTestTime);
246 app = await runVSCode(pureRNWorkspacePath);
247 console.log("Android emulator save test: Terminating Android emulator");
248 AndroidEmulatorHelper.terminateAndroidEmulator();
249 await AndroidEmulatorHelper.waitUntilAndroidEmulatorTerminating();
250 console.log("Android emulator save test: Starting debugging in first time");
251 await app.workbench.quickaccess.runDebugScenario(RNDebugConfigName);
252 console.log("Android emulator save test: Debugging started in first time");
253 console.log("Android emulator save test: Wait until emulator starting");
254 await AndroidEmulatorHelper.waitUntilEmulatorStarting();
255 const isScenarioUpdated = await waitUntilLaunchScenarioTargetUpdate(pureRNWorkspacePath, Platform.Android);
256 console.log(`Android emulator save test: launch.json is ${isScenarioUpdated ? "" : "not "}contains '"target": "${AndroidEmulatorHelper.getDevice()}"'`);
257 assert.notStrictEqual(isScenarioUpdated, false, "The launch.json has not been updated");
258 console.log("Android emulator save test: Dispose all");
259 await disposeAll();
260 app = await runVSCode(pureRNWorkspacePath);
261 console.log("Android emulator save test: Terminating Android emulator");
262 AndroidEmulatorHelper.terminateAndroidEmulator();
263 await AndroidEmulatorHelper.waitUntilAndroidEmulatorTerminating();
264 console.log("Android emulator save test: Starting debugging in second time");
265 await app.workbench.quickaccess.runDebugScenario(RNDebugConfigName);
266 console.log("Android emulator save test: Debugging started in second time");
267 await AndroidEmulatorHelper.waitUntilEmulatorStarting();
268 const devices = AndroidEmulatorHelper.getOnlineDevices();
269 assert.strictEqual(devices.length, 1, "The emulator has not been started after update launch.json");
270 });
271 });
272}
273