@wundr.io/cli 1.0.10 → 1.0.12
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/bin/wundr.js +8 -4
- package/package.json +23 -23
- package/src/ai/ai-service.ts +16 -17
- package/src/ai/claude-client.ts +16 -16
- package/src/ai/conversation-manager.ts +29 -29
- package/src/cli.ts +4 -4
- package/src/commands/ai.ts +246 -78
- package/src/commands/alignment.ts +74 -74
- package/src/commands/analyze-optimized.ts +111 -78
- package/src/commands/analyze.ts +14 -14
- package/src/commands/batch.ts +179 -42
- package/src/commands/chat.ts +37 -30
- package/src/commands/claude-init.ts +41 -45
- package/src/commands/claude-setup.ts +204 -119
- package/src/commands/computer-setup.ts +85 -43
- package/src/commands/create-command.ts +4 -4
- package/src/commands/create.ts +27 -27
- package/src/commands/dashboard.ts +24 -24
- package/src/commands/govern.ts +25 -25
- package/src/commands/governance.ts +34 -34
- package/src/commands/guardian.ts +56 -56
- package/src/commands/init.ts +25 -22
- package/src/commands/orchestrator.ts +68 -41
- package/src/commands/performance-optimizer.ts +34 -35
- package/src/commands/plugins.ts +27 -27
- package/src/commands/project-update.ts +175 -72
- package/src/commands/rag.ts +185 -78
- package/src/commands/session.ts +35 -35
- package/src/commands/setup.ts +40 -344
- package/src/commands/test-init.ts +3 -3
- package/src/commands/test.ts +4 -4
- package/src/commands/watch.ts +28 -29
- package/src/commands/worktree.ts +49 -49
- package/src/context/context-manager.ts +10 -10
- package/src/context/session-manager.ts +41 -41
- package/src/framework/command-interface.ts +520 -0
- package/src/framework/command-registry.ts +942 -0
- package/src/framework/completion-exporter.ts +383 -0
- package/src/framework/debug-logger.ts +519 -0
- package/src/framework/error-handler.ts +867 -0
- package/src/framework/help-generator.ts +540 -0
- package/src/framework/index.ts +169 -0
- package/src/framework/interactive-repl.ts +703 -0
- package/src/framework/output-formatter.ts +834 -0
- package/src/framework/progress-manager.ts +539 -0
- package/src/index.ts +4 -4
- package/src/interactive/interactive-mode.ts +16 -16
- package/src/lib/conflict-resolution.ts +799 -9
- package/src/lib/merge-strategy.ts +529 -7
- package/src/lib/safety-mechanisms.ts +422 -18
- package/src/lib/state-detection.ts +1015 -13
- package/src/nlp/command-mapper.ts +29 -29
- package/src/nlp/command-parser.ts +17 -17
- package/src/nlp/intent-classifier.ts +7 -7
- package/src/nlp/intent-parser.ts +54 -52
- package/src/plugins/plugin-manager.ts +61 -39
- package/src/tests/computer-setup-integration.test.ts +46 -15
- package/src/types/modules.d.ts +424 -1
- package/src/utils/backup-rollback-manager.ts +11 -8
- package/src/utils/config-manager.ts +3 -3
- package/src/utils/error-handler.ts +2 -2
- package/src/utils/logger.ts +22 -22
- package/templates/batch/ci-cd.yaml +7 -7
- package/test-suites/api/health.spec.ts +20 -23
- package/test-suites/helpers/test-config.ts +14 -13
- package/test-suites/ui/accessibility.spec.ts +27 -22
- package/test-suites/ui/smoke.spec.ts +26 -21
- package/LICENSE +0 -21
- package/dist/ai/ai-service.d.ts +0 -152
- package/dist/ai/ai-service.d.ts.map +0 -1
- package/dist/ai/ai-service.js +0 -430
- package/dist/ai/ai-service.js.map +0 -1
- package/dist/ai/claude-client.d.ts +0 -130
- package/dist/ai/claude-client.d.ts.map +0 -1
- package/dist/ai/claude-client.js +0 -340
- package/dist/ai/claude-client.js.map +0 -1
- package/dist/ai/conversation-manager.d.ts +0 -164
- package/dist/ai/conversation-manager.d.ts.map +0 -1
- package/dist/ai/conversation-manager.js +0 -614
- package/dist/ai/conversation-manager.js.map +0 -1
- package/dist/ai/index.d.ts +0 -5
- package/dist/ai/index.d.ts.map +0 -1
- package/dist/ai/index.js +0 -8
- package/dist/ai/index.js.map +0 -1
- package/dist/cli.d.ts +0 -36
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -192
- package/dist/cli.js.map +0 -1
- package/dist/commands/ai.d.ts +0 -89
- package/dist/commands/ai.d.ts.map +0 -1
- package/dist/commands/ai.js +0 -799
- package/dist/commands/ai.js.map +0 -1
- package/dist/commands/alignment.d.ts +0 -78
- package/dist/commands/alignment.d.ts.map +0 -1
- package/dist/commands/alignment.js +0 -817
- package/dist/commands/alignment.js.map +0 -1
- package/dist/commands/analyze-optimized.d.ts +0 -14
- package/dist/commands/analyze-optimized.d.ts.map +0 -1
- package/dist/commands/analyze-optimized.js +0 -600
- package/dist/commands/analyze-optimized.js.map +0 -1
- package/dist/commands/analyze.d.ts +0 -65
- package/dist/commands/analyze.d.ts.map +0 -1
- package/dist/commands/analyze.js +0 -435
- package/dist/commands/analyze.js.map +0 -1
- package/dist/commands/batch.d.ts +0 -71
- package/dist/commands/batch.d.ts.map +0 -1
- package/dist/commands/batch.js +0 -738
- package/dist/commands/batch.js.map +0 -1
- package/dist/commands/chat.d.ts +0 -71
- package/dist/commands/chat.d.ts.map +0 -1
- package/dist/commands/chat.js +0 -674
- package/dist/commands/chat.js.map +0 -1
- package/dist/commands/claude-init.d.ts +0 -28
- package/dist/commands/claude-init.d.ts.map +0 -1
- package/dist/commands/claude-init.js +0 -591
- package/dist/commands/claude-init.js.map +0 -1
- package/dist/commands/claude-setup.d.ts +0 -119
- package/dist/commands/claude-setup.d.ts.map +0 -1
- package/dist/commands/claude-setup.js +0 -1073
- package/dist/commands/claude-setup.js.map +0 -1
- package/dist/commands/computer-setup-commands.d.ts +0 -53
- package/dist/commands/computer-setup-commands.d.ts.map +0 -1
- package/dist/commands/computer-setup-commands.js +0 -705
- package/dist/commands/computer-setup-commands.js.map +0 -1
- package/dist/commands/computer-setup.d.ts +0 -7
- package/dist/commands/computer-setup.d.ts.map +0 -1
- package/dist/commands/computer-setup.js +0 -849
- package/dist/commands/computer-setup.js.map +0 -1
- package/dist/commands/create-command.d.ts +0 -7
- package/dist/commands/create-command.d.ts.map +0 -1
- package/dist/commands/create-command.js +0 -158
- package/dist/commands/create-command.js.map +0 -1
- package/dist/commands/create.d.ts +0 -74
- package/dist/commands/create.d.ts.map +0 -1
- package/dist/commands/create.js +0 -556
- package/dist/commands/create.js.map +0 -1
- package/dist/commands/dashboard.d.ts +0 -91
- package/dist/commands/dashboard.d.ts.map +0 -1
- package/dist/commands/dashboard.js +0 -538
- package/dist/commands/dashboard.js.map +0 -1
- package/dist/commands/govern.d.ts +0 -70
- package/dist/commands/govern.d.ts.map +0 -1
- package/dist/commands/govern.js +0 -481
- package/dist/commands/govern.js.map +0 -1
- package/dist/commands/governance.d.ts +0 -17
- package/dist/commands/governance.d.ts.map +0 -1
- package/dist/commands/governance.js +0 -703
- package/dist/commands/governance.js.map +0 -1
- package/dist/commands/guardian.d.ts +0 -20
- package/dist/commands/guardian.d.ts.map +0 -1
- package/dist/commands/guardian.js +0 -597
- package/dist/commands/guardian.js.map +0 -1
- package/dist/commands/init.d.ts +0 -59
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js +0 -650
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/orchestrator.d.ts +0 -7
- package/dist/commands/orchestrator.d.ts.map +0 -1
- package/dist/commands/orchestrator.js +0 -571
- package/dist/commands/orchestrator.js.map +0 -1
- package/dist/commands/performance-optimizer.d.ts +0 -30
- package/dist/commands/performance-optimizer.d.ts.map +0 -1
- package/dist/commands/performance-optimizer.js +0 -650
- package/dist/commands/performance-optimizer.js.map +0 -1
- package/dist/commands/plugins.d.ts +0 -87
- package/dist/commands/plugins.d.ts.map +0 -1
- package/dist/commands/plugins.js +0 -685
- package/dist/commands/plugins.js.map +0 -1
- package/dist/commands/rag.d.ts +0 -7
- package/dist/commands/rag.d.ts.map +0 -1
- package/dist/commands/rag.js +0 -748
- package/dist/commands/rag.js.map +0 -1
- package/dist/commands/session.d.ts +0 -41
- package/dist/commands/session.d.ts.map +0 -1
- package/dist/commands/session.js +0 -441
- package/dist/commands/session.js.map +0 -1
- package/dist/commands/setup.d.ts +0 -29
- package/dist/commands/setup.d.ts.map +0 -1
- package/dist/commands/setup.js +0 -397
- package/dist/commands/setup.js.map +0 -1
- package/dist/commands/test-init.d.ts +0 -9
- package/dist/commands/test-init.d.ts.map +0 -1
- package/dist/commands/test-init.js +0 -222
- package/dist/commands/test-init.js.map +0 -1
- package/dist/commands/test.d.ts +0 -25
- package/dist/commands/test.d.ts.map +0 -1
- package/dist/commands/test.js +0 -217
- package/dist/commands/test.js.map +0 -1
- package/dist/commands/vp.d.ts +0 -7
- package/dist/commands/vp.d.ts.map +0 -1
- package/dist/commands/vp.js +0 -571
- package/dist/commands/vp.js.map +0 -1
- package/dist/commands/watch.d.ts +0 -76
- package/dist/commands/watch.d.ts.map +0 -1
- package/dist/commands/watch.js +0 -613
- package/dist/commands/watch.js.map +0 -1
- package/dist/commands/worktree.d.ts +0 -63
- package/dist/commands/worktree.d.ts.map +0 -1
- package/dist/commands/worktree.js +0 -774
- package/dist/commands/worktree.js.map +0 -1
- package/dist/context/context-manager.d.ts +0 -155
- package/dist/context/context-manager.d.ts.map +0 -1
- package/dist/context/context-manager.js +0 -383
- package/dist/context/context-manager.js.map +0 -1
- package/dist/context/index.d.ts +0 -3
- package/dist/context/index.d.ts.map +0 -1
- package/dist/context/index.js +0 -6
- package/dist/context/index.js.map +0 -1
- package/dist/context/session-manager.d.ts +0 -207
- package/dist/context/session-manager.d.ts.map +0 -1
- package/dist/context/session-manager.js +0 -686
- package/dist/context/session-manager.js.map +0 -1
- package/dist/index.d.ts +0 -8
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -51
- package/dist/index.js.map +0 -1
- package/dist/interactive/interactive-mode.d.ts +0 -76
- package/dist/interactive/interactive-mode.d.ts.map +0 -1
- package/dist/interactive/interactive-mode.js +0 -732
- package/dist/interactive/interactive-mode.js.map +0 -1
- package/dist/nlp/command-mapper.d.ts +0 -174
- package/dist/nlp/command-mapper.d.ts.map +0 -1
- package/dist/nlp/command-mapper.js +0 -624
- package/dist/nlp/command-mapper.js.map +0 -1
- package/dist/nlp/command-parser.d.ts +0 -106
- package/dist/nlp/command-parser.d.ts.map +0 -1
- package/dist/nlp/command-parser.js +0 -417
- package/dist/nlp/command-parser.js.map +0 -1
- package/dist/nlp/index.d.ts +0 -5
- package/dist/nlp/index.d.ts.map +0 -1
- package/dist/nlp/index.js +0 -8
- package/dist/nlp/index.js.map +0 -1
- package/dist/nlp/intent-classifier.d.ts +0 -59
- package/dist/nlp/intent-classifier.d.ts.map +0 -1
- package/dist/nlp/intent-classifier.js +0 -384
- package/dist/nlp/intent-classifier.js.map +0 -1
- package/dist/nlp/intent-parser.d.ts +0 -152
- package/dist/nlp/intent-parser.d.ts.map +0 -1
- package/dist/nlp/intent-parser.js +0 -744
- package/dist/nlp/intent-parser.js.map +0 -1
- package/dist/plugins/plugin-manager.d.ts +0 -120
- package/dist/plugins/plugin-manager.d.ts.map +0 -1
- package/dist/plugins/plugin-manager.js +0 -595
- package/dist/plugins/plugin-manager.js.map +0 -1
- package/dist/types/index.d.ts +0 -224
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -3
- package/dist/types/index.js.map +0 -1
- package/dist/utils/backup-rollback-manager.d.ts +0 -72
- package/dist/utils/backup-rollback-manager.d.ts.map +0 -1
- package/dist/utils/backup-rollback-manager.js +0 -289
- package/dist/utils/backup-rollback-manager.js.map +0 -1
- package/dist/utils/claude-config-installer.d.ts +0 -98
- package/dist/utils/claude-config-installer.d.ts.map +0 -1
- package/dist/utils/claude-config-installer.js +0 -678
- package/dist/utils/claude-config-installer.js.map +0 -1
- package/dist/utils/config-manager.d.ts +0 -73
- package/dist/utils/config-manager.d.ts.map +0 -1
- package/dist/utils/config-manager.js +0 -339
- package/dist/utils/config-manager.js.map +0 -1
- package/dist/utils/error-handler.d.ts +0 -46
- package/dist/utils/error-handler.d.ts.map +0 -1
- package/dist/utils/error-handler.js +0 -169
- package/dist/utils/error-handler.js.map +0 -1
- package/dist/utils/logger.d.ts +0 -25
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js +0 -105
- package/dist/utils/logger.js.map +0 -1
- package/src/commands/computer-setup-commands.ts +0 -872
package/src/utils/logger.ts
CHANGED
|
@@ -19,8 +19,8 @@ class WundrLogger implements Logger {
|
|
|
19
19
|
|
|
20
20
|
private shouldLog(level: string): boolean {
|
|
21
21
|
if (this.silent) {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
24
|
|
|
25
25
|
const levels = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
26
26
|
return levels[level as keyof typeof levels] >= levels[this.level];
|
|
@@ -40,73 +40,73 @@ return false;
|
|
|
40
40
|
|
|
41
41
|
debug(message: string, ...args: any[]): void {
|
|
42
42
|
if (!this.shouldLog('debug')) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
45
|
console.log(chalk.gray(this.formatMessage('debug', message, ...args)));
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
info(message: string, ...args: any[]): void {
|
|
49
49
|
if (!this.shouldLog('info')) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
52
|
console.log(chalk.blue(this.formatMessage('info', message, ...args)));
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
warn(message: string, ...args: any[]): void {
|
|
56
56
|
if (!this.shouldLog('warn')) {
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
59
|
console.warn(chalk.yellow(this.formatMessage('warn', message, ...args)));
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
error(message: string, ...args: any[]): void {
|
|
63
63
|
if (!this.shouldLog('error')) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
66
|
console.error(chalk.red(this.formatMessage('error', message, ...args)));
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
success(message: string, ...args: any[]): void {
|
|
70
70
|
if (!this.shouldLog('info')) {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
73
|
console.log(chalk.green(this.formatMessage('success', message, ...args)));
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
// Utility methods for structured logging
|
|
77
77
|
table(data: any[]): void {
|
|
78
78
|
if (this.silent) {
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
81
|
console.table(data);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
json(data: any): void {
|
|
85
85
|
if (this.silent) {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
88
|
console.log(JSON.stringify(data, null, 2));
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
group(label: string): void {
|
|
92
92
|
if (this.silent) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
95
|
console.group(chalk.cyan(label));
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
groupEnd(): void {
|
|
99
99
|
if (this.silent) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
102
|
console.groupEnd();
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
// Progress logging
|
|
106
106
|
progress(current: number, total: number, message?: string): void {
|
|
107
107
|
if (this.silent) {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
110
|
const percentage = Math.round((current / total) * 100);
|
|
111
111
|
const bar = '█'.repeat(Math.round(percentage / 2));
|
|
112
112
|
const empty = '░'.repeat(50 - Math.round(percentage / 2));
|
|
@@ -7,7 +7,7 @@ description: Continuous Integration and Deployment pipeline
|
|
|
7
7
|
# Global settings
|
|
8
8
|
parallel: false
|
|
9
9
|
continueOnError: false
|
|
10
|
-
timeout: 1800000
|
|
10
|
+
timeout: 1800000 # 30 minutes
|
|
11
11
|
|
|
12
12
|
# Environment variables
|
|
13
13
|
variables:
|
|
@@ -23,7 +23,7 @@ commands:
|
|
|
23
23
|
# Install dependencies
|
|
24
24
|
- command: "npm ci"
|
|
25
25
|
retry: 2
|
|
26
|
-
timeout: 300000
|
|
26
|
+
timeout: 300000 # 5 minutes
|
|
27
27
|
|
|
28
28
|
# Code quality checks
|
|
29
29
|
- command: "npm run lint"
|
|
@@ -34,11 +34,11 @@ commands:
|
|
|
34
34
|
|
|
35
35
|
# Testing
|
|
36
36
|
- command: "npm run test"
|
|
37
|
-
timeout: 600000
|
|
37
|
+
timeout: 600000 # 10 minutes
|
|
38
38
|
|
|
39
39
|
- command: "npm run test:e2e"
|
|
40
40
|
condition: "e2e-tests-exist"
|
|
41
|
-
timeout: 900000
|
|
41
|
+
timeout: 900000 # 15 minutes
|
|
42
42
|
|
|
43
43
|
# Security audit
|
|
44
44
|
- command: "npm audit --audit-level high"
|
|
@@ -46,7 +46,7 @@ commands:
|
|
|
46
46
|
|
|
47
47
|
# Build
|
|
48
48
|
- command: "npm run build"
|
|
49
|
-
timeout: 300000
|
|
49
|
+
timeout: 300000 # 5 minutes
|
|
50
50
|
|
|
51
51
|
# Package
|
|
52
52
|
- command: "npm pack"
|
|
@@ -55,8 +55,8 @@ commands:
|
|
|
55
55
|
# Deploy (conditional)
|
|
56
56
|
- command: "npm run deploy"
|
|
57
57
|
condition: "production"
|
|
58
|
-
timeout: 600000
|
|
58
|
+
timeout: 600000 # 10 minutes
|
|
59
59
|
|
|
60
60
|
# Cleanup
|
|
61
61
|
- command: "echo 'CI/CD pipeline completed'"
|
|
62
|
-
condition: "always"
|
|
62
|
+
condition: "always"
|
|
@@ -15,11 +15,11 @@ test.describe('API Health Checks', () => {
|
|
|
15
15
|
'/status',
|
|
16
16
|
'/api/status',
|
|
17
17
|
'/_health',
|
|
18
|
-
'/ping'
|
|
18
|
+
'/ping',
|
|
19
19
|
];
|
|
20
20
|
|
|
21
21
|
let healthyEndpoint = null;
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
for (const endpoint of healthEndpoints) {
|
|
24
24
|
try {
|
|
25
25
|
const response = await request.get(`${baseURL}${endpoint}`);
|
|
@@ -38,23 +38,18 @@ test.describe('API Health Checks', () => {
|
|
|
38
38
|
|
|
39
39
|
test('API returns proper content types', async ({ request, baseURL }) => {
|
|
40
40
|
// Try to find an API endpoint
|
|
41
|
-
const apiEndpoints = [
|
|
42
|
-
'/api',
|
|
43
|
-
'/api/v1',
|
|
44
|
-
'/api/v2',
|
|
45
|
-
'/graphql'
|
|
46
|
-
];
|
|
41
|
+
const apiEndpoints = ['/api', '/api/v1', '/api/v2', '/graphql'];
|
|
47
42
|
|
|
48
43
|
for (const endpoint of apiEndpoints) {
|
|
49
44
|
try {
|
|
50
45
|
const response = await request.get(`${baseURL}${endpoint}`);
|
|
51
46
|
if (response.ok() || response.status() === 404) {
|
|
52
47
|
const contentType = response.headers()['content-type'];
|
|
53
|
-
|
|
48
|
+
|
|
54
49
|
// Should return JSON or HTML
|
|
55
50
|
expect(
|
|
56
51
|
contentType?.includes('application/json') ||
|
|
57
|
-
|
|
52
|
+
contentType?.includes('text/html')
|
|
58
53
|
).toBeTruthy();
|
|
59
54
|
}
|
|
60
55
|
} catch {
|
|
@@ -65,11 +60,13 @@ test.describe('API Health Checks', () => {
|
|
|
65
60
|
|
|
66
61
|
test('API handles errors gracefully', async ({ request, baseURL }) => {
|
|
67
62
|
// Test 404 handling
|
|
68
|
-
const response = await request.get(
|
|
69
|
-
|
|
63
|
+
const response = await request.get(
|
|
64
|
+
`${baseURL}/api/nonexistent-endpoint-${Date.now()}`
|
|
65
|
+
);
|
|
66
|
+
|
|
70
67
|
// Should return appropriate status code
|
|
71
68
|
expect([404, 400, 401, 403]).toContain(response.status());
|
|
72
|
-
|
|
69
|
+
|
|
73
70
|
// Should not expose sensitive information
|
|
74
71
|
const body = await response.text();
|
|
75
72
|
expect(body).not.toContain('stack');
|
|
@@ -78,12 +75,12 @@ test.describe('API Health Checks', () => {
|
|
|
78
75
|
|
|
79
76
|
test('API responds within acceptable time', async ({ request, baseURL }) => {
|
|
80
77
|
const startTime = Date.now();
|
|
81
|
-
|
|
78
|
+
|
|
82
79
|
// Make a simple request
|
|
83
80
|
await request.get(`${baseURL}/`);
|
|
84
|
-
|
|
81
|
+
|
|
85
82
|
const responseTime = Date.now() - startTime;
|
|
86
|
-
|
|
83
|
+
|
|
87
84
|
// Should respond within 5 seconds
|
|
88
85
|
expect(responseTime).toBeLessThan(5000);
|
|
89
86
|
});
|
|
@@ -92,18 +89,18 @@ test.describe('API Health Checks', () => {
|
|
|
92
89
|
try {
|
|
93
90
|
const response = await request.get(`${baseURL}/api`, {
|
|
94
91
|
headers: {
|
|
95
|
-
|
|
96
|
-
}
|
|
92
|
+
Origin: 'https://example.com',
|
|
93
|
+
},
|
|
97
94
|
});
|
|
98
95
|
|
|
99
96
|
const headers = response.headers();
|
|
100
|
-
|
|
97
|
+
|
|
101
98
|
// Check for CORS headers if API exists
|
|
102
99
|
if (response.status() !== 404) {
|
|
103
|
-
const hasCorsHeaders =
|
|
100
|
+
const hasCorsHeaders =
|
|
104
101
|
headers['access-control-allow-origin'] !== undefined ||
|
|
105
102
|
headers['access-control-allow-methods'] !== undefined;
|
|
106
|
-
|
|
103
|
+
|
|
107
104
|
// Log CORS configuration
|
|
108
105
|
console.log('CORS configured:', hasCorsHeaders);
|
|
109
106
|
}
|
|
@@ -119,7 +116,7 @@ test.describe('API Health Checks', () => {
|
|
|
119
116
|
for (const method of methods) {
|
|
120
117
|
try {
|
|
121
118
|
const response = await request.fetch(`${baseURL}/api`, {
|
|
122
|
-
method
|
|
119
|
+
method,
|
|
123
120
|
});
|
|
124
121
|
results[method] = response.status();
|
|
125
122
|
} catch {
|
|
@@ -131,4 +128,4 @@ test.describe('API Health Checks', () => {
|
|
|
131
128
|
expect(results['GET']).toBeGreaterThan(0);
|
|
132
129
|
expect(results['OPTIONS']).toBeGreaterThan(0);
|
|
133
130
|
});
|
|
134
|
-
});
|
|
131
|
+
});
|
|
@@ -12,7 +12,7 @@ export interface TestConfig {
|
|
|
12
12
|
screenshot: 'off' | 'on' | 'only-on-failure';
|
|
13
13
|
video: 'off' | 'on' | 'retain-on-failure';
|
|
14
14
|
trace: 'off' | 'on' | 'on-first-retry';
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
// Custom selectors for specific apps
|
|
17
17
|
selectors?: {
|
|
18
18
|
navigation?: string;
|
|
@@ -21,14 +21,14 @@ export interface TestConfig {
|
|
|
21
21
|
searchInput?: string;
|
|
22
22
|
loginButton?: string;
|
|
23
23
|
};
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
// API configuration
|
|
26
26
|
api?: {
|
|
27
27
|
baseURL?: string;
|
|
28
28
|
headers?: Record<string, string>;
|
|
29
29
|
timeout?: number;
|
|
30
30
|
};
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
// Test data
|
|
33
33
|
testData?: {
|
|
34
34
|
validUser?: {
|
|
@@ -47,18 +47,19 @@ export const defaultConfig: TestConfig = {
|
|
|
47
47
|
screenshot: 'only-on-failure',
|
|
48
48
|
video: 'retain-on-failure',
|
|
49
49
|
trace: 'on-first-retry',
|
|
50
|
-
|
|
50
|
+
|
|
51
51
|
selectors: {
|
|
52
52
|
navigation: 'nav, [role="navigation"], header',
|
|
53
53
|
mainContent: 'main, [role="main"], #content',
|
|
54
54
|
footer: 'footer, [role="contentinfo"]',
|
|
55
55
|
searchInput: 'input[type="search"], input[placeholder*="search" i]',
|
|
56
|
-
loginButton:
|
|
56
|
+
loginButton:
|
|
57
|
+
'button[type="submit"], button:has-text("Login"), button:has-text("Sign in")',
|
|
57
58
|
},
|
|
58
|
-
|
|
59
|
+
|
|
59
60
|
api: {
|
|
60
|
-
timeout: 10000
|
|
61
|
-
}
|
|
61
|
+
timeout: 10000,
|
|
62
|
+
},
|
|
62
63
|
};
|
|
63
64
|
|
|
64
65
|
/**
|
|
@@ -70,15 +71,15 @@ export function loadConfig(customConfig?: Partial<TestConfig>): TestConfig {
|
|
|
70
71
|
...customConfig,
|
|
71
72
|
selectors: {
|
|
72
73
|
...defaultConfig.selectors,
|
|
73
|
-
...customConfig?.selectors
|
|
74
|
+
...customConfig?.selectors,
|
|
74
75
|
},
|
|
75
76
|
api: {
|
|
76
77
|
...defaultConfig.api,
|
|
77
|
-
...customConfig?.api
|
|
78
|
+
...customConfig?.api,
|
|
78
79
|
},
|
|
79
80
|
testData: {
|
|
80
81
|
...defaultConfig.testData,
|
|
81
|
-
...customConfig?.testData
|
|
82
|
-
}
|
|
82
|
+
...customConfig?.testData,
|
|
83
|
+
},
|
|
83
84
|
};
|
|
84
|
-
}
|
|
85
|
+
}
|
|
@@ -8,23 +8,23 @@ import AxeBuilder from '@axe-core/playwright';
|
|
|
8
8
|
test.describe('Accessibility Tests', () => {
|
|
9
9
|
test('homepage meets WCAG standards', async ({ page }) => {
|
|
10
10
|
await page.goto('/');
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
const accessibilityScanResults = await new AxeBuilder({ page })
|
|
13
13
|
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
|
|
14
14
|
.analyze();
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
expect(accessibilityScanResults.violations).toEqual([]);
|
|
17
17
|
});
|
|
18
18
|
|
|
19
19
|
test('all images have alt text', async ({ page }) => {
|
|
20
20
|
await page.goto('/');
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
const images = await page.locator('img').all();
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
for (const img of images) {
|
|
25
25
|
const alt = await img.getAttribute('alt');
|
|
26
26
|
const role = await img.getAttribute('role');
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
// Images should have alt text or be marked as decorative
|
|
29
29
|
expect(alt !== null || role === 'presentation').toBeTruthy();
|
|
30
30
|
}
|
|
@@ -32,18 +32,19 @@ test.describe('Accessibility Tests', () => {
|
|
|
32
32
|
|
|
33
33
|
test('forms have proper labels', async ({ page }) => {
|
|
34
34
|
await page.goto('/');
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
const inputs = await page.locator('input, select, textarea').all();
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
for (const input of inputs) {
|
|
39
39
|
const id = await input.getAttribute('id');
|
|
40
40
|
const ariaLabel = await input.getAttribute('aria-label');
|
|
41
41
|
const ariaLabelledBy = await input.getAttribute('aria-labelledby');
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
if (id) {
|
|
44
44
|
// Check for associated label
|
|
45
45
|
const label = await page.locator(`label[for="${id}"]`).count();
|
|
46
|
-
const hasLabel =
|
|
46
|
+
const hasLabel =
|
|
47
|
+
label > 0 || ariaLabel !== null || ariaLabelledBy !== null;
|
|
47
48
|
expect(hasLabel).toBeTruthy();
|
|
48
49
|
}
|
|
49
50
|
}
|
|
@@ -51,47 +52,51 @@ test.describe('Accessibility Tests', () => {
|
|
|
51
52
|
|
|
52
53
|
test('focus is visible and logical', async ({ page }) => {
|
|
53
54
|
await page.goto('/');
|
|
54
|
-
|
|
55
|
+
|
|
55
56
|
// Tab through interactive elements
|
|
56
57
|
await page.keyboard.press('Tab');
|
|
57
|
-
|
|
58
|
+
|
|
58
59
|
// Check if focused element has visible outline
|
|
59
|
-
const focusedElement = await page.evaluateHandle(
|
|
60
|
-
|
|
60
|
+
const focusedElement = await page.evaluateHandle(
|
|
61
|
+
() => document.activeElement
|
|
62
|
+
);
|
|
63
|
+
const hasOutline = await focusedElement.evaluate(el => {
|
|
61
64
|
if (!el) return false;
|
|
62
65
|
const styles = window.getComputedStyle(el as Element);
|
|
63
66
|
return styles.outlineStyle !== 'none' || styles.boxShadow !== 'none';
|
|
64
67
|
});
|
|
65
|
-
|
|
68
|
+
|
|
66
69
|
expect(hasOutline).toBeTruthy();
|
|
67
70
|
});
|
|
68
71
|
|
|
69
72
|
test('color contrast meets standards', async ({ page }) => {
|
|
70
73
|
await page.goto('/');
|
|
71
|
-
|
|
74
|
+
|
|
72
75
|
const accessibilityScanResults = await new AxeBuilder({ page })
|
|
73
76
|
.withTags(['color-contrast'])
|
|
74
77
|
.analyze();
|
|
75
|
-
|
|
78
|
+
|
|
76
79
|
expect(accessibilityScanResults.violations).toEqual([]);
|
|
77
80
|
});
|
|
78
81
|
|
|
79
82
|
test('page has proper heading structure', async ({ page }) => {
|
|
80
83
|
await page.goto('/');
|
|
81
|
-
|
|
84
|
+
|
|
82
85
|
// Check for h1
|
|
83
86
|
const h1Count = await page.locator('h1').count();
|
|
84
87
|
expect(h1Count).toBeGreaterThan(0);
|
|
85
|
-
|
|
88
|
+
|
|
86
89
|
// Check heading hierarchy
|
|
87
90
|
const headings = await page.evaluate(() => {
|
|
88
|
-
const headingElements = document.querySelectorAll(
|
|
91
|
+
const headingElements = document.querySelectorAll(
|
|
92
|
+
'h1, h2, h3, h4, h5, h6'
|
|
93
|
+
);
|
|
89
94
|
return Array.from(headingElements).map(h => ({
|
|
90
95
|
level: parseInt(h.tagName[1]),
|
|
91
|
-
text: h.textContent
|
|
96
|
+
text: h.textContent,
|
|
92
97
|
}));
|
|
93
98
|
});
|
|
94
|
-
|
|
99
|
+
|
|
95
100
|
// Verify no skipped heading levels
|
|
96
101
|
let previousLevel = 0;
|
|
97
102
|
for (const heading of headings) {
|
|
@@ -99,4 +104,4 @@ test.describe('Accessibility Tests', () => {
|
|
|
99
104
|
previousLevel = heading.level;
|
|
100
105
|
}
|
|
101
106
|
});
|
|
102
|
-
});
|
|
107
|
+
});
|
|
@@ -8,8 +8,8 @@ import { test, expect } from '@playwright/test';
|
|
|
8
8
|
test.describe('Portable Smoke Tests', () => {
|
|
9
9
|
test('homepage loads without errors', async ({ page }) => {
|
|
10
10
|
const jsErrors: string[] = [];
|
|
11
|
-
|
|
12
|
-
page.on('pageerror',
|
|
11
|
+
|
|
12
|
+
page.on('pageerror', error => {
|
|
13
13
|
jsErrors.push(error.message);
|
|
14
14
|
});
|
|
15
15
|
|
|
@@ -18,31 +18,33 @@ test.describe('Portable Smoke Tests', () => {
|
|
|
18
18
|
|
|
19
19
|
// Basic structure should be present
|
|
20
20
|
await expect(page.locator('body')).toBeVisible();
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
// Should not have critical JavaScript errors
|
|
23
|
-
const criticalErrors = jsErrors.filter(
|
|
24
|
-
error
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
const criticalErrors = jsErrors.filter(
|
|
24
|
+
error =>
|
|
25
|
+
error.includes('Cannot read') ||
|
|
26
|
+
error.includes('undefined is not') ||
|
|
27
|
+
error.includes('Uncaught')
|
|
27
28
|
);
|
|
28
|
-
|
|
29
|
+
|
|
29
30
|
expect(criticalErrors.length).toBe(0);
|
|
30
31
|
});
|
|
31
32
|
|
|
32
33
|
test('navigation elements are present', async ({ page }) => {
|
|
33
34
|
await page.goto('/');
|
|
34
|
-
|
|
35
|
+
|
|
35
36
|
// Check for common navigation patterns
|
|
36
|
-
const hasNavigation =
|
|
37
|
+
const hasNavigation =
|
|
38
|
+
(await page.locator('nav, [role="navigation"], header').count()) > 0;
|
|
37
39
|
expect(hasNavigation).toBeTruthy();
|
|
38
40
|
});
|
|
39
41
|
|
|
40
42
|
test('interactive elements are clickable', async ({ page }) => {
|
|
41
43
|
await page.goto('/');
|
|
42
|
-
|
|
44
|
+
|
|
43
45
|
// Find clickable elements
|
|
44
46
|
const buttons = await page.locator('button:visible, a:visible').all();
|
|
45
|
-
|
|
47
|
+
|
|
46
48
|
if (buttons.length > 0) {
|
|
47
49
|
// Test first button/link
|
|
48
50
|
const firstElement = buttons[0];
|
|
@@ -52,10 +54,10 @@ test.describe('Portable Smoke Tests', () => {
|
|
|
52
54
|
|
|
53
55
|
test('forms accept input', async ({ page }) => {
|
|
54
56
|
await page.goto('/');
|
|
55
|
-
|
|
57
|
+
|
|
56
58
|
// Look for form inputs
|
|
57
59
|
const inputs = await page.locator('input:visible, textarea:visible').all();
|
|
58
|
-
|
|
60
|
+
|
|
59
61
|
if (inputs.length > 0) {
|
|
60
62
|
const firstInput = inputs[0];
|
|
61
63
|
await firstInput.fill('test');
|
|
@@ -66,27 +68,30 @@ test.describe('Portable Smoke Tests', () => {
|
|
|
66
68
|
|
|
67
69
|
test('responsive layout works', async ({ page }) => {
|
|
68
70
|
await page.goto('/');
|
|
69
|
-
|
|
71
|
+
|
|
70
72
|
// Test mobile viewport
|
|
71
73
|
await page.setViewportSize({ width: 375, height: 667 });
|
|
72
|
-
|
|
74
|
+
|
|
73
75
|
// Should not have horizontal scroll
|
|
74
76
|
const hasHorizontalScroll = await page.evaluate(() => {
|
|
75
|
-
return
|
|
77
|
+
return (
|
|
78
|
+
document.documentElement.scrollWidth >
|
|
79
|
+
document.documentElement.clientWidth
|
|
80
|
+
);
|
|
76
81
|
});
|
|
77
|
-
|
|
82
|
+
|
|
78
83
|
expect(hasHorizontalScroll).toBeFalsy();
|
|
79
84
|
});
|
|
80
85
|
|
|
81
86
|
test('page has proper metadata', async ({ page }) => {
|
|
82
87
|
await page.goto('/');
|
|
83
|
-
|
|
88
|
+
|
|
84
89
|
// Check for title
|
|
85
90
|
const title = await page.title();
|
|
86
91
|
expect(title).toBeTruthy();
|
|
87
|
-
|
|
92
|
+
|
|
88
93
|
// Check for language attribute
|
|
89
94
|
const lang = await page.locator('html').getAttribute('lang');
|
|
90
95
|
expect(lang).toBeTruthy();
|
|
91
96
|
});
|
|
92
|
-
});
|
|
97
|
+
});
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright(c) 2025 Adaptic Technologies, Inc.
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files(the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|