@mseep/ai-tech-app-agent 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env +24 -0
- package/.env.example +24 -0
- package/Jenkinsfile +210 -0
- package/MCP-SERVER-GUIDE.md +405 -0
- package/README.MD +450 -0
- package/dist/config/app.config.d.ts +65 -0
- package/dist/config/app.config.d.ts.map +1 -0
- package/dist/config/app.config.js +94 -0
- package/dist/config/app.config.js.map +1 -0
- package/dist/config/llm.config.d.ts +63 -0
- package/dist/config/llm.config.d.ts.map +1 -0
- package/dist/config/llm.config.js +158 -0
- package/dist/config/llm.config.js.map +1 -0
- package/dist/config/mcp.config.d.ts +175 -0
- package/dist/config/mcp.config.d.ts.map +1 -0
- package/dist/config/mcp.config.js +215 -0
- package/dist/config/mcp.config.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +175 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/llamaClient.d.ts +14 -0
- package/dist/llm/llamaClient.d.ts.map +1 -0
- package/dist/llm/llamaClient.js +136 -0
- package/dist/llm/llamaClient.js.map +1 -0
- package/dist/mcp/mcpClient.d.ts +132 -0
- package/dist/mcp/mcpClient.d.ts.map +1 -0
- package/dist/mcp/mcpClient.js +784 -0
- package/dist/mcp/mcpClient.js.map +1 -0
- package/dist/models/testSpec.d.ts +78 -0
- package/dist/models/testSpec.d.ts.map +1 -0
- package/dist/models/testSpec.js +3 -0
- package/dist/models/testSpec.js.map +1 -0
- package/dist/orchestrator/aiTestRunner.d.ts +18 -0
- package/dist/orchestrator/aiTestRunner.d.ts.map +1 -0
- package/dist/orchestrator/aiTestRunner.js +247 -0
- package/dist/orchestrator/aiTestRunner.js.map +1 -0
- package/dist/utils/logger.d.ts +4 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +49 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/promptBuilder.d.ts +62 -0
- package/dist/utils/promptBuilder.d.ts.map +1 -0
- package/dist/utils/promptBuilder.js +333 -0
- package/dist/utils/promptBuilder.js.map +1 -0
- package/knowledge/app-knowledge.txt +100 -0
- package/logs/combined.log +486 -0
- package/logs/error.log +50 -0
- package/package.json +62 -0
- package/reports/screenshots/screenshot_1764535110518.png +0 -0
- package/reports/test-report.json +106 -0
- package/scripts/check-mcp-server.sh +100 -0
- package/scripts/extract-pom-knowledge.js +222 -0
- package/scripts/pre-test-setup.js +262 -0
- package/scripts/start-mcp-server.sh +76 -0
- package/src/config/app.config.ts +175 -0
- package/src/config/llm.config.ts +220 -0
- package/src/config/mcp.config.ts +291 -0
- package/src/index.ts +161 -0
- package/src/llm/llamaClient.ts +159 -0
- package/src/mcp/mcpClient.ts +878 -0
- package/src/models/testSpec.ts +85 -0
- package/src/orchestrator/aiTestRunner.ts +286 -0
- package/src/utils/logger.ts +59 -0
- package/src/utils/promptBuilder.ts +384 -0
- package/tests/nlp-specs/login-flow.yaml +31 -0
- package/tsconfig.json +31 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pre-test setup script
|
|
5
|
+
* Ensures all required services are running before executing tests
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { spawn } = require('child_process');
|
|
9
|
+
const axios = require('axios');
|
|
10
|
+
const dotenv = require('dotenv');
|
|
11
|
+
|
|
12
|
+
dotenv.config();
|
|
13
|
+
|
|
14
|
+
const colors = {
|
|
15
|
+
red: '\x1b[31m',
|
|
16
|
+
green: '\x1b[32m',
|
|
17
|
+
yellow: '\x1b[33m',
|
|
18
|
+
reset: '\x1b[0m'
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function log(message, color = 'reset') {
|
|
22
|
+
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function checkOllama() {
|
|
26
|
+
const ollamaUrl = process.env.OLLAMA_BASE_URL || 'http://localhost:11434';
|
|
27
|
+
const modelName = process.env.LLM_MODEL || 'llama3.2:3b';
|
|
28
|
+
|
|
29
|
+
log('\n1. Checking Ollama (LLM) Server...', 'yellow');
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
// Check if Ollama is running
|
|
33
|
+
const response = await axios.get(`${ollamaUrl}/api/tags`, { timeout: 5000 });
|
|
34
|
+
log('✓ Ollama is running', 'green');
|
|
35
|
+
|
|
36
|
+
// Check if model is available
|
|
37
|
+
const models = response.data.models || [];
|
|
38
|
+
const modelExists = models.some(m => m.name === modelName);
|
|
39
|
+
|
|
40
|
+
if (modelExists) {
|
|
41
|
+
log(`✓ Model ${modelName} is available`, 'green');
|
|
42
|
+
return true;
|
|
43
|
+
} else {
|
|
44
|
+
log(`✗ Model ${modelName} not found`, 'red');
|
|
45
|
+
log(` Available models: ${models.map(m => m.name).join(', ')}`, 'yellow');
|
|
46
|
+
log(` Run: ollama pull ${modelName}`, 'yellow');
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
} catch (error) {
|
|
50
|
+
log('✗ Ollama is not running or not accessible', 'red');
|
|
51
|
+
log(' Start Ollama with: ollama serve', 'yellow');
|
|
52
|
+
log(` Then pull model: ollama pull ${modelName}`, 'yellow');
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function checkAppium() {
|
|
58
|
+
const appiumUrl = process.env.APPIUM_SERVER_URL || 'http://localhost:4723';
|
|
59
|
+
|
|
60
|
+
log('\n2. Checking Appium Server...', 'yellow');
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const response = await axios.get(`${appiumUrl}/status`, { timeout: 5000 });
|
|
64
|
+
log(`✓ Appium server is running at ${appiumUrl}`, 'green');
|
|
65
|
+
log(` Build: ${JSON.stringify(response.data.value?.build || 'unknown')}`, 'reset');
|
|
66
|
+
return true;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
log(`⚠ Appium server not accessible at ${appiumUrl}`, 'yellow');
|
|
69
|
+
|
|
70
|
+
// Check if using LambdaTest
|
|
71
|
+
const ltUrl = process.env.LAMBDATEST_GRID_URL;
|
|
72
|
+
if (ltUrl && ltUrl.includes('lambdatest')) {
|
|
73
|
+
log(' Using LambdaTest remote grid - this is OK', 'green');
|
|
74
|
+
return true;
|
|
75
|
+
} else {
|
|
76
|
+
log(' If using local Appium, start with: appium', 'yellow');
|
|
77
|
+
log(' If using LambdaTest, ensure LAMBDATEST_GRID_URL is set', 'yellow');
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function checkMCPServer() {
|
|
84
|
+
const mcpPort = process.env.MCP_SERVER_PORT || 3000;
|
|
85
|
+
|
|
86
|
+
log('\n3. Checking MCP-Appium Server...', 'yellow');
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
// Try to connect to MCP server
|
|
90
|
+
await axios.get(`http://localhost:${mcpPort}/health`, { timeout: 2000 });
|
|
91
|
+
log('✓ MCP-Appium server is running', 'green');
|
|
92
|
+
return true;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
log('⚠ MCP-Appium server not running', 'yellow');
|
|
95
|
+
log(' MCP server starts automatically when tests run', 'green');
|
|
96
|
+
log(' Or start manually: npm run start-mcp', 'yellow');
|
|
97
|
+
return true; // Not critical, will start automatically
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function checkEnvironmentVariables() {
|
|
102
|
+
log('\n4. Checking Environment Variables...', 'yellow');
|
|
103
|
+
|
|
104
|
+
const required = [
|
|
105
|
+
'LAMBDATEST_USERNAME',
|
|
106
|
+
'LAMBDATEST_ACCESS_KEY',
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
const optional = [
|
|
110
|
+
'OLLAMA_BASE_URL',
|
|
111
|
+
'LLM_MODEL',
|
|
112
|
+
'APPIUM_SERVER_URL',
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
let allPresent = true;
|
|
116
|
+
|
|
117
|
+
required.forEach(varName => {
|
|
118
|
+
if (!process.env[varName]) {
|
|
119
|
+
log(`✗ Required: ${varName} is not set`, 'red');
|
|
120
|
+
allPresent = false;
|
|
121
|
+
} else {
|
|
122
|
+
const value = varName.includes('KEY') || varName.includes('PASSWORD')
|
|
123
|
+
? '***'
|
|
124
|
+
: process.env[varName];
|
|
125
|
+
log(`✓ ${varName}: ${value}`, 'green');
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
optional.forEach(varName => {
|
|
130
|
+
if (process.env[varName]) {
|
|
131
|
+
log(`✓ ${varName}: ${process.env[varName]}`, 'green');
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
return allPresent;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function checkProjectStructure() {
|
|
139
|
+
const fs = require('fs');
|
|
140
|
+
const path = require('path');
|
|
141
|
+
|
|
142
|
+
log('\n5. Checking Project Structure...', 'yellow');
|
|
143
|
+
|
|
144
|
+
const requiredDirs = [
|
|
145
|
+
'src/config',
|
|
146
|
+
'src/mcp',
|
|
147
|
+
'src/llm',
|
|
148
|
+
'src/utils',
|
|
149
|
+
'src/orchestrator',
|
|
150
|
+
'tests/nlp-specs',
|
|
151
|
+
'logs',
|
|
152
|
+
'reports',
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
let allExist = true;
|
|
156
|
+
|
|
157
|
+
requiredDirs.forEach(dir => {
|
|
158
|
+
const fullPath = path.join(process.cwd(), dir);
|
|
159
|
+
if (fs.existsSync(fullPath)) {
|
|
160
|
+
log(`✓ ${dir}`, 'green');
|
|
161
|
+
} else {
|
|
162
|
+
log(`✗ ${dir} not found`, 'red');
|
|
163
|
+
allExist = false;
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Check if build exists
|
|
168
|
+
const distPath = path.join(process.cwd(), 'dist');
|
|
169
|
+
if (fs.existsSync(distPath)) {
|
|
170
|
+
log('✓ TypeScript compiled (dist/ exists)', 'green');
|
|
171
|
+
} else {
|
|
172
|
+
log('✗ Project not built. Run: npm run build', 'red');
|
|
173
|
+
allExist = false;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return allExist;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async function startOllama() {
|
|
180
|
+
log('\nAttempting to start Ollama...', 'yellow');
|
|
181
|
+
|
|
182
|
+
return new Promise((resolve) => {
|
|
183
|
+
const ollama = spawn('ollama', ['serve'], {
|
|
184
|
+
detached: true,
|
|
185
|
+
stdio: 'ignore'
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
ollama.unref();
|
|
189
|
+
|
|
190
|
+
log('✓ Ollama server started in background', 'green');
|
|
191
|
+
log(' Waiting 3 seconds for initialization...', 'yellow');
|
|
192
|
+
|
|
193
|
+
setTimeout(() => resolve(true), 3000);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function main() {
|
|
198
|
+
console.log('==========================================');
|
|
199
|
+
console.log('Pre-Test Setup Checker');
|
|
200
|
+
console.log('==========================================');
|
|
201
|
+
|
|
202
|
+
const results = {
|
|
203
|
+
ollama: false,
|
|
204
|
+
appium: false,
|
|
205
|
+
mcp: false,
|
|
206
|
+
env: false,
|
|
207
|
+
structure: false,
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
// Check all services
|
|
211
|
+
results.ollama = await checkOllama();
|
|
212
|
+
results.appium = await checkAppium();
|
|
213
|
+
results.mcp = await checkMCPServer();
|
|
214
|
+
results.env = checkEnvironmentVariables();
|
|
215
|
+
results.structure = await checkProjectStructure();
|
|
216
|
+
|
|
217
|
+
// Summary
|
|
218
|
+
log('\n==========================================', 'yellow');
|
|
219
|
+
log('Setup Summary', 'yellow');
|
|
220
|
+
log('==========================================', 'yellow');
|
|
221
|
+
|
|
222
|
+
const allGood = Object.values(results).every(r => r === true);
|
|
223
|
+
|
|
224
|
+
if (allGood) {
|
|
225
|
+
log('\n✓ All checks passed! Ready to run tests.', 'green');
|
|
226
|
+
log('\nRun your tests with:', 'reset');
|
|
227
|
+
log(' npm run test', 'yellow');
|
|
228
|
+
log(' or', 'reset');
|
|
229
|
+
log(' npm run test:single', 'yellow');
|
|
230
|
+
process.exit(0);
|
|
231
|
+
} else {
|
|
232
|
+
log('\n⚠ Some checks failed. Please fix the issues above.', 'yellow');
|
|
233
|
+
|
|
234
|
+
// Auto-fix attempt
|
|
235
|
+
log('\nAttempting auto-fixes...', 'yellow');
|
|
236
|
+
|
|
237
|
+
if (!results.ollama) {
|
|
238
|
+
try {
|
|
239
|
+
await startOllama();
|
|
240
|
+
// Re-check Ollama
|
|
241
|
+
const ollamaOk = await checkOllama();
|
|
242
|
+
if (ollamaOk) {
|
|
243
|
+
log('✓ Ollama started successfully!', 'green');
|
|
244
|
+
}
|
|
245
|
+
} catch (error) {
|
|
246
|
+
log('✗ Could not auto-start Ollama', 'red');
|
|
247
|
+
log(' Please start manually: ollama serve', 'yellow');
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
log('\nAfter fixing issues, run this script again:', 'reset');
|
|
252
|
+
log(' node scripts/pre-test-setup.js', 'yellow');
|
|
253
|
+
|
|
254
|
+
process.exit(1);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Run the checks
|
|
259
|
+
main().catch(error => {
|
|
260
|
+
log(`\nError: ${error.message}`, 'red');
|
|
261
|
+
process.exit(1);
|
|
262
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Start MCP-Appium server manually
|
|
4
|
+
# This script is optional - MCP starts automatically during tests
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
# Color codes
|
|
9
|
+
GREEN='\033[0;32m'
|
|
10
|
+
YELLOW='\033[1;33m'
|
|
11
|
+
RED='\033[0;31m'
|
|
12
|
+
NC='\033[0m'
|
|
13
|
+
|
|
14
|
+
echo "=========================================="
|
|
15
|
+
echo "Starting MCP-Appium Server"
|
|
16
|
+
echo "=========================================="
|
|
17
|
+
echo ""
|
|
18
|
+
|
|
19
|
+
# Load environment variables
|
|
20
|
+
if [ -f .env ]; then
|
|
21
|
+
export $(cat .env | grep -v '^#' | xargs)
|
|
22
|
+
echo -e "${GREEN}✓${NC} Loaded environment variables from .env"
|
|
23
|
+
else
|
|
24
|
+
echo -e "${YELLOW}⚠${NC} No .env file found, using defaults"
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# Set defaults
|
|
28
|
+
APPIUM_SERVER_URL=${APPIUM_SERVER_URL:-http://localhost:4723}
|
|
29
|
+
MCP_SERVER_PORT=${MCP_SERVER_PORT:-3000}
|
|
30
|
+
|
|
31
|
+
echo "Configuration:"
|
|
32
|
+
echo " Appium URL: $APPIUM_SERVER_URL"
|
|
33
|
+
echo " MCP Port: $MCP_SERVER_PORT"
|
|
34
|
+
echo ""
|
|
35
|
+
|
|
36
|
+
# Check if mcp-appium is installed
|
|
37
|
+
if ! command -v npx &> /dev/null; then
|
|
38
|
+
echo -e "${RED}✗${NC} npx not found. Please install Node.js"
|
|
39
|
+
exit 1
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# Check if already running
|
|
43
|
+
if lsof -Pi :$MCP_SERVER_PORT -sTCP:LISTEN -t >/dev/null 2>&1; then
|
|
44
|
+
PID=$(lsof -Pi :$MCP_SERVER_PORT -sTCP:LISTEN -t)
|
|
45
|
+
echo -e "${YELLOW}⚠${NC} Port $MCP_SERVER_PORT is already in use by PID: $PID"
|
|
46
|
+
read -p "Kill existing process? (y/n) " -n 1 -r
|
|
47
|
+
echo
|
|
48
|
+
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
49
|
+
kill -9 $PID
|
|
50
|
+
echo -e "${GREEN}✓${NC} Killed existing process"
|
|
51
|
+
sleep 2
|
|
52
|
+
else
|
|
53
|
+
echo "Exiting..."
|
|
54
|
+
exit 1
|
|
55
|
+
fi
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# Check if Appium is accessible
|
|
59
|
+
echo "Checking Appium server connectivity..."
|
|
60
|
+
if curl -s "$APPIUM_SERVER_URL/status" > /dev/null 2>&1; then
|
|
61
|
+
echo -e "${GREEN}✓${NC} Appium server is accessible"
|
|
62
|
+
else
|
|
63
|
+
echo -e "${YELLOW}⚠${NC} Cannot reach Appium server at $APPIUM_SERVER_URL"
|
|
64
|
+
echo " If using LambdaTest, this is OK"
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
echo ""
|
|
68
|
+
echo "Starting MCP-Appium server..."
|
|
69
|
+
echo "Press Ctrl+C to stop"
|
|
70
|
+
echo ""
|
|
71
|
+
|
|
72
|
+
# Start MCP-Appium server
|
|
73
|
+
npx mcp-appium
|
|
74
|
+
|
|
75
|
+
# Note: The process will run in foreground
|
|
76
|
+
# To run in background, use: npx mcp-appium > logs/mcp-server.log 2>&1 &
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import dotenv from 'dotenv';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
dotenv.config();
|
|
5
|
+
|
|
6
|
+
export interface AppConfig {
|
|
7
|
+
env: string;
|
|
8
|
+
name: string;
|
|
9
|
+
version: string;
|
|
10
|
+
|
|
11
|
+
// Directories
|
|
12
|
+
paths: {
|
|
13
|
+
root: string;
|
|
14
|
+
logs: string;
|
|
15
|
+
reports: string;
|
|
16
|
+
screenshots: string;
|
|
17
|
+
testSpecs: string;
|
|
18
|
+
knowledge: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Test execution settings
|
|
22
|
+
execution: {
|
|
23
|
+
defaultTimeout: number;
|
|
24
|
+
maxRetryAttempts: number;
|
|
25
|
+
retryFailedSteps: boolean;
|
|
26
|
+
screenshotOnFailure: boolean;
|
|
27
|
+
continueOnFailure: boolean;
|
|
28
|
+
parallelExecution: boolean;
|
|
29
|
+
maxParallelTests: number;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Element interaction settings
|
|
33
|
+
interaction: {
|
|
34
|
+
implicitWait: number;
|
|
35
|
+
explicitWait: number;
|
|
36
|
+
actionDelay: number;
|
|
37
|
+
tapDuration: number;
|
|
38
|
+
swipeSpeed: number;
|
|
39
|
+
scrollPercentage: number;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Reporting
|
|
43
|
+
reporting: {
|
|
44
|
+
format: 'json' | 'html' | 'allure';
|
|
45
|
+
includeScreenshots: boolean;
|
|
46
|
+
includeStepDetails: boolean;
|
|
47
|
+
includeTimestamps: boolean;
|
|
48
|
+
verboseLogging: boolean;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// LambdaTest configuration
|
|
52
|
+
lambdatest: {
|
|
53
|
+
username: string;
|
|
54
|
+
accessKey: string;
|
|
55
|
+
gridUrl: string;
|
|
56
|
+
tunnel: boolean;
|
|
57
|
+
tunnelName?: string;
|
|
58
|
+
buildName: string;
|
|
59
|
+
projectName: string;
|
|
60
|
+
tags: string[];
|
|
61
|
+
network: boolean;
|
|
62
|
+
video: boolean;
|
|
63
|
+
console: boolean;
|
|
64
|
+
visual: boolean;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Device preferences
|
|
68
|
+
devices: {
|
|
69
|
+
android: {
|
|
70
|
+
defaultVersion: string;
|
|
71
|
+
defaultDevice: string;
|
|
72
|
+
};
|
|
73
|
+
ios: {
|
|
74
|
+
defaultVersion: string;
|
|
75
|
+
defaultDevice: string;
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const appConfig: AppConfig = {
|
|
81
|
+
env: process.env.NODE_ENV || 'development',
|
|
82
|
+
name: process.env.APP_NAME || 'ai-tech-app-agent',
|
|
83
|
+
version: process.env.APP_VERSION || '1.0.0',
|
|
84
|
+
|
|
85
|
+
paths: {
|
|
86
|
+
root: process.cwd(),
|
|
87
|
+
logs: path.resolve(process.cwd(), process.env.LOG_DIR || './logs'),
|
|
88
|
+
reports: path.resolve(process.cwd(), process.env.REPORT_DIR || './reports'),
|
|
89
|
+
screenshots: path.resolve(process.cwd(), process.env.SCREENSHOT_DIR || './reports/screenshots'),
|
|
90
|
+
testSpecs: path.resolve(process.cwd(), process.env.TEST_SPEC_DIR || './tests/nlp-specs'),
|
|
91
|
+
knowledge: path.resolve(process.cwd(), process.env.KNOWLEDGE_DIR || './knowledge'),
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
execution: {
|
|
95
|
+
defaultTimeout: parseInt(process.env.DEFAULT_TIMEOUT || '30000'),
|
|
96
|
+
maxRetryAttempts: parseInt(process.env.MAX_RETRY_ATTEMPTS || '2'),
|
|
97
|
+
retryFailedSteps: process.env.RETRY_FAILED_STEPS === 'true',
|
|
98
|
+
screenshotOnFailure: process.env.SCREENSHOT_ON_FAILURE !== 'false',
|
|
99
|
+
continueOnFailure: process.env.CONTINUE_ON_FAILURE === 'true',
|
|
100
|
+
parallelExecution: process.env.PARALLEL_EXECUTION === 'true',
|
|
101
|
+
maxParallelTests: parseInt(process.env.MAX_PARALLEL_TESTS || '3'),
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
interaction: {
|
|
105
|
+
implicitWait: parseInt(process.env.IMPLICIT_WAIT || '5000'),
|
|
106
|
+
explicitWait: parseInt(process.env.EXPLICIT_WAIT || '10000'),
|
|
107
|
+
actionDelay: parseInt(process.env.ACTION_DELAY || '500'),
|
|
108
|
+
tapDuration: parseInt(process.env.TAP_DURATION || '100'),
|
|
109
|
+
swipeSpeed: parseInt(process.env.SWIPE_SPEED || '1000'),
|
|
110
|
+
scrollPercentage: parseFloat(process.env.SCROLL_PERCENTAGE || '0.75'),
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
reporting: {
|
|
114
|
+
format: (process.env.REPORT_FORMAT as 'json' | 'html' | 'allure') || 'json',
|
|
115
|
+
includeScreenshots: process.env.INCLUDE_SCREENSHOTS !== 'false',
|
|
116
|
+
includeStepDetails: process.env.INCLUDE_STEP_DETAILS !== 'false',
|
|
117
|
+
includeTimestamps: process.env.INCLUDE_TIMESTAMPS !== 'false',
|
|
118
|
+
verboseLogging: process.env.VERBOSE_LOGGING === 'true',
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
lambdatest: {
|
|
122
|
+
username: process.env.LAMBDATEST_USERNAME || '',
|
|
123
|
+
accessKey: process.env.LAMBDATEST_ACCESS_KEY || '',
|
|
124
|
+
gridUrl: process.env.LAMBDATEST_GRID_URL || 'https://mobile-hub.lambdatest.com/wd/hub',
|
|
125
|
+
tunnel: process.env.LAMBDATEST_TUNNEL === 'true',
|
|
126
|
+
tunnelName: process.env.LAMBDATEST_TUNNEL_NAME,
|
|
127
|
+
buildName: process.env.LAMBDATEST_BUILD_NAME || `AI-Test-Build`,
|
|
128
|
+
projectName: process.env.LAMBDATEST_PROJECT_NAME || 'AI Mobile Test Automation',
|
|
129
|
+
tags: (process.env.LAMBDATEST_TAGS || 'ai,mcp,automation').split(','),
|
|
130
|
+
network: process.env.LAMBDATEST_NETWORK !== 'false',
|
|
131
|
+
video: process.env.LAMBDATEST_VIDEO !== 'false',
|
|
132
|
+
console: process.env.LAMBDATEST_CONSOLE !== 'false',
|
|
133
|
+
visual: process.env.LAMBDATEST_VISUAL !== 'false',
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
devices: {
|
|
137
|
+
android: {
|
|
138
|
+
defaultVersion: process.env.ANDROID_DEFAULT_VERSION || '13',
|
|
139
|
+
defaultDevice: process.env.ANDROID_DEFAULT_DEVICE || 'Pixel 7',
|
|
140
|
+
},
|
|
141
|
+
ios: {
|
|
142
|
+
defaultVersion: process.env.IOS_DEFAULT_VERSION || '16',
|
|
143
|
+
defaultDevice: process.env.IOS_DEFAULT_DEVICE || 'iPhone 14',
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// Validation
|
|
149
|
+
export function validateAppConfig(): void {
|
|
150
|
+
const errors: string[] = [];
|
|
151
|
+
|
|
152
|
+
// Check required LambdaTest credentials
|
|
153
|
+
if (!appConfig.lambdatest.username) {
|
|
154
|
+
errors.push('LAMBDATEST_USERNAME is required');
|
|
155
|
+
}
|
|
156
|
+
if (!appConfig.lambdatest.accessKey) {
|
|
157
|
+
errors.push('LAMBDATEST_ACCESS_KEY is required');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Validate timeout values
|
|
161
|
+
if (appConfig.execution.defaultTimeout < 1000) {
|
|
162
|
+
errors.push('DEFAULT_TIMEOUT must be at least 1000ms');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Validate retry attempts
|
|
166
|
+
if (appConfig.execution.maxRetryAttempts < 0 || appConfig.execution.maxRetryAttempts > 5) {
|
|
167
|
+
errors.push('MAX_RETRY_ATTEMPTS must be between 0 and 5');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (errors.length > 0) {
|
|
171
|
+
throw new Error(`App configuration validation failed:\n${errors.join('\n')}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export default appConfig;
|