claude-cli-advanced-starter-pack 1.0.12 → 1.0.14
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 +527 -345
- package/package.json +1 -1
- package/src/commands/init.js +336 -42
- package/src/commands/test-setup.js +7 -6
- package/src/data/releases.json +102 -5
- package/src/testing/config.js +213 -84
- package/src/utils/smart-merge.js +457 -0
- package/src/utils/version-check.js +213 -0
- package/templates/commands/create-task-list.template.md +332 -17
- package/templates/commands/update-smart.template.md +111 -0
- package/templates/hooks/ccasp-update-check.template.js +74 -0
- package/templates/hooks/usage-tracking.template.js +222 -0
package/src/data/releases.json
CHANGED
|
@@ -1,16 +1,96 @@
|
|
|
1
1
|
{
|
|
2
2
|
"releases": [
|
|
3
|
+
{
|
|
4
|
+
"version": "1.0.14",
|
|
5
|
+
"date": "2026-01-30",
|
|
6
|
+
"summary": "Fix: Complete feature deployment - hooks, commands, and auto-selection now work correctly",
|
|
7
|
+
"highlights": [
|
|
8
|
+
"Feature commands are now auto-included when a feature is selected",
|
|
9
|
+
"Feature hooks are now properly deployed during init",
|
|
10
|
+
"OPTIONAL_FEATURES cleaned up to only reference existing templates",
|
|
11
|
+
"tech-stack.json now tracks deployed commands and hooks for verification",
|
|
12
|
+
"Step 6b added to show feature hook deployment progress"
|
|
13
|
+
],
|
|
14
|
+
"newFeatures": {
|
|
15
|
+
"commands": [],
|
|
16
|
+
"agents": [],
|
|
17
|
+
"skills": [],
|
|
18
|
+
"hooks": [],
|
|
19
|
+
"other": [
|
|
20
|
+
{
|
|
21
|
+
"name": "feature-auto-deployment",
|
|
22
|
+
"description": "When selecting a feature, its commands and hooks are automatically deployed"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "deployment-tracking",
|
|
26
|
+
"description": "tech-stack.json now includes _deployment section tracking what was installed"
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"breaking": [],
|
|
31
|
+
"deprecated": []
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"version": "1.0.13",
|
|
35
|
+
"date": "2026-01-30",
|
|
36
|
+
"summary": "Feature: Smart Update Merge Tracking - Intelligent handling of customized assets during updates",
|
|
37
|
+
"highlights": [
|
|
38
|
+
"Tracks usage of commands, skills, agents, and hooks in usage-tracking.json",
|
|
39
|
+
"Smart merge detection: identifies customized assets that have updates available",
|
|
40
|
+
"Interactive merge exploration: Claude explains what changes, offers merge/replace/skip options",
|
|
41
|
+
"New /update-smart command for manual merge exploration",
|
|
42
|
+
"Usage tracking hook runs on PostToolUse for Skill and Read tools"
|
|
43
|
+
],
|
|
44
|
+
"newFeatures": {
|
|
45
|
+
"commands": [
|
|
46
|
+
{
|
|
47
|
+
"name": "update-smart",
|
|
48
|
+
"description": "Smart merge manager for customized assets during updates",
|
|
49
|
+
"category": "Maintenance"
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"agents": [],
|
|
53
|
+
"skills": [],
|
|
54
|
+
"hooks": [
|
|
55
|
+
{
|
|
56
|
+
"name": "usage-tracking",
|
|
57
|
+
"description": "Tracks usage of commands, skills, agents for smart merge detection"
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"other": [
|
|
61
|
+
{
|
|
62
|
+
"name": "smart-merge-system",
|
|
63
|
+
"description": "Intelligent diff comparison and merge exploration for customized assets"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "usage-tracking-json",
|
|
67
|
+
"description": "Persistent tracking of asset usage in .claude/config/usage-tracking.json"
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
"breaking": [],
|
|
72
|
+
"deprecated": []
|
|
73
|
+
},
|
|
3
74
|
{
|
|
4
75
|
"version": "1.0.12",
|
|
5
76
|
"date": "2026-01-30",
|
|
6
|
-
"summary": "
|
|
7
|
-
"highlights": [
|
|
77
|
+
"summary": "Feature: /project-impl recommendation banner in /menu",
|
|
78
|
+
"highlights": [
|
|
79
|
+
"Shows setup tip when /project-impl hasn't been run yet",
|
|
80
|
+
"Tracks projectImplCompleted state in ccasp-state.json",
|
|
81
|
+
"Banner disappears after running any /project-impl option"
|
|
82
|
+
],
|
|
8
83
|
"newFeatures": {
|
|
9
84
|
"commands": [],
|
|
10
85
|
"agents": [],
|
|
11
86
|
"skills": [],
|
|
12
87
|
"hooks": [],
|
|
13
|
-
"other": [
|
|
88
|
+
"other": [
|
|
89
|
+
{
|
|
90
|
+
"name": "project-impl-banner",
|
|
91
|
+
"description": "Recommends running /project-impl for new installations"
|
|
92
|
+
}
|
|
93
|
+
]
|
|
14
94
|
},
|
|
15
95
|
"breaking": [],
|
|
16
96
|
"deprecated": []
|
|
@@ -18,8 +98,11 @@
|
|
|
18
98
|
{
|
|
19
99
|
"version": "1.0.11",
|
|
20
100
|
"date": "2026-01-30",
|
|
21
|
-
"summary": "
|
|
22
|
-
"highlights": [
|
|
101
|
+
"summary": "Security: Removed project-specific example text from prompts",
|
|
102
|
+
"highlights": [
|
|
103
|
+
"Changed ngrok example from 'my.app.benefits360' to 'my-app-name'",
|
|
104
|
+
"Security audit confirmed no personal data in npm package"
|
|
105
|
+
],
|
|
23
106
|
"newFeatures": {
|
|
24
107
|
"commands": [],
|
|
25
108
|
"agents": [],
|
|
@@ -413,6 +496,20 @@
|
|
|
413
496
|
"update-check": {
|
|
414
497
|
"addedIn": "1.0.5",
|
|
415
498
|
"required": false
|
|
499
|
+
},
|
|
500
|
+
"update-smart": {
|
|
501
|
+
"addedIn": "1.0.13",
|
|
502
|
+
"required": false
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
"hooks": {
|
|
506
|
+
"ccasp-update-check": {
|
|
507
|
+
"addedIn": "1.0.7",
|
|
508
|
+
"required": true
|
|
509
|
+
},
|
|
510
|
+
"usage-tracking": {
|
|
511
|
+
"addedIn": "1.0.13",
|
|
512
|
+
"required": false
|
|
416
513
|
}
|
|
417
514
|
},
|
|
418
515
|
"optionalFeatures": {
|
package/src/testing/config.js
CHANGED
|
@@ -1,16 +1,65 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Testing Configuration Module
|
|
3
3
|
*
|
|
4
|
-
* Manages testing modes, credentials, and environment configuration
|
|
4
|
+
* Manages testing modes, credentials, and environment configuration.
|
|
5
|
+
* Testing config is stored in tech-stack.json under the `testing` section
|
|
6
|
+
* for unified configuration management.
|
|
5
7
|
*/
|
|
6
8
|
|
|
7
9
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
8
|
-
import { join } from 'path';
|
|
9
|
-
|
|
10
|
-
// Default paths
|
|
11
|
-
const
|
|
10
|
+
import { join, dirname } from 'path';
|
|
11
|
+
|
|
12
|
+
// Default paths - now uses tech-stack.json
|
|
13
|
+
const TECH_STACK_PATHS = [
|
|
14
|
+
join(process.cwd(), '.claude', 'tech-stack.json'),
|
|
15
|
+
join(process.cwd(), 'tech-stack.json'),
|
|
16
|
+
];
|
|
17
|
+
const RULES_DIR = join(process.cwd(), '.claude', 'task-lists');
|
|
12
18
|
const TESTING_RULES_FILE = 'TESTING_RULES.md';
|
|
13
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Get path to tech-stack.json (prefers .claude/tech-stack.json)
|
|
22
|
+
*/
|
|
23
|
+
function getTechStackPath() {
|
|
24
|
+
for (const path of TECH_STACK_PATHS) {
|
|
25
|
+
if (existsSync(path)) {
|
|
26
|
+
return path;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return TECH_STACK_PATHS[0];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Load tech-stack.json
|
|
34
|
+
*/
|
|
35
|
+
function loadTechStackJson() {
|
|
36
|
+
const techStackPath = getTechStackPath();
|
|
37
|
+
if (existsSync(techStackPath)) {
|
|
38
|
+
try {
|
|
39
|
+
return JSON.parse(readFileSync(techStackPath, 'utf8'));
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Save tech-stack.json
|
|
49
|
+
*/
|
|
50
|
+
function saveTechStackJson(techStack) {
|
|
51
|
+
const techStackPath = getTechStackPath();
|
|
52
|
+
const configDir = dirname(techStackPath);
|
|
53
|
+
|
|
54
|
+
if (!existsSync(configDir)) {
|
|
55
|
+
mkdirSync(configDir, { recursive: true });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
techStack._lastModified = new Date().toISOString();
|
|
59
|
+
writeFileSync(techStackPath, JSON.stringify(techStack, null, 2), 'utf8');
|
|
60
|
+
return techStackPath;
|
|
61
|
+
}
|
|
62
|
+
|
|
14
63
|
/**
|
|
15
64
|
* Testing mode definitions
|
|
16
65
|
*/
|
|
@@ -99,107 +148,155 @@ export const CREDENTIAL_SOURCES = {
|
|
|
99
148
|
};
|
|
100
149
|
|
|
101
150
|
/**
|
|
102
|
-
* Testing configuration structure
|
|
151
|
+
* Testing configuration structure (compatible with tech-stack.json `testing` section)
|
|
152
|
+
*
|
|
153
|
+
* This structure maps to tech-stack.json testing fields:
|
|
154
|
+
* - testing.e2e.framework -> e2e framework
|
|
155
|
+
* - testing.e2e.configFile -> playwright config
|
|
156
|
+
* - testing.selectors.* -> login selectors
|
|
157
|
+
* - testing.credentials.* -> env var names
|
|
103
158
|
*/
|
|
104
159
|
export function createTestingConfig(options = {}) {
|
|
105
160
|
return {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
161
|
+
// E2E testing configuration
|
|
162
|
+
e2e: {
|
|
163
|
+
framework: options.playwrightEnabled ? 'playwright' : 'none',
|
|
164
|
+
configFile: options.playwrightConfig || 'playwright.config.ts',
|
|
165
|
+
testCommand: 'npx playwright test',
|
|
166
|
+
browser: options.browser || 'chromium',
|
|
167
|
+
headless: options.headless ?? true,
|
|
168
|
+
timeout: options.timeout || 30000,
|
|
169
|
+
},
|
|
109
170
|
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
autoRetry: true,
|
|
116
|
-
} : null,
|
|
171
|
+
// Unit testing (preserved from existing config)
|
|
172
|
+
unit: {
|
|
173
|
+
framework: 'none',
|
|
174
|
+
testCommand: 'npm test',
|
|
175
|
+
},
|
|
117
176
|
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
177
|
+
// Test selectors for login flow
|
|
178
|
+
selectors: {
|
|
179
|
+
strategy: 'data-testid',
|
|
180
|
+
username: options.usernameSelector || '[data-testid="username-input"]',
|
|
181
|
+
password: options.passwordSelector || '[data-testid="password-input"]',
|
|
182
|
+
loginButton: options.loginButtonSelector || '[data-testid="login-submit"]',
|
|
183
|
+
loginSuccess: options.loginSuccessSelector || '[data-testid="dashboard"]',
|
|
124
184
|
},
|
|
125
185
|
|
|
126
|
-
// Credentials
|
|
186
|
+
// Credentials (env var names, never actual credentials)
|
|
127
187
|
credentials: {
|
|
188
|
+
usernameEnvVar: options.envVars?.username || 'TEST_USER_USERNAME',
|
|
189
|
+
passwordEnvVar: options.envVars?.password || 'TEST_USER_PASSWORD',
|
|
128
190
|
source: options.credentialSource || 'env',
|
|
129
|
-
envVars: options.envVars || {
|
|
130
|
-
username: 'TEST_USER_USERNAME',
|
|
131
|
-
password: 'TEST_USER_PASSWORD',
|
|
132
|
-
},
|
|
133
|
-
// Only stored if source is 'config'
|
|
134
|
-
username: options.credentialSource === 'config' ? options.username : undefined,
|
|
135
|
-
password: options.credentialSource === 'config' ? options.password : undefined,
|
|
136
191
|
},
|
|
137
192
|
|
|
138
|
-
//
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
timeout: options.timeout || 30000,
|
|
193
|
+
// Environment configuration
|
|
194
|
+
environment: {
|
|
195
|
+
type: options.envType || 'localhost',
|
|
196
|
+
baseUrl: options.baseUrl || 'http://localhost:5173',
|
|
197
|
+
port: options.port || 5173,
|
|
198
|
+
requiresSetup: options.requiresSetup || [],
|
|
145
199
|
},
|
|
146
200
|
|
|
147
|
-
//
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
},
|
|
201
|
+
// Testing mode (ralph loop, manual, minimal)
|
|
202
|
+
mode: options.mode || 'manual',
|
|
203
|
+
ralphConfig: options.mode === 'ralph' ? {
|
|
204
|
+
maxIterations: options.maxIterations || 10,
|
|
205
|
+
completionPromise: options.completionPromise || 'all tasks complete and tests passing',
|
|
206
|
+
autoRetry: true,
|
|
207
|
+
} : null,
|
|
154
208
|
|
|
155
209
|
// Persistent rules file path
|
|
156
210
|
rulesFile: options.rulesFile || null,
|
|
211
|
+
|
|
212
|
+
// Configuration metadata
|
|
213
|
+
_configuredAt: new Date().toISOString(),
|
|
214
|
+
_configuredBy: 'ccasp-test-setup',
|
|
157
215
|
};
|
|
158
216
|
}
|
|
159
217
|
|
|
160
218
|
/**
|
|
161
|
-
* Save testing configuration
|
|
219
|
+
* Save testing configuration to tech-stack.json
|
|
162
220
|
*/
|
|
163
221
|
export function saveTestingConfig(config) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
222
|
+
// Load existing tech-stack or create default
|
|
223
|
+
let techStack = loadTechStackJson() || {
|
|
224
|
+
version: '2.0.0',
|
|
225
|
+
project: { name: 'unnamed', description: '' },
|
|
226
|
+
frontend: {},
|
|
227
|
+
backend: {},
|
|
228
|
+
testing: {},
|
|
229
|
+
};
|
|
170
230
|
|
|
171
|
-
|
|
231
|
+
// Merge testing config into tech-stack
|
|
232
|
+
techStack.testing = {
|
|
233
|
+
...techStack.testing,
|
|
234
|
+
...config,
|
|
235
|
+
};
|
|
172
236
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
237
|
+
const configPath = saveTechStackJson(techStack);
|
|
238
|
+
|
|
239
|
+
// Also save to legacy location for backwards compatibility
|
|
240
|
+
// (will be removed in future version)
|
|
241
|
+
const legacyDir = join(process.cwd(), '.gtask');
|
|
242
|
+
if (existsSync(legacyDir)) {
|
|
243
|
+
try {
|
|
244
|
+
writeFileSync(
|
|
245
|
+
join(legacyDir, 'testing.json'),
|
|
246
|
+
JSON.stringify(config, null, 2),
|
|
247
|
+
'utf8'
|
|
248
|
+
);
|
|
249
|
+
} catch {
|
|
250
|
+
// Ignore legacy save errors
|
|
251
|
+
}
|
|
176
252
|
}
|
|
177
253
|
|
|
178
254
|
return configPath;
|
|
179
255
|
}
|
|
180
256
|
|
|
181
257
|
/**
|
|
182
|
-
* Load testing configuration
|
|
258
|
+
* Load testing configuration from tech-stack.json
|
|
183
259
|
*/
|
|
184
260
|
export function loadTestingConfig() {
|
|
185
|
-
const
|
|
261
|
+
const techStack = loadTechStackJson();
|
|
186
262
|
|
|
187
|
-
if (
|
|
188
|
-
return
|
|
263
|
+
if (techStack?.testing && Object.keys(techStack.testing).length > 0) {
|
|
264
|
+
return techStack.testing;
|
|
189
265
|
}
|
|
190
266
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
267
|
+
// Fallback to legacy .gtask/testing.json for backwards compatibility
|
|
268
|
+
const legacyPath = join(process.cwd(), '.gtask', 'testing.json');
|
|
269
|
+
if (existsSync(legacyPath)) {
|
|
270
|
+
try {
|
|
271
|
+
return JSON.parse(readFileSync(legacyPath, 'utf8'));
|
|
272
|
+
} catch {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
195
275
|
}
|
|
276
|
+
|
|
277
|
+
return null;
|
|
196
278
|
}
|
|
197
279
|
|
|
198
280
|
/**
|
|
199
|
-
* Check if testing is configured
|
|
281
|
+
* Check if testing is configured (checks tech-stack.json and legacy location)
|
|
200
282
|
*/
|
|
201
283
|
export function hasTestingConfig() {
|
|
202
|
-
|
|
284
|
+
const techStack = loadTechStackJson();
|
|
285
|
+
|
|
286
|
+
// Check if tech-stack.json has meaningful testing config
|
|
287
|
+
if (techStack?.testing) {
|
|
288
|
+
const testing = techStack.testing;
|
|
289
|
+
// Consider configured if has e2e framework or selectors
|
|
290
|
+
if (testing.e2e?.framework && testing.e2e.framework !== 'none') {
|
|
291
|
+
return true;
|
|
292
|
+
}
|
|
293
|
+
if (testing.selectors?.username) {
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Fallback to legacy location
|
|
299
|
+
return existsSync(join(process.cwd(), '.gtask', 'testing.json'));
|
|
203
300
|
}
|
|
204
301
|
|
|
205
302
|
/**
|
|
@@ -320,14 +417,14 @@ npx playwright test --ui
|
|
|
320
417
|
}
|
|
321
418
|
|
|
322
419
|
/**
|
|
323
|
-
* Save testing rules markdown file
|
|
420
|
+
* Save testing rules markdown file to .claude/task-lists/
|
|
324
421
|
*/
|
|
325
422
|
export function saveTestingRules(config, filename = TESTING_RULES_FILE) {
|
|
326
|
-
if (!existsSync(
|
|
327
|
-
mkdirSync(
|
|
423
|
+
if (!existsSync(RULES_DIR)) {
|
|
424
|
+
mkdirSync(RULES_DIR, { recursive: true });
|
|
328
425
|
}
|
|
329
426
|
|
|
330
|
-
const rulesPath = join(
|
|
427
|
+
const rulesPath = join(RULES_DIR, filename);
|
|
331
428
|
const content = generateTestingRules(config);
|
|
332
429
|
|
|
333
430
|
writeFileSync(rulesPath, content, 'utf8');
|
|
@@ -356,24 +453,19 @@ function ensureGitignore(pattern) {
|
|
|
356
453
|
}
|
|
357
454
|
|
|
358
455
|
/**
|
|
359
|
-
* Get credentials based on config
|
|
456
|
+
* Get credentials based on config (uses new tech-stack.json structure)
|
|
360
457
|
*/
|
|
361
458
|
export function getCredentials(config) {
|
|
362
|
-
if (!config || config.credentials
|
|
459
|
+
if (!config || config.credentials?.source === 'none') {
|
|
363
460
|
return null;
|
|
364
461
|
}
|
|
365
462
|
|
|
366
|
-
if (config.credentials
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
password: process.env[config.credentials.envVars.password] || null,
|
|
370
|
-
};
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
if (config.credentials.source === 'config') {
|
|
463
|
+
if (config.credentials?.source === 'env') {
|
|
464
|
+
const usernameVar = config.credentials.usernameEnvVar || config.credentials.envVars?.username;
|
|
465
|
+
const passwordVar = config.credentials.passwordEnvVar || config.credentials.envVars?.password;
|
|
374
466
|
return {
|
|
375
|
-
username:
|
|
376
|
-
password:
|
|
467
|
+
username: process.env[usernameVar] || null,
|
|
468
|
+
password: process.env[passwordVar] || null,
|
|
377
469
|
};
|
|
378
470
|
}
|
|
379
471
|
|
|
@@ -382,10 +474,11 @@ export function getCredentials(config) {
|
|
|
382
474
|
}
|
|
383
475
|
|
|
384
476
|
/**
|
|
385
|
-
* Validate testing configuration
|
|
477
|
+
* Validate testing configuration (works with tech-stack.json structure)
|
|
386
478
|
*/
|
|
387
479
|
export function validateConfig(config) {
|
|
388
480
|
const errors = [];
|
|
481
|
+
const warnings = [];
|
|
389
482
|
|
|
390
483
|
if (!config.environment?.baseUrl) {
|
|
391
484
|
errors.push('Base URL is required');
|
|
@@ -393,9 +486,12 @@ export function validateConfig(config) {
|
|
|
393
486
|
|
|
394
487
|
if (config.credentials?.source === 'env') {
|
|
395
488
|
const creds = getCredentials(config);
|
|
489
|
+
const usernameVar = config.credentials.usernameEnvVar || config.credentials.envVars?.username;
|
|
490
|
+
const passwordVar = config.credentials.passwordEnvVar || config.credentials.envVars?.password;
|
|
491
|
+
|
|
396
492
|
if (!creds?.username || !creds?.password) {
|
|
397
|
-
|
|
398
|
-
`Environment variables not set: ${
|
|
493
|
+
warnings.push(
|
|
494
|
+
`Environment variables not set: ${usernameVar}, ${passwordVar}`
|
|
399
495
|
);
|
|
400
496
|
}
|
|
401
497
|
}
|
|
@@ -404,8 +500,41 @@ export function validateConfig(config) {
|
|
|
404
500
|
errors.push('Ralph configuration missing');
|
|
405
501
|
}
|
|
406
502
|
|
|
503
|
+
if (config.e2e?.framework === 'none') {
|
|
504
|
+
warnings.push('No E2E testing framework configured');
|
|
505
|
+
}
|
|
506
|
+
|
|
407
507
|
return {
|
|
408
508
|
valid: errors.length === 0,
|
|
409
509
|
errors,
|
|
510
|
+
warnings,
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Get a summary of what testing features are configured
|
|
516
|
+
*/
|
|
517
|
+
export function getTestingConfigSummary() {
|
|
518
|
+
const config = loadTestingConfig();
|
|
519
|
+
|
|
520
|
+
if (!config) {
|
|
521
|
+
return {
|
|
522
|
+
configured: false,
|
|
523
|
+
e2eFramework: null,
|
|
524
|
+
hasSelectors: false,
|
|
525
|
+
hasCredentials: false,
|
|
526
|
+
environment: null,
|
|
527
|
+
mode: null,
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
return {
|
|
532
|
+
configured: true,
|
|
533
|
+
e2eFramework: config.e2e?.framework || config.playwright?.enabled ? 'playwright' : null,
|
|
534
|
+
hasSelectors: !!(config.selectors?.username || config.selectors?.usernameInput),
|
|
535
|
+
hasCredentials: !!(config.credentials?.usernameEnvVar || config.credentials?.envVars?.username),
|
|
536
|
+
environment: config.environment?.type || 'localhost',
|
|
537
|
+
baseUrl: config.environment?.baseUrl,
|
|
538
|
+
mode: config.mode || 'manual',
|
|
410
539
|
};
|
|
411
540
|
}
|