@wundr.io/cli 1.0.0 → 1.0.2-dev.20260530174250.ef0ec927

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.
Files changed (230) hide show
  1. package/README.md +696 -280
  2. package/bin/wundr.js +13 -5
  3. package/package.json +30 -9
  4. package/src/ai/ai-service.ts +6 -4
  5. package/src/ai/claude-client.ts +6 -2
  6. package/src/ai/conversation-manager.ts +12 -5
  7. package/src/cli.ts +42 -13
  8. package/src/commands/ai.ts +340 -64
  9. package/src/commands/alignment.ts +1212 -0
  10. package/src/commands/analyze-optimized.ts +371 -33
  11. package/src/commands/analyze.ts +8 -6
  12. package/src/commands/batch.ts +166 -26
  13. package/src/commands/chat.ts +20 -10
  14. package/src/commands/claude-init.ts +31 -27
  15. package/src/commands/claude-setup.ts +761 -81
  16. package/src/commands/computer-setup.ts +524 -12
  17. package/src/commands/create-command.ts +3 -3
  18. package/src/commands/create.ts +9 -6
  19. package/src/commands/dashboard.ts +11 -6
  20. package/src/commands/govern.ts +11 -6
  21. package/src/commands/governance.ts +1005 -0
  22. package/src/commands/guardian.ts +887 -0
  23. package/src/commands/init.ts +104 -11
  24. package/src/commands/orchestrator.ts +789 -0
  25. package/src/commands/performance-optimizer.ts +15 -10
  26. package/src/commands/plugins.ts +8 -5
  27. package/src/commands/project-update.ts +1156 -0
  28. package/src/commands/rag.ts +1011 -0
  29. package/src/commands/session.ts +631 -0
  30. package/src/commands/setup.ts +42 -344
  31. package/src/commands/test-init.ts +3 -2
  32. package/src/commands/test.ts +3 -2
  33. package/src/commands/watch.ts +21 -11
  34. package/src/commands/worktree.ts +1057 -0
  35. package/src/context/context-manager.ts +5 -2
  36. package/src/context/session-manager.ts +18 -7
  37. package/src/framework/command-interface.ts +520 -0
  38. package/src/framework/command-registry.ts +942 -0
  39. package/src/framework/completion-exporter.ts +383 -0
  40. package/src/framework/debug-logger.ts +519 -0
  41. package/src/framework/error-handler.ts +867 -0
  42. package/src/framework/help-generator.ts +540 -0
  43. package/src/framework/index.ts +169 -0
  44. package/src/framework/interactive-repl.ts +703 -0
  45. package/src/framework/output-formatter.ts +834 -0
  46. package/src/framework/progress-manager.ts +539 -0
  47. package/src/index.ts +3 -2
  48. package/src/interactive/interactive-mode.ts +14 -7
  49. package/src/lib/conflict-resolution.ts +818 -0
  50. package/src/lib/merge-strategy.ts +550 -0
  51. package/src/lib/safety-mechanisms.ts +451 -0
  52. package/src/lib/state-detection.ts +1030 -0
  53. package/src/nlp/command-mapper.ts +8 -3
  54. package/src/nlp/command-parser.ts +5 -2
  55. package/src/nlp/intent-parser.ts +23 -9
  56. package/src/plugins/plugin-manager.ts +50 -24
  57. package/src/tests/computer-setup-integration.test.ts +470 -0
  58. package/src/types/index.ts +1 -1
  59. package/src/types/modules.d.ts +425 -1
  60. package/src/utils/backup-rollback-manager.ts +366 -0
  61. package/src/utils/claude-config-installer.ts +823 -0
  62. package/src/utils/config-manager.ts +9 -6
  63. package/src/utils/error-handler.ts +3 -1
  64. package/src/utils/logger.ts +35 -12
  65. package/templates/batch/ci-cd.yaml +7 -7
  66. package/test-suites/api/health.spec.ts +20 -23
  67. package/test-suites/helpers/test-config.ts +14 -13
  68. package/test-suites/ui/accessibility.spec.ts +27 -22
  69. package/test-suites/ui/smoke.spec.ts +26 -21
  70. package/dist/ai/ai-service.d.ts +0 -152
  71. package/dist/ai/ai-service.d.ts.map +0 -1
  72. package/dist/ai/ai-service.js +0 -430
  73. package/dist/ai/ai-service.js.map +0 -1
  74. package/dist/ai/claude-client.d.ts +0 -130
  75. package/dist/ai/claude-client.d.ts.map +0 -1
  76. package/dist/ai/claude-client.js +0 -339
  77. package/dist/ai/claude-client.js.map +0 -1
  78. package/dist/ai/conversation-manager.d.ts +0 -164
  79. package/dist/ai/conversation-manager.d.ts.map +0 -1
  80. package/dist/ai/conversation-manager.js +0 -612
  81. package/dist/ai/conversation-manager.js.map +0 -1
  82. package/dist/ai/index.d.ts +0 -5
  83. package/dist/ai/index.d.ts.map +0 -1
  84. package/dist/ai/index.js +0 -8
  85. package/dist/ai/index.js.map +0 -1
  86. package/dist/cli.d.ts +0 -36
  87. package/dist/cli.d.ts.map +0 -1
  88. package/dist/cli.js +0 -173
  89. package/dist/cli.js.map +0 -1
  90. package/dist/commands/ai.d.ts +0 -89
  91. package/dist/commands/ai.d.ts.map +0 -1
  92. package/dist/commands/ai.js +0 -735
  93. package/dist/commands/ai.js.map +0 -1
  94. package/dist/commands/analyze-optimized.d.ts +0 -14
  95. package/dist/commands/analyze-optimized.d.ts.map +0 -1
  96. package/dist/commands/analyze-optimized.js +0 -437
  97. package/dist/commands/analyze-optimized.js.map +0 -1
  98. package/dist/commands/analyze.d.ts +0 -65
  99. package/dist/commands/analyze.d.ts.map +0 -1
  100. package/dist/commands/analyze.js +0 -435
  101. package/dist/commands/analyze.js.map +0 -1
  102. package/dist/commands/batch.d.ts +0 -71
  103. package/dist/commands/batch.d.ts.map +0 -1
  104. package/dist/commands/batch.js +0 -738
  105. package/dist/commands/batch.js.map +0 -1
  106. package/dist/commands/chat.d.ts +0 -71
  107. package/dist/commands/chat.d.ts.map +0 -1
  108. package/dist/commands/chat.js +0 -674
  109. package/dist/commands/chat.js.map +0 -1
  110. package/dist/commands/claude-init.d.ts +0 -28
  111. package/dist/commands/claude-init.d.ts.map +0 -1
  112. package/dist/commands/claude-init.js +0 -587
  113. package/dist/commands/claude-init.js.map +0 -1
  114. package/dist/commands/claude-setup.d.ts +0 -32
  115. package/dist/commands/claude-setup.d.ts.map +0 -1
  116. package/dist/commands/claude-setup.js +0 -570
  117. package/dist/commands/claude-setup.js.map +0 -1
  118. package/dist/commands/computer-setup-commands.d.ts +0 -39
  119. package/dist/commands/computer-setup-commands.d.ts.map +0 -1
  120. package/dist/commands/computer-setup-commands.js +0 -563
  121. package/dist/commands/computer-setup-commands.js.map +0 -1
  122. package/dist/commands/computer-setup.d.ts +0 -7
  123. package/dist/commands/computer-setup.d.ts.map +0 -1
  124. package/dist/commands/computer-setup.js +0 -481
  125. package/dist/commands/computer-setup.js.map +0 -1
  126. package/dist/commands/create-command.d.ts +0 -7
  127. package/dist/commands/create-command.d.ts.map +0 -1
  128. package/dist/commands/create-command.js +0 -158
  129. package/dist/commands/create-command.js.map +0 -1
  130. package/dist/commands/create.d.ts +0 -74
  131. package/dist/commands/create.d.ts.map +0 -1
  132. package/dist/commands/create.js +0 -556
  133. package/dist/commands/create.js.map +0 -1
  134. package/dist/commands/dashboard.d.ts +0 -91
  135. package/dist/commands/dashboard.d.ts.map +0 -1
  136. package/dist/commands/dashboard.js +0 -537
  137. package/dist/commands/dashboard.js.map +0 -1
  138. package/dist/commands/govern.d.ts +0 -70
  139. package/dist/commands/govern.d.ts.map +0 -1
  140. package/dist/commands/govern.js +0 -480
  141. package/dist/commands/govern.js.map +0 -1
  142. package/dist/commands/init.d.ts +0 -55
  143. package/dist/commands/init.d.ts.map +0 -1
  144. package/dist/commands/init.js +0 -584
  145. package/dist/commands/init.js.map +0 -1
  146. package/dist/commands/performance-optimizer.d.ts +0 -30
  147. package/dist/commands/performance-optimizer.d.ts.map +0 -1
  148. package/dist/commands/performance-optimizer.js +0 -649
  149. package/dist/commands/performance-optimizer.js.map +0 -1
  150. package/dist/commands/plugins.d.ts +0 -87
  151. package/dist/commands/plugins.d.ts.map +0 -1
  152. package/dist/commands/plugins.js +0 -685
  153. package/dist/commands/plugins.js.map +0 -1
  154. package/dist/commands/setup.d.ts +0 -29
  155. package/dist/commands/setup.d.ts.map +0 -1
  156. package/dist/commands/setup.js +0 -399
  157. package/dist/commands/setup.js.map +0 -1
  158. package/dist/commands/test-init.d.ts +0 -9
  159. package/dist/commands/test-init.d.ts.map +0 -1
  160. package/dist/commands/test-init.js +0 -222
  161. package/dist/commands/test-init.js.map +0 -1
  162. package/dist/commands/test.d.ts +0 -25
  163. package/dist/commands/test.d.ts.map +0 -1
  164. package/dist/commands/test.js +0 -217
  165. package/dist/commands/test.js.map +0 -1
  166. package/dist/commands/watch.d.ts +0 -76
  167. package/dist/commands/watch.d.ts.map +0 -1
  168. package/dist/commands/watch.js +0 -610
  169. package/dist/commands/watch.js.map +0 -1
  170. package/dist/context/context-manager.d.ts +0 -155
  171. package/dist/context/context-manager.d.ts.map +0 -1
  172. package/dist/context/context-manager.js +0 -383
  173. package/dist/context/context-manager.js.map +0 -1
  174. package/dist/context/index.d.ts +0 -3
  175. package/dist/context/index.d.ts.map +0 -1
  176. package/dist/context/index.js +0 -6
  177. package/dist/context/index.js.map +0 -1
  178. package/dist/context/session-manager.d.ts +0 -207
  179. package/dist/context/session-manager.d.ts.map +0 -1
  180. package/dist/context/session-manager.js +0 -682
  181. package/dist/context/session-manager.js.map +0 -1
  182. package/dist/index.d.ts +0 -8
  183. package/dist/index.d.ts.map +0 -1
  184. package/dist/index.js +0 -51
  185. package/dist/index.js.map +0 -1
  186. package/dist/interactive/interactive-mode.d.ts +0 -76
  187. package/dist/interactive/interactive-mode.d.ts.map +0 -1
  188. package/dist/interactive/interactive-mode.js +0 -730
  189. package/dist/interactive/interactive-mode.js.map +0 -1
  190. package/dist/nlp/command-mapper.d.ts +0 -174
  191. package/dist/nlp/command-mapper.d.ts.map +0 -1
  192. package/dist/nlp/command-mapper.js +0 -623
  193. package/dist/nlp/command-mapper.js.map +0 -1
  194. package/dist/nlp/command-parser.d.ts +0 -106
  195. package/dist/nlp/command-parser.d.ts.map +0 -1
  196. package/dist/nlp/command-parser.js +0 -416
  197. package/dist/nlp/command-parser.js.map +0 -1
  198. package/dist/nlp/index.d.ts +0 -5
  199. package/dist/nlp/index.d.ts.map +0 -1
  200. package/dist/nlp/index.js +0 -8
  201. package/dist/nlp/index.js.map +0 -1
  202. package/dist/nlp/intent-classifier.d.ts +0 -59
  203. package/dist/nlp/intent-classifier.d.ts.map +0 -1
  204. package/dist/nlp/intent-classifier.js +0 -384
  205. package/dist/nlp/intent-classifier.js.map +0 -1
  206. package/dist/nlp/intent-parser.d.ts +0 -152
  207. package/dist/nlp/intent-parser.d.ts.map +0 -1
  208. package/dist/nlp/intent-parser.js +0 -739
  209. package/dist/nlp/intent-parser.js.map +0 -1
  210. package/dist/plugins/plugin-manager.d.ts +0 -120
  211. package/dist/plugins/plugin-manager.d.ts.map +0 -1
  212. package/dist/plugins/plugin-manager.js +0 -595
  213. package/dist/plugins/plugin-manager.js.map +0 -1
  214. package/dist/types/index.d.ts +0 -224
  215. package/dist/types/index.d.ts.map +0 -1
  216. package/dist/types/index.js +0 -3
  217. package/dist/types/index.js.map +0 -1
  218. package/dist/utils/config-manager.d.ts +0 -73
  219. package/dist/utils/config-manager.d.ts.map +0 -1
  220. package/dist/utils/config-manager.js +0 -339
  221. package/dist/utils/config-manager.js.map +0 -1
  222. package/dist/utils/error-handler.d.ts +0 -46
  223. package/dist/utils/error-handler.d.ts.map +0 -1
  224. package/dist/utils/error-handler.js +0 -169
  225. package/dist/utils/error-handler.js.map +0 -1
  226. package/dist/utils/logger.d.ts +0 -25
  227. package/dist/utils/logger.d.ts.map +0 -1
  228. package/dist/utils/logger.js +0 -94
  229. package/dist/utils/logger.js.map +0 -1
  230. package/src/commands/computer-setup-commands.ts +0 -709
