agentic-qe 2.1.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/dist/agents/QXPartnerAgent.d.ts +40 -1
- package/dist/agents/QXPartnerAgent.d.ts.map +1 -1
- package/dist/agents/QXPartnerAgent.js +918 -19
- package/dist/agents/QXPartnerAgent.js.map +1 -1
- package/dist/core/memory/ReflexionMemoryAdapter.d.ts +109 -0
- package/dist/core/memory/ReflexionMemoryAdapter.d.ts.map +1 -0
- package/dist/core/memory/ReflexionMemoryAdapter.js +306 -0
- package/dist/core/memory/ReflexionMemoryAdapter.js.map +1 -0
- package/dist/core/memory/RuVectorPatternStore.d.ts +28 -0
- package/dist/core/memory/RuVectorPatternStore.d.ts.map +1 -1
- package/dist/core/memory/RuVectorPatternStore.js +70 -0
- package/dist/core/memory/RuVectorPatternStore.js.map +1 -1
- package/dist/core/memory/SparseVectorSearch.d.ts +55 -0
- package/dist/core/memory/SparseVectorSearch.d.ts.map +1 -0
- package/dist/core/memory/SparseVectorSearch.js +130 -0
- package/dist/core/memory/SparseVectorSearch.js.map +1 -0
- package/dist/core/memory/TieredCompression.d.ts +81 -0
- package/dist/core/memory/TieredCompression.d.ts.map +1 -0
- package/dist/core/memory/TieredCompression.js +270 -0
- package/dist/core/memory/TieredCompression.js.map +1 -0
- package/dist/core/memory/index.d.ts +6 -0
- package/dist/core/memory/index.d.ts.map +1 -1
- package/dist/core/memory/index.js +29 -1
- package/dist/core/memory/index.js.map +1 -1
- package/dist/mcp/handlers/chaos/chaos-inject-failure.d.ts +5 -0
- package/dist/mcp/handlers/chaos/chaos-inject-failure.d.ts.map +1 -1
- package/dist/mcp/handlers/chaos/chaos-inject-failure.js +36 -2
- package/dist/mcp/handlers/chaos/chaos-inject-failure.js.map +1 -1
- package/dist/mcp/handlers/chaos/chaos-inject-latency.d.ts +5 -0
- package/dist/mcp/handlers/chaos/chaos-inject-latency.d.ts.map +1 -1
- package/dist/mcp/handlers/chaos/chaos-inject-latency.js +36 -2
- package/dist/mcp/handlers/chaos/chaos-inject-latency.js.map +1 -1
- package/dist/types/qx.d.ts +74 -0
- package/dist/types/qx.d.ts.map +1 -1
- package/dist/types/qx.js.map +1 -1
- package/package.json +4 -1
|
@@ -16,12 +16,50 @@
|
|
|
16
16
|
* - Integration with testability scoring
|
|
17
17
|
* - Contextual recommendations generation
|
|
18
18
|
*/
|
|
19
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
22
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
23
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
24
|
+
}
|
|
25
|
+
Object.defineProperty(o, k2, desc);
|
|
26
|
+
}) : (function(o, m, k, k2) {
|
|
27
|
+
if (k2 === undefined) k2 = k;
|
|
28
|
+
o[k2] = m[k];
|
|
29
|
+
}));
|
|
30
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
31
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
32
|
+
}) : function(o, v) {
|
|
33
|
+
o["default"] = v;
|
|
34
|
+
});
|
|
35
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
36
|
+
var ownKeys = function(o) {
|
|
37
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
38
|
+
var ar = [];
|
|
39
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
40
|
+
return ar;
|
|
41
|
+
};
|
|
42
|
+
return ownKeys(o);
|
|
43
|
+
};
|
|
44
|
+
return function (mod) {
|
|
45
|
+
if (mod && mod.__esModule) return mod;
|
|
46
|
+
var result = {};
|
|
47
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
48
|
+
__setModuleDefault(result, mod);
|
|
49
|
+
return result;
|
|
50
|
+
};
|
|
51
|
+
})();
|
|
19
52
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
53
|
exports.QXPartnerAgent = void 0;
|
|
21
54
|
const BaseAgent_1 = require("./BaseAgent");
|
|
22
55
|
const types_1 = require("../types");
|
|
23
56
|
const playwright_1 = require("playwright");
|
|
57
|
+
const fs = __importStar(require("fs"));
|
|
58
|
+
const path = __importStar(require("path"));
|
|
59
|
+
const child_process_1 = require("child_process");
|
|
60
|
+
const util_1 = require("util");
|
|
24
61
|
const qx_1 = require("../types/qx");
|
|
62
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
25
63
|
class ConsoleLogger {
|
|
26
64
|
info(message, ...args) {
|
|
27
65
|
console.log(`[INFO] ${message}`, ...args);
|
|
@@ -264,14 +302,18 @@ class QXPartnerAgent extends BaseAgent_1.BaseAgent {
|
|
|
264
302
|
const userNeeds = await this.analyzeUserNeeds(context, problemAnalysis);
|
|
265
303
|
// 4. Analyze business needs
|
|
266
304
|
const businessNeeds = await this.analyzeBusinessNeeds(context, problemAnalysis);
|
|
267
|
-
// 5.
|
|
305
|
+
// 5. Analyze creativity - drawing inspiration from diverse domains
|
|
306
|
+
const creativityAnalysis = await this.analyzeCreativity(context, problemAnalysis);
|
|
307
|
+
// 6. Analyze design - exactness, intuitive, and counter-intuitive design
|
|
308
|
+
const designAnalysis = await this.analyzeDesign(context, problemAnalysis);
|
|
309
|
+
// 7. Detect oracle problems
|
|
268
310
|
const oracleProblems = this.config.detectOracleProblems
|
|
269
311
|
? await this.detectOracleProblemsFromContext(context, userNeeds, businessNeeds)
|
|
270
312
|
: [];
|
|
271
|
-
//
|
|
313
|
+
// 8. Perform impact analysis
|
|
272
314
|
const impactAnalysis = await this.analyzeImpact(context, problemAnalysis);
|
|
273
|
-
//
|
|
274
|
-
const heuristics = await this.applyAllHeuristics(context, problemAnalysis, userNeeds, businessNeeds);
|
|
315
|
+
// 9. Apply heuristics
|
|
316
|
+
const heuristics = await this.applyAllHeuristics(context, problemAnalysis, userNeeds, businessNeeds, creativityAnalysis, designAnalysis);
|
|
275
317
|
// 8. Integrate testability (if enabled)
|
|
276
318
|
const testabilityIntegration = this.config.integrateTestability
|
|
277
319
|
? await this.integrateTestabilityScoring(params)
|
|
@@ -279,7 +321,7 @@ class QXPartnerAgent extends BaseAgent_1.BaseAgent {
|
|
|
279
321
|
// 9. Generate recommendations
|
|
280
322
|
const recommendations = await this.generateRecommendations(problemAnalysis, userNeeds, businessNeeds, oracleProblems, impactAnalysis, heuristics, testabilityIntegration);
|
|
281
323
|
// 10. Calculate overall score
|
|
282
|
-
const overallScore = this.calculateOverallQXScore(problemAnalysis, userNeeds, businessNeeds, impactAnalysis, heuristics);
|
|
324
|
+
const overallScore = this.calculateOverallQXScore(problemAnalysis, userNeeds, businessNeeds, creativityAnalysis, designAnalysis, impactAnalysis, heuristics);
|
|
283
325
|
const grade = this.scoreToGrade(overallScore);
|
|
284
326
|
const analysis = {
|
|
285
327
|
overallScore,
|
|
@@ -289,6 +331,8 @@ class QXPartnerAgent extends BaseAgent_1.BaseAgent {
|
|
|
289
331
|
problemAnalysis,
|
|
290
332
|
userNeeds,
|
|
291
333
|
businessNeeds,
|
|
334
|
+
creativityAnalysis,
|
|
335
|
+
designAnalysis,
|
|
292
336
|
oracleProblems,
|
|
293
337
|
impactAnalysis,
|
|
294
338
|
heuristics,
|
|
@@ -300,8 +344,633 @@ class QXPartnerAgent extends BaseAgent_1.BaseAgent {
|
|
|
300
344
|
await this.storeMemory(`qx-analysis:${target}`, analysis);
|
|
301
345
|
const duration = Date.now() - startTime;
|
|
302
346
|
this.logger.info(`QX analysis completed in ${duration}ms. Score: ${overallScore}/100 (${grade})`);
|
|
347
|
+
// Generate HTML report and auto-launch
|
|
348
|
+
try {
|
|
349
|
+
const reportPath = await this.generateHTMLReport(analysis);
|
|
350
|
+
this.logger.info(`HTML report generated: ${reportPath}`);
|
|
351
|
+
// Auto-launch browser
|
|
352
|
+
await this.launchReportInBrowser(reportPath);
|
|
353
|
+
this.logger.info(`Report launched in browser`);
|
|
354
|
+
}
|
|
355
|
+
catch (error) {
|
|
356
|
+
this.logger.warn(`Failed to generate/launch HTML report:`, error);
|
|
357
|
+
// Don't fail the analysis if report generation fails
|
|
358
|
+
}
|
|
303
359
|
return analysis;
|
|
304
360
|
}
|
|
361
|
+
/**
|
|
362
|
+
* Generate HTML report from QX analysis
|
|
363
|
+
*/
|
|
364
|
+
async generateHTMLReport(analysis) {
|
|
365
|
+
const sanitizedTarget = analysis.target.replace(/[^a-zA-Z0-9]/g, '-').substring(0, 50);
|
|
366
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').substring(0, 19);
|
|
367
|
+
const filename = `qx-report-${sanitizedTarget}-${timestamp}.html`;
|
|
368
|
+
const reportsDir = path.join(process.cwd(), 'docs', 'qx-reports');
|
|
369
|
+
// Ensure reports directory exists
|
|
370
|
+
if (!fs.existsSync(reportsDir)) {
|
|
371
|
+
fs.mkdirSync(reportsDir, { recursive: true });
|
|
372
|
+
}
|
|
373
|
+
const reportPath = path.join(reportsDir, filename);
|
|
374
|
+
const html = this.generateHTMLContent(analysis);
|
|
375
|
+
fs.writeFileSync(reportPath, html, 'utf8');
|
|
376
|
+
return reportPath;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Generate HTML content for the report
|
|
380
|
+
*/
|
|
381
|
+
generateHTMLContent(analysis) {
|
|
382
|
+
const date = analysis.timestamp.toLocaleDateString();
|
|
383
|
+
const time = analysis.timestamp.toLocaleTimeString();
|
|
384
|
+
return `<!DOCTYPE html>
|
|
385
|
+
<html lang="en">
|
|
386
|
+
<head>
|
|
387
|
+
<meta charset="UTF-8">
|
|
388
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
389
|
+
<title>QX Analysis: ${this.escapeHtml(analysis.target)}</title>
|
|
390
|
+
${this.getReportStyles()}
|
|
391
|
+
</head>
|
|
392
|
+
<body>
|
|
393
|
+
<div class="container">
|
|
394
|
+
<div class="header">
|
|
395
|
+
<h1>🍵 Quality Experience (QX) Analysis</h1>
|
|
396
|
+
<div class="subtitle">${this.escapeHtml(analysis.target)}</div>
|
|
397
|
+
<div class="meta">
|
|
398
|
+
<strong>URL:</strong> ${this.escapeHtml(analysis.target)}<br>
|
|
399
|
+
<strong>Analysis Date:</strong> ${date} at ${time}<br>
|
|
400
|
+
<strong>Framework:</strong> QX Partner (Quality + UX Advocacy)
|
|
401
|
+
</div>
|
|
402
|
+
</div>
|
|
403
|
+
|
|
404
|
+
<div class="content">
|
|
405
|
+
<!-- Executive Summary -->
|
|
406
|
+
<div class="section">
|
|
407
|
+
<h2>📊 Executive Summary</h2>
|
|
408
|
+
<p>
|
|
409
|
+
This comprehensive QX analysis evaluates <strong>${this.escapeHtml(analysis.context.title || analysis.target)}</strong>
|
|
410
|
+
through the lens of Quality Experience, examining how quality is co-created for all stakeholders.
|
|
411
|
+
</p>
|
|
412
|
+
</div>
|
|
413
|
+
|
|
414
|
+
<!-- Overall QX Score -->
|
|
415
|
+
<div class="section">
|
|
416
|
+
<h2>🎯 Overall QX Score</h2>
|
|
417
|
+
<div class="score-card">
|
|
418
|
+
<div class="score-item">
|
|
419
|
+
<h4>Problem Clarity</h4>
|
|
420
|
+
<div class="score-value">${analysis.problemAnalysis.clarityScore}</div>
|
|
421
|
+
<div class="score-label">/ 100</div>
|
|
422
|
+
</div>
|
|
423
|
+
<div class="score-item">
|
|
424
|
+
<h4>User Needs Alignment</h4>
|
|
425
|
+
<div class="score-value">${analysis.userNeeds.alignmentScore}</div>
|
|
426
|
+
<div class="score-label">/ 100</div>
|
|
427
|
+
</div>
|
|
428
|
+
<div class="score-item">
|
|
429
|
+
<h4>Business Alignment</h4>
|
|
430
|
+
<div class="score-value">${analysis.businessNeeds.alignmentScore}</div>
|
|
431
|
+
<div class="score-label">/ 100</div>
|
|
432
|
+
</div>
|
|
433
|
+
<div class="score-item">
|
|
434
|
+
<h4>Impact Assessment</h4>
|
|
435
|
+
<div class="score-value">${100 - analysis.impactAnalysis.overallImpactScore}</div>
|
|
436
|
+
<div class="score-label">/ 100</div>
|
|
437
|
+
</div>
|
|
438
|
+
</div>
|
|
439
|
+
<div style="text-align: center; margin-top: 30px;">
|
|
440
|
+
<div class="score-value" style="font-size: 3em; color: ${this.getScoreColor(analysis.overallScore)};">${analysis.overallScore}</div>
|
|
441
|
+
<div class="score-label" style="font-size: 1.2em;">OVERALL QX SCORE (Grade: ${analysis.grade})</div>
|
|
442
|
+
</div>
|
|
443
|
+
</div>
|
|
444
|
+
|
|
445
|
+
<!-- Problem Analysis -->
|
|
446
|
+
<div class="section">
|
|
447
|
+
<h2>🔍 Problem Analysis</h2>
|
|
448
|
+
<div class="info-box">
|
|
449
|
+
<h3>Problem Statement</h3>
|
|
450
|
+
<p>${this.escapeHtml(analysis.problemAnalysis.problemStatement)}</p>
|
|
451
|
+
<p><strong>Complexity:</strong> ${analysis.problemAnalysis.complexity}</p>
|
|
452
|
+
<p><strong>Clarity Score:</strong> ${analysis.problemAnalysis.clarityScore}/100</p>
|
|
453
|
+
</div>
|
|
454
|
+
${analysis.problemAnalysis.potentialFailures.length > 0 ? `
|
|
455
|
+
<div class="improvements">
|
|
456
|
+
<h3>⚠️ Potential Failure Modes</h3>
|
|
457
|
+
<ul>
|
|
458
|
+
${analysis.problemAnalysis.potentialFailures.map(f => `
|
|
459
|
+
<li>
|
|
460
|
+
<strong>[${f.severity.toUpperCase()}]</strong> ${this.escapeHtml(f.description)}
|
|
461
|
+
<br><small>Likelihood: ${f.likelihood}</small>
|
|
462
|
+
</li>
|
|
463
|
+
`).join('')}
|
|
464
|
+
</ul>
|
|
465
|
+
</div>
|
|
466
|
+
` : ''}
|
|
467
|
+
</div>
|
|
468
|
+
|
|
469
|
+
<!-- User Needs -->
|
|
470
|
+
<div class="section">
|
|
471
|
+
<h2>👥 User Needs Analysis</h2>
|
|
472
|
+
<p><strong>Suitability:</strong> ${analysis.userNeeds.suitability} | <strong>Score:</strong> ${analysis.userNeeds.alignmentScore}/100</p>
|
|
473
|
+
${analysis.userNeeds.needs.length > 0 ? `
|
|
474
|
+
<div class="strengths">
|
|
475
|
+
<h3>✅ User Needs</h3>
|
|
476
|
+
<ul>
|
|
477
|
+
${analysis.userNeeds.needs.map(n => `
|
|
478
|
+
<li>
|
|
479
|
+
<strong>[${n.priority}]</strong> ${this.escapeHtml(n.description)}
|
|
480
|
+
${n.addressed ? '✓ Addressed' : '✗ Not Addressed'}
|
|
481
|
+
</li>
|
|
482
|
+
`).join('')}
|
|
483
|
+
</ul>
|
|
484
|
+
</div>
|
|
485
|
+
` : ''}
|
|
486
|
+
${analysis.userNeeds.challenges.length > 0 ? `
|
|
487
|
+
<div class="improvements">
|
|
488
|
+
<h3>⚠️ User Challenges</h3>
|
|
489
|
+
<ul>
|
|
490
|
+
${analysis.userNeeds.challenges.map(c => `<li>${this.escapeHtml(c)}</li>`).join('')}
|
|
491
|
+
</ul>
|
|
492
|
+
</div>
|
|
493
|
+
` : ''}
|
|
494
|
+
</div>
|
|
495
|
+
|
|
496
|
+
<!-- Business Needs -->
|
|
497
|
+
<div class="section">
|
|
498
|
+
<h2>💼 Business Needs Analysis</h2>
|
|
499
|
+
<p><strong>Primary Goal:</strong> ${analysis.businessNeeds.primaryGoal}</p>
|
|
500
|
+
<p><strong>Compromises UX:</strong> ${analysis.businessNeeds.compromisesUX ? 'Yes ⚠️' : 'No ✓'}</p>
|
|
501
|
+
${analysis.businessNeeds.kpisAffected.length > 0 ? `
|
|
502
|
+
<div class="info-box">
|
|
503
|
+
<h3>KPIs Affected</h3>
|
|
504
|
+
<ul>
|
|
505
|
+
${analysis.businessNeeds.kpisAffected.map(k => `<li>${this.escapeHtml(k)}</li>`).join('')}
|
|
506
|
+
</ul>
|
|
507
|
+
</div>
|
|
508
|
+
` : ''}
|
|
509
|
+
</div>
|
|
510
|
+
|
|
511
|
+
<!-- Creativity Analysis -->
|
|
512
|
+
<div class="section">
|
|
513
|
+
<h2>🎨 Creativity & Innovation Analysis</h2>
|
|
514
|
+
<p><strong>Creativity Score:</strong> ${analysis.creativityAnalysis.creativityScore}/100</p>
|
|
515
|
+
<p><strong>Domains Explored:</strong> ${analysis.creativityAnalysis.domainsExplored.join(', ')}</p>
|
|
516
|
+
${analysis.creativityAnalysis.innovativeApproaches.length > 0 ? `
|
|
517
|
+
<div class="strengths">
|
|
518
|
+
<h3>✨ Innovative Testing Approaches</h3>
|
|
519
|
+
<ul>
|
|
520
|
+
${analysis.creativityAnalysis.innovativeApproaches.map(a => `
|
|
521
|
+
<li>
|
|
522
|
+
<strong>[${a.inspirationSource.toUpperCase()}]</strong> ${this.escapeHtml(a.description)}
|
|
523
|
+
<br><small>Applicability: ${a.applicability} | Novelty: ${a.novelty}</small>
|
|
524
|
+
</li>
|
|
525
|
+
`).join('')}
|
|
526
|
+
</ul>
|
|
527
|
+
</div>
|
|
528
|
+
` : ''}
|
|
529
|
+
${analysis.creativityAnalysis.perspectives.length > 0 ? `
|
|
530
|
+
<div class="info-box">
|
|
531
|
+
<h3>🔍 Testing Perspectives Applied</h3>
|
|
532
|
+
<ul>
|
|
533
|
+
${analysis.creativityAnalysis.perspectives.map(p => `<li>${this.escapeHtml(p)}</li>`).join('')}
|
|
534
|
+
</ul>
|
|
535
|
+
</div>
|
|
536
|
+
` : ''}
|
|
537
|
+
</div>
|
|
538
|
+
|
|
539
|
+
<!-- Design Quality Analysis -->
|
|
540
|
+
<div class="section">
|
|
541
|
+
<h2>🎯 Design Quality Analysis</h2>
|
|
542
|
+
<p><strong>Overall Design Score:</strong> ${analysis.designAnalysis.overallDesignScore}/100</p>
|
|
543
|
+
|
|
544
|
+
<!-- Exactness -->
|
|
545
|
+
<div class="info-box" style="margin-top: 20px;">
|
|
546
|
+
<h3>📏 Exactness & Clarity (${analysis.designAnalysis.exactness.score}/100)</h3>
|
|
547
|
+
<p><strong>Clarity Level:</strong> ${analysis.designAnalysis.exactness.clarity}</p>
|
|
548
|
+
${analysis.designAnalysis.exactness.clearElements.length > 0 ? `
|
|
549
|
+
<div style="margin-top: 15px;">
|
|
550
|
+
<strong>✓ Clear Elements:</strong>
|
|
551
|
+
<ul>
|
|
552
|
+
${analysis.designAnalysis.exactness.clearElements.map(e => `<li>${this.escapeHtml(e)}</li>`).join('')}
|
|
553
|
+
</ul>
|
|
554
|
+
</div>
|
|
555
|
+
` : ''}
|
|
556
|
+
${analysis.designAnalysis.exactness.unclearElements.length > 0 ? `
|
|
557
|
+
<div style="margin-top: 15px;">
|
|
558
|
+
<strong>⚠️ Unclear Elements:</strong>
|
|
559
|
+
<ul>
|
|
560
|
+
${analysis.designAnalysis.exactness.unclearElements.map(e => `<li>${this.escapeHtml(e)}</li>`).join('')}
|
|
561
|
+
</ul>
|
|
562
|
+
</div>
|
|
563
|
+
` : ''}
|
|
564
|
+
</div>
|
|
565
|
+
|
|
566
|
+
<!-- Intuitive Design -->
|
|
567
|
+
<div class="strengths" style="margin-top: 20px;">
|
|
568
|
+
<h3>🧭 Intuitive Design (${analysis.designAnalysis.intuitive.score}/100)</h3>
|
|
569
|
+
<p><strong>Follows Conventions:</strong> ${analysis.designAnalysis.intuitive.followsConventions ? 'Yes ✓' : 'No ⚠️'}</p>
|
|
570
|
+
${analysis.designAnalysis.intuitive.intuitivePatterns.length > 0 ? `
|
|
571
|
+
<div style="margin-top: 15px;">
|
|
572
|
+
<strong>Intuitive Patterns Detected:</strong>
|
|
573
|
+
<ul>
|
|
574
|
+
${analysis.designAnalysis.intuitive.intuitivePatterns.map(p => `<li>${this.escapeHtml(p)}</li>`).join('')}
|
|
575
|
+
</ul>
|
|
576
|
+
</div>
|
|
577
|
+
` : ''}
|
|
578
|
+
${analysis.designAnalysis.intuitive.culturalIssues.length > 0 ? `
|
|
579
|
+
<div style="margin-top: 15px;">
|
|
580
|
+
<strong>⚠️ Cultural Considerations:</strong>
|
|
581
|
+
<ul>
|
|
582
|
+
${analysis.designAnalysis.intuitive.culturalIssues.map(i => `<li>${this.escapeHtml(i)}</li>`).join('')}
|
|
583
|
+
</ul>
|
|
584
|
+
</div>
|
|
585
|
+
` : ''}
|
|
586
|
+
</div>
|
|
587
|
+
|
|
588
|
+
<!-- Counter-intuitive Design -->
|
|
589
|
+
${analysis.designAnalysis.counterIntuitive.deviations.length > 0 ? `
|
|
590
|
+
<div class="improvements" style="margin-top: 20px;">
|
|
591
|
+
<h3>🔄 Counter-intuitive Design Patterns</h3>
|
|
592
|
+
<p><strong>Issues Found:</strong> ${analysis.designAnalysis.counterIntuitive.issuesCount}</p>
|
|
593
|
+
<p><strong>Fresh Eyes Perspective Applied:</strong> ${analysis.designAnalysis.counterIntuitive.freshEyesPerspective ? 'Yes ✓' : 'No'}</p>
|
|
594
|
+
<ul>
|
|
595
|
+
${analysis.designAnalysis.counterIntuitive.deviations.map(d => `
|
|
596
|
+
<li>
|
|
597
|
+
<strong>${this.escapeHtml(d.element)}</strong>
|
|
598
|
+
<br>Expected: ${this.escapeHtml(d.expectedBehavior)}
|
|
599
|
+
<br>Actual: ${this.escapeHtml(d.actualBehavior)}
|
|
600
|
+
<br><small>Impact: ${d.impact} ${d.justification ? '| ' + this.escapeHtml(d.justification) : ''}</small>
|
|
601
|
+
</li>
|
|
602
|
+
`).join('')}
|
|
603
|
+
</ul>
|
|
604
|
+
</div>
|
|
605
|
+
` : ''}
|
|
606
|
+
</div>
|
|
607
|
+
|
|
608
|
+
<!-- Oracle Problems -->
|
|
609
|
+
${analysis.oracleProblems.length > 0 ? `
|
|
610
|
+
<div class="section">
|
|
611
|
+
<h2>🔮 Oracle Problems Detected</h2>
|
|
612
|
+
${analysis.oracleProblems.map(p => `
|
|
613
|
+
<div class="improvements">
|
|
614
|
+
<h3>[${p.severity.toUpperCase()}] ${p.type}</h3>
|
|
615
|
+
<p>${this.escapeHtml(p.description)}</p>
|
|
616
|
+
${p.stakeholders ? `<p><strong>Stakeholders:</strong> ${p.stakeholders.join(', ')}</p>` : ''}
|
|
617
|
+
${p.resolutionApproach ? `
|
|
618
|
+
<p><strong>Resolution Approach:</strong></p>
|
|
619
|
+
<ul>
|
|
620
|
+
${p.resolutionApproach.map(r => `<li>${this.escapeHtml(r)}</li>`).join('')}
|
|
621
|
+
</ul>
|
|
622
|
+
` : ''}
|
|
623
|
+
</div>
|
|
624
|
+
`).join('')}
|
|
625
|
+
</div>
|
|
626
|
+
` : ''}
|
|
627
|
+
|
|
628
|
+
<!-- Recommendations -->
|
|
629
|
+
<div class="section">
|
|
630
|
+
<h2>💡 Strategic Recommendations</h2>
|
|
631
|
+
${analysis.recommendations.slice(0, 10).map((rec, idx) => `
|
|
632
|
+
<div class="recommendations">
|
|
633
|
+
<h3>🎯 Priority ${idx + 1}: ${this.escapeHtml(rec.principle)}</h3>
|
|
634
|
+
<p>${this.escapeHtml(rec.recommendation)}</p>
|
|
635
|
+
<p>
|
|
636
|
+
<strong>Severity:</strong> ${rec.severity} |
|
|
637
|
+
<strong>Impact:</strong> ${rec.impactPercentage || rec.impact}% |
|
|
638
|
+
<strong>Effort:</strong> ${rec.estimatedEffort || rec.effort}
|
|
639
|
+
</p>
|
|
640
|
+
</div>
|
|
641
|
+
`).join('')}
|
|
642
|
+
</div>
|
|
643
|
+
|
|
644
|
+
<!-- Heuristics Results -->
|
|
645
|
+
${analysis.heuristics.length > 0 ? `
|
|
646
|
+
<div class="section">
|
|
647
|
+
<h2>📐 Heuristics Analysis</h2>
|
|
648
|
+
<div class="score-card">
|
|
649
|
+
${analysis.heuristics.slice(0, 8).map(h => `
|
|
650
|
+
<div class="score-item">
|
|
651
|
+
<h4>${this.formatHeuristicName(h.name)}</h4>
|
|
652
|
+
<div class="score-value" style="font-size: 1.8em; color: ${this.getScoreColor(h.score)};">${h.score}</div>
|
|
653
|
+
<div class="score-label">/ 100</div>
|
|
654
|
+
</div>
|
|
655
|
+
`).join('')}
|
|
656
|
+
</div>
|
|
657
|
+
</div>
|
|
658
|
+
` : ''}
|
|
659
|
+
|
|
660
|
+
<!-- Impact Analysis -->
|
|
661
|
+
<div class="section">
|
|
662
|
+
<h2>⚡ Impact Analysis</h2>
|
|
663
|
+
<div class="score-card">
|
|
664
|
+
<div class="score-item">
|
|
665
|
+
<h4>Visible Impact</h4>
|
|
666
|
+
<div class="score-value">${analysis.impactAnalysis.visible.score}</div>
|
|
667
|
+
<div class="score-label">/ 100</div>
|
|
668
|
+
</div>
|
|
669
|
+
<div class="score-item">
|
|
670
|
+
<h4>Invisible Impact</h4>
|
|
671
|
+
<div class="score-value">${analysis.impactAnalysis.invisible.score}</div>
|
|
672
|
+
<div class="score-label">/ 100</div>
|
|
673
|
+
</div>
|
|
674
|
+
</div>
|
|
675
|
+
${analysis.impactAnalysis.visible.userFeelings && analysis.impactAnalysis.visible.userFeelings.length > 0 ? `
|
|
676
|
+
<div class="info-box">
|
|
677
|
+
<h3>User Feelings</h3>
|
|
678
|
+
<ul>
|
|
679
|
+
${analysis.impactAnalysis.visible.userFeelings.map(f => {
|
|
680
|
+
if (typeof f === 'string') {
|
|
681
|
+
return `<li>${this.escapeHtml(f)}</li>`;
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
return `<li><strong>${f.feeling}</strong> (${f.likelihood}): ${this.escapeHtml(f.context)}</li>`;
|
|
685
|
+
}
|
|
686
|
+
}).join('')}
|
|
687
|
+
</ul>
|
|
688
|
+
</div>
|
|
689
|
+
` : ''}
|
|
690
|
+
</div>
|
|
691
|
+
|
|
692
|
+
<!-- Conclusion -->
|
|
693
|
+
<div class="section">
|
|
694
|
+
<h2>🎓 Conclusion</h2>
|
|
695
|
+
<p>
|
|
696
|
+
This QX analysis reveals an overall score of <strong>${analysis.overallScore}/100 (Grade: ${analysis.grade})</strong>.
|
|
697
|
+
${this.getScoreInterpretation(analysis.overallScore)}
|
|
698
|
+
</p>
|
|
699
|
+
</div>
|
|
700
|
+
|
|
701
|
+
<!-- QX Methodology -->
|
|
702
|
+
<div class="section" style="background: linear-gradient(135deg, #f5f7fa 0%, #e8ecf1 100%); padding: 30px; border-radius: 8px; margin-top: 40px;">
|
|
703
|
+
<h2>📚 QX Methodology: Key Concepts</h2>
|
|
704
|
+
|
|
705
|
+
<div style="margin-top: 20px;">
|
|
706
|
+
<h3 style="color: #667eea; margin-bottom: 10px;">🤝 What is Quality Experience (QX)?</h3>
|
|
707
|
+
<p style="text-align: justify;">
|
|
708
|
+
<strong>Quality Experience (QX)</strong> is the marriage between <strong>Quality Advocacy (QA)</strong> and
|
|
709
|
+
<strong>User Experience (UX)</strong>. Unlike traditional testing that focuses solely on defects, QX recognizes
|
|
710
|
+
that quality is co-created by everyone associated with the product—developers, testers, designers, users, and
|
|
711
|
+
business stakeholders. QX enables testers to collaborate meaningfully with UX professionals by understanding
|
|
712
|
+
design effectiveness beyond technical correctness.
|
|
713
|
+
</p>
|
|
714
|
+
</div>
|
|
715
|
+
|
|
716
|
+
<div style="margin-top: 25px;">
|
|
717
|
+
<h3 style="color: #667eea; margin-bottom: 10px;">🎨 Creativity in Testing</h3>
|
|
718
|
+
<p style="text-align: justify;">
|
|
719
|
+
QX encourages drawing inspiration from <strong>diverse domains</strong>—philosophy, social science, medicine,
|
|
720
|
+
e-commerce, fashion, gaming—to generate innovative test ideas when conventional approaches fall short. This
|
|
721
|
+
cross-disciplinary perspective helps testers uncover unconventional risks and approach problems from fresh angles
|
|
722
|
+
that technical testing alone might miss.
|
|
723
|
+
</p>
|
|
724
|
+
</div>
|
|
725
|
+
|
|
726
|
+
<div style="margin-top: 25px;">
|
|
727
|
+
<h3 style="color: #667eea; margin-bottom: 10px;">📏 Exactness & Clarity</h3>
|
|
728
|
+
<p style="text-align: justify;">
|
|
729
|
+
<strong>Exactness</strong> evaluates how clearly a product communicates its intent to users. Testers should assess
|
|
730
|
+
whether menu items, buttons, labels, and terminology are self-evident. Are component interactions obvious? Do users
|
|
731
|
+
understand what will happen when they click? Exactness testing identifies ambiguities that create confusion, focusing
|
|
732
|
+
on <em>clarity of communication</em> rather than just functional correctness.
|
|
733
|
+
</p>
|
|
734
|
+
</div>
|
|
735
|
+
|
|
736
|
+
<div style="margin-top: 25px;">
|
|
737
|
+
<h3 style="color: #667eea; margin-bottom: 10px;">🧭 Intuitive Design</h3>
|
|
738
|
+
<p style="text-align: justify;">
|
|
739
|
+
<strong>Intuitive design</strong> follows common conventions and user expectations. QX testing evaluates whether
|
|
740
|
+
component interactions follow familiar patterns, respect cultural sensitivities, and align with mental models users
|
|
741
|
+
bring from other products. Intuitive design reduces cognitive load and makes products immediately usable without
|
|
742
|
+
extensive training.
|
|
743
|
+
</p>
|
|
744
|
+
</div>
|
|
745
|
+
|
|
746
|
+
<div style="margin-top: 25px;">
|
|
747
|
+
<h3 style="color: #667eea; margin-bottom: 10px;">🔄 Counter-intuitive Design Detection</h3>
|
|
748
|
+
<p style="text-align: justify;">
|
|
749
|
+
QX testing deliberately <strong>looks at products like an unexperienced user</strong> to spot design elements that
|
|
750
|
+
deviate from expectations. Counter-intuitive patterns aren't always bad—they might represent innovation—but they
|
|
751
|
+
require justification. The key is distinguishing between deliberate, valuable innovations and accidental friction
|
|
752
|
+
that experienced users have normalized but newcomers will struggle with.
|
|
753
|
+
</p>
|
|
754
|
+
</div>
|
|
755
|
+
|
|
756
|
+
<div style="margin-top: 25px; padding: 20px; background: white; border-left: 4px solid #667eea; border-radius: 4px;">
|
|
757
|
+
<p style="text-align: justify; font-style: italic;">
|
|
758
|
+
<strong>The QX Advantage:</strong> By combining quality advocacy with UX design thinking, QX enables testers to
|
|
759
|
+
contribute informed insights about user-facing quality, bridge the gap between QA and UX teams, and ensure that
|
|
760
|
+
testing serves the genuine experience quality that all stakeholders care about—not just technical correctness.
|
|
761
|
+
</p>
|
|
762
|
+
</div>
|
|
763
|
+
|
|
764
|
+
<div style="margin-top: 20px; text-align: center;">
|
|
765
|
+
<p style="font-size: 0.9em;">
|
|
766
|
+
<strong>Learn more:</strong>
|
|
767
|
+
<a href="https://talesoftesting.com/quality-experienceqx-co-creating-quality-experience-for-everyone-associated-with-the-product/"
|
|
768
|
+
target="_blank" rel="noopener noreferrer" style="color: #667eea; text-decoration: none;">
|
|
769
|
+
Quality Experience (QX) - Tales of Testing
|
|
770
|
+
</a>
|
|
771
|
+
</p>
|
|
772
|
+
</div>
|
|
773
|
+
</div>
|
|
774
|
+
</div>
|
|
775
|
+
|
|
776
|
+
<div class="footer">
|
|
777
|
+
<p><strong>QX Analysis Report</strong></p>
|
|
778
|
+
<p>Generated by: Agentic QE Fleet v2.1.0 - QX Partner Agent</p>
|
|
779
|
+
<p>Framework: Quality Experience (QX) Analysis</p>
|
|
780
|
+
<p>Analysis Date: ${date} at ${time}</p>
|
|
781
|
+
<hr style="margin: 20px 0; border: none; border-top: 1px solid #dee2e6;">
|
|
782
|
+
<p style="font-size: 0.9em; line-height: 1.6;">
|
|
783
|
+
This report applies the QX framework developed to bridge Quality Advocacy (QA) and User Experience (UX).<br>
|
|
784
|
+
<em>"Quality is value to someone who matters"</em> - when multiple stakeholders matter simultaneously,<br>
|
|
785
|
+
QX helps find balance and solve oracle problems. It is one of the key concepts originally covered in
|
|
786
|
+
<a href="https://talesoftesting.com/qcsd/" target="_blank" rel="noopener noreferrer" style="color: #007bff; text-decoration: none;">
|
|
787
|
+
QCSD - Quality Conscious Software Delivery Framework</a> created by Lalitkumar Bhamare.
|
|
788
|
+
</p>
|
|
789
|
+
</div>
|
|
790
|
+
</div>
|
|
791
|
+
</body>
|
|
792
|
+
</html>`;
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Get CSS styles for the report
|
|
796
|
+
*/
|
|
797
|
+
getReportStyles() {
|
|
798
|
+
return `
|
|
799
|
+
<style>
|
|
800
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
801
|
+
body {
|
|
802
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
803
|
+
line-height: 1.6;
|
|
804
|
+
color: #333;
|
|
805
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
806
|
+
padding: 20px;
|
|
807
|
+
}
|
|
808
|
+
.container {
|
|
809
|
+
max-width: 1200px;
|
|
810
|
+
margin: 0 auto;
|
|
811
|
+
background: white;
|
|
812
|
+
border-radius: 12px;
|
|
813
|
+
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
|
814
|
+
overflow: hidden;
|
|
815
|
+
}
|
|
816
|
+
.header {
|
|
817
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
818
|
+
color: white;
|
|
819
|
+
padding: 40px;
|
|
820
|
+
text-align: center;
|
|
821
|
+
}
|
|
822
|
+
.header h1 { font-size: 2.5em; margin-bottom: 10px; font-weight: 700; }
|
|
823
|
+
.header .subtitle { font-size: 1.2em; opacity: 0.9; }
|
|
824
|
+
.header .meta { margin-top: 20px; font-size: 0.9em; opacity: 0.8; }
|
|
825
|
+
.content { padding: 40px; }
|
|
826
|
+
.section { margin-bottom: 40px; }
|
|
827
|
+
.section h2 {
|
|
828
|
+
color: #667eea;
|
|
829
|
+
font-size: 1.8em;
|
|
830
|
+
margin-bottom: 20px;
|
|
831
|
+
padding-bottom: 10px;
|
|
832
|
+
border-bottom: 3px solid #667eea;
|
|
833
|
+
}
|
|
834
|
+
.section h3 { color: #764ba2; font-size: 1.4em; margin: 25px 0 15px 0; }
|
|
835
|
+
.section p { margin-bottom: 15px; text-align: justify; }
|
|
836
|
+
.score-card {
|
|
837
|
+
display: grid;
|
|
838
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
839
|
+
gap: 20px;
|
|
840
|
+
margin: 30px 0;
|
|
841
|
+
}
|
|
842
|
+
.score-item {
|
|
843
|
+
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
|
844
|
+
padding: 20px;
|
|
845
|
+
border-radius: 8px;
|
|
846
|
+
text-align: center;
|
|
847
|
+
transition: transform 0.3s ease;
|
|
848
|
+
}
|
|
849
|
+
.score-item:hover { transform: translateY(-5px); box-shadow: 0 5px 20px rgba(0,0,0,0.1); }
|
|
850
|
+
.score-item h4 { color: #667eea; font-size: 1.1em; margin-bottom: 10px; }
|
|
851
|
+
.score-value {
|
|
852
|
+
font-size: 2.5em;
|
|
853
|
+
font-weight: bold;
|
|
854
|
+
color: #764ba2;
|
|
855
|
+
margin: 10px 0;
|
|
856
|
+
}
|
|
857
|
+
.score-label {
|
|
858
|
+
font-size: 0.9em;
|
|
859
|
+
color: #666;
|
|
860
|
+
text-transform: uppercase;
|
|
861
|
+
letter-spacing: 1px;
|
|
862
|
+
}
|
|
863
|
+
.strengths, .improvements, .recommendations, .info-box {
|
|
864
|
+
background: #f8f9fa;
|
|
865
|
+
padding: 25px;
|
|
866
|
+
border-radius: 8px;
|
|
867
|
+
margin: 20px 0;
|
|
868
|
+
}
|
|
869
|
+
.strengths { border-left: 5px solid #28a745; }
|
|
870
|
+
.improvements { border-left: 5px solid #ffc107; }
|
|
871
|
+
.recommendations { border-left: 5px solid #17a2b8; }
|
|
872
|
+
.info-box { border-left: 5px solid #6c757d; }
|
|
873
|
+
.strengths h3 { color: #28a745; }
|
|
874
|
+
.improvements h3 { color: #ffc107; }
|
|
875
|
+
.recommendations h3 { color: #17a2b8; }
|
|
876
|
+
.info-box h3 { color: #6c757d; }
|
|
877
|
+
ul { margin-left: 20px; margin-top: 10px; }
|
|
878
|
+
li { margin-bottom: 10px; line-height: 1.8; }
|
|
879
|
+
.footer {
|
|
880
|
+
background: #f8f9fa;
|
|
881
|
+
padding: 30px;
|
|
882
|
+
text-align: center;
|
|
883
|
+
color: #666;
|
|
884
|
+
border-top: 1px solid #e0e0e0;
|
|
885
|
+
}
|
|
886
|
+
.footer p { margin-bottom: 10px; }
|
|
887
|
+
@media print {
|
|
888
|
+
body { background: white; padding: 0; }
|
|
889
|
+
.container { box-shadow: none; }
|
|
890
|
+
}
|
|
891
|
+
</style>`;
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* Escape HTML special characters
|
|
895
|
+
*/
|
|
896
|
+
escapeHtml(text) {
|
|
897
|
+
const map = {
|
|
898
|
+
'&': '&',
|
|
899
|
+
'<': '<',
|
|
900
|
+
'>': '>',
|
|
901
|
+
'"': '"',
|
|
902
|
+
"'": '''
|
|
903
|
+
};
|
|
904
|
+
return text.replace(/[&<>"']/g, m => map[m]);
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Format heuristic name for display
|
|
908
|
+
*/
|
|
909
|
+
formatHeuristicName(name) {
|
|
910
|
+
return name
|
|
911
|
+
.split('-')
|
|
912
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
913
|
+
.join(' ');
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* Get color based on score
|
|
917
|
+
*/
|
|
918
|
+
getScoreColor(score) {
|
|
919
|
+
if (score >= 90)
|
|
920
|
+
return '#28a745'; // Green
|
|
921
|
+
if (score >= 80)
|
|
922
|
+
return '#17a2b8'; // Blue
|
|
923
|
+
if (score >= 70)
|
|
924
|
+
return '#ffc107'; // Yellow
|
|
925
|
+
if (score >= 60)
|
|
926
|
+
return '#fd7e14'; // Orange
|
|
927
|
+
return '#dc3545'; // Red
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* Get score interpretation
|
|
931
|
+
*/
|
|
932
|
+
getScoreInterpretation(score) {
|
|
933
|
+
if (score >= 90) {
|
|
934
|
+
return 'Excellent quality experience with strong alignment across all dimensions.';
|
|
935
|
+
}
|
|
936
|
+
else if (score >= 80) {
|
|
937
|
+
return 'Good quality experience with minor areas for improvement.';
|
|
938
|
+
}
|
|
939
|
+
else if (score >= 70) {
|
|
940
|
+
return 'Adequate quality experience but significant improvements recommended.';
|
|
941
|
+
}
|
|
942
|
+
else if (score >= 60) {
|
|
943
|
+
return 'Below target quality experience. Priority improvements required.';
|
|
944
|
+
}
|
|
945
|
+
else {
|
|
946
|
+
return 'Poor quality experience. Immediate action needed across multiple areas.';
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Launch report in default browser
|
|
951
|
+
*/
|
|
952
|
+
async launchReportInBrowser(reportPath) {
|
|
953
|
+
try {
|
|
954
|
+
const platform = process.platform;
|
|
955
|
+
let command;
|
|
956
|
+
if (platform === 'darwin') {
|
|
957
|
+
command = `open "${reportPath}"`;
|
|
958
|
+
}
|
|
959
|
+
else if (platform === 'win32') {
|
|
960
|
+
command = `start "" "${reportPath}"`;
|
|
961
|
+
}
|
|
962
|
+
else {
|
|
963
|
+
// Linux and others
|
|
964
|
+
command = `xdg-open "${reportPath}"`;
|
|
965
|
+
}
|
|
966
|
+
await execAsync(command);
|
|
967
|
+
this.logger.info(`Launched report in browser: ${reportPath}`);
|
|
968
|
+
}
|
|
969
|
+
catch (error) {
|
|
970
|
+
this.logger.warn(`Failed to auto-launch browser:`, error);
|
|
971
|
+
this.logger.info(`Report available at: ${reportPath}`);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
305
974
|
/**
|
|
306
975
|
* Collect QX context from target using Playwright
|
|
307
976
|
*/
|
|
@@ -875,6 +1544,186 @@ class QXPartnerAgent extends BaseAgent_1.BaseAgent {
|
|
|
875
1544
|
alignmentScore
|
|
876
1545
|
};
|
|
877
1546
|
}
|
|
1547
|
+
/**
|
|
1548
|
+
* Analyze Creativity - Drawing inspiration from diverse domains
|
|
1549
|
+
*/
|
|
1550
|
+
async analyzeCreativity(context, problemAnalysis) {
|
|
1551
|
+
this.logger.debug('Analyzing creativity and innovation');
|
|
1552
|
+
const innovativeApproaches = [];
|
|
1553
|
+
// Analyze based on problem complexity
|
|
1554
|
+
if (problemAnalysis.complexity === 'complex' || problemAnalysis.complexity === 'moderate') {
|
|
1555
|
+
// Philosophy-inspired: Question fundamental assumptions
|
|
1556
|
+
innovativeApproaches.push({
|
|
1557
|
+
description: 'Question fundamental assumptions about user mental models and expected workflows',
|
|
1558
|
+
inspirationSource: 'philosophy',
|
|
1559
|
+
applicability: 'high',
|
|
1560
|
+
novelty: 'moderately-novel'
|
|
1561
|
+
});
|
|
1562
|
+
// Medicine-inspired: Diagnostic approach
|
|
1563
|
+
if (context.errorIndicators?.hasErrorMessages) {
|
|
1564
|
+
innovativeApproaches.push({
|
|
1565
|
+
description: 'Apply diagnostic testing - systematically isolate error sources through controlled scenarios',
|
|
1566
|
+
inspirationSource: 'medicine',
|
|
1567
|
+
applicability: 'high',
|
|
1568
|
+
novelty: 'moderately-novel'
|
|
1569
|
+
});
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
// E-commerce/Fashion-inspired: User journey and aesthetics
|
|
1573
|
+
if (context.domMetrics?.forms && context.domMetrics.forms > 0) {
|
|
1574
|
+
innovativeApproaches.push({
|
|
1575
|
+
description: 'Test checkout/form flows like fashion retail - focus on friction points, abandonment triggers',
|
|
1576
|
+
inspirationSource: 'e-commerce',
|
|
1577
|
+
applicability: 'high',
|
|
1578
|
+
novelty: 'incremental'
|
|
1579
|
+
});
|
|
1580
|
+
}
|
|
1581
|
+
// Social Science-inspired: Cultural sensitivity and demographics
|
|
1582
|
+
innovativeApproaches.push({
|
|
1583
|
+
description: 'Analyze through diverse demographic lenses (age, gender, culture, ability) for inclusive testing',
|
|
1584
|
+
inspirationSource: 'social science',
|
|
1585
|
+
applicability: 'high',
|
|
1586
|
+
novelty: 'moderately-novel'
|
|
1587
|
+
});
|
|
1588
|
+
// Gaming-inspired: Edge cases and exploits
|
|
1589
|
+
if (context.domMetrics?.interactiveElements && context.domMetrics.interactiveElements > 20) {
|
|
1590
|
+
innovativeApproaches.push({
|
|
1591
|
+
description: 'Test for "game-breaking" exploits - unexpected interaction sequences, boundary conditions',
|
|
1592
|
+
inspirationSource: 'gaming',
|
|
1593
|
+
applicability: 'medium',
|
|
1594
|
+
novelty: 'highly-novel'
|
|
1595
|
+
});
|
|
1596
|
+
}
|
|
1597
|
+
const domainsExplored = [...new Set(innovativeApproaches.map(a => a.inspirationSource))];
|
|
1598
|
+
const perspectives = [
|
|
1599
|
+
'Unexperienced user perspective (fresh eyes)',
|
|
1600
|
+
'Power user perspective (efficiency focus)',
|
|
1601
|
+
'Accessibility perspective (assistive tech users)',
|
|
1602
|
+
'International perspective (cultural differences)'
|
|
1603
|
+
];
|
|
1604
|
+
// Calculate creativity score
|
|
1605
|
+
let creativityScore = 50; // Base score
|
|
1606
|
+
creativityScore += innovativeApproaches.length * 8; // +8 per approach
|
|
1607
|
+
creativityScore += domainsExplored.length * 5; // +5 per domain
|
|
1608
|
+
creativityScore = Math.min(100, creativityScore);
|
|
1609
|
+
return {
|
|
1610
|
+
innovativeApproaches,
|
|
1611
|
+
domainsExplored,
|
|
1612
|
+
perspectives,
|
|
1613
|
+
creativityScore,
|
|
1614
|
+
notes: [
|
|
1615
|
+
'Creativity draws from diverse domains to uncover unconventional testing approaches',
|
|
1616
|
+
'Higher complexity problems benefit from cross-disciplinary inspiration',
|
|
1617
|
+
`Applied ${innovativeApproaches.length} creative approaches from ${domainsExplored.length} domains`
|
|
1618
|
+
]
|
|
1619
|
+
};
|
|
1620
|
+
}
|
|
1621
|
+
/**
|
|
1622
|
+
* Analyze Design - Exactness, Intuitive, and Counter-intuitive Design
|
|
1623
|
+
*/
|
|
1624
|
+
async analyzeDesign(context, _problemAnalysis) {
|
|
1625
|
+
this.logger.debug('Analyzing design quality');
|
|
1626
|
+
// 1. Exactness Analysis - How clearly the product communicates its intent
|
|
1627
|
+
const clearElements = [];
|
|
1628
|
+
const unclearElements = [];
|
|
1629
|
+
// Check semantic structure for clarity
|
|
1630
|
+
if (context.domMetrics?.semanticStructure?.hasNav) {
|
|
1631
|
+
clearElements.push('Navigation structure clearly defined with semantic <nav> element');
|
|
1632
|
+
}
|
|
1633
|
+
if (context.domMetrics?.semanticStructure?.hasMain) {
|
|
1634
|
+
clearElements.push('Main content area clearly identified');
|
|
1635
|
+
}
|
|
1636
|
+
if (context.domMetrics?.semanticStructure?.hasHeader && context.domMetrics?.semanticStructure?.hasFooter) {
|
|
1637
|
+
clearElements.push('Header and footer provide clear page structure');
|
|
1638
|
+
}
|
|
1639
|
+
// Check for unclear elements
|
|
1640
|
+
const ariaLabels = context.semanticQuality?.ariaLabels || 0;
|
|
1641
|
+
const interactiveElements = context.domMetrics?.interactiveElements || 0;
|
|
1642
|
+
if (interactiveElements > 0 && ariaLabels < interactiveElements * 0.5) {
|
|
1643
|
+
unclearElements.push('Many interactive elements lack ARIA labels for clarity');
|
|
1644
|
+
}
|
|
1645
|
+
if (context.errorIndicators?.hasErrorMessages) {
|
|
1646
|
+
unclearElements.push('Error messages present - may indicate unclear user guidance');
|
|
1647
|
+
}
|
|
1648
|
+
const exactnessClarity = unclearElements.length === 0 ? 'excellent' :
|
|
1649
|
+
unclearElements.length <= 2 ? 'good' :
|
|
1650
|
+
unclearElements.length <= 4 ? 'adequate' : 'poor';
|
|
1651
|
+
let exactnessScore = 50;
|
|
1652
|
+
exactnessScore += clearElements.length * 10;
|
|
1653
|
+
exactnessScore -= unclearElements.length * 8;
|
|
1654
|
+
exactnessScore = Math.max(0, Math.min(100, exactnessScore));
|
|
1655
|
+
// 2. Intuitive Design Analysis
|
|
1656
|
+
const intuitivePatterns = [];
|
|
1657
|
+
const culturalIssues = [];
|
|
1658
|
+
if (context.domMetrics?.semanticStructure?.hasNav) {
|
|
1659
|
+
intuitivePatterns.push('Standard navigation patterns (semantic nav element)');
|
|
1660
|
+
}
|
|
1661
|
+
if (context.domMetrics?.forms && context.domMetrics.forms > 0) {
|
|
1662
|
+
intuitivePatterns.push('Standard form patterns detected');
|
|
1663
|
+
}
|
|
1664
|
+
if (context.metadata?.viewport) {
|
|
1665
|
+
intuitivePatterns.push('Responsive design viewport configured');
|
|
1666
|
+
}
|
|
1667
|
+
// Cultural sensitivity check (basic)
|
|
1668
|
+
if (context.title && /[^\x00-\x7F]/.test(context.title || '')) {
|
|
1669
|
+
// Non-ASCII characters detected - could be good (internationalization) or need review
|
|
1670
|
+
culturalIssues.push('International characters detected - ensure cultural appropriateness');
|
|
1671
|
+
}
|
|
1672
|
+
const followsConventions = intuitivePatterns.length >= 2;
|
|
1673
|
+
let intuitiveScore = followsConventions ? 70 : 50;
|
|
1674
|
+
intuitiveScore += intuitivePatterns.length * 8;
|
|
1675
|
+
intuitiveScore -= culturalIssues.length * 10;
|
|
1676
|
+
intuitiveScore = Math.max(0, Math.min(100, intuitiveScore));
|
|
1677
|
+
// 3. Counter-intuitive Design Detection
|
|
1678
|
+
const deviations = [];
|
|
1679
|
+
// Check for potential counter-intuitive patterns
|
|
1680
|
+
const buttons = context.domMetrics?.buttons || 0;
|
|
1681
|
+
const forms = context.domMetrics?.forms || 0;
|
|
1682
|
+
if (buttons > 20 && forms === 0) {
|
|
1683
|
+
deviations.push({
|
|
1684
|
+
element: 'Multiple buttons without forms',
|
|
1685
|
+
expectedBehavior: 'Forms typically accompany many buttons',
|
|
1686
|
+
actualBehavior: 'Many buttons present without traditional forms',
|
|
1687
|
+
impact: 'neutral',
|
|
1688
|
+
justification: 'May be single-page app or API-driven interface'
|
|
1689
|
+
});
|
|
1690
|
+
}
|
|
1691
|
+
if (!context.domMetrics?.semanticStructure?.hasMain && (context.domMetrics?.totalElements || 0) > 50) {
|
|
1692
|
+
deviations.push({
|
|
1693
|
+
element: 'Complex page without main landmark',
|
|
1694
|
+
expectedBehavior: 'Complex pages typically have <main> landmark',
|
|
1695
|
+
actualBehavior: 'No main content landmark defined',
|
|
1696
|
+
impact: 'negative',
|
|
1697
|
+
justification: 'Reduces accessibility and clarity'
|
|
1698
|
+
});
|
|
1699
|
+
}
|
|
1700
|
+
const innovativeJustification = deviations.some(d => d.impact === 'positive' || d.justification?.includes('innovation'));
|
|
1701
|
+
const freshEyesPerspective = deviations.length > 0; // We're looking from unexperienced user view
|
|
1702
|
+
const issuesCount = deviations.filter(d => d.impact === 'negative').length;
|
|
1703
|
+
// 4. Overall Design Score
|
|
1704
|
+
const overallDesignScore = Math.round((exactnessScore + intuitiveScore) / 2);
|
|
1705
|
+
return {
|
|
1706
|
+
exactness: {
|
|
1707
|
+
clarity: exactnessClarity,
|
|
1708
|
+
clearElements,
|
|
1709
|
+
unclearElements,
|
|
1710
|
+
score: exactnessScore
|
|
1711
|
+
},
|
|
1712
|
+
intuitive: {
|
|
1713
|
+
followsConventions,
|
|
1714
|
+
intuitivePatterns,
|
|
1715
|
+
culturalIssues,
|
|
1716
|
+
score: intuitiveScore
|
|
1717
|
+
},
|
|
1718
|
+
counterIntuitive: {
|
|
1719
|
+
deviations,
|
|
1720
|
+
innovativeJustification,
|
|
1721
|
+
freshEyesPerspective,
|
|
1722
|
+
issuesCount
|
|
1723
|
+
},
|
|
1724
|
+
overallDesignScore
|
|
1725
|
+
};
|
|
1726
|
+
}
|
|
878
1727
|
/**
|
|
879
1728
|
* Detect oracle problems from analysis context
|
|
880
1729
|
*/
|
|
@@ -896,11 +1745,63 @@ class QXPartnerAgent extends BaseAgent_1.BaseAgent {
|
|
|
896
1745
|
/**
|
|
897
1746
|
* Apply all enabled heuristics
|
|
898
1747
|
*/
|
|
899
|
-
async applyAllHeuristics(context, problemAnalysis, userNeeds, businessNeeds) {
|
|
1748
|
+
async applyAllHeuristics(context, problemAnalysis, userNeeds, businessNeeds, creativityAnalysis, designAnalysis) {
|
|
900
1749
|
if (!this.heuristicsEngine) {
|
|
901
1750
|
throw new Error('Heuristics engine not initialized');
|
|
902
1751
|
}
|
|
903
|
-
|
|
1752
|
+
// Get standard heuristics
|
|
1753
|
+
const standardHeuristics = await this.heuristicsEngine.applyAll(context, problemAnalysis, userNeeds, businessNeeds);
|
|
1754
|
+
// Add creativity and design heuristics
|
|
1755
|
+
const creativityHeuristic = {
|
|
1756
|
+
name: 'creativity-innovation',
|
|
1757
|
+
category: 'creativity',
|
|
1758
|
+
applied: true,
|
|
1759
|
+
score: creativityAnalysis.creativityScore,
|
|
1760
|
+
findings: [
|
|
1761
|
+
`Applied ${creativityAnalysis.innovativeApproaches.length} creative approaches`,
|
|
1762
|
+
`Explored ${creativityAnalysis.domainsExplored.length} diverse domains: ${creativityAnalysis.domainsExplored.join(', ')}`,
|
|
1763
|
+
...creativityAnalysis.notes
|
|
1764
|
+
],
|
|
1765
|
+
issues: creativityAnalysis.innovativeApproaches
|
|
1766
|
+
.filter(a => a.applicability === 'low')
|
|
1767
|
+
.map(a => ({
|
|
1768
|
+
description: `Low applicability approach: ${a.description}`,
|
|
1769
|
+
severity: 'low'
|
|
1770
|
+
})),
|
|
1771
|
+
recommendations: creativityAnalysis.innovativeApproaches
|
|
1772
|
+
.filter(a => a.applicability === 'high')
|
|
1773
|
+
.map(a => `Consider: ${a.description} (${a.inspirationSource})`)
|
|
1774
|
+
};
|
|
1775
|
+
const designHeuristic = {
|
|
1776
|
+
name: 'design-quality',
|
|
1777
|
+
category: 'design',
|
|
1778
|
+
applied: true,
|
|
1779
|
+
score: designAnalysis.overallDesignScore,
|
|
1780
|
+
findings: [
|
|
1781
|
+
`Exactness: ${designAnalysis.exactness.clarity} (${designAnalysis.exactness.score}/100)`,
|
|
1782
|
+
`Intuitive Design: ${designAnalysis.intuitive.followsConventions ? 'Follows' : 'Deviates from'} conventions (${designAnalysis.intuitive.score}/100)`,
|
|
1783
|
+
`Counter-intuitive issues: ${designAnalysis.counterIntuitive.issuesCount}`,
|
|
1784
|
+
...designAnalysis.exactness.clearElements.map(e => `✓ ${e}`),
|
|
1785
|
+
...designAnalysis.intuitive.intuitivePatterns.map(p => `✓ ${p}`)
|
|
1786
|
+
],
|
|
1787
|
+
issues: [
|
|
1788
|
+
...designAnalysis.exactness.unclearElements.map(e => ({
|
|
1789
|
+
description: e,
|
|
1790
|
+
severity: 'medium'
|
|
1791
|
+
})),
|
|
1792
|
+
...designAnalysis.counterIntuitive.deviations
|
|
1793
|
+
.filter(d => d.impact === 'negative')
|
|
1794
|
+
.map(d => ({
|
|
1795
|
+
description: `${d.element}: ${d.expectedBehavior} vs ${d.actualBehavior}`,
|
|
1796
|
+
severity: 'medium'
|
|
1797
|
+
}))
|
|
1798
|
+
],
|
|
1799
|
+
recommendations: [
|
|
1800
|
+
...designAnalysis.exactness.unclearElements.map(e => `Improve clarity: ${e}`),
|
|
1801
|
+
...designAnalysis.intuitive.culturalIssues.map(i => `Address: ${i}`)
|
|
1802
|
+
]
|
|
1803
|
+
};
|
|
1804
|
+
return [...standardHeuristics, creativityHeuristic, designHeuristic];
|
|
904
1805
|
}
|
|
905
1806
|
/**
|
|
906
1807
|
* Generate QX recommendations
|
|
@@ -1044,23 +1945,19 @@ class QXPartnerAgent extends BaseAgent_1.BaseAgent {
|
|
|
1044
1945
|
});
|
|
1045
1946
|
return sorted;
|
|
1046
1947
|
}
|
|
1047
|
-
formatHeuristicName(heuristic) {
|
|
1048
|
-
return heuristic
|
|
1049
|
-
.split('-')
|
|
1050
|
-
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
1051
|
-
.join(' ');
|
|
1052
|
-
}
|
|
1053
1948
|
/**
|
|
1054
1949
|
* Calculate overall QX score
|
|
1055
1950
|
*/
|
|
1056
|
-
calculateOverallQXScore(problemAnalysis, userNeeds, businessNeeds, impactAnalysis, heuristics) {
|
|
1951
|
+
calculateOverallQXScore(problemAnalysis, userNeeds, businessNeeds, creativityAnalysis, designAnalysis, impactAnalysis, heuristics) {
|
|
1057
1952
|
// Weighted average of all components
|
|
1058
1953
|
const weights = {
|
|
1059
|
-
problem: 0.20
|
|
1060
|
-
userNeeds: 0.25
|
|
1061
|
-
businessNeeds: 0.20
|
|
1062
|
-
|
|
1063
|
-
|
|
1954
|
+
problem: 0.15, // Reduced from 0.20
|
|
1955
|
+
userNeeds: 0.20, // Reduced from 0.25
|
|
1956
|
+
businessNeeds: 0.15, // Reduced from 0.20
|
|
1957
|
+
creativity: 0.15, // NEW
|
|
1958
|
+
design: 0.15, // NEW
|
|
1959
|
+
impact: 0.10, // Reduced from 0.15
|
|
1960
|
+
heuristics: 0.10 // Reduced from 0.20
|
|
1064
1961
|
};
|
|
1065
1962
|
const heuristicsAvg = heuristics.length > 0
|
|
1066
1963
|
? heuristics.reduce((sum, h) => sum + h.score, 0) / heuristics.length
|
|
@@ -1069,6 +1966,8 @@ class QXPartnerAgent extends BaseAgent_1.BaseAgent {
|
|
|
1069
1966
|
const score = problemAnalysis.clarityScore * weights.problem +
|
|
1070
1967
|
userNeeds.alignmentScore * weights.userNeeds +
|
|
1071
1968
|
businessNeeds.alignmentScore * weights.businessNeeds +
|
|
1969
|
+
creativityAnalysis.creativityScore * weights.creativity +
|
|
1970
|
+
designAnalysis.overallDesignScore * weights.design +
|
|
1072
1971
|
impactScore * weights.impact +
|
|
1073
1972
|
heuristicsAvg * weights.heuristics;
|
|
1074
1973
|
return Math.round(score);
|