/**
* E2E Test: Build-Test-Debug Cycle
* Tests tool registration and basic workflow
*/
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { getToolRegistry } from '../../src/tools/register.js';
import { resetConfig, setConfig } from '../../src/config.js';
// Import tool registration functions directly
import { registerBuildAppTool } from '../../src/tools/build/build-app.js';
import { registerInstallAppTool } from '../../src/tools/build/install-app.js';
import { registerLaunchAppTool } from '../../src/tools/build/launch-app.js';
import { registerGetUIContextTool } from '../../src/tools/ui/get-ui-context.js';
import { registerInteractWithUITool } from '../../src/tools/ui/interact-with-ui.js';
import { registerRunUnitTestsTool } from '../../src/tools/testing/run-unit-tests.js';
import { registerRunMaestroFlowTool } from '../../src/tools/testing/run-maestro-flow.js';
import { registerRunLinterTool } from '../../src/tools/testing/run-linter.js';
import { registerListDevicesTool } from '../../src/tools/environment/list-devices.js';
import { registerManageEnvTool } from '../../src/tools/environment/manage-env.js';
import { registerCleanProjectTool } from '../../src/tools/environment/clean-project.js';
import { registerAnalyzeCrashTool } from '../../src/tools/crash/analyze-crash.js';
import { registerDeepLinkNavigateTool } from '../../src/tools/navigation/deep-link-navigate.js';
import { registerInspectAppStateTool } from '../../src/tools/observability/inspect-app-state.js';
import { registerInspectLogsTool } from '../../src/tools/observability/inspect-logs.js';
/**
* Register all tools for E2E testing
*/
function registerTestTools(): void {
const registry = getToolRegistry();
registry.clear();
registerBuildAppTool();
registerInstallAppTool();
registerLaunchAppTool();
registerGetUIContextTool();
registerInteractWithUITool();
registerRunUnitTestsTool();
registerRunMaestroFlowTool();
registerRunLinterTool();
registerListDevicesTool();
registerManageEnvTool();
registerCleanProjectTool();
registerAnalyzeCrashTool();
registerDeepLinkNavigateTool();
registerInspectAppStateTool();
registerInspectLogsTool();
}
describe('Build-Test-Debug Cycle E2E', () => {
beforeAll(() => {
resetConfig();
setConfig({ debug: false, logLevel: 'error' });
registerTestTools();
});
afterAll(() => {
resetConfig();
getToolRegistry().clear();
});
describe('Tool Registration', () => {
it('should register all 15 expected tools', () => {
const registry = getToolRegistry();
const tools = registry.listTools();
const expectedTools = [
'build_app',
'install_app',
'launch_app',
'get_ui_context',
'interact_with_ui',
'run_unit_tests',
'run_maestro_flow',
'run_linter',
'list_devices',
'manage_env',
'clean_project',
'analyze_crash',
'deep_link_navigate',
'inspect_app_state',
'inspect_logs',
];
expect(tools.length).toBe(expectedTools.length);
for (const toolName of expectedTools) {
expect(registry.hasTool(toolName)).toBe(true);
}
});
it('should have valid schemas for all tools', () => {
const registry = getToolRegistry();
const tools = registry.listTools();
for (const tool of tools) {
expect(tool.name).toBeTruthy();
expect(tool.description).toBeTruthy();
expect(tool.inputSchema).toBeDefined();
expect(tool.inputSchema.type).toBe('object');
expect(tool.inputSchema.properties).toBeDefined();
}
});
it('should have handlers for all tools', () => {
const registry = getToolRegistry();
const tools = registry.listTools();
for (const tool of tools) {
const registered = registry.getTool(tool.name);
expect(registered).toBeDefined();
expect(registered!.handler).toBeInstanceOf(Function);
}
});
});
describe('Tool Schema Validation', () => {
it('build_app should have platform and variant in schema properties', () => {
const registry = getToolRegistry();
const tool = registry.getTool('build_app');
expect(tool!.definition.inputSchema.properties).toHaveProperty('platform');
expect(tool!.definition.inputSchema.properties).toHaveProperty('variant');
});
it('list_devices should have platform in schema properties', () => {
const registry = getToolRegistry();
const tool = registry.getTool('list_devices');
expect(tool!.definition.inputSchema.properties).toHaveProperty('platform');
});
it('deep_link_navigate should have required fields', () => {
const registry = getToolRegistry();
const tool = registry.getTool('deep_link_navigate');
expect(tool!.definition.inputSchema.properties).toHaveProperty('platform');
expect(tool!.definition.inputSchema.properties).toHaveProperty('uri');
});
it('inspect_app_state should require platform and appId', () => {
const registry = getToolRegistry();
const tool = registry.getTool('inspect_app_state');
expect(tool!.definition.inputSchema.required).toContain('platform');
expect(tool!.definition.inputSchema.required).toContain('appId');
});
it('inspect_logs should require platform', () => {
const registry = getToolRegistry();
const tool = registry.getTool('inspect_logs');
expect(tool!.definition.inputSchema.required).toContain('platform');
});
it('analyze_crash should require platform', () => {
const registry = getToolRegistry();
const tool = registry.getTool('analyze_crash');
expect(tool!.definition.inputSchema.required).toContain('platform');
});
});
describe('Tool Categories', () => {
it('should have build tools', () => {
const registry = getToolRegistry();
const buildTools = ['build_app', 'install_app', 'launch_app'];
for (const name of buildTools) {
expect(registry.hasTool(name)).toBe(true);
}
});
it('should have UI tools', () => {
const registry = getToolRegistry();
const uiTools = ['get_ui_context', 'interact_with_ui'];
for (const name of uiTools) {
expect(registry.hasTool(name)).toBe(true);
}
});
it('should have testing tools', () => {
const registry = getToolRegistry();
const testTools = ['run_unit_tests', 'run_maestro_flow', 'run_linter'];
for (const name of testTools) {
expect(registry.hasTool(name)).toBe(true);
}
});
it('should have environment tools', () => {
const registry = getToolRegistry();
const envTools = ['list_devices', 'manage_env', 'clean_project'];
for (const name of envTools) {
expect(registry.hasTool(name)).toBe(true);
}
});
it('should have observability tools', () => {
const registry = getToolRegistry();
const obsTools = ['inspect_app_state', 'inspect_logs', 'analyze_crash'];
for (const name of obsTools) {
expect(registry.hasTool(name)).toBe(true);
}
});
it('should have navigation tools', () => {
const registry = getToolRegistry();
expect(registry.hasTool('deep_link_navigate')).toBe(true);
});
});
describe('Build Tool Flow (T037, T038)', () => {
it('T037: build_app should return structured BuildResult on success', async () => {
const registry = getToolRegistry();
const tool = registry.getTool('build_app');
// The handler returns a BuildResult with success/failure
// In test environment without Gradle, it will fail but still return structured result
try {
const result = await tool!.handler({
platform: 'android',
variant: 'debug',
});
// Verify structured result format
expect(result).toHaveProperty('success');
expect(result).toHaveProperty('platform');
expect(result).toHaveProperty('variant');
expect(result).toHaveProperty('durationMs');
expect(result).toHaveProperty('command');
expect(result).toHaveProperty('exitCode');
} catch (error) {
// Build fails in test env (no Gradle), but error should be structured
expect(error).toBeDefined();
}
});
it('T038: build_app should return structured error summary on failure', async () => {
const registry = getToolRegistry();
const tool = registry.getTool('build_app');
// Test that invalid inputs return proper validation errors
await expect(
tool!.handler({
platform: 'android',
variant: 'invalid-variant',
})
).rejects.toThrow(/Invalid variant/);
});
it('build_app result should include errorSummary on build failure', async () => {
const registry = getToolRegistry();
const tool = registry.getTool('build_app');
try {
const result = await tool!.handler({
platform: 'android',
variant: 'debug',
timeoutMs: 1000, // Short timeout to trigger failure
});
// If build fails, it should have error summary
if (!(result as { success: boolean }).success) {
expect(result).toHaveProperty('exitCode');
// errorSummary is present when build fails
expect(result).toHaveProperty('errorSummary');
}
} catch {
// Expected in test environment without build tools
}
});
it('install_app should validate platform argument', async () => {
const registry = getToolRegistry();
const tool = registry.getTool('install_app');
await expect(
tool!.handler({
platform: 'windows',
artifactPath: '/path/to/app.apk',
})
).rejects.toThrow(/Invalid platform/);
});
it('launch_app should validate required appId', async () => {
const registry = getToolRegistry();
const tool = registry.getTool('launch_app');
await expect(
tool!.handler({
platform: 'android',
})
).rejects.toThrow();
});
});
});