Skip to main content
Glama
build.integration.test.ts4.95 kB
/** * Android Gradle Build Integration Tests * Tests against real KMM project (specter-test-subject) * * Prerequisites: * - Java/JDK installed * - Android SDK installed * - specter-test-subject project exists */ import { describe, it, expect, beforeAll } from 'vitest'; import { executeShell } from '../../../src/utils/shell.js'; import { buildGradle, GradleBuildOptions } from '../../../src/platforms/android/gradle.js'; import { parseGradleLog } from '../../../src/tools/build/log-parser.js'; import * as path from 'path'; const TEST_PROJECT_PATH = path.resolve(__dirname, '../../../test-apps/specter-test-subject'); async function isGradleAvailable(): Promise<boolean> { try { const result = await executeShell('java', ['-version']); return result.exitCode === 0 || result.stderr.includes('version'); } catch { return false; } } async function projectExists(): Promise<boolean> { try { const result = await executeShell('ls', [path.join(TEST_PROJECT_PATH, 'build.gradle.kts')]); return result.exitCode === 0; } catch { return false; } } describe('Android Gradle Build Integration', () => { let gradleAvailable = false; let projectReady = false; beforeAll(async () => { gradleAvailable = await isGradleAvailable(); projectReady = await projectExists(); console.log(`Gradle available: ${gradleAvailable}`); console.log(`Project ready: ${projectReady}`); console.log(`Project path: ${TEST_PROJECT_PATH}`); }); describe('buildGradle', () => { it('should build debug APK successfully', async () => { expect(gradleAvailable, 'Gradle/Java not available').toBe(true); expect(projectReady, `Project not found at ${TEST_PROJECT_PATH}`).toBe(true); const options: GradleBuildOptions = { projectPath: TEST_PROJECT_PATH, module: 'androidApp', variant: 'debug', clean: false, timeoutMs: 600000, // 10 minutes }; const result = await buildGradle(options); console.log(`Build success: ${result.success}`); console.log(`Duration: ${result.durationMs}ms`); if (result.success) { expect(result.artifactPath).toBeDefined(); console.log(`Artifact: ${result.artifactPath}`); } else { const errors = result.errorSummary?.topErrors ?? []; console.log(`Build failed with ${errors.length} errors`); for (const error of errors.slice(0, 5)) { console.log(` - ${error.file}:${error.line}: ${error.message}`); } } expect(result).toHaveProperty('success'); expect(result).toHaveProperty('durationMs'); }, 600000); it('should clean and build', async () => { expect(gradleAvailable, 'Gradle/Java not available').toBe(true); expect(projectReady, `Project not found at ${TEST_PROJECT_PATH}`).toBe(true); const options: GradleBuildOptions = { projectPath: TEST_PROJECT_PATH, module: 'androidApp', variant: 'debug', clean: true, timeoutMs: 900000, // 15 minutes for clean build }; const result = await buildGradle(options); console.log(`Clean build success: ${result.success}`); console.log(`Duration: ${result.durationMs}ms`); expect(result).toHaveProperty('success'); }, 900000); }); describe('parseGradleLog', () => { it('should parse successful build logs', () => { const logs = ` > Task :shared:compileKotlinJvm > Task :shared:compileJava NO-SOURCE > Task :androidApp:compileDebugKotlin > Task :androidApp:assembleDebug BUILD SUCCESSFUL in 45s 12 actionable tasks: 12 executed `; const result = parseGradleLog(logs); // ParsedLog has errors array, not success boolean expect(result.errors).toHaveLength(0); expect(result.warnings).toBeDefined(); }); it('should parse build with errors', () => { const logs = ` > Task :shared:compileKotlinJvm e: /Users/test/project/shared/src/commonMain/kotlin/Greeting.kt:12:5 Type mismatch: inferred type is String but Int was expected e: /Users/test/project/shared/src/commonMain/kotlin/Greeting.kt:15:10 Unresolved reference: foo FAILURE: Build failed with an exception. BUILD FAILED in 10s `; const result = parseGradleLog(logs); // Has errors = failed build expect(result.errors.length).toBeGreaterThan(0); expect(result.errors[0].file).toContain('Greeting.kt'); expect(result.errors[0].line).toBe(12); }); it('should extract warnings', () => { const logs = ` > Task :shared:compileKotlinJvm w: /Users/test/project/shared/src/commonMain/kotlin/Utils.kt:20:5 Deprecation: foo is deprecated w: /Users/test/project/shared/src/commonMain/kotlin/Utils.kt:25:10 Unreachable code BUILD SUCCESSFUL in 30s `; const result = parseGradleLog(logs); expect(result.warnings.length).toBe(2); expect(result.warnings[0].severity).toBe('warning'); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/abd3lraouf/specter-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server