@@ -1,10 +1,13 @@
1
- import fs from 'fs-extra';
2
- import path from 'path';
3
1
  import os from 'os';
2
+ import path from 'path';
3
+
4
+ import fs from 'fs-extra';
4
5
  import { z } from 'zod';
5
- import { WundrConfig } from '../types';
6
- import { logger } from './logger';
6
+
7
7
  import { errorHandler } from './error-handler';
8
+ import { logger } from './logger';
9
+
10
+ import type { WundrConfig } from '../types';
8
11
 
9
12
  // Zod schema for configuration validation
10
13
  const WundrConfigSchema = z.object({
@@ -213,7 +216,7 @@ export class ConfigManager {
213
216
  throw new Error(`Invalid path: empty key at position ${i}`);
214
217
  }
215
218
  if (!current || typeof current !== 'object') {
216
- throw new Error(`Invalid path: cannot set property on non-object`);
219
+ throw new Error('Invalid path: cannot set property on non-object');
217
220
  }
218
221
  if (!current[key] || typeof current[key] !== 'object') {
219
222
  current[key] = {};
@@ -226,7 +229,7 @@ export class ConfigManager {
226
229
  throw new Error('Invalid path: empty final key');
227
230
  }
228
231
  if (!finalKey || !current || typeof current !== 'object') {
229
- throw new Error(`Invalid path: cannot set property`);
232
+ throw new Error('Invalid path: cannot set property');
230
233
  }
231
234
  current[finalKey] = value;
232
235
  }
@@ -1,7 +1,9 @@
1
1
  import chalk from 'chalk';
2
- import { WundrError } from '../types';
2
+
3
3
  import { logger } from './logger';
4
4
 
5
+ import type { WundrError } from '../types';
6
+
5
7
  /**
6
8
  * Centralized error handling system
7
9
  */
@@ -1,5 +1,6 @@
1
1
  import chalk from 'chalk';
2
- import { Logger } from '../types';
2
+
3
+ import type { Logger } from '../types';
3
4
 
4
5
  /**
5
6
  * Enhanced logger with multiple levels and colored output
@@ -17,7 +18,9 @@ class WundrLogger implements Logger {
17
18
  }
18
19
 
19
20
  private shouldLog(level: string): boolean {
20
- if (this.silent) return false;
21
+ if (this.silent) {
22
+ return false;
23
+ }
21
24
 
22
25
  const levels = { debug: 0, info: 1, warn: 2, error: 3 };
23
26
  return levels[level as keyof typeof levels] >= levels[this.level];
@@ -36,54 +39,74 @@ class WundrLogger implements Logger {
36
39
  }
37
40
 
38
41
  debug(message: string, ...args: any[]): void {
39
- if (!this.shouldLog('debug')) return;
42
+ if (!this.shouldLog('debug')) {
43
+ return;
44
+ }
40
45
  console.log(chalk.gray(this.formatMessage('debug', message, ...args)));
41
46
  }
42
47
 
43
48
  info(message: string, ...args: any[]): void {
44
- if (!this.shouldLog('info')) return;
49
+ if (!this.shouldLog('info')) {
50
+ return;
51
+ }
45
52
  console.log(chalk.blue(this.formatMessage('info', message, ...args)));
46
53
  }
47
54
 
48
55
  warn(message: string, ...args: any[]): void {
49
- if (!this.shouldLog('warn')) return;
56
+ if (!this.shouldLog('warn')) {
57
+ return;
58
+ }
50
59
  console.warn(chalk.yellow(this.formatMessage('warn', message, ...args)));
51
60
  }
52
61
 
53
62
  error(message: string, ...args: any[]): void {
54
- if (!this.shouldLog('error')) return;
63
+ if (!this.shouldLog('error')) {
64
+ return;
65
+ }
55
66
  console.error(chalk.red(this.formatMessage('error', message, ...args)));
56
67
  }
57
68
 
58
69
  success(message: string, ...args: any[]): void {
59
- if (!this.shouldLog('info')) return;
70
+ if (!this.shouldLog('info')) {
71
+ return;
72
+ }
60
73
  console.log(chalk.green(this.formatMessage('success', message, ...args)));
61
74
  }
62
75
 
63
76
  // Utility methods for structured logging
64
77
  table(data: any[]): void {
65
- if (this.silent) return;
78
+ if (this.silent) {
79
+ return;
80
+ }
66
81
  console.table(data);
67
82
  }
68
83
 
69
84
  json(data: any): void {
70
- if (this.silent) return;
85
+ if (this.silent) {
86
+ return;
87
+ }
71
88
  console.log(JSON.stringify(data, null, 2));
72
89
  }
73
90
 
74
91
  group(label: string): void {
75
- if (this.silent) return;
92
+ if (this.silent) {
93
+ return;
94
+ }
76
95
  console.group(chalk.cyan(label));
77
96
  }
78
97
 
79
98
  groupEnd(): void {
80
- if (this.silent) return;
99
+ if (this.silent) {
100
+ return;
101
+ }
81
102
  console.groupEnd();
82
103
  }
83
104
 
84
105
  // Progress logging
85
106
  progress(current: number, total: number, message?: string): void {
86
- if (this.silent) return;
107
+ if (this.silent) {
108
+ return;
109
+ }
87
110
  const percentage = Math.round((current / total) * 100);
88
111
  const bar = '█'.repeat(Math.round(percentage / 2));
89
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 # 30 minutes
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 # 5 minutes
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 # 10 minutes
37
+ timeout: 600000 # 10 minutes
38
38
 
39
39
  - command: "npm run test:e2e"
40
40
  condition: "e2e-tests-exist"
41
- timeout: 900000 # 15 minutes
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 # 5 minutes
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 # 10 minutes
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
- contentType?.includes('text/html')
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(`${baseURL}/api/nonexistent-endpoint-${Date.now()}`);
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
- 'Origin': 'https://example.com'
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: 'button[type="submit"], button:has-text("Login"), button:has-text("Sign in")'
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 = label > 0 || ariaLabel !== null || ariaLabelledBy !== null;
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(() => document.activeElement);
60
- const hasOutline = await focusedElement.evaluate((el) => {
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('h1, h2, h3, h4, h5, h6');
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', (error) => {
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(error =>
24
- error.includes('Cannot read') ||
25
- error.includes('undefined is not') ||
26
- error.includes('Uncaught')
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 = await page.locator('nav, [role="navigation"], header').count() > 0;
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 document.documentElement.scrollWidth > document.documentElement.clientWidth;
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
+ });