endorphin-ai 0.1.0 โ 0.2.1
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/README.md
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<img src="./doc/images/endorphin.
|
|
2
|
+
<img src="./doc/images/endorphin-ai-logo-no-bg.png" alt="Endorphin Logo" width="200" />
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
# ๐ ENDORPHIN
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
## E2E Testing Reinvented with AI
|
|
7
7
|
</div>
|
|
8
8
|
|
|
9
9
|
Write tests in plain English. Let AI generate, validate, and fix them automatically.
|
|
10
10
|
|
|
11
|
+
<div align="center">
|
|
12
|
+
<img src="./doc/images/playwright-logo.png" alt="Playwright" height="40" />
|
|
13
|
+
<span style="margin: 10px 15px; font-size: 24px; display: inline-block; vertical-align: middle;">+</span>
|
|
14
|
+
<img src="./doc/images/langchain-logo.png" alt="LangChain" height="40" />
|
|
15
|
+
</div>
|
|
16
|
+
|
|
11
17
|
A powerful, modular browser automation framework using AI-powered testing with LangChain, OpenAI GPT-4o, and Playwright. Provides intelligent browser automation with automatic element detection, visual validation, and comprehensive test management.
|
|
12
18
|
|
|
13
19
|
## ๐ Quick Start
|
|
14
20
|
|
|
15
21
|
### Installation
|
|
16
22
|
```bash
|
|
23
|
+
# Local installation (recommended)
|
|
24
|
+
npm install endorphin-ai
|
|
25
|
+
|
|
26
|
+
# Global installation (optional)
|
|
17
27
|
npm install -g endorphin-ai
|
|
18
28
|
```
|
|
19
29
|
|
|
@@ -23,17 +33,28 @@ npm install -g endorphin-ai
|
|
|
23
33
|
mkdir my-test-project && cd my-test-project
|
|
24
34
|
```
|
|
25
35
|
|
|
26
|
-
2.
|
|
36
|
+
2. Initialize with ES modules:
|
|
37
|
+
```bash
|
|
38
|
+
npm init -y
|
|
39
|
+
npm pkg set type="module"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
3. Install Endorphin AI:
|
|
43
|
+
```bash
|
|
44
|
+
npm install endorphin-ai
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
4. Set up your `.env` file with your OpenAI API key:
|
|
27
48
|
```env
|
|
28
49
|
OPENAI_API_KEY=your_api_key_here
|
|
29
50
|
```
|
|
30
51
|
|
|
31
|
-
|
|
52
|
+
5. Create tests directory:
|
|
32
53
|
```bash
|
|
33
54
|
mkdir tests
|
|
34
55
|
```
|
|
35
56
|
|
|
36
|
-
|
|
57
|
+
6. Create your first test file `tests/login-test.js`:
|
|
37
58
|
```javascript
|
|
38
59
|
export const QE001 = {
|
|
39
60
|
id: "QE-001",
|
|
@@ -55,64 +76,74 @@ npm install -g endorphin-ai
|
|
|
55
76
|
};
|
|
56
77
|
```
|
|
57
78
|
|
|
79
|
+
7. Add scripts to your `package.json`:
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"scripts": {
|
|
83
|
+
"test": "endorphin run test all",
|
|
84
|
+
"test:smoke": "endorphin run test --tag smoke",
|
|
85
|
+
"test:auth": "endorphin run test --tag authentication",
|
|
86
|
+
"test:single": "endorphin run test",
|
|
87
|
+
"test:record": "endorphin run test-recorder"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
58
92
|
### Usage Commands
|
|
59
93
|
|
|
60
94
|
#### ๐งช Run Specific Test
|
|
61
95
|
```bash
|
|
96
|
+
# Using npm scripts (recommended)
|
|
97
|
+
npm run test:single QE-001
|
|
98
|
+
|
|
99
|
+
# Using npx
|
|
100
|
+
npx endorphin run test QE-001
|
|
101
|
+
|
|
102
|
+
# Global installation
|
|
62
103
|
endorphin run test QE-001
|
|
63
104
|
```
|
|
64
105
|
|
|
65
106
|
#### ๐ท๏ธ Run Tests by Category
|
|
66
107
|
```bash
|
|
67
|
-
#
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
# High priority tests
|
|
71
|
-
endorphin run test --priority High
|
|
108
|
+
# Using npm scripts
|
|
109
|
+
npm run test:smoke
|
|
110
|
+
npm run test:auth
|
|
72
111
|
|
|
73
|
-
#
|
|
74
|
-
endorphin run test --tag
|
|
112
|
+
# Using npx/global
|
|
113
|
+
npx endorphin run test --tag authentication
|
|
114
|
+
npx endorphin run test --priority High
|
|
75
115
|
```
|
|
76
116
|
|
|
77
117
|
#### ๐ฏ Run All Tests
|
|
78
118
|
```bash
|
|
79
|
-
|
|
119
|
+
# Using npm scripts
|
|
120
|
+
npm test
|
|
121
|
+
|
|
122
|
+
# Using npx/global
|
|
123
|
+
npx endorphin run test all
|
|
80
124
|
```
|
|
81
125
|
|
|
82
126
|
#### ๐ฌ Test Recorder Mode
|
|
83
127
|
```bash
|
|
84
|
-
#
|
|
85
|
-
|
|
128
|
+
# Using npm scripts
|
|
129
|
+
npm run test:record
|
|
130
|
+
|
|
131
|
+
# Using npx/global
|
|
132
|
+
npx endorphin run test-recorder
|
|
86
133
|
```
|
|
87
134
|
|
|
88
135
|
## ๐๏ธ Framework Architecture
|
|
89
136
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
โ โโโ browser-framework.js # Main framework class
|
|
101
|
-
โ โโโ config-loader.js # Configuration management
|
|
102
|
-
โ โโโ test-discovery.js # Test discovery & execution
|
|
103
|
-
โ โโโ test-manager.js # Test management
|
|
104
|
-
โ โโโ test-runner.js # Test execution
|
|
105
|
-
โ โโโ test-session.js # Session tracking
|
|
106
|
-
โโโ tools/ # Browser automation tools
|
|
107
|
-
โ โโโ navigation.js # Page navigation
|
|
108
|
-
โ โโโ interaction.js # Clicks, form filling
|
|
109
|
-
โ โโโ verification.js # Element verification
|
|
110
|
-
โ โโโ content.js # Page content analysis
|
|
111
|
-
โ โโโ utilities.js # Screenshots, waits
|
|
112
|
-
โโโ demos/ # Framework demonstrations
|
|
113
|
-
โโโ interactive/ # Interactive testing tools
|
|
114
|
-
โโโ testing/ # Testing utilities
|
|
115
|
-
```
|
|
137
|
+
Endorphin AI is built with a modular, extensible architecture designed for reliability and maintainability.
|
|
138
|
+
|
|
139
|
+
๐ **[View detailed Framework Architecture documentation](./doc/Framework-Architecture.md)**
|
|
140
|
+
|
|
141
|
+
### Key Components
|
|
142
|
+
- **Core Framework**: Main test execution engine and session management
|
|
143
|
+
- **Browser Tools**: Intelligent automation tools powered by AI
|
|
144
|
+
- **Configuration System**: Flexible, hierarchical configuration management
|
|
145
|
+
- **Test Discovery**: Automatic test file detection and loading
|
|
146
|
+
- **Interactive Tools**: Real-time test creation and debugging
|
|
116
147
|
|
|
117
148
|
## โ๏ธ Configuration
|
|
118
149
|
|
|
@@ -122,45 +153,20 @@ Endorphin AI works out of the box with sensible defaults, but you can customize
|
|
|
122
153
|
```javascript
|
|
123
154
|
// endorphin.config.js
|
|
124
155
|
export default {
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
},
|
|
135
|
-
|
|
136
|
-
// AI configuration
|
|
137
|
-
ai: {
|
|
138
|
-
model: 'gpt-4o-mini', // OpenAI model to use
|
|
139
|
-
temperature: 0.1, // AI creativity (0-1)
|
|
140
|
-
maxRetries: 3 // Max retries for AI calls
|
|
141
|
-
},
|
|
142
|
-
|
|
143
|
-
// Test execution configuration
|
|
144
|
-
execution: {
|
|
145
|
-
timeout: 60000, // Test timeout in milliseconds
|
|
146
|
-
parallel: 1, // Number of parallel tests
|
|
147
|
-
screenshots: true, // Take screenshots on failure
|
|
148
|
-
testsDirectory: './tests', // Directory containing test files
|
|
149
|
-
dataDirectory: './data' // Directory containing test data
|
|
156
|
+
// Global test settings
|
|
157
|
+
defaultTimeout: 30000,
|
|
158
|
+
headless: false,
|
|
159
|
+
viewport: { width: 1280, height: 720 },
|
|
160
|
+
|
|
161
|
+
// Default test data
|
|
162
|
+
testData: {
|
|
163
|
+
baseUrl: "https://staging.example.com",
|
|
164
|
+
adminEmail: "admin@example.com"
|
|
150
165
|
},
|
|
151
|
-
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
baseUrl: 'http://localhost:3000'
|
|
156
|
-
},
|
|
157
|
-
staging: {
|
|
158
|
-
baseUrl: 'https://staging.example.com'
|
|
159
|
-
},
|
|
160
|
-
production: {
|
|
161
|
-
baseUrl: 'https://example.com'
|
|
162
|
-
}
|
|
163
|
-
}
|
|
166
|
+
|
|
167
|
+
// Result settings
|
|
168
|
+
screenshots: true,
|
|
169
|
+
recordVideo: false
|
|
164
170
|
};
|
|
165
171
|
```
|
|
166
172
|
|
|
@@ -168,23 +174,17 @@ export default {
|
|
|
168
174
|
You can override configuration with CLI flags:
|
|
169
175
|
|
|
170
176
|
```bash
|
|
171
|
-
#
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
endorphin run test all --viewport 1920x1080
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
endorphin run test all --
|
|
182
|
-
|
|
183
|
-
# Use different AI model
|
|
184
|
-
endorphin run test all --model gpt-4
|
|
185
|
-
|
|
186
|
-
# Set environment
|
|
187
|
-
endorphin run test all --env staging
|
|
177
|
+
# Using npm scripts with -- to pass flags
|
|
178
|
+
npm test -- --browser firefox
|
|
179
|
+
npm run test:single QE-001 -- --no-headless
|
|
180
|
+
|
|
181
|
+
# Using npx/global
|
|
182
|
+
npx endorphin run test all --browser firefox
|
|
183
|
+
npx endorphin run test QE-001 --no-headless
|
|
184
|
+
npx endorphin run test all --viewport 1920x1080
|
|
185
|
+
npx endorphin run test all --parallel 3
|
|
186
|
+
npx endorphin run test all --model gpt-4
|
|
187
|
+
npx endorphin run test all --env staging
|
|
188
188
|
```
|
|
189
189
|
|
|
190
190
|
## ๐ Test Categories
|
|
@@ -265,48 +265,6 @@ export const QE002 = {
|
|
|
265
265
|
};
|
|
266
266
|
```
|
|
267
267
|
|
|
268
|
-
## โ๏ธ Configuration
|
|
269
|
-
|
|
270
|
-
### Optional: endorphin.config.js
|
|
271
|
-
```javascript
|
|
272
|
-
export default {
|
|
273
|
-
// Global test settings
|
|
274
|
-
defaultTimeout: 30000,
|
|
275
|
-
headless: false,
|
|
276
|
-
viewport: { width: 1280, height: 720 },
|
|
277
|
-
|
|
278
|
-
// Default test data
|
|
279
|
-
testData: {
|
|
280
|
-
baseUrl: "https://staging.example.com",
|
|
281
|
-
adminEmail: "admin@example.com"
|
|
282
|
-
},
|
|
283
|
-
|
|
284
|
-
// Result settings
|
|
285
|
-
screenshots: true,
|
|
286
|
-
recordVideo: false
|
|
287
|
-
};
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
## ๐ง Configuration
|
|
291
|
-
|
|
292
|
-
### Browser Configuration (`framework/config/browser-config.js`)
|
|
293
|
-
- Browser launch options (headless mode, viewport size)
|
|
294
|
-
- Timeouts and delays
|
|
295
|
-
- Screenshot settings
|
|
296
|
-
- Page loading options
|
|
297
|
-
|
|
298
|
-
### AI Agent Configuration (`framework/config/agent-config.js`)
|
|
299
|
-
- OpenAI API settings
|
|
300
|
-
- Model selection (GPT-4o)
|
|
301
|
-
- Recursion limits and timeouts
|
|
302
|
-
- Stop phrases for test completion
|
|
303
|
-
- Execution timing settings
|
|
304
|
-
|
|
305
|
-
### Path Configuration (`framework/config/paths.js`)
|
|
306
|
-
- Test result directories
|
|
307
|
-
- Recording locations
|
|
308
|
-
- Screenshot storage
|
|
309
|
-
|
|
310
268
|
## ๐ Test Results
|
|
311
269
|
|
|
312
270
|
Each test execution creates:
|
|
@@ -318,26 +276,21 @@ Each test execution creates:
|
|
|
318
276
|
|
|
319
277
|
### Example Test Output
|
|
320
278
|
```
|
|
321
|
-
๐ฏ Running
|
|
322
|
-
๐ Task: Test the login functionality with valid credentials
|
|
323
|
-
โฐ Started at: 2025-06-19T05:36:37.705Z
|
|
324
|
-
|
|
325
|
-
๐ Created test session: qe-001_2025-06-19T05-36-37-706Z
|
|
326
|
-
๐ Navigate to: https://qafromla.herokuapp.com
|
|
279
|
+
๐ฏ Running: QE-001 - Basic Login Test
|
|
327
280
|
๐ธ Screenshot taken: step-1-navigation.png
|
|
328
|
-
๐ Found login elements
|
|
329
|
-
๐ Filling login form...
|
|
330
281
|
โ
Login successful - test completed!
|
|
331
|
-
|
|
332
282
|
๐ Result: PASSED
|
|
333
|
-
๐ Results: test-result/qe-001_2025-06-19T05-36-37-706Z
|
|
334
283
|
```
|
|
335
284
|
|
|
336
285
|
## ๐ฎ Interactive Features
|
|
337
286
|
|
|
338
287
|
### Custom Test Creation
|
|
339
288
|
```bash
|
|
340
|
-
npm
|
|
289
|
+
# Using npm scripts
|
|
290
|
+
npm run test:record
|
|
291
|
+
|
|
292
|
+
# Using npx/global
|
|
293
|
+
npx endorphin run test-recorder
|
|
341
294
|
```
|
|
342
295
|
Create tests on-the-fly with guided prompts:
|
|
343
296
|
- Custom navigation tasks
|
|
@@ -345,114 +298,11 @@ Create tests on-the-fly with guided prompts:
|
|
|
345
298
|
- Login test automation
|
|
346
299
|
- Content verification
|
|
347
300
|
|
|
348
|
-
### Framework Demonstration
|
|
349
|
-
```bash
|
|
350
|
-
npm run interactive-demo
|
|
351
|
-
```
|
|
352
|
-
Runs pre-built demonstration tests showcasing:
|
|
353
|
-
- Navigation capabilities
|
|
354
|
-
- Form interaction
|
|
355
|
-
- Content analysis
|
|
356
|
-
- Result tracking
|
|
357
|
-
|
|
358
301
|
## ๐ Browser Automation Tools
|
|
359
302
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
### Navigation Tools
|
|
363
|
-
- **navigate**: Smart URL navigation with wait conditions
|
|
364
|
-
- **getPageContent**: Intelligent HTML analysis for element detection
|
|
365
|
-
|
|
366
|
-
### Interaction Tools
|
|
367
|
-
- **click**: AI-powered element clicking with automatic waiting
|
|
368
|
-
- **fill**: Smart form filling with focus management
|
|
369
|
-
- **clearField**: Intelligent field clearing before input
|
|
370
|
-
|
|
371
|
-
### Verification Tools
|
|
372
|
-
- **verifyElement**: Element visibility and interaction verification
|
|
373
|
-
- **getElementInfo**: Detailed element analysis and properties
|
|
374
|
-
|
|
375
|
-
### Utility Tools
|
|
376
|
-
- **wait**: Configurable delays and timing control
|
|
377
|
-
- **screenshot**: High-quality visual documentation
|
|
378
|
-
|
|
379
|
-
## ๐ฎ Command Examples
|
|
380
|
-
|
|
381
|
-
### Basic Commands
|
|
382
|
-
```bash
|
|
383
|
-
# Run specific test
|
|
384
|
-
endorphin run test QE-001
|
|
385
|
-
|
|
386
|
-
# Run all tests
|
|
387
|
-
endorphin run test all
|
|
388
|
-
|
|
389
|
-
# Run by priority
|
|
390
|
-
endorphin run test --priority High
|
|
391
|
-
endorphin run test --priority Medium
|
|
392
|
-
|
|
393
|
-
# Run by tags
|
|
394
|
-
endorphin run test --tag authentication
|
|
395
|
-
endorphin run test --tag smoke
|
|
396
|
-
endorphin run test --tag checkout
|
|
303
|
+
Intelligent AI-powered tools for navigation, interaction, verification, and utilities.
|
|
397
304
|
|
|
398
|
-
|
|
399
|
-
endorphin run test-recorder
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
### Multiple Tag Support
|
|
403
|
-
```bash
|
|
404
|
-
# Run tests matching any of these tags
|
|
405
|
-
endorphin run test --tag "authentication,smoke"
|
|
406
|
-
|
|
407
|
-
# Run high priority authentication tests
|
|
408
|
-
endorphin run test --priority High --tag authentication
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
## ๐ Getting Started Examples
|
|
412
|
-
|
|
413
|
-
### Quick Smoke Test
|
|
414
|
-
```bash
|
|
415
|
-
endorphin run test --tag smoke
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
### Authentication Testing
|
|
419
|
-
```bash
|
|
420
|
-
endorphin run test --tag authentication
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
### Complete Test Suite
|
|
424
|
-
```bash
|
|
425
|
-
endorphin run test all
|
|
426
|
-
```
|
|
427
|
-
|
|
428
|
-
### Create Custom Test
|
|
429
|
-
```bash
|
|
430
|
-
endorphin run test-recorder
|
|
431
|
-
# Follow prompts to create your own test
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
### Example Test File
|
|
435
|
-
Create `tests/my-first-test.js`:
|
|
436
|
-
```javascript
|
|
437
|
-
export const QE001 = {
|
|
438
|
-
id: "QE-001",
|
|
439
|
-
name: "Homepage Navigation Test",
|
|
440
|
-
description: "Verify main navigation works correctly",
|
|
441
|
-
priority: "High",
|
|
442
|
-
tags: ["navigation", "smoke"],
|
|
443
|
-
site: "https://example.com/",
|
|
444
|
-
task: `Navigate to https://example.com/.
|
|
445
|
-
Click on "About" link in navigation.
|
|
446
|
-
Wait 2 seconds for page load.
|
|
447
|
-
Verify page title contains "About".
|
|
448
|
-
Take a screenshot.`
|
|
449
|
-
};
|
|
450
|
-
```
|
|
451
|
-
|
|
452
|
-
Then run it:
|
|
453
|
-
```bash
|
|
454
|
-
endorphin run test QE-001
|
|
455
|
-
```
|
|
305
|
+
๐ **[View detailed tool documentation](./doc/Framework-Architecture.md#browser-automation-tools)**
|
|
456
306
|
|
|
457
307
|
## ๐ Features
|
|
458
308
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// Endorphin e2e AI test framework
|
|
2
|
-
// Copyright (C)
|
|
1
|
+
// Endorphin e2e AI test framework
|
|
2
|
+
// Copyright (C) 2025 Redstudio Agency
|
|
3
3
|
|
|
4
4
|
// This program is free software: you can redistribute it and/or modify
|
|
5
5
|
// it under the terms of the GNU Affero General Public License as
|
|
@@ -34,31 +34,32 @@ export class TestRecorder {
|
|
|
34
34
|
this.stepCounter = 0;
|
|
35
35
|
this.recordingId = null;
|
|
36
36
|
this.recordingPath = null;
|
|
37
|
-
this.
|
|
37
|
+
this.stepsPath = null;
|
|
38
38
|
this.isRecording = false;
|
|
39
|
+
this.startTime = null;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
/**
|
|
42
43
|
* Start recording session
|
|
43
44
|
*/
|
|
44
45
|
async startRecording() {
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
this.startTime = new Date();
|
|
47
|
+
const timestamp = Date.now();
|
|
48
|
+
this.recordingId = `${this.testData.id || 'REC'}-${timestamp}`;
|
|
47
49
|
|
|
48
|
-
// Create recording directories
|
|
49
|
-
|
|
50
|
-
this.
|
|
51
|
-
this.screenshotsPath = path.join(this.recordingPath, 'screenshots');
|
|
50
|
+
// Create recording directories in USER project (not framework)
|
|
51
|
+
this.recordingPath = path.join(process.cwd(), 'test-recorder', this.recordingId);
|
|
52
|
+
this.stepsPath = path.join(this.recordingPath, 'steps');
|
|
52
53
|
|
|
53
54
|
await fs.mkdir(this.recordingPath, { recursive: true });
|
|
54
|
-
await fs.mkdir(this.
|
|
55
|
+
await fs.mkdir(this.stepsPath, { recursive: true });
|
|
55
56
|
|
|
56
57
|
this.isRecording = true;
|
|
57
58
|
this.stepCounter = 0;
|
|
58
59
|
this.steps = [];
|
|
59
60
|
|
|
60
|
-
console.log(
|
|
61
|
-
console.log(
|
|
61
|
+
console.log('Recording session:', this.recordingId);
|
|
62
|
+
console.log('Artifacts will be saved to:', this.recordingPath);
|
|
62
63
|
|
|
63
64
|
return this.recordingId;
|
|
64
65
|
}
|
|
@@ -66,69 +67,73 @@ export class TestRecorder {
|
|
|
66
67
|
/**
|
|
67
68
|
* Record a step with tool call and screenshot
|
|
68
69
|
*/
|
|
69
|
-
async recordStep(
|
|
70
|
+
async recordStep(description, type, data, result) {
|
|
70
71
|
if (!this.isRecording) return;
|
|
71
72
|
|
|
72
73
|
this.stepCounter++;
|
|
73
|
-
const stepId =
|
|
74
|
+
const stepId = String(this.stepCounter).padStart(3, '0');
|
|
75
|
+
const stepFolderName = `${stepId}-${this.sanitizeFileName(description)}`;
|
|
76
|
+
const stepPath = path.join(this.stepsPath, stepFolderName);
|
|
74
77
|
|
|
75
|
-
//
|
|
76
|
-
|
|
78
|
+
// Create step folder
|
|
79
|
+
await fs.mkdir(stepPath, { recursive: true });
|
|
77
80
|
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
// Take BEFORE screenshot
|
|
82
|
+
const beforeScreenshot = path.join(stepPath, 'before.png');
|
|
83
|
+
await this.framework.page.screenshot({ path: beforeScreenshot, fullPage: true });
|
|
84
|
+
|
|
85
|
+
// Record step info
|
|
86
|
+
const stepInfo = {
|
|
80
87
|
stepNumber: this.stepCounter,
|
|
88
|
+
description,
|
|
89
|
+
type,
|
|
81
90
|
timestamp: new Date().toISOString(),
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
},
|
|
87
|
-
result: result,
|
|
88
|
-
screenshots: {
|
|
89
|
-
before: screenshotBefore
|
|
90
|
-
}
|
|
91
|
+
data,
|
|
92
|
+
result,
|
|
93
|
+
beforeScreenshot: 'before.png',
|
|
94
|
+
afterScreenshot: 'after.png'
|
|
91
95
|
};
|
|
92
96
|
|
|
93
|
-
// Take screenshot
|
|
94
|
-
await
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
+
// Take AFTER screenshot (small delay to ensure DOM updates)
|
|
98
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
99
|
+
const afterScreenshot = path.join(stepPath, 'after.png');
|
|
100
|
+
await this.framework.page.screenshot({ path: afterScreenshot, fullPage: true });
|
|
101
|
+
|
|
102
|
+
// Save step info
|
|
103
|
+
await fs.writeFile(
|
|
104
|
+
path.join(stepPath, 'step-info.json'),
|
|
105
|
+
JSON.stringify(stepInfo, null, 2)
|
|
106
|
+
);
|
|
97
107
|
|
|
98
|
-
|
|
108
|
+
// Add to steps array
|
|
109
|
+
this.steps.push({
|
|
110
|
+
...stepInfo,
|
|
111
|
+
stepFolder: stepFolderName
|
|
112
|
+
});
|
|
99
113
|
|
|
100
|
-
|
|
101
|
-
console.log(`\n๐ Step ${this.stepCounter}: ${prompt}`);
|
|
102
|
-
console.log(`๐ง Tool: ${toolName}`);
|
|
103
|
-
console.log(`๐ธ Screenshots: ${screenshotBefore}, ${screenshotAfter}`);
|
|
114
|
+
console.log(`Step ${this.stepCounter} recorded: ${description}`);
|
|
104
115
|
|
|
105
|
-
// Show visual feedback in browser
|
|
106
|
-
await this.showBrowserFeedback(
|
|
116
|
+
// Show visual feedback in browser
|
|
117
|
+
await this.showBrowserFeedback(this.stepCounter, description, type);
|
|
107
118
|
|
|
108
|
-
return
|
|
119
|
+
return stepInfo;
|
|
109
120
|
}
|
|
110
121
|
|
|
111
122
|
/**
|
|
112
|
-
*
|
|
123
|
+
* Sanitize filename for step folders
|
|
113
124
|
*/
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
});
|
|
121
|
-
return `${filename}.png`;
|
|
122
|
-
} catch (error) {
|
|
123
|
-
console.log(`โ ๏ธ Screenshot failed: ${error.message}`);
|
|
124
|
-
return null;
|
|
125
|
-
}
|
|
125
|
+
sanitizeFileName(description) {
|
|
126
|
+
return description
|
|
127
|
+
.toLowerCase()
|
|
128
|
+
.replace(/[^a-z0-9\s-]/g, '')
|
|
129
|
+
.replace(/\s+/g, '-')
|
|
130
|
+
.substring(0, 30);
|
|
126
131
|
}
|
|
127
132
|
|
|
128
133
|
/**
|
|
129
134
|
* Show visual feedback in browser
|
|
130
135
|
*/
|
|
131
|
-
async showBrowserFeedback(stepId,
|
|
136
|
+
async showBrowserFeedback(stepId, description, type) {
|
|
132
137
|
try {
|
|
133
138
|
await this.framework.page.evaluate((data) => {
|
|
134
139
|
// Remove previous feedback
|
|
@@ -155,9 +160,9 @@ export class TestRecorder {
|
|
|
155
160
|
`;
|
|
156
161
|
|
|
157
162
|
overlay.innerHTML = `
|
|
158
|
-
<div style="font-weight: bold; margin-bottom: 8px;"
|
|
159
|
-
<div style="margin-bottom: 5px;"><strong>Action:</strong> ${data.
|
|
160
|
-
<div><strong>
|
|
163
|
+
<div style="font-weight: bold; margin-bottom: 8px;">Recording Step ${data.stepId}</div>
|
|
164
|
+
<div style="margin-bottom: 5px;"><strong>Action:</strong> ${data.description}</div>
|
|
165
|
+
<div><strong>Type:</strong> ${data.type}</div>
|
|
161
166
|
`;
|
|
162
167
|
|
|
163
168
|
// Add animation keyframes if not exists
|
|
@@ -183,7 +188,7 @@ export class TestRecorder {
|
|
|
183
188
|
}
|
|
184
189
|
}, 3000);
|
|
185
190
|
|
|
186
|
-
}, { stepId,
|
|
191
|
+
}, { stepId, description, type });
|
|
187
192
|
} catch (error) {
|
|
188
193
|
// Browser feedback is optional, don't fail if it doesn't work
|
|
189
194
|
}
|
|
@@ -231,9 +236,9 @@ export class TestRecorder {
|
|
|
231
236
|
// Generate test file
|
|
232
237
|
await this.generateTestFile();
|
|
233
238
|
|
|
234
|
-
console.log(
|
|
235
|
-
console.log(
|
|
236
|
-
console.log(
|
|
239
|
+
console.log('Recording completed:', this.recordingId);
|
|
240
|
+
console.log('Artifacts saved to:', this.recordingPath);
|
|
241
|
+
console.log('Test file generated in tests/ folder');
|
|
237
242
|
|
|
238
243
|
return {
|
|
239
244
|
recordingId: this.recordingId,
|
|
@@ -249,43 +254,39 @@ export class TestRecorder {
|
|
|
249
254
|
async generateTestFile() {
|
|
250
255
|
const testId = this.testData.id || 'QE-NEW';
|
|
251
256
|
const filename = `${testId.toLowerCase()}-recorded-test.js`;
|
|
252
|
-
|
|
257
|
+
|
|
258
|
+
// Ensure tests directory exists
|
|
259
|
+
const testsDir = path.join(process.cwd(), 'tests');
|
|
260
|
+
await fs.mkdir(testsDir, { recursive: true });
|
|
261
|
+
|
|
262
|
+
const testPath = path.join(testsDir, filename);
|
|
253
263
|
|
|
254
264
|
// Build task from recorded steps
|
|
255
265
|
const taskSteps = this.steps.map(step => {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
switch (toolName) {
|
|
260
|
-
case 'navigate':
|
|
261
|
-
return `Navigate to ${params.url}.`;
|
|
262
|
-
case 'click':
|
|
263
|
-
return `Click on "${params.selector || 'element'}".`;
|
|
264
|
-
case 'fill':
|
|
265
|
-
return `Fill "${params.selector || 'field'}" with "${params.value}".`;
|
|
266
|
-
case 'clearField':
|
|
267
|
-
return `Clear field "${params.selector}".`;
|
|
268
|
-
case 'wait':
|
|
269
|
-
return `Wait ${params.time || 1000}ms.`;
|
|
270
|
-
case 'screenshot':
|
|
271
|
-
return `Take screenshot.`;
|
|
272
|
-
default:
|
|
273
|
-
return step.prompt;
|
|
274
|
-
}
|
|
266
|
+
// For now, use generic descriptions until we implement proper task building
|
|
267
|
+
return step.description;
|
|
275
268
|
}).join(' ');
|
|
276
269
|
|
|
270
|
+
// Add "recorded" tag if not already present
|
|
271
|
+
const tags = this.testData.tags || [];
|
|
272
|
+
if (!tags.includes('recorded')) {
|
|
273
|
+
tags.push('recorded');
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const exportName = testId.replace(/-/g, '_');
|
|
277
|
+
|
|
277
278
|
const testContent = `// ${testId}: ${this.testData.name}
|
|
278
279
|
// Description: ${this.testData.description}
|
|
279
280
|
// Priority: ${this.testData.priority || 'Medium'}
|
|
280
|
-
// Tags: ${
|
|
281
|
+
// Tags: ${tags.join(', ')}
|
|
281
282
|
// Generated by Test Recorder: ${this.recordingId}
|
|
282
283
|
|
|
283
|
-
export const ${
|
|
284
|
+
export const ${exportName} = {
|
|
284
285
|
"id": "${testId}",
|
|
285
286
|
"name": "${this.testData.name}",
|
|
286
287
|
"description": "${this.testData.description}",
|
|
287
288
|
"priority": "${this.testData.priority || 'Medium'}",
|
|
288
|
-
"tags": ${JSON.stringify(
|
|
289
|
+
"tags": ${JSON.stringify(tags, null, 4)},
|
|
289
290
|
"site": "${this.testData.site}",
|
|
290
291
|
"testData": ${JSON.stringify(this.testData.testData || {}, null, 4)},
|
|
291
292
|
"task": "${taskSteps} STOP - test completed.",
|
|
@@ -295,7 +296,7 @@ export const ${testId.replace(/-/g, '')} = {
|
|
|
295
296
|
`;
|
|
296
297
|
|
|
297
298
|
await fs.writeFile(testPath, testContent);
|
|
298
|
-
console.log(
|
|
299
|
+
console.log('Test file created:', filename);
|
|
299
300
|
|
|
300
301
|
return testPath;
|
|
301
302
|
}
|
package/framework/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// Endorphin e2e AI test framework
|
|
2
|
-
// Copyright (C)
|
|
1
|
+
// Endorphin e2e AI test framework
|
|
2
|
+
// Copyright (C) 2025 Redstudio Agency
|
|
3
3
|
|
|
4
4
|
// This program is free software: you can redistribute it and/or modify
|
|
5
5
|
// it under the terms of the GNU Affero General Public License as
|
|
@@ -28,7 +28,6 @@ export { AGENT_CONFIG } from './config/agent-config.js';
|
|
|
28
28
|
export { PATHS } from './config/paths.js';
|
|
29
29
|
|
|
30
30
|
// Module exports for organized components
|
|
31
|
-
export * as Demos from './demos/index.js';
|
|
32
31
|
export * as Interactive from './interactive/index.js';
|
|
33
32
|
export * as Testing from './testing/index.js';
|
|
34
33
|
|
|
@@ -108,7 +108,7 @@ async function collectTestData() {
|
|
|
108
108
|
return testData;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
async function runInteractiveRecorder() {
|
|
111
|
+
async function runInteractiveRecorder(config = {}) {
|
|
112
112
|
console.log('\n๐ฌ Interactive Test Recorder');
|
|
113
113
|
console.log('โ'.repeat(50));
|
|
114
114
|
console.log('Record browser interactions step by step!');
|
|
@@ -126,7 +126,8 @@ async function runInteractiveRecorder() {
|
|
|
126
126
|
return;
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
// Create framework with the config from CLI
|
|
130
|
+
const framework = new EnhancedBrowserTestFramework(config);
|
|
130
131
|
const recorder = new TestRecorder(framework, testData);
|
|
131
132
|
|
|
132
133
|
try {
|
|
@@ -211,7 +212,6 @@ async function runInteractiveRecorder() {
|
|
|
211
212
|
} finally {
|
|
212
213
|
await framework.cleanup();
|
|
213
214
|
rl.close();
|
|
214
|
-
rl.close();
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "endorphin-ai",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "E2E Testing Reinvented with AI - A powerful browser automation framework using AI-powered testing with LangChain, OpenAI GPT-4o, and Playwright",
|
|
5
5
|
"main": "framework/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -13,20 +13,15 @@
|
|
|
13
13
|
"test:watch": "vitest --watch",
|
|
14
14
|
"test:ui": "vitest --ui",
|
|
15
15
|
"test:coverage": "vitest run --coverage",
|
|
16
|
+
"test:recorder": "vitest run dev-tests/test-recorder*.test.js",
|
|
16
17
|
"framework:test": "node framework/test-framework.js --test",
|
|
17
18
|
"framework:demo": "node framework/test-framework.js",
|
|
18
19
|
"framework:all": "node framework/test-framework.js --all",
|
|
19
20
|
"framework:list": "node framework/test-framework.js --list",
|
|
20
|
-
"framework:comprehensive": "node framework/test-framework.js --comprehensive",
|
|
21
|
-
"framework:QE-001": "node framework/test-framework.js --test QE-001",
|
|
22
|
-
"framework:QE-002": "node framework/test-framework.js --test QE-002",
|
|
23
21
|
"framework:auth": "node framework/test-framework.js --tag authentication",
|
|
24
22
|
"framework:smoke": "node framework/test-framework.js --tag smoke",
|
|
25
23
|
"framework:high": "node framework/test-framework.js --priority High",
|
|
26
|
-
"
|
|
27
|
-
"test-recorder": "node framework/interactive/enhanced-interactive-recorder.js",
|
|
28
|
-
"test-recorder-demo": "node framework/demos/interactive-demo.js",
|
|
29
|
-
"test-framework": "node framework/testing/test-modular-framework.js"
|
|
24
|
+
"test-recorder": "node framework/interactive/enhanced-interactive-recorder.js"
|
|
30
25
|
},
|
|
31
26
|
"keywords": [
|
|
32
27
|
"ai",
|
|
@@ -81,4 +76,4 @@
|
|
|
81
76
|
"vitest": "^2.1.8",
|
|
82
77
|
"@vitest/ui": "^2.1.8"
|
|
83
78
|
}
|
|
84
|
-
}
|
|
79
|
+
}
|