Skip to content

Commit 9ddd665

Browse files
committed
Fix TypeScript errors and implement missing test helper functions
1 parent e34a6cc commit 9ddd665

File tree

3 files changed

+77
-11
lines changed

3 files changed

+77
-11
lines changed

e2e-tests/helpers/test_helper.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,73 @@ export class PageObject {
10201020
await new Promise((resolve) => setTimeout(resolve, ms));
10211021
}
10221022
}
1023+
// Helper functions for e2e tests
1024+
1025+
export async function createApp(page: Page, appName: string, options: { isFullStack: boolean; selectedBackendFramework: string }): Promise<number> {
1026+
await page.getByRole("link", { name: "Chat" }).click();
1027+
const prompt = `Create a ${options.isFullStack ? 'fullstack' : 'frontend'} app named ${appName}${options.isFullStack ? ` with ${options.selectedBackendFramework} backend` : ''}`;
1028+
await page.getByRole("textbox", { name: "Ask AliFullStack to build..." }).fill(prompt);
1029+
await page.getByRole("button", { name: "Send message" }).click();
1030+
await page.waitForSelector('[data-testid="retry-button"]', { timeout: Timeout.MEDIUM });
1031+
return 0;
1032+
}
1033+
1034+
export async function deleteApp(page: Page, appId: number): Promise<void> {
1035+
await page.getByRole("link", { name: "Apps" }).click();
1036+
const appItems = page.locator('[data-testid^="app-list-item-"]');
1037+
await appItems.nth(appId).click();
1038+
await page.getByTestId("app-details-more-options-button").click();
1039+
await page.getByRole("button", { name: "Delete" }).click();
1040+
await page.getByRole("button", { name: "Delete App" }).click();
1041+
}
1042+
1043+
export async function startApp(page: Page, appId: number, mode: string): Promise<void> {
1044+
await page.getByRole("link", { name: "Chat" }).click();
1045+
const prompt = `Start the app in ${mode} mode`;
1046+
await page.getByRole("textbox", { name: "Ask AliFullStack to build..." }).fill(prompt);
1047+
await page.getByRole("button", { name: "Send message" }).click();
1048+
await page.waitForSelector('[data-testid="retry-button"]', { timeout: Timeout.MEDIUM });
1049+
}
1050+
1051+
export async function stopApp(page: Page, appId: number): Promise<void> {
1052+
await page.getByRole("link", { name: "Chat" }).click();
1053+
const prompt = `Stop the app`;
1054+
await page.getByRole("textbox", { name: "Ask AliFullStack to build..." }).fill(prompt);
1055+
await page.getByRole("button", { name: "Send message" }).click();
1056+
await page.waitForSelector('[data-testid="retry-button"]', { timeout: Timeout.MEDIUM });
1057+
}
1058+
1059+
export async function getAppOutput(page: Page, appId: number): Promise<string> {
1060+
const messagesList = page.getByTestId("messages-list");
1061+
return (await messagesList.textContent()) || '';
1062+
}
1063+
1064+
export async function switchTerminal(page: Page, terminal: string): Promise<void> {
1065+
await page.getByRole("tab", { name: terminal }).click();
1066+
}
1067+
1068+
export async function getTerminalOutput(page: Page, appId: number, terminal: string): Promise<string> {
1069+
// Assume the terminal content is in a locator after switching
1070+
// This might need adjustment based on actual UI
1071+
const terminalLocator = page.locator('.terminal');
1072+
return (await terminalLocator.textContent()) || '';
1073+
}
1074+
1075+
export async function createBackendFile(page: Page, appId: number, filePath: string, content: string): Promise<void> {
1076+
await page.getByRole("link", { name: "Chat" }).click();
1077+
const prompt = `Create a backend file ${filePath} with the following content:\n${content}`;
1078+
await page.getByRole("textbox", { name: "Ask AliFullStack to build..." }).fill(prompt);
1079+
await page.getByRole("button", { name: "Send message" }).click();
1080+
await page.waitForSelector('[data-testid="retry-button"]', { timeout: Timeout.MEDIUM });
1081+
}
1082+
1083+
export async function createFrontendFile(page: Page, appId: number, filePath: string, content: string): Promise<void> {
1084+
await page.getByRole("link", { name: "Chat" }).click();
1085+
const prompt = `Create a frontend file ${filePath} with the following content:\n${content}`;
1086+
await page.getByRole("textbox", { name: "Ask AliFullStack to build..." }).fill(prompt);
1087+
await page.getByRole("button", { name: "Send message" }).click();
1088+
await page.waitForSelector('[data-testid="retry-button"]', { timeout: Timeout.MEDIUM });
1089+
}
10231090

10241091
interface ElectronConfig {
10251092
preLaunchHook?: ({ userDataDir }: { userDataDir: string }) => Promise<void>;

src/ipc/handlers/app_handlers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ export function getExtendedPath(): string {
9999
*
100100
* @returns The complete environment variables from the user's login shell.
101101
*/
102-
function getShellEnv(): NodeJS.ProcessEnv {
102+
export function getShellEnv(): NodeJS.ProcessEnv {
103103
if (cachedShellEnv) {
104104
return cachedShellEnv;
105105
}
@@ -403,7 +403,7 @@ python app.py
403403
* Execute a command, using a temporary script file for complex commands with shell operators.
404404
* This allows handling of multi-line commands, pipes, conditionals, and other shell features.
405405
*/
406-
async function executeComplexCommand(
406+
export async function executeComplexCommand(
407407
command: string,
408408
workingDir: string,
409409
env: NodeJS.ProcessEnv

src/ipc/utils/runShellCommand.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { spawn } from "child_process";
22
import log from "electron-log";
3-
import { executeComplexCommand } from "../handlers/app_handlers";
4-
import { getShellEnv } from "../handlers/app_handlers";
3+
import { executeComplexCommand, getShellEnv } from "../handlers/app_handlers";
54

65
const logger = log.scope("runShellCommand");
76

@@ -14,35 +13,35 @@ export function runShellCommand(command: string, workingDir?: string): Promise<s
1413
// Check if the command contains shell operators that require script execution
1514
const hasShellOperators = /(&&|\|\||source|\||;|\$\(|`.*`)/.test(command);
1615

17-
let process;
16+
let childProcess;
1817
if (hasShellOperators) {
1918
logger.debug(`Using executeComplexCommand for complex command: ${command}`);
20-
process = await executeComplexCommand(command, cwd, getShellEnv());
19+
childProcess = await executeComplexCommand(command, cwd, getShellEnv());
2120
} else {
2221
logger.debug(`Using spawn for simple command: ${command}`);
23-
process = spawn(command, {
22+
childProcess = spawn(command, {
2423
shell: true,
2524
stdio: ["ignore", "pipe", "pipe"], // ignore stdin, pipe stdout/stderr
2625
cwd,
2726
env: getShellEnv(),
2827
});
2928
}
3029

31-
process.stdout?.on("data", (data) => {
30+
childProcess.stdout?.on("data", (data) => {
3231
output += data.toString();
3332
});
3433

35-
process.stderr?.on("data", (data) => {
34+
childProcess.stderr?.on("data", (data) => {
3635
// Log stderr but don't treat it as a failure unless the exit code is non-zero
3736
logger.warn(`Stderr from "${command}": ${data.toString().trim()}`);
3837
});
3938

40-
process.on("error", (error) => {
39+
childProcess.on("error", (error) => {
4140
logger.error(`Error executing command "${command}":`, error.message);
4241
resolve(null); // Command execution failed
4342
});
4443

45-
process.on("close", (code) => {
44+
childProcess.on("close", (code) => {
4645
if (code === 0) {
4746
logger.debug(
4847
`Command "${command}" succeeded with code ${code}: ${output.trim()}`,

0 commit comments

Comments
 (0)