Skip to content

Commit 14497d5

Browse files
authored
tests: Radon diagnostics test coverage (#1762)
This pull request adds test coverage for diagnostic functionality in Radon IDE extension. ### How Has This Been Tested: The tests have been verified to pass on locally hosted GitHub CI runner: <img width="452" height="87" alt="Screenshot 2025-11-24 at 13 17 03" src="https://github.com/user-attachments/assets/acde8421-e044-4927-8209-286979b43e90" /> <img width="401" height="87" alt="Screenshot 2025-11-24 at 13 12 21" src="https://github.com/user-attachments/assets/e8c64331-0b89-49e6-8439-ec3410829c2a" /> to reproduce tests can be ran via Actions tab in GitHub. ### How Has This Change Been Documented: No documentation yet.
1 parent 11021b7 commit 14497d5

File tree

4 files changed

+339
-11
lines changed

4 files changed

+339
-11
lines changed

.github/workflows/ui-tests.yaml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,6 @@ jobs:
107107
- name: Show Xcode version
108108
run: xcodebuild -version
109109

110-
- name: Setup Node.js
111-
uses: actions/setup-node@v4
112-
with:
113-
node-version: ${{ matrix.node }}
114-
115110
- name: Enforce HTTPS for submodules
116111
run: git config --global url."https://github.com/".insteadOf "[email protected]:"
117112

@@ -177,6 +172,7 @@ jobs:
177172
CODE_VERSION: ${{ matrix.codeVersion }}
178173
IS_ANDROID: ${{ matrix.isAndroid }}
179174
RADON_IDE_LICENSE_KEY: ${{ secrets.RADON_IDE_LICENSE_KEY }}
175+
ALLOW_ENVIRONMENT_MODIFICATIONS: "true"
180176

181177
- name: Upload test output artifact
182178
if: always()

packages/vscode-extension-tester/configuration.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ const defaultConfig = {
1010
// android tests can be run on a local machine with android studio installed
1111
IS_ANDROID: false,
1212
IS_GITHUB_ACTIONS: false,
13+
// Allows tests to modify the environment (e.g. disabling node)
14+
// Enabling this may lead to unexpected behavior.
15+
ALLOW_ENVIRONMENT_MODIFICATIONS: false,
1316
};
1417

1518
function prioritizeEnv(field) {
@@ -22,10 +25,14 @@ export default function getConfiguration() {
2225
const IS_RECORDING = prioritizeEnv("IS_RECORDING");
2326
const IS_ANDROID = prioritizeEnv("IS_ANDROID");
2427
const IS_GITHUB_ACTIONS = prioritizeEnv("IS_GITHUB_ACTIONS");
28+
const ALLOW_ENVIRONMENT_MODIFICATIONS = prioritizeEnv(
29+
"ALLOW_ENVIRONMENT_MODIFICATIONS"
30+
);
2531

2632
return {
2733
IS_RECORDING,
2834
IS_ANDROID,
2935
IS_GITHUB_ACTIONS,
36+
ALLOW_ENVIRONMENT_MODIFICATIONS,
3037
};
3138
}
Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
import { execSync } from "child_process";
2+
import path from "path";
3+
import * as fs from "fs";
4+
import { WebView, EditorView } from "vscode-extension-tester";
5+
import { assert } from "chai";
6+
import getConfiguration from "../configuration.js";
7+
import initServices from "../services/index.js";
8+
import { describeIf, itIf } from "../utils/helpers.js";
9+
import { get } from "./setupTest.js";
10+
11+
const raw = fs.readFileSync("./data/react-native-app/package.json");
12+
const data = JSON.parse(raw);
13+
const IS_EXPO = data.name.includes("expo");
14+
15+
const { ALLOW_ENVIRONMENT_MODIFICATIONS } = getConfiguration();
16+
17+
describeIf(ALLOW_ENVIRONMENT_MODIFICATIONS, "17 - Diagnostics tests", () => {
18+
let driver;
19+
let {
20+
elementHelperService,
21+
radonViewsService,
22+
managingDevicesService,
23+
appManipulationService,
24+
} = initServices();
25+
26+
before(async () => {
27+
driver = get().driver;
28+
29+
({
30+
elementHelperService,
31+
radonViewsService,
32+
managingDevicesService,
33+
appManipulationService,
34+
} = initServices(driver));
35+
36+
await managingDevicesService.prepareDevices();
37+
await appManipulationService.waitForAppToLoad();
38+
39+
let view = new WebView();
40+
await view.switchBack();
41+
42+
await managingDevicesService.deleteAllDevices();
43+
await view.switchBack();
44+
await new EditorView().closeAllEditors();
45+
});
46+
47+
beforeEach(async function () {
48+
({ driver } = get());
49+
await radonViewsService.openRadonIDEPanel();
50+
await elementHelperService.findAndWaitForElementByTag(
51+
"radon-top-bar-settings-dropdown-trigger"
52+
);
53+
await radonViewsService.openRadonSettingsMenu();
54+
await elementHelperService.findAndClickElementByTag(
55+
"settings-dropdown-run-diagnostics-button"
56+
);
57+
58+
await elementHelperService.findAndWaitForElementByTag("diagnostics-view");
59+
});
60+
61+
async function testDiagnostic(
62+
name,
63+
damageFunction,
64+
fixFunction,
65+
errorMessage
66+
) {
67+
await elementHelperService.findAndWaitForElementByTag(
68+
`diagnostic-icon-${name}-installed`
69+
);
70+
await damageFunction();
71+
try {
72+
await elementHelperService.findAndClickElementByTag(
73+
"rerun-diagnostics-button"
74+
);
75+
console.log(`Testing ${name} diagnostic`);
76+
await elementHelperService.findAndWaitForElementByTag(
77+
`diagnostic-icon-${name}-notInstalled`
78+
);
79+
if (errorMessage) {
80+
const errorElement =
81+
await elementHelperService.findAndClickElementByTag(
82+
`diagnostic-error-${name}`
83+
);
84+
assert.equal(
85+
await errorElement.getText(),
86+
errorMessage,
87+
`Error message for ${name} is not correct`
88+
);
89+
}
90+
} finally {
91+
await fixFunction();
92+
await elementHelperService.findAndClickElementByTag(
93+
"rerun-diagnostics-button"
94+
);
95+
await elementHelperService.findAndWaitForElementByTag(
96+
`diagnostic-icon-${name}-installed`
97+
);
98+
}
99+
}
100+
101+
function getPackageVersion(packageName) {
102+
const packageJson = JSON.parse(
103+
fs.readFileSync("./data/react-native-app/package.json", "utf8")
104+
);
105+
if (!packageJson.dependencies || !packageJson.dependencies[packageName]) {
106+
throw new Error(`${packageName} not found in dependencies`);
107+
}
108+
return packageJson.dependencies[packageName];
109+
}
110+
111+
it("should show correct diagnostic for node", async function () {
112+
await testDiagnostic(
113+
"nodejs",
114+
async () => {
115+
execSync("brew unlink node");
116+
},
117+
async () => {
118+
execSync("brew link node");
119+
},
120+
`Node.js was not found, or the version in the PATH does not satisfy minimum version requirements. You can find more information in our documentation.`
121+
);
122+
});
123+
124+
it("should show correct diagnostic for npm", async function () {
125+
await testDiagnostic(
126+
"packageManager",
127+
async () => {
128+
execSync("rm /opt/homebrew/bin/npm");
129+
},
130+
async () => {
131+
execSync("brew unlink node && brew link node");
132+
},
133+
`Package manager not found or uninstalled. Make sure to install the package manager used in the project.`
134+
);
135+
});
136+
137+
it("should show correct diagnostic for node_modules", async function () {
138+
await testDiagnostic(
139+
"nodeModules",
140+
async () => {
141+
execSync(
142+
"mv ./data/react-native-app/node_modules ./data/react-native-app/not_node_modules"
143+
);
144+
},
145+
async () => {
146+
execSync(
147+
"mv ./data/react-native-app/not_node_modules ./data/react-native-app/node_modules"
148+
);
149+
},
150+
`Node modules are not installed.`
151+
);
152+
});
153+
154+
itIf(!IS_EXPO, "should show correct diagnostic for pods", async function () {
155+
await testDiagnostic(
156+
"pods",
157+
async () => {
158+
execSync(
159+
"mv ./data/react-native-app/ios/Pods ./data/react-native-app/ios/not_Pods"
160+
);
161+
},
162+
async () => {
163+
execSync(
164+
"mv ./data/react-native-app/ios/not_Pods ./data/react-native-app/ios/Pods"
165+
);
166+
},
167+
`Pods are not installed.`
168+
);
169+
});
170+
171+
itIf(!IS_EXPO, "should show correct diagnostic for ios", async function () {
172+
await testDiagnostic(
173+
"ios",
174+
async () => {
175+
execSync(
176+
"mv ./data/react-native-app/ios ./data/react-native-app/not_ios"
177+
);
178+
},
179+
async () => {
180+
execSync(
181+
"mv ./data/react-native-app/not_ios ./data/react-native-app/ios"
182+
);
183+
},
184+
`"ios" directory does not exist in the main application directory`
185+
);
186+
});
187+
188+
itIf(
189+
!IS_EXPO,
190+
"should show correct diagnostic for android",
191+
async function () {
192+
await testDiagnostic(
193+
"android",
194+
async () => {
195+
execSync(
196+
"mv ./data/react-native-app/android ./data/react-native-app/not_android"
197+
);
198+
},
199+
async () => {
200+
execSync(
201+
"mv ./data/react-native-app/not_android ./data/react-native-app/android"
202+
);
203+
},
204+
`"android" directory does not exist in the main application directory`
205+
);
206+
}
207+
);
208+
209+
itIf(
210+
!IS_EXPO,
211+
"should show correct diagnostic for cocoapods",
212+
async function () {
213+
await testDiagnostic(
214+
"cocoaPods",
215+
async () => {
216+
execSync("brew unlink cocoapods");
217+
execSync(
218+
"mv ./data/react-native-app/Gemfile ./data/react-native-app/not_Gemfile"
219+
);
220+
},
221+
async () => {
222+
execSync("brew link cocoapods");
223+
execSync(
224+
"mv ./data/react-native-app/not_Gemfile ./data/react-native-app/Gemfile"
225+
);
226+
},
227+
`CocoaPods was not found. Make sure to install CocoaPods.`
228+
);
229+
}
230+
);
231+
232+
itIf(
233+
!IS_EXPO,
234+
"should show correct diagnostic for react-native",
235+
async function () {
236+
const reactNativeVersion = getPackageVersion("react-native");
237+
const targetDir = path.join(process.cwd(), "data", "react-native-app");
238+
await testDiagnostic(
239+
"reactNative",
240+
async () => {
241+
execSync("npm uninstall react-native", { cwd: targetDir });
242+
execSync("npm uninstall @react-native/new-app-screen", {
243+
cwd: targetDir,
244+
});
245+
},
246+
async () => {
247+
execSync(`npm install react-native@${reactNativeVersion}`, {
248+
cwd: targetDir,
249+
});
250+
execSync("npm install @react-native/new-app-screen", {
251+
cwd: targetDir,
252+
});
253+
},
254+
`React Native is not installed or it is older than supported version 0.71.0.`
255+
);
256+
}
257+
);
258+
259+
itIf(IS_EXPO, "should show correct diagnostic for expo", async function () {
260+
const targetDir = path.join(process.cwd(), "data", "react-native-app");
261+
const packageJsonPath = path.join(targetDir, "package.json");
262+
const originalPackageJson = fs.readFileSync(packageJsonPath, "utf8");
263+
264+
await testDiagnostic(
265+
"expo",
266+
async () => {
267+
const packageData = JSON.parse(originalPackageJson);
268+
269+
const filterDeps = (deps) => {
270+
if (!deps) return {};
271+
const newDeps = {};
272+
Object.keys(deps).forEach((key) => {
273+
if (!key.startsWith("expo") && !key.startsWith("@expo")) {
274+
newDeps[key] = deps[key];
275+
}
276+
});
277+
return newDeps;
278+
};
279+
280+
if (packageData.dependencies) {
281+
packageData.dependencies = filterDeps(packageData.dependencies);
282+
}
283+
if (packageData.devDependencies) {
284+
packageData.devDependencies = filterDeps(packageData.devDependencies);
285+
}
286+
287+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageData, null, 2));
288+
execSync("npm install", { cwd: targetDir, stdio: "inherit" });
289+
},
290+
async () => {
291+
if (originalPackageJson) {
292+
fs.writeFileSync(packageJsonPath, originalPackageJson);
293+
execSync("npm install", { cwd: targetDir, stdio: "inherit" });
294+
}
295+
}
296+
);
297+
});
298+
299+
itIf(
300+
IS_EXPO,
301+
"should show correct diagnostic for expo-router",
302+
async function () {
303+
const targetDir = path.join(process.cwd(), "data", "react-native-app");
304+
const packageJsonPath = path.join(targetDir, "package.json");
305+
const originalPackageJson = fs.readFileSync(packageJsonPath, "utf8");
306+
await testDiagnostic(
307+
"expoRouter",
308+
async () => {
309+
execSync("npm uninstall expo-router", { cwd: targetDir });
310+
},
311+
async () => {
312+
if (originalPackageJson) {
313+
fs.writeFileSync(packageJsonPath, originalPackageJson);
314+
execSync("npm install", { cwd: targetDir, stdio: "inherit" });
315+
}
316+
}
317+
);
318+
}
319+
);
320+
});

0 commit comments

Comments
 (0)