endorphin-ai 0.1.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/LICENSE.md +209 -0
- package/README.md +474 -0
- package/bin/endorphin.js +256 -0
- package/examples/endorphin.config.js +22 -0
- package/examples/tests/QE-001-basic-login-test.js +18 -0
- package/examples/tests/sample-test.js +9 -0
- package/examples/tools/.gitkeep +0 -0
- package/framework/config/agent-config.js +53 -0
- package/framework/config/browser-config.js +53 -0
- package/framework/config/paths.js +40 -0
- package/framework/core/agent-setup.js +75 -0
- package/framework/core/browser-framework.js +766 -0
- package/framework/core/config-loader.js +309 -0
- package/framework/core/test-discovery.js +402 -0
- package/framework/core/test-manager.js +343 -0
- package/framework/core/test-recorder.js +302 -0
- package/framework/core/test-runner.js +133 -0
- package/framework/core/test-session.js +98 -0
- package/framework/index.js +44 -0
- package/framework/interactive/enhanced-interactive-recorder.js +223 -0
- package/framework/interactive/index.js +18 -0
- package/framework/interactive/interactive-test-clean.js +33 -0
- package/framework/interactive/interactive-test.js +33 -0
- package/framework/test-framework.js +29 -0
- package/framework/testing/index.js +15 -0
- package/framework/testing/test-interactive-recorder.js +83 -0
- package/framework/testing/test-modular-framework.js +47 -0
- package/framework/testing/verify-test-format.js +58 -0
- package/framework/tools/content.js +67 -0
- package/framework/tools/index.js +52 -0
- package/framework/tools/interaction.js +180 -0
- package/framework/tools/navigation.js +43 -0
- package/framework/tools/utilities.js +99 -0
- package/framework/tools/verification.js +84 -0
- package/package.json +84 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// Endorphin e2e AI test framework>
|
|
2
|
+
// Copyright (C) 2025 Redstudio Agency
|
|
3
|
+
|
|
4
|
+
// This program is free software: you can redistribute it and/or modify
|
|
5
|
+
// it under the terms of the GNU Affero General Public License as
|
|
6
|
+
// published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
// License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
// This program is distributed in the hope that it will be useful,
|
|
10
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
// GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
import { HumanMessage } from "@langchain/core/messages";
|
|
20
|
+
import { AGENT_CONFIG } from '../config/agent-config.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Run a test task using the AI agent
|
|
24
|
+
* @param {Object} framework - Framework instance
|
|
25
|
+
* @param {string} taskDescription - Description of the task to perform
|
|
26
|
+
* @param {string} testName - Optional test name
|
|
27
|
+
* @returns {Object} Test result
|
|
28
|
+
*/
|
|
29
|
+
export async function runTask(framework, taskDescription, testName = null) {
|
|
30
|
+
const timestamp = new Date().toISOString();
|
|
31
|
+
const name = testName || `Test-${Date.now()}`;
|
|
32
|
+
|
|
33
|
+
console.log(`\nšÆ Running Task: ${name}`);
|
|
34
|
+
console.log(`š Task: ${taskDescription}`);
|
|
35
|
+
console.log(`ā° Started at: ${timestamp}\n`);
|
|
36
|
+
|
|
37
|
+
// Create test session
|
|
38
|
+
const session = framework.createTestSession(name, name.replace(/\s+/g, '-').toLowerCase());
|
|
39
|
+
framework.currentTestSession = session;
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
// Log initial step
|
|
43
|
+
framework.logTestStep("Test started", null, null, `Starting task: ${taskDescription}`, true);
|
|
44
|
+
await framework.takeStepScreenshot("Initial page state");
|
|
45
|
+
|
|
46
|
+
const finalState = await framework.agent.invoke({
|
|
47
|
+
messages: [new HumanMessage(taskDescription)],
|
|
48
|
+
}, {
|
|
49
|
+
recursionLimit: AGENT_CONFIG.agent.recursionLimit,
|
|
50
|
+
configurable: { thread_id: `session-${framework.currentTestSession.sessionId}` }
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const result = finalState.messages[finalState.messages.length - 1].content;
|
|
54
|
+
|
|
55
|
+
// Log final step
|
|
56
|
+
framework.logTestStep("Test completed", null, null, result, true);
|
|
57
|
+
await framework.takeStepScreenshot("Final page state");
|
|
58
|
+
|
|
59
|
+
// Finish session
|
|
60
|
+
await framework.finishTestSession('SUCCESS', result);
|
|
61
|
+
|
|
62
|
+
console.log(`\nā
Task "${name}" completed successfully!`);
|
|
63
|
+
console.log(`š Result: ${result}\n`);
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
testName: name,
|
|
67
|
+
task: taskDescription,
|
|
68
|
+
timestamp,
|
|
69
|
+
status: 'SUCCESS',
|
|
70
|
+
result: result,
|
|
71
|
+
duration: Date.now() - new Date(timestamp).getTime(),
|
|
72
|
+
sessionDir: session.sessionDir
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.error(`\nā Task "${name}" failed:`);
|
|
77
|
+
console.error(`š„ Error: ${error.message}\n`);
|
|
78
|
+
|
|
79
|
+
// Log error step
|
|
80
|
+
framework.logTestStep("Test failed", null, null, error.message, false);
|
|
81
|
+
await framework.takeStepScreenshot("Error state");
|
|
82
|
+
|
|
83
|
+
// Finish session with failure
|
|
84
|
+
await framework.finishTestSession('FAILED', error.message);
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
testName: name,
|
|
88
|
+
task: taskDescription,
|
|
89
|
+
timestamp,
|
|
90
|
+
status: 'FAILED',
|
|
91
|
+
error: error.message,
|
|
92
|
+
duration: Date.now() - new Date(timestamp).getTime(),
|
|
93
|
+
sessionDir: session.sessionDir
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Run multiple test tasks in sequence
|
|
100
|
+
* @param {Object} framework - Framework instance
|
|
101
|
+
* @param {Array} tasks - Array of task objects {name, description}
|
|
102
|
+
* @returns {Array} Array of test results
|
|
103
|
+
*/
|
|
104
|
+
export async function runTaskSequence(framework, tasks) {
|
|
105
|
+
const results = [];
|
|
106
|
+
|
|
107
|
+
console.log(`\nšÆ Running ${tasks.length} tasks in sequence...\n`);
|
|
108
|
+
|
|
109
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
110
|
+
const task = tasks[i];
|
|
111
|
+
console.log(`\nš Task ${i + 1}/${tasks.length}: ${task.name}`);
|
|
112
|
+
|
|
113
|
+
const result = await runTask(framework, task.description, task.name);
|
|
114
|
+
results.push(result);
|
|
115
|
+
|
|
116
|
+
// Add delay between tasks if configured
|
|
117
|
+
if (AGENT_CONFIG.execution.stepDelay && i < tasks.length - 1) {
|
|
118
|
+
console.log(`ā±ļø Waiting ${AGENT_CONFIG.execution.stepDelay}ms before next task...`);
|
|
119
|
+
await new Promise(resolve => setTimeout(resolve, AGENT_CONFIG.execution.stepDelay));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Print summary
|
|
124
|
+
const successful = results.filter(r => r.status === 'SUCCESS').length;
|
|
125
|
+
const failed = results.filter(r => r.status === 'FAILED').length;
|
|
126
|
+
|
|
127
|
+
console.log(`\nš Task Sequence Summary:`);
|
|
128
|
+
console.log(` ā
Successful: ${successful}`);
|
|
129
|
+
console.log(` ā Failed: ${failed}`);
|
|
130
|
+
console.log(` š Success Rate: ${(successful / results.length * 100).toFixed(1)}%\n`);
|
|
131
|
+
|
|
132
|
+
return results;
|
|
133
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Endorphin e2e AI test framework>
|
|
2
|
+
// Copyright (C) 2025 Redstudio Agency
|
|
3
|
+
|
|
4
|
+
// This program is free software: you can redistribute it and/or modify
|
|
5
|
+
// it under the terms of the GNU Affero General Public License as
|
|
6
|
+
// published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
// License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
// This program is distributed in the hope that it will be useful,
|
|
10
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
// GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
import fs from 'fs';
|
|
19
|
+
import path from 'path';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Create a new test session with directory structure and metadata
|
|
23
|
+
* @param {string} testName - Name of the test
|
|
24
|
+
* @param {string} testId - Optional test ID
|
|
25
|
+
* @param {string} resultBaseDir - Base directory for test results
|
|
26
|
+
* @returns {Object} Test session object
|
|
27
|
+
*/
|
|
28
|
+
export function createTestSession(testName, testId = null, resultBaseDir) {
|
|
29
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
30
|
+
const sessionId = testId || `test-${Date.now()}`;
|
|
31
|
+
const sessionName = `${sessionId}_${timestamp}`;
|
|
32
|
+
const sessionDir = path.join(resultBaseDir, sessionName);
|
|
33
|
+
const screenshotsDir = path.join(sessionDir, 'screenshots');
|
|
34
|
+
|
|
35
|
+
// Create directories
|
|
36
|
+
fs.mkdirSync(sessionDir, { recursive: true });
|
|
37
|
+
fs.mkdirSync(screenshotsDir, { recursive: true });
|
|
38
|
+
|
|
39
|
+
const session = {
|
|
40
|
+
sessionId,
|
|
41
|
+
sessionName,
|
|
42
|
+
testName,
|
|
43
|
+
testId,
|
|
44
|
+
startTime: new Date().toISOString(),
|
|
45
|
+
endTime: null,
|
|
46
|
+
sessionDir,
|
|
47
|
+
screenshotsDir,
|
|
48
|
+
steps: [],
|
|
49
|
+
toolCalls: [],
|
|
50
|
+
stepCounter: 0,
|
|
51
|
+
screenshotCounter: 0,
|
|
52
|
+
status: 'RUNNING',
|
|
53
|
+
finalResult: null,
|
|
54
|
+
duration: null
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
console.log(`š Created test session: ${sessionName}`);
|
|
58
|
+
return session;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Generate test session summary
|
|
63
|
+
* @param {Object} session - Test session object
|
|
64
|
+
* @returns {Object} Session summary
|
|
65
|
+
*/
|
|
66
|
+
export function generateSessionSummary(session) {
|
|
67
|
+
return {
|
|
68
|
+
testName: session.testName,
|
|
69
|
+
sessionId: session.sessionId,
|
|
70
|
+
status: session.status,
|
|
71
|
+
startTime: session.startTime,
|
|
72
|
+
endTime: session.endTime,
|
|
73
|
+
duration: session.duration,
|
|
74
|
+
totalSteps: session.steps.length,
|
|
75
|
+
successfulSteps: session.steps.filter(s => s.status === 'SUCCESS').length,
|
|
76
|
+
failedSteps: session.steps.filter(s => s.status === 'FAILED').length,
|
|
77
|
+
totalScreenshots: session.screenshotCounter,
|
|
78
|
+
finalResult: session.finalResult
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Save test session data to files
|
|
84
|
+
* @param {Object} session - Test session object
|
|
85
|
+
*/
|
|
86
|
+
export function saveTestSession(session) {
|
|
87
|
+
// Save complete session data
|
|
88
|
+
const sessionFile = path.join(session.sessionDir, 'test-session.json');
|
|
89
|
+
fs.writeFileSync(sessionFile, JSON.stringify(session, null, 2));
|
|
90
|
+
|
|
91
|
+
// Save summary
|
|
92
|
+
const summary = generateSessionSummary(session);
|
|
93
|
+
const summaryFile = path.join(session.sessionDir, 'summary.json');
|
|
94
|
+
fs.writeFileSync(summaryFile, JSON.stringify(summary, null, 2));
|
|
95
|
+
|
|
96
|
+
console.log(`š¾ Session data saved to: ${session.sessionDir}`);
|
|
97
|
+
return summary;
|
|
98
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Endorphin e2e AI test framework>
|
|
2
|
+
// Copyright (C) 2025 Redstudio Agency
|
|
3
|
+
|
|
4
|
+
// This program is free software: you can redistribute it and/or modify
|
|
5
|
+
// it under the terms of the GNU Affero General Public License as
|
|
6
|
+
// published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
// License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
// This program is distributed in the hope that it will be useful,
|
|
10
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
// GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
export { EnhancedBrowserTestFramework } from './core/browser-framework.js';
|
|
18
|
+
export { TestRecorder } from './core/test-recorder.js';
|
|
19
|
+
export { runTask, runTaskSequence } from './core/test-runner.js';
|
|
20
|
+
export { createTestSession, generateSessionSummary, saveTestSession } from './core/test-session.js';
|
|
21
|
+
export { setupAgent } from './core/agent-setup.js';
|
|
22
|
+
export { createAllTools } from './tools/index.js';
|
|
23
|
+
export { TestManager } from './core/test-manager.js';
|
|
24
|
+
|
|
25
|
+
// Configuration exports
|
|
26
|
+
export { BROWSER_CONFIG } from './config/browser-config.js';
|
|
27
|
+
export { AGENT_CONFIG } from './config/agent-config.js';
|
|
28
|
+
export { PATHS } from './config/paths.js';
|
|
29
|
+
|
|
30
|
+
// Module exports for organized components
|
|
31
|
+
export * as Demos from './demos/index.js';
|
|
32
|
+
export * as Interactive from './interactive/index.js';
|
|
33
|
+
export * as Testing from './testing/index.js';
|
|
34
|
+
|
|
35
|
+
// Individual tool creators for custom setups
|
|
36
|
+
export { createNavigationTool } from './tools/navigation.js';
|
|
37
|
+
export { createGetPageContentTool, createGetSimplePageContentTool } from './tools/content.js';
|
|
38
|
+
export { createClickTool, createFillTool, createClearFieldTool } from './tools/interaction.js';
|
|
39
|
+
export { createVerifyElementTool, createGetElementInfoTool } from './tools/verification.js';
|
|
40
|
+
export { createWaitTool, createScreenshotTool } from './tools/utilities.js';
|
|
41
|
+
|
|
42
|
+
// Default export for simple usage: import EndorphinAI from 'endorphin-ai'
|
|
43
|
+
import { EnhancedBrowserTestFramework } from './core/browser-framework.js';
|
|
44
|
+
export default EnhancedBrowserTestFramework;
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
// Endorphin e2e AI test framework>
|
|
2
|
+
// Copyright (C) 2025 Redstudio Agency
|
|
3
|
+
|
|
4
|
+
// This program is free software: you can redistribute it and/or modify
|
|
5
|
+
// it under the terms of the GNU Affero General Public License as
|
|
6
|
+
// published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
// License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
// This program is distributed in the hope that it will be useful,
|
|
10
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
// GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
import { EnhancedBrowserTestFramework } from '../index.js';
|
|
18
|
+
import { TestRecorder } from '../core/test-recorder.js';
|
|
19
|
+
import readline from 'readline';
|
|
20
|
+
import dotenv from 'dotenv';
|
|
21
|
+
|
|
22
|
+
// Load environment variables
|
|
23
|
+
dotenv.config();
|
|
24
|
+
|
|
25
|
+
const rl = readline.createInterface({
|
|
26
|
+
input: process.stdin,
|
|
27
|
+
output: process.stdout
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
function askQuestion(question) {
|
|
31
|
+
return new Promise((resolve) => {
|
|
32
|
+
rl.question(question, (answer) => {
|
|
33
|
+
resolve(answer);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function collectTestData() {
|
|
39
|
+
console.log('\nš Test Data Collection');
|
|
40
|
+
console.log('ā'.repeat(40));
|
|
41
|
+
|
|
42
|
+
const testData = {};
|
|
43
|
+
|
|
44
|
+
// Required fields
|
|
45
|
+
testData.id = await askQuestion('Test ID (e.g., QE-012): ');
|
|
46
|
+
testData.name = await askQuestion('Test Name: ');
|
|
47
|
+
testData.description = await askQuestion('Test Description: ');
|
|
48
|
+
|
|
49
|
+
// Optional fields
|
|
50
|
+
const priority = await askQuestion('Priority (High/Medium/Low) [Medium]: ');
|
|
51
|
+
testData.priority = priority || 'Medium';
|
|
52
|
+
|
|
53
|
+
const tags = await askQuestion('Tags (comma-separated): ');
|
|
54
|
+
testData.tags = tags ? tags.split(',').map(tag => tag.trim()) : [];
|
|
55
|
+
|
|
56
|
+
// Site URL (use env variable as default)
|
|
57
|
+
const defaultSite = process.env.BASE_URL || 'https://qafromla.herokuapp.com/';
|
|
58
|
+
const site = await askQuestion(`Site URL [${defaultSite}]: `);
|
|
59
|
+
testData.site = site || defaultSite;
|
|
60
|
+
|
|
61
|
+
// Collect test data object
|
|
62
|
+
console.log('\nš§ Test Data (for form filling, login, etc.)');
|
|
63
|
+
console.log('Press Enter to skip any field');
|
|
64
|
+
|
|
65
|
+
const testDataObj = {};
|
|
66
|
+
|
|
67
|
+
const uid = await askQuestion('User ID: ');
|
|
68
|
+
if (uid) testDataObj.uid = uid;
|
|
69
|
+
|
|
70
|
+
const email = await askQuestion('Email: ');
|
|
71
|
+
if (email) testDataObj.email = email;
|
|
72
|
+
|
|
73
|
+
const password = await askQuestion('Password: ');
|
|
74
|
+
if (password) testDataObj.password = password;
|
|
75
|
+
|
|
76
|
+
const firstName = await askQuestion('First Name: ');
|
|
77
|
+
if (firstName) testDataObj.firstName = firstName;
|
|
78
|
+
|
|
79
|
+
const lastName = await askQuestion('Last Name: ');
|
|
80
|
+
if (lastName) testDataObj.lastName = lastName;
|
|
81
|
+
|
|
82
|
+
// Add any additional custom fields
|
|
83
|
+
console.log('\nAdd custom fields (key=value format, or press Enter to finish):');
|
|
84
|
+
while (true) {
|
|
85
|
+
const customField = await askQuestion('Custom field (key=value): ');
|
|
86
|
+
if (!customField) break;
|
|
87
|
+
|
|
88
|
+
const [key, ...valueParts] = customField.split('=');
|
|
89
|
+
const value = valueParts.join('=');
|
|
90
|
+
if (key && value) {
|
|
91
|
+
testDataObj[key.trim()] = value.trim();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
testData.testData = testDataObj;
|
|
96
|
+
|
|
97
|
+
// Display collected data
|
|
98
|
+
console.log('\nš Collected Test Data:');
|
|
99
|
+
console.log('ā'.repeat(40));
|
|
100
|
+
console.log(JSON.stringify(testData, null, 2));
|
|
101
|
+
|
|
102
|
+
const confirm = await askQuestion('\nConfirm test data? (y/n): ');
|
|
103
|
+
if (confirm.toLowerCase() !== 'y') {
|
|
104
|
+
console.log('ā Test data collection cancelled');
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return testData;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function runInteractiveRecorder() {
|
|
112
|
+
console.log('\nš¬ Interactive Test Recorder');
|
|
113
|
+
console.log('ā'.repeat(50));
|
|
114
|
+
console.log('Record browser interactions step by step!');
|
|
115
|
+
console.log('Commands:');
|
|
116
|
+
console.log('⢠Type natural language commands (e.g., "click login button")');
|
|
117
|
+
console.log('⢠Type "done" to stop recording and generate test');
|
|
118
|
+
console.log('⢠Each step will be recorded with screenshots');
|
|
119
|
+
console.log('ā'.repeat(50));
|
|
120
|
+
|
|
121
|
+
// Collect test data first
|
|
122
|
+
const testData = await collectTestData();
|
|
123
|
+
if (!testData) {
|
|
124
|
+
console.log('š Exiting...');
|
|
125
|
+
rl.close();
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const framework = new EnhancedBrowserTestFramework();
|
|
130
|
+
const recorder = new TestRecorder(framework, testData);
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
// Initialize framework
|
|
134
|
+
console.log('\nš Initializing browser...');
|
|
135
|
+
await framework.initialize();
|
|
136
|
+
|
|
137
|
+
// Start recording
|
|
138
|
+
const recordingId = await recorder.startRecording();
|
|
139
|
+
|
|
140
|
+
// Navigate to the site
|
|
141
|
+
console.log(`\nš Navigating to: ${testData.site}`);
|
|
142
|
+
await framework.tools.navigate({ url: testData.site });
|
|
143
|
+
|
|
144
|
+
// Record the navigation step
|
|
145
|
+
await recorder.recordStep(
|
|
146
|
+
`Navigate to ${testData.site}`,
|
|
147
|
+
'navigate',
|
|
148
|
+
{ url: testData.site },
|
|
149
|
+
'Navigation completed'
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
console.log('\nš¬ Ready for interactive commands!');
|
|
153
|
+
console.log('Type your commands or "done" to finish recording.\n');
|
|
154
|
+
|
|
155
|
+
// Interactive command loop
|
|
156
|
+
while (true) {
|
|
157
|
+
const prompt = await askQuestion('š¬ Next step: ');
|
|
158
|
+
|
|
159
|
+
if (prompt.toLowerCase() === 'done') {
|
|
160
|
+
console.log('\nš Stopping recording...');
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (!prompt.trim()) {
|
|
165
|
+
console.log('ā ļø Please enter a command or "done" to finish.');
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
// Execute the command using the framework's AI agent
|
|
171
|
+
console.log(`\nš¤ Processing: "${prompt}"`);
|
|
172
|
+
|
|
173
|
+
// Use the AI agent to interpret and execute the command
|
|
174
|
+
const result = await framework.runTask(prompt, `Interactive-Step-${Date.now()}`);
|
|
175
|
+
|
|
176
|
+
// Record this step
|
|
177
|
+
await recorder.recordStep(
|
|
178
|
+
prompt,
|
|
179
|
+
'ai-agent',
|
|
180
|
+
{ command: prompt },
|
|
181
|
+
result.result || 'Command executed by AI agent'
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
console.log(`ā
Step completed: ${result.result || 'Success'}`);
|
|
185
|
+
|
|
186
|
+
} catch (error) {
|
|
187
|
+
console.log(`ā Error executing command: ${error.message}`);
|
|
188
|
+
|
|
189
|
+
// Still record the failed attempt
|
|
190
|
+
await recorder.recordStep(
|
|
191
|
+
prompt,
|
|
192
|
+
'error',
|
|
193
|
+
{ error: error.message },
|
|
194
|
+
`Error: ${error.message}`
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Stop recording and generate files
|
|
200
|
+
const recordingResult = await recorder.stopRecording();
|
|
201
|
+
|
|
202
|
+
console.log('\nš Recording Complete!');
|
|
203
|
+
console.log('ā'.repeat(40));
|
|
204
|
+
console.log(`š Recording ID: ${recordingResult.recordingId}`);
|
|
205
|
+
console.log(`š Artifacts: ${recordingResult.recordingPath}`);
|
|
206
|
+
console.log(`š§Ŗ Steps recorded: ${recordingResult.steps}`);
|
|
207
|
+
console.log(`š Test file generated in tests/ folder`);
|
|
208
|
+
|
|
209
|
+
} catch (error) {
|
|
210
|
+
console.error(`š„ Error in interactive recorder: ${error.message}`);
|
|
211
|
+
} finally {
|
|
212
|
+
await framework.cleanup();
|
|
213
|
+
rl.close();
|
|
214
|
+
rl.close();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Run the interactive recorder
|
|
219
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
220
|
+
runInteractiveRecorder().catch(console.error);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export { runInteractiveRecorder, collectTestData };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Endorphin e2e AI test framework>
|
|
2
|
+
// Copyright (C) 2025 Redstudio Agency
|
|
3
|
+
|
|
4
|
+
// This program is free software: you can redistribute it and/or modify
|
|
5
|
+
// it under the terms of the GNU Affero General Public License as
|
|
6
|
+
// published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
// License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
// This program is distributed in the hope that it will be useful,
|
|
10
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
// GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
export { runInteractiveRecorder as EnhancedInteractiveRecorder } from './enhanced-interactive-recorder.js';
|
|
18
|
+
// Note: interactive-test.js is deprecated and shows upgrade notice only
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Endorphin e2e AI test framework>
|
|
2
|
+
// Copyright (C) 2025 Redstudio Agency
|
|
3
|
+
|
|
4
|
+
// This program is free software: you can redistribute it and/or modify
|
|
5
|
+
// it under the terms of the GNU Affero General Public License as
|
|
6
|
+
// published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
// License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
// This program is distributed in the hope that it will be useful,
|
|
10
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
// GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
// DEPRECATED: This file has been replaced by enhanced-interactive-recorder.js
|
|
18
|
+
// This file is kept for backward compatibility
|
|
19
|
+
|
|
20
|
+
console.log('\nā ļø NOTICE: This interactive mode has been upgraded!');
|
|
21
|
+
console.log('ā'.repeat(60));
|
|
22
|
+
console.log('š¬ Enhanced Interactive Test Recorder is now available');
|
|
23
|
+
console.log('š Features: Step-by-step recording, test data collection, and more');
|
|
24
|
+
console.log('');
|
|
25
|
+
console.log('Please use:');
|
|
26
|
+
console.log(' npm run interactive');
|
|
27
|
+
console.log('');
|
|
28
|
+
console.log('Or run directly:');
|
|
29
|
+
console.log(' node framework/interactive/enhanced-interactive-recorder.js');
|
|
30
|
+
console.log('ā'.repeat(60));
|
|
31
|
+
console.log('');
|
|
32
|
+
|
|
33
|
+
process.exit(0);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Endorphin e2e AI test framework>
|
|
2
|
+
// Copyright (C) 2025 Redstudio Agency
|
|
3
|
+
|
|
4
|
+
// This program is free software: you can redistribute it and/or modify
|
|
5
|
+
// it under the terms of the GNU Affero General Public License as
|
|
6
|
+
// published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
// License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
// This program is distributed in the hope that it will be useful,
|
|
10
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
// GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
// DEPRECATED: This file has been replaced by enhanced-interactive-recorder.js
|
|
18
|
+
// This file is kept for backward compatibility
|
|
19
|
+
|
|
20
|
+
console.log('\nā ļø NOTICE: This interactive mode has been upgraded!');
|
|
21
|
+
console.log('ā'.repeat(60));
|
|
22
|
+
console.log('š¬ Enhanced Interactive Test Recorder is now available');
|
|
23
|
+
console.log('š Features: Step-by-step recording, test data collection, and more');
|
|
24
|
+
console.log('');
|
|
25
|
+
console.log('Please use:');
|
|
26
|
+
console.log(' npm run interactive');
|
|
27
|
+
console.log('');
|
|
28
|
+
console.log('Or run directly:');
|
|
29
|
+
console.log(' node framework/interactive/enhanced-interactive-recorder.js');
|
|
30
|
+
console.log('ā'.repeat(60));
|
|
31
|
+
console.log('');
|
|
32
|
+
|
|
33
|
+
process.exit(0);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Endorphin e2e AI test framework
|
|
2
|
+
// Copyright (C) 2025 Redstudio Agency
|
|
3
|
+
|
|
4
|
+
// This program is free software: you can redistribute it and/or modify
|
|
5
|
+
// it under the terms of the GNU Affero General Public License as
|
|
6
|
+
// published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
// License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
// This program is distributed in the hope that it will be useful,
|
|
10
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
// GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
import { EnhancedBrowserTestFramework } from './index.js';
|
|
18
|
+
|
|
19
|
+
// Re-export the framework for compatibility
|
|
20
|
+
export { EnhancedBrowserTestFramework };
|
|
21
|
+
|
|
22
|
+
// Export test discovery functions for CLI
|
|
23
|
+
export {
|
|
24
|
+
runSingleTestById,
|
|
25
|
+
runTestsByTag,
|
|
26
|
+
runTestsByPriority,
|
|
27
|
+
runAllTests,
|
|
28
|
+
listAllTests
|
|
29
|
+
} from './core/test-discovery.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Endorphin e2e AI test framework>
|
|
2
|
+
// Copyright (C) 2025 Redstudio Agency
|
|
3
|
+
|
|
4
|
+
// This program is free software: you can redistribute it and/or modify
|
|
5
|
+
// it under the terms of the GNU Affero General Public License as
|
|
6
|
+
// published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
// License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
// This program is distributed in the hope that it will be useful,
|
|
10
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
// GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|