@sparkleideas/browser 3.0.0-alpha.3
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 +730 -0
- package/agents/architect.yaml +11 -0
- package/agents/coder.yaml +11 -0
- package/agents/reviewer.yaml +10 -0
- package/agents/security-architect.yaml +10 -0
- package/agents/tester.yaml +10 -0
- package/docker/Dockerfile +22 -0
- package/docker/docker-compose.yml +52 -0
- package/docker/test-fixtures/index.html +61 -0
- package/package.json +56 -0
- package/skills/browser/SKILL.md +204 -0
- package/src/agent/index.ts +35 -0
- package/src/application/browser-service.ts +570 -0
- package/src/domain/types.ts +324 -0
- package/src/index.ts +156 -0
- package/src/infrastructure/agent-browser-adapter.ts +654 -0
- package/src/infrastructure/hooks-integration.ts +170 -0
- package/src/infrastructure/memory-integration.ts +449 -0
- package/src/infrastructure/reasoningbank-adapter.ts +282 -0
- package/src/infrastructure/security-integration.ts +528 -0
- package/src/infrastructure/workflow-templates.ts +479 -0
- package/src/mcp-tools/browser-tools.ts +1210 -0
- package/src/mcp-tools/index.ts +6 -0
- package/src/skill/index.ts +24 -0
- package/tests/agent-browser-adapter.test.ts +328 -0
- package/tests/browser-service.test.ts +137 -0
- package/tests/e2e/browser-e2e.test.ts +175 -0
- package/tests/memory-integration.test.ts +277 -0
- package/tests/reasoningbank-adapter.test.ts +219 -0
- package/tests/security-integration.test.ts +194 -0
- package/tests/workflow-templates.test.ts +231 -0
- package/tmp.json +0 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +15 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sparkleideas/browser - Workflow Templates Tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
6
|
+
import {
|
|
7
|
+
WorkflowManager,
|
|
8
|
+
getWorkflowManager,
|
|
9
|
+
listWorkflows,
|
|
10
|
+
getWorkflow,
|
|
11
|
+
WORKFLOW_TEMPLATES,
|
|
12
|
+
type WorkflowTemplate,
|
|
13
|
+
} from '../src/infrastructure/workflow-templates.js';
|
|
14
|
+
|
|
15
|
+
describe('WorkflowManager', () => {
|
|
16
|
+
let manager: WorkflowManager;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
manager = new WorkflowManager();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('listTemplates', () => {
|
|
23
|
+
it('should list all templates', () => {
|
|
24
|
+
const templates = manager.listTemplates();
|
|
25
|
+
expect(templates.length).toBeGreaterThan(0);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should filter by category', () => {
|
|
29
|
+
const authTemplates = manager.listTemplates('authentication');
|
|
30
|
+
expect(authTemplates.every(t => t.category === 'authentication')).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('getTemplate', () => {
|
|
35
|
+
it('should get template by ID', () => {
|
|
36
|
+
const template = manager.getTemplate('login-basic');
|
|
37
|
+
expect(template).toBeDefined();
|
|
38
|
+
expect(template?.name).toBe('Basic Login');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should return undefined for non-existent template', () => {
|
|
42
|
+
const template = manager.getTemplate('non-existent');
|
|
43
|
+
expect(template).toBeUndefined();
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('registerTemplate', () => {
|
|
48
|
+
it('should register a custom template', () => {
|
|
49
|
+
const customTemplate: WorkflowTemplate = {
|
|
50
|
+
id: 'custom-workflow',
|
|
51
|
+
name: 'Custom Workflow',
|
|
52
|
+
description: 'A custom workflow for testing',
|
|
53
|
+
category: 'testing',
|
|
54
|
+
tags: ['custom', 'test'],
|
|
55
|
+
estimatedDuration: 1000,
|
|
56
|
+
variables: [
|
|
57
|
+
{ name: 'url', type: 'string', required: true, description: 'URL to test' },
|
|
58
|
+
],
|
|
59
|
+
steps: [
|
|
60
|
+
{ id: 'open', action: 'open', target: '\${url}' },
|
|
61
|
+
],
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
manager.registerTemplate(customTemplate);
|
|
65
|
+
const retrieved = manager.getTemplate('custom-workflow');
|
|
66
|
+
expect(retrieved).toBeDefined();
|
|
67
|
+
expect(retrieved?.name).toBe('Custom Workflow');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe('searchTemplates', () => {
|
|
72
|
+
it('should search templates by query', () => {
|
|
73
|
+
const results = manager.searchTemplates('login');
|
|
74
|
+
expect(results.length).toBeGreaterThan(0);
|
|
75
|
+
expect(results.some(t => t.name.toLowerCase().includes('login'))).toBe(true);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should search by tags', () => {
|
|
79
|
+
const results = manager.searchTemplates('scrape');
|
|
80
|
+
expect(results.length).toBeGreaterThan(0);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should return empty array for no matches', () => {
|
|
84
|
+
const results = manager.searchTemplates('xyznonexistent');
|
|
85
|
+
expect(results.length).toBe(0);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('validateVariables', () => {
|
|
90
|
+
it('should validate required variables', () => {
|
|
91
|
+
const result = manager.validateVariables('login-basic', {});
|
|
92
|
+
expect(result.valid).toBe(false);
|
|
93
|
+
expect(result.errors.some(e => e.includes('url'))).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should pass with all required variables', () => {
|
|
97
|
+
const result = manager.validateVariables('login-basic', {
|
|
98
|
+
url: 'https://example.com/login',
|
|
99
|
+
username: 'testuser',
|
|
100
|
+
password: 'testpass',
|
|
101
|
+
});
|
|
102
|
+
expect(result.valid).toBe(true);
|
|
103
|
+
expect(result.errors.length).toBe(0);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should validate number types', () => {
|
|
107
|
+
const result = manager.validateVariables('uptime-check', {
|
|
108
|
+
url: 'https://example.com',
|
|
109
|
+
timeout: 'not-a-number',
|
|
110
|
+
});
|
|
111
|
+
expect(result.errors.some(e => e.includes('timeout') && e.includes('number'))).toBe(true);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should return error for non-existent template', () => {
|
|
115
|
+
const result = manager.validateVariables('non-existent', {});
|
|
116
|
+
expect(result.valid).toBe(false);
|
|
117
|
+
expect(result.errors[0]).toContain('not found');
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe('interpolateStep', () => {
|
|
122
|
+
it('should interpolate variables in step', () => {
|
|
123
|
+
const step = {
|
|
124
|
+
id: 'test',
|
|
125
|
+
action: 'fill' as const,
|
|
126
|
+
target: '\${selector}',
|
|
127
|
+
value: '\${value}',
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const interpolated = manager.interpolateStep(step, {
|
|
131
|
+
selector: '#username',
|
|
132
|
+
value: 'testuser',
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
expect(interpolated.target).toBe('#username');
|
|
136
|
+
expect(interpolated.value).toBe('testuser');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should preserve unmatched placeholders', () => {
|
|
140
|
+
const step = {
|
|
141
|
+
id: 'test',
|
|
142
|
+
action: 'open' as const,
|
|
143
|
+
target: '\${missing}',
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const interpolated = manager.interpolateStep(step, {});
|
|
147
|
+
expect(interpolated.target).toBe('${missing}');
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
describe('WORKFLOW_TEMPLATES', () => {
|
|
153
|
+
it('should include authentication templates', () => {
|
|
154
|
+
const authTemplates = WORKFLOW_TEMPLATES.filter(t => t.category === 'authentication');
|
|
155
|
+
expect(authTemplates.length).toBeGreaterThanOrEqual(2);
|
|
156
|
+
expect(authTemplates.some(t => t.id === 'login-basic')).toBe(true);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('should include data extraction templates', () => {
|
|
160
|
+
const dataTemplates = WORKFLOW_TEMPLATES.filter(t => t.category === 'data-extraction');
|
|
161
|
+
expect(dataTemplates.length).toBeGreaterThanOrEqual(1);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should include testing templates', () => {
|
|
165
|
+
const testTemplates = WORKFLOW_TEMPLATES.filter(t => t.category === 'testing');
|
|
166
|
+
expect(testTemplates.length).toBeGreaterThanOrEqual(1);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('should include monitoring templates', () => {
|
|
170
|
+
const monitorTemplates = WORKFLOW_TEMPLATES.filter(t => t.category === 'monitoring');
|
|
171
|
+
expect(monitorTemplates.length).toBeGreaterThanOrEqual(1);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
describe('template validation', () => {
|
|
175
|
+
it('all templates should have required fields', () => {
|
|
176
|
+
for (const template of WORKFLOW_TEMPLATES) {
|
|
177
|
+
expect(template.id).toBeDefined();
|
|
178
|
+
expect(template.name).toBeDefined();
|
|
179
|
+
expect(template.description).toBeDefined();
|
|
180
|
+
expect(template.category).toBeDefined();
|
|
181
|
+
expect(template.steps).toBeDefined();
|
|
182
|
+
expect(Array.isArray(template.steps)).toBe(true);
|
|
183
|
+
expect(template.steps.length).toBeGreaterThan(0);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('all steps should have required fields', () => {
|
|
188
|
+
for (const template of WORKFLOW_TEMPLATES) {
|
|
189
|
+
for (const step of template.steps) {
|
|
190
|
+
expect(step.id).toBeDefined();
|
|
191
|
+
expect(step.action).toBeDefined();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('all variables should have required fields', () => {
|
|
197
|
+
for (const template of WORKFLOW_TEMPLATES) {
|
|
198
|
+
for (const variable of template.variables) {
|
|
199
|
+
expect(variable.name).toBeDefined();
|
|
200
|
+
expect(variable.type).toBeDefined();
|
|
201
|
+
expect(typeof variable.required).toBe('boolean');
|
|
202
|
+
expect(variable.description).toBeDefined();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
describe('factory functions', () => {
|
|
210
|
+
it('getWorkflowManager should return singleton', () => {
|
|
211
|
+
const manager1 = getWorkflowManager();
|
|
212
|
+
const manager2 = getWorkflowManager();
|
|
213
|
+
expect(manager1).toBe(manager2);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('listWorkflows should return templates', () => {
|
|
217
|
+
const workflows = listWorkflows();
|
|
218
|
+
expect(workflows.length).toBeGreaterThan(0);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('listWorkflows should filter by category', () => {
|
|
222
|
+
const authWorkflows = listWorkflows('authentication');
|
|
223
|
+
expect(authWorkflows.every(w => w.category === 'authentication')).toBe(true);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('getWorkflow should return template by ID', () => {
|
|
227
|
+
const workflow = getWorkflow('login-basic');
|
|
228
|
+
expect(workflow).toBeDefined();
|
|
229
|
+
expect(workflow?.id).toBe('login-basic');
|
|
230
|
+
});
|
|
231
|
+
});
|
package/tmp.json
ADDED
|
File without changes
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true,
|
|
16
|
+
"resolveJsonModule": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
|
20
|
+
}
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
globals: true,
|
|
6
|
+
environment: 'node',
|
|
7
|
+
include: ['tests/**/*.test.ts'],
|
|
8
|
+
coverage: {
|
|
9
|
+
provider: 'v8',
|
|
10
|
+
reporter: ['text', 'json', 'html'],
|
|
11
|
+
include: ['src/**/*.ts'],
|
|
12
|
+
exclude: ['src/**/*.d.ts', 'src/**/index.ts'],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
});
|