@tayo-dev/rtl 1.0.0

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 (150) hide show
  1. package/README.md +250 -0
  2. package/dist/analyzer/mocks/detector.d.ts +59 -0
  3. package/dist/analyzer/mocks/detector.d.ts.map +1 -0
  4. package/dist/analyzer/mocks/detector.js +264 -0
  5. package/dist/analyzer/mocks/detector.js.map +1 -0
  6. package/dist/analyzer/mocks/target-analyzer.d.ts +92 -0
  7. package/dist/analyzer/mocks/target-analyzer.d.ts.map +1 -0
  8. package/dist/analyzer/mocks/target-analyzer.js +305 -0
  9. package/dist/analyzer/mocks/target-analyzer.js.map +1 -0
  10. package/dist/analyzer/visual/element-analyzer.d.ts +44 -0
  11. package/dist/analyzer/visual/element-analyzer.d.ts.map +1 -0
  12. package/dist/analyzer/visual/element-analyzer.js +176 -0
  13. package/dist/analyzer/visual/element-analyzer.js.map +1 -0
  14. package/dist/analyzer/visual/inspector.d.ts +49 -0
  15. package/dist/analyzer/visual/inspector.d.ts.map +1 -0
  16. package/dist/analyzer/visual/inspector.js +109 -0
  17. package/dist/analyzer/visual/inspector.js.map +1 -0
  18. package/dist/cli/commands/generate.d.ts +13 -0
  19. package/dist/cli/commands/generate.d.ts.map +1 -0
  20. package/dist/cli/commands/generate.js +417 -0
  21. package/dist/cli/commands/generate.js.map +1 -0
  22. package/dist/core/generator.d.ts +32 -0
  23. package/dist/core/generator.d.ts.map +1 -0
  24. package/dist/core/generator.js +173 -0
  25. package/dist/core/generator.js.map +1 -0
  26. package/dist/core/js-parser.d.ts +48 -0
  27. package/dist/core/js-parser.d.ts.map +1 -0
  28. package/dist/core/js-parser.js +244 -0
  29. package/dist/core/js-parser.js.map +1 -0
  30. package/dist/core/mock-intelligence.d.ts +14 -0
  31. package/dist/core/mock-intelligence.d.ts.map +1 -0
  32. package/dist/core/mock-intelligence.js +140 -0
  33. package/dist/core/mock-intelligence.js.map +1 -0
  34. package/dist/core/orchestrator.d.ts +49 -0
  35. package/dist/core/orchestrator.d.ts.map +1 -0
  36. package/dist/core/orchestrator.js +315 -0
  37. package/dist/core/orchestrator.js.map +1 -0
  38. package/dist/core/parser.d.ts +9 -0
  39. package/dist/core/parser.d.ts.map +1 -0
  40. package/dist/core/parser.js +120 -0
  41. package/dist/core/parser.js.map +1 -0
  42. package/dist/core/recording-intelligence.d.ts +15 -0
  43. package/dist/core/recording-intelligence.d.ts.map +1 -0
  44. package/dist/core/recording-intelligence.js +178 -0
  45. package/dist/core/recording-intelligence.js.map +1 -0
  46. package/dist/core/resolver.d.ts +58 -0
  47. package/dist/core/resolver.d.ts.map +1 -0
  48. package/dist/core/resolver.js +291 -0
  49. package/dist/core/resolver.js.map +1 -0
  50. package/dist/core/scanner.d.ts +51 -0
  51. package/dist/core/scanner.d.ts.map +1 -0
  52. package/dist/core/scanner.js +310 -0
  53. package/dist/core/scanner.js.map +1 -0
  54. package/dist/core/scorer.d.ts +8 -0
  55. package/dist/core/scorer.d.ts.map +1 -0
  56. package/dist/core/scorer.js +76 -0
  57. package/dist/core/scorer.js.map +1 -0
  58. package/dist/core/validator.d.ts +134 -0
  59. package/dist/core/validator.d.ts.map +1 -0
  60. package/dist/core/validator.js +44 -0
  61. package/dist/core/validator.js.map +1 -0
  62. package/dist/core/verifier.d.ts +10 -0
  63. package/dist/core/verifier.d.ts.map +1 -0
  64. package/dist/core/verifier.js +30 -0
  65. package/dist/core/verifier.js.map +1 -0
  66. package/dist/core/writer.d.ts +15 -0
  67. package/dist/core/writer.d.ts.map +1 -0
  68. package/dist/core/writer.js +43 -0
  69. package/dist/core/writer.js.map +1 -0
  70. package/dist/generator/mocks/builder.d.ts +47 -0
  71. package/dist/generator/mocks/builder.d.ts.map +1 -0
  72. package/dist/generator/mocks/builder.js +335 -0
  73. package/dist/generator/mocks/builder.js.map +1 -0
  74. package/dist/generator/transforms/dialog-transform.d.ts +35 -0
  75. package/dist/generator/transforms/dialog-transform.d.ts.map +1 -0
  76. package/dist/generator/transforms/dialog-transform.js +293 -0
  77. package/dist/generator/transforms/dialog-transform.js.map +1 -0
  78. package/dist/index.d.ts +7 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +18 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/learner/analyzer.d.ts +13 -0
  83. package/dist/learner/analyzer.d.ts.map +1 -0
  84. package/dist/learner/analyzer.js +484 -0
  85. package/dist/learner/analyzer.js.map +1 -0
  86. package/dist/learner/index.d.ts +66 -0
  87. package/dist/learner/index.d.ts.map +1 -0
  88. package/dist/learner/index.js +247 -0
  89. package/dist/learner/index.js.map +1 -0
  90. package/dist/learner/storage.d.ts +68 -0
  91. package/dist/learner/storage.d.ts.map +1 -0
  92. package/dist/learner/storage.js +201 -0
  93. package/dist/learner/storage.js.map +1 -0
  94. package/dist/learner/types.d.ts +41 -0
  95. package/dist/learner/types.d.ts.map +1 -0
  96. package/dist/learner/types.js +31 -0
  97. package/dist/learner/types.js.map +1 -0
  98. package/dist/parser/recorder-parser.d.ts +40 -0
  99. package/dist/parser/recorder-parser.d.ts.map +1 -0
  100. package/dist/parser/recorder-parser.js +139 -0
  101. package/dist/parser/recorder-parser.js.map +1 -0
  102. package/dist/parser/steps/deduplicator.d.ts +19 -0
  103. package/dist/parser/steps/deduplicator.d.ts.map +1 -0
  104. package/dist/parser/steps/deduplicator.js +75 -0
  105. package/dist/parser/steps/deduplicator.js.map +1 -0
  106. package/dist/parser/steps/dialog-detector.d.ts +38 -0
  107. package/dist/parser/steps/dialog-detector.d.ts.map +1 -0
  108. package/dist/parser/steps/dialog-detector.js +290 -0
  109. package/dist/parser/steps/dialog-detector.js.map +1 -0
  110. package/dist/parser/steps/noise-filter.d.ts +21 -0
  111. package/dist/parser/steps/noise-filter.d.ts.map +1 -0
  112. package/dist/parser/steps/noise-filter.js +138 -0
  113. package/dist/parser/steps/noise-filter.js.map +1 -0
  114. package/dist/scorer/index.d.ts +43 -0
  115. package/dist/scorer/index.d.ts.map +1 -0
  116. package/dist/scorer/index.js +82 -0
  117. package/dist/scorer/index.js.map +1 -0
  118. package/dist/scorer/post-verify.d.ts +17 -0
  119. package/dist/scorer/post-verify.d.ts.map +1 -0
  120. package/dist/scorer/post-verify.js +163 -0
  121. package/dist/scorer/post-verify.js.map +1 -0
  122. package/dist/scorer/pre-audit.d.ts +32 -0
  123. package/dist/scorer/pre-audit.d.ts.map +1 -0
  124. package/dist/scorer/pre-audit.js +99 -0
  125. package/dist/scorer/pre-audit.js.map +1 -0
  126. package/dist/scorer/quality-gates.d.ts +17 -0
  127. package/dist/scorer/quality-gates.d.ts.map +1 -0
  128. package/dist/scorer/quality-gates.js +304 -0
  129. package/dist/scorer/quality-gates.js.map +1 -0
  130. package/dist/scorer/types.d.ts +27 -0
  131. package/dist/scorer/types.d.ts.map +1 -0
  132. package/dist/scorer/types.js +5 -0
  133. package/dist/scorer/types.js.map +1 -0
  134. package/dist/templates/test-template.d.ts +21 -0
  135. package/dist/templates/test-template.d.ts.map +1 -0
  136. package/dist/templates/test-template.js +92 -0
  137. package/dist/templates/test-template.js.map +1 -0
  138. package/dist/types/conventions.d.ts +49 -0
  139. package/dist/types/conventions.d.ts.map +1 -0
  140. package/dist/types/conventions.js +13 -0
  141. package/dist/types/conventions.js.map +1 -0
  142. package/dist/types/recording.d.ts +143 -0
  143. package/dist/types/recording.d.ts.map +1 -0
  144. package/dist/types/recording.js +5 -0
  145. package/dist/types/recording.js.map +1 -0
  146. package/dist/types/score.d.ts +18 -0
  147. package/dist/types/score.d.ts.map +1 -0
  148. package/dist/types/score.js +2 -0
  149. package/dist/types/score.js.map +1 -0
  150. package/package.json +51 -0
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Noise event filter - removes irrelevant events from recordings
3
+ *
4
+ * Filters out:
5
+ * - dblClick events (double clicks)
6
+ * - mousemove/mouseover/mouseout (cursor wandering)
7
+ * - Accidental scroll events (scroll with no action within 2s)
8
+ *
9
+ * Preserves:
10
+ * - click, fill, select, change, navigate, keyPress, assert
11
+ */
12
+ const INTENTIONAL_SCROLL_THRESHOLD_MS = 2000;
13
+ /**
14
+ * Step types that are considered noise and should be filtered
15
+ */
16
+ const NOISE_STEP_TYPES = [
17
+ 'doubleClick',
18
+ ];
19
+ /**
20
+ * Step types that are definitely intentional (never noise)
21
+ */
22
+ const INTENTIONAL_STEP_TYPES = [
23
+ 'click',
24
+ 'fill',
25
+ 'select',
26
+ 'assert',
27
+ 'waitForSelector',
28
+ 'keyDown',
29
+ 'navigate',
30
+ ];
31
+ /**
32
+ * Step types that might be noise depending on context
33
+ */
34
+ const POTENTIALLY_NOISE_STEP_TYPES = [
35
+ 'scroll',
36
+ ];
37
+ /**
38
+ * Check if a step type is definitely noise
39
+ */
40
+ function isNoiseStepType(step) {
41
+ return NOISE_STEP_TYPES.includes(step.type);
42
+ }
43
+ /**
44
+ * Check if step is cursor-related noise
45
+ */
46
+ function isCursorNoise(step) {
47
+ const action = step.action?.toLowerCase() || '';
48
+ return (action === 'mousemove' ||
49
+ action === 'mouseover' ||
50
+ action === 'mouseout' ||
51
+ action === 'mouseenter' ||
52
+ action === 'mouseleave');
53
+ }
54
+ /**
55
+ * Check if step is scroll-related
56
+ */
57
+ function isScrollStep(step) {
58
+ return step.type === 'scroll' || step.action?.toLowerCase() === 'scroll';
59
+ }
60
+ /**
61
+ * Check if there's any intentional action after the scroll within the threshold
62
+ *
63
+ * @param scrollIndex - Index of the scroll step in the array
64
+ * @param steps - All steps
65
+ * @returns true if there's an intentional action within 2s after the scroll
66
+ */
67
+ function hasIntentionalActionAfter(scrollIndex, steps) {
68
+ const scrollStep = steps[scrollIndex];
69
+ const scrollTime = scrollStep.timestamp || 0;
70
+ for (let i = scrollIndex + 1; i < steps.length; i++) {
71
+ const step = steps[i];
72
+ const stepTime = step.timestamp || 0;
73
+ // If we've passed the threshold, stop looking
74
+ if (stepTime - scrollTime > INTENTIONAL_SCROLL_THRESHOLD_MS) {
75
+ break;
76
+ }
77
+ // Check if this is an intentional step
78
+ if (INTENTIONAL_STEP_TYPES.includes(step.type)) {
79
+ return true;
80
+ }
81
+ }
82
+ return false;
83
+ }
84
+ /**
85
+ * Determine if a scroll step is noise (accidental scroll with no subsequent action)
86
+ */
87
+ function isAccidentalScroll(scrollIndex, steps) {
88
+ // If there's no timestamp, we can't determine - keep it to be safe
89
+ if (steps[scrollIndex].timestamp === undefined) {
90
+ return false;
91
+ }
92
+ // If there's an intentional action within 2s, it's not accidental
93
+ return !hasIntentionalActionAfter(scrollIndex, steps);
94
+ }
95
+ /**
96
+ * Filter noise events from recording steps
97
+ *
98
+ * @param steps - Array of recording steps
99
+ * @returns Filtered array with noise events removed
100
+ */
101
+ export function filterNoiseSteps(steps) {
102
+ if (!steps || steps.length === 0) {
103
+ return [];
104
+ }
105
+ const filteredSteps = [];
106
+ for (let i = 0; i < steps.length; i++) {
107
+ const step = steps[i];
108
+ let shouldKeep = true;
109
+ let reason;
110
+ // Check for explicit noise types
111
+ if (isNoiseStepType(step)) {
112
+ shouldKeep = false;
113
+ reason = 'dblClick filtered';
114
+ }
115
+ // Check for cursor noise
116
+ else if (isCursorNoise(step)) {
117
+ shouldKeep = false;
118
+ reason = 'cursor movement filtered';
119
+ }
120
+ // Check for accidental scroll
121
+ else if (isScrollStep(step) && isAccidentalScroll(i, steps)) {
122
+ shouldKeep = false;
123
+ reason = 'accidental scroll filtered';
124
+ }
125
+ if (shouldKeep) {
126
+ filteredSteps.push(step);
127
+ }
128
+ else if (step.metadata) {
129
+ // Mark filtered steps with metadata (for debugging/analysis)
130
+ step.metadata.isNoiseFiltered = true;
131
+ step.metadata.noiseReason = reason;
132
+ filteredSteps.push(step);
133
+ }
134
+ }
135
+ return filteredSteps;
136
+ }
137
+ export { filterNoiseSteps as default };
138
+ //# sourceMappingURL=noise-filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"noise-filter.js","sourceRoot":"","sources":["../../../src/parser/steps/noise-filter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Main scorer module - orchestrates test quality evaluation
3
+ */
4
+ import { AuditResult } from './pre-audit.js';
5
+ import { VerificationResult } from './post-verify.js';
6
+ import { QualityScore, ScoringResult } from './types.js';
7
+ export interface Recording {
8
+ id: string;
9
+ name: string;
10
+ steps: Array<{
11
+ action: string;
12
+ selector?: string;
13
+ value?: string;
14
+ }>;
15
+ }
16
+ export interface OrchestrateOptions {
17
+ recording: Recording;
18
+ outputPath: string;
19
+ generateTest: (recording: Recording) => string;
20
+ }
21
+ export interface OrchestrateResult {
22
+ success: boolean;
23
+ outputPath?: string;
24
+ audit?: AuditResult;
25
+ verification?: VerificationResult;
26
+ score?: QualityScore;
27
+ error?: string;
28
+ }
29
+ /**
30
+ * Score a test file or code string
31
+ */
32
+ export declare function scoreTest(code: string): ScoringResult;
33
+ /**
34
+ * Orchestrate test generation with pre/post validation
35
+ * @param options Recording and generation options
36
+ * @returns Complete result with audit, verification, and scoring
37
+ */
38
+ export declare function orchestrateWithScoring(options: OrchestrateOptions): OrchestrateResult;
39
+ export { QualityScore, QualityIssue, QualityCriteria } from './types.js';
40
+ export { evaluateQualityGates } from './quality-gates.js';
41
+ export { preWriteAudit, AuditResult } from './pre-audit.js';
42
+ export { postWriteVerification, VerificationResult } from './post-verify.js';
43
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scorer/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAiB,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAyB,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEzD,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,CAAC;QACX,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,MAAM,CAAC;CAChD;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAQrD;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,kBAAkB,GAAG,iBAAiB,CA4DrF;AAED,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Main scorer module - orchestrates test quality evaluation
3
+ */
4
+ import { writeFileSync } from 'fs';
5
+ import { evaluateQualityGates } from './quality-gates.js';
6
+ import { preWriteAudit } from './pre-audit.js';
7
+ import { postWriteVerification } from './post-verify.js';
8
+ /**
9
+ * Score a test file or code string
10
+ */
11
+ export function scoreTest(code) {
12
+ const score = evaluateQualityGates(code);
13
+ return {
14
+ score,
15
+ code,
16
+ timestamp: Date.now()
17
+ };
18
+ }
19
+ /**
20
+ * Orchestrate test generation with pre/post validation
21
+ * @param options Recording and generation options
22
+ * @returns Complete result with audit, verification, and scoring
23
+ */
24
+ export function orchestrateWithScoring(options) {
25
+ const { recording, outputPath, generateTest } = options;
26
+ // Step 1: Generate test code
27
+ let testCode;
28
+ try {
29
+ testCode = generateTest(recording);
30
+ }
31
+ catch (error) {
32
+ return {
33
+ success: false,
34
+ error: `Failed to generate test: ${error.message}`
35
+ };
36
+ }
37
+ // Step 2: Pre-write audit
38
+ const audit = preWriteAudit(testCode);
39
+ // If blocking issues, don't write the file
40
+ if (!audit.valid) {
41
+ return {
42
+ success: false,
43
+ audit,
44
+ error: 'Pre-write audit failed: ' + audit.blocking.join('; ')
45
+ };
46
+ }
47
+ // Step 3: Write the file
48
+ try {
49
+ writeFileSync(outputPath, testCode, 'utf-8');
50
+ }
51
+ catch (error) {
52
+ return {
53
+ success: false,
54
+ audit,
55
+ error: `Failed to write test file: ${error.message}`
56
+ };
57
+ }
58
+ // Step 4: Post-write verification
59
+ const verification = postWriteVerification(outputPath);
60
+ // If verification has errors, consider it a failure
61
+ if (!verification.valid) {
62
+ return {
63
+ success: false,
64
+ audit,
65
+ verification,
66
+ error: 'Post-write verification failed: ' + verification.errors.join('; ')
67
+ };
68
+ }
69
+ // Step 5: Calculate quality score (get full QualityScore from evaluateQualityGates)
70
+ const score = evaluateQualityGates(testCode);
71
+ return {
72
+ success: true,
73
+ outputPath,
74
+ audit,
75
+ verification,
76
+ score
77
+ };
78
+ }
79
+ export { evaluateQualityGates } from './quality-gates.js';
80
+ export { preWriteAudit } from './pre-audit.js';
81
+ export { postWriteVerification } from './post-verify.js';
82
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scorer/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAc,MAAM,IAAI,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAe,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAsB,MAAM,kBAAkB,CAAC;AA4B7E;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,MAAM,KAAK,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAEzC,OAAO;QACL,KAAK;QACL,IAAI;QACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;KACtB,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAA2B;IAChE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;IAExD,6BAA6B;IAC7B,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,4BAA6B,KAAe,CAAC,OAAO,EAAE;SAC9D,CAAC;IACJ,CAAC;IAED,0BAA0B;IAC1B,MAAM,KAAK,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAEtC,2CAA2C;IAC3C,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACjB,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK;YACL,KAAK,EAAE,0BAA0B,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;SAC9D,CAAC;IACJ,CAAC;IAED,yBAAyB;IACzB,IAAI,CAAC;QACH,aAAa,CAAC,UAAU,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK;YACL,KAAK,EAAE,8BAA+B,KAAe,CAAC,OAAO,EAAE;SAChE,CAAC;IACJ,CAAC;IAED,kCAAkC;IAClC,MAAM,YAAY,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;IAEvD,oDAAoD;IACpD,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;QACxB,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK;YACL,YAAY;YACZ,KAAK,EAAE,kCAAkC,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;SAC3E,CAAC;IACJ,CAAC;IAED,oFAAoF;IACpF,MAAM,KAAK,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAE7C,OAAO;QACL,OAAO,EAAE,IAAI;QACb,UAAU;QACV,KAAK;QACL,YAAY;QACZ,KAAK;KACN,CAAC;AACJ,CAAC;AAGD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAe,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAsB,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Post-write verification for test files - validates file after creation
3
+ */
4
+ export interface VerificationResult {
5
+ valid: boolean;
6
+ errors: string[];
7
+ warnings: string[];
8
+ filePath: string;
9
+ parsed?: boolean;
10
+ }
11
+ /**
12
+ * Run post-write verification on a test file
13
+ * @param filePath Path to the test file to verify
14
+ * @returns VerificationResult with errors and warnings
15
+ */
16
+ export declare function postWriteVerification(filePath: string): VerificationResult;
17
+ //# sourceMappingURL=post-verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"post-verify.d.ts","sourceRoot":"","sources":["../../src/scorer/post-verify.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AASD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CA2E1E"}
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Post-write verification for test files - validates file after creation
3
+ */
4
+ import { readFileSync, existsSync } from 'fs';
5
+ import { parse } from '@typescript-eslint/typescript-estree';
6
+ /**
7
+ * Run post-write verification on a test file
8
+ * @param filePath Path to the test file to verify
9
+ * @returns VerificationResult with errors and warnings
10
+ */
11
+ export function postWriteVerification(filePath) {
12
+ const errors = [];
13
+ const warnings = [];
14
+ // Check if file exists
15
+ if (!existsSync(filePath)) {
16
+ errors.push(`File does not exist: ${filePath}`);
17
+ return {
18
+ valid: false,
19
+ errors,
20
+ warnings,
21
+ filePath,
22
+ parsed: false
23
+ };
24
+ }
25
+ // Read file content
26
+ let code;
27
+ try {
28
+ code = readFileSync(filePath, 'utf-8');
29
+ }
30
+ catch (error) {
31
+ errors.push(`Failed to read file: ${error.message}`);
32
+ return {
33
+ valid: false,
34
+ errors,
35
+ warnings,
36
+ filePath,
37
+ parsed: false
38
+ };
39
+ }
40
+ // Check for valid TypeScript syntax
41
+ let ast;
42
+ try {
43
+ ast = parse(code, {
44
+ loc: true,
45
+ range: true,
46
+ jsx: true,
47
+ ecmaVersion: 2020,
48
+ sourceType: 'module'
49
+ });
50
+ }
51
+ catch (parseError) {
52
+ const errorMessage = parseError.message;
53
+ // Extract line number if available
54
+ const lineMatch = errorMessage.match(/line (\d+)/i);
55
+ const lineInfo = lineMatch ? ` at line ${lineMatch[1]}` : '';
56
+ errors.push(`Syntax parse error${lineInfo}: ${errorMessage}`);
57
+ return {
58
+ valid: false,
59
+ errors,
60
+ warnings,
61
+ filePath,
62
+ parsed: false
63
+ };
64
+ }
65
+ // Check for required imports
66
+ const importChecks = checkRequiredImports(code, ast);
67
+ errors.push(...importChecks.errors);
68
+ warnings.push(...importChecks.warnings);
69
+ // Check for common issues
70
+ const commonChecks = checkCommonIssues(code);
71
+ warnings.push(...commonChecks.warnings);
72
+ // Determine if valid (no errors)
73
+ const valid = errors.length === 0;
74
+ return {
75
+ valid,
76
+ errors,
77
+ warnings,
78
+ filePath,
79
+ parsed: true
80
+ };
81
+ }
82
+ /**
83
+ * Check for required imports
84
+ */
85
+ function checkRequiredImports(code, ast) {
86
+ const errors = [];
87
+ const warnings = [];
88
+ // Check for @testing-library/react import
89
+ const hasTestingLibrary = /import\s+.*from\s+['"]@testing-library\/react['"]/.test(code);
90
+ if (!hasTestingLibrary) {
91
+ errors.push('Missing required import: @testing-library/react');
92
+ }
93
+ // Check for test framework imports (describe, it/test, expect)
94
+ const hasDescribeImport = /import\s+.*\bdescribe\b/.test(code);
95
+ const hasItImport = /import\s+.*\b(it|test)\b/.test(code);
96
+ const hasExpectImport = /import\s+.*\bexpect\b/.test(code);
97
+ // Check for inline imports or global usage
98
+ const hasDescribeUsage = code.includes('describe(');
99
+ const hasItUsage = code.includes('it(') || code.includes('test(');
100
+ const hasExpectUsage = code.includes('expect(');
101
+ // Check if using vitest globals (no import needed)
102
+ const usesVitestGlobals = code.includes('/// <reference types="vitest" />') ||
103
+ /"vitest\/globals"/.test(code);
104
+ if (!hasDescribeImport && !usesVitestGlobals && !hasDescribeUsage) {
105
+ warnings.push('No describe import detected - ensure describe is available globally or imported');
106
+ }
107
+ if (!hasItImport && !usesVitestGlobals && !hasItUsage) {
108
+ warnings.push('No it/test import detected - ensure test functions are available globally or imported');
109
+ }
110
+ if (!hasExpectImport && !usesVitestGlobals && !hasExpectUsage) {
111
+ warnings.push('No expect import detected - ensure expect is available globally or imported');
112
+ }
113
+ // Check for render function (required for React Testing Library)
114
+ const hasRender = /render\(/.test(code);
115
+ if (!hasRender) {
116
+ warnings.push('No render() call detected - tests should use Testing Library render');
117
+ }
118
+ return { errors, warnings };
119
+ }
120
+ /**
121
+ * Check for common issues in test files
122
+ */
123
+ function checkCommonIssues(code) {
124
+ const errors = [];
125
+ const warnings = [];
126
+ // Check for screen.debug() - useful for debugging but should not be in production tests
127
+ if (/screen\.debug\(/.test(code)) {
128
+ warnings.push('screen.debug() found - remove before committing to production');
129
+ }
130
+ // Check for skipped tests
131
+ const skippedTests = code.match(/\b(it|test)\.skip\s*\(/g);
132
+ if (skippedTests) {
133
+ warnings.push(`Found ${skippedTests.length} skipped test(s) - consider removing .skip or adding reason`);
134
+ }
135
+ // Check for only tests
136
+ const onlyTests = code.match(/\b(it|test)\.only\s*\(/g);
137
+ if (onlyTests) {
138
+ warnings.push(`Found ${onlyTests.length} .only test(s) - remove .only before committing`);
139
+ }
140
+ // Check for console.log in tests
141
+ const consoleLogs = code.match(/console\.log\s*\(/g);
142
+ if (consoleLogs) {
143
+ warnings.push(`Found ${consoleLogs.length} console.log statement(s) - consider removing for cleaner test output`);
144
+ }
145
+ // Check for empty test blocks
146
+ const emptyTests = code.match(/it\s*\(\s*['"][^'"]+['"]\s*,\s*\(\s*\)\s*=>\s*\{\s*\}/g);
147
+ if (emptyTests) {
148
+ errors.push(`Found ${emptyTests.length} empty test block(s) - add test implementation or remove`);
149
+ }
150
+ // Check for TODO comments in tests
151
+ const todoComments = code.match(/\/\/\s*TODO|\/\*\s*TODO/i);
152
+ if (todoComments) {
153
+ warnings.push('Found TODO comment(s) - ensure tests are complete before finishing');
154
+ }
155
+ // Check for potential memory leaks - missing cleanup
156
+ const hasCleanup = /cleanup\(\)|unmount\(\)/.test(code);
157
+ const hasDescribeEach = code.includes('describe.each');
158
+ if (hasDescribeEach && !hasCleanup) {
159
+ warnings.push('Using describe.each without explicit cleanup - consider adding afterEach(cleanup)');
160
+ }
161
+ return { errors, warnings };
162
+ }
163
+ //# sourceMappingURL=post-verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"post-verify.js","sourceRoot":"","sources":["../../src/scorer/post-verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Pre-write audit for test files - validates structure before file creation
3
+ */
4
+ export interface AuditResult {
5
+ valid: boolean;
6
+ blocking: string[];
7
+ warnings: string[];
8
+ qualityScore?: {
9
+ overall: number;
10
+ criteria: {
11
+ structure: number;
12
+ queries: number;
13
+ matchers: number;
14
+ noFragility: number;
15
+ };
16
+ issues: Array<{
17
+ type: string;
18
+ severity: string;
19
+ message: string;
20
+ suggestion?: string;
21
+ }>;
22
+ passed: boolean;
23
+ };
24
+ }
25
+ /**
26
+ * Run pre-write audit on test code before file creation
27
+ * @param code The test code to audit
28
+ * @returns AuditResult with blocking issues and warnings
29
+ */
30
+ export declare function preWriteAudit(code: string): AuditResult;
31
+ export type { StructureRules, QueryRules } from './quality-gates.js';
32
+ //# sourceMappingURL=pre-audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pre-audit.d.ts","sourceRoot":"","sources":["../../src/scorer/pre-audit.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,CAAC,EAAE;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE;YACR,SAAS,EAAE,MAAM,CAAC;YAClB,OAAO,EAAE,MAAM,CAAC;YAChB,QAAQ,EAAE,MAAM,CAAC;YACjB,WAAW,EAAE,MAAM,CAAC;SACrB,CAAC;QACF,MAAM,EAAE,KAAK,CAAC;YACZ,IAAI,EAAE,MAAM,CAAC;YACb,QAAQ,EAAE,MAAM,CAAC;YACjB,OAAO,EAAE,MAAM,CAAC;YAChB,UAAU,CAAC,EAAE,MAAM,CAAC;SACrB,CAAC,CAAC;QACH,MAAM,EAAE,OAAO,CAAC;KACjB,CAAC;CACH;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CA6CvD;AA+DD,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Pre-write audit for test files - validates structure before file creation
3
+ */
4
+ import { evaluateQualityGates } from './quality-gates.js';
5
+ /**
6
+ * Run pre-write audit on test code before file creation
7
+ * @param code The test code to audit
8
+ * @returns AuditResult with blocking issues and warnings
9
+ */
10
+ export function preWriteAudit(code) {
11
+ const blocking = [];
12
+ const warnings = [];
13
+ // Run quality gates first for detailed analysis
14
+ const qualityResult = evaluateQualityGates(code);
15
+ // Extract blocking issues from quality gates (errors only)
16
+ const qualityErrors = qualityResult.issues.filter(i => i.severity === 'error');
17
+ const qualityWarnings = qualityResult.issues.filter(i => i.severity === 'warning');
18
+ // Add quality gate errors as blocking issues
19
+ for (const error of qualityErrors) {
20
+ blocking.push(error.message);
21
+ }
22
+ // Add quality gate warnings as warnings
23
+ for (const warning of qualityWarnings) {
24
+ warnings.push(warning.message);
25
+ }
26
+ // Additional structural checks beyond quality gates
27
+ const structuralChecks = performStructuralChecks(code);
28
+ blocking.push(...structuralChecks.blocking);
29
+ warnings.push(...structuralChecks.warnings);
30
+ // Determine if valid (no blocking issues)
31
+ const valid = blocking.length === 0;
32
+ return {
33
+ valid,
34
+ blocking,
35
+ warnings,
36
+ qualityScore: valid ? {
37
+ overall: qualityResult.overall,
38
+ criteria: qualityResult.criteria,
39
+ issues: qualityResult.issues.map(i => ({
40
+ type: i.type,
41
+ severity: i.severity,
42
+ message: i.message,
43
+ suggestion: i.suggestion
44
+ })),
45
+ passed: qualityResult.passed
46
+ } : undefined
47
+ };
48
+ }
49
+ /**
50
+ * Perform additional structural validation checks
51
+ */
52
+ function performStructuralChecks(code) {
53
+ const blocking = [];
54
+ const warnings = [];
55
+ // Check for required imports
56
+ const hasTestingLibrary = /@testing-library\/react/.test(code);
57
+ const hasDescribe = /import\s+.*\bdescribe\b/.test(code) || code.includes("describe('") || code.includes('describe("');
58
+ const hasIt = /\bit\(|\btest\(/.test(code);
59
+ const hasExpect = /\bexpect\(/.test(code);
60
+ // Blocking: Missing essential imports
61
+ if (!hasTestingLibrary && !code.includes('render(')) {
62
+ blocking.push('Missing @testing-library/react import or render() call');
63
+ }
64
+ // Blocking: No test structure
65
+ if (!hasDescribe) {
66
+ blocking.push('Missing describe block - tests must be organized in describe()');
67
+ }
68
+ // Blocking: No test cases
69
+ if (!hasIt) {
70
+ blocking.push('Missing test case - need it() or test() blocks');
71
+ }
72
+ // Blocking: No assertions
73
+ if (!hasExpect) {
74
+ blocking.push('Missing expect statements - tests must have assertions');
75
+ }
76
+ // Warnings: Check for fragile queries
77
+ const fragileQueryPatterns = [
78
+ { pattern: /getByTestId|queryByTestId|findByTestId/, message: 'Using getByTestId - consider semantic queries' },
79
+ { pattern: /querySelector/, message: 'Using querySelector - consider Testing Library queries' }
80
+ ];
81
+ for (const { pattern, message } of fragileQueryPatterns) {
82
+ if (pattern.test(code)) {
83
+ warnings.push(message);
84
+ }
85
+ }
86
+ // Warnings: Missing common matchers
87
+ const hasCommonMatchers = /toBe|toEqual|toContain|toHaveLength|toBeTruthy|toBeFalsy/.test(code);
88
+ if (hasExpect && !hasCommonMatchers) {
89
+ warnings.push('Consider using more specific matchers (toBe, toEqual, toContain)');
90
+ }
91
+ // Warnings: Check for async without findBy
92
+ const hasAsync = code.includes('async') || code.includes('await');
93
+ const hasFindBy = /findBy/.test(code);
94
+ if (hasAsync && !hasFindBy) {
95
+ warnings.push('Async operations detected - consider using findBy* queries for async elements');
96
+ }
97
+ return { blocking, warnings };
98
+ }
99
+ //# sourceMappingURL=pre-audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pre-audit.js","sourceRoot":"","sources":["../../src/scorer/pre-audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Quality gates evaluation using AST-based analysis
3
+ */
4
+ import { QualityScore } from './types.js';
5
+ /**
6
+ * Evaluate quality gates on test code
7
+ */
8
+ export declare function evaluateQualityGates(code: string): QualityScore;
9
+ export interface StructureRules {
10
+ requireDescribe: boolean;
11
+ requireTest: boolean;
12
+ }
13
+ export interface QueryRules {
14
+ preferRobust: boolean;
15
+ disallowTestId: boolean;
16
+ }
17
+ //# sourceMappingURL=quality-gates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality-gates.d.ts","sourceRoot":"","sources":["../../src/scorer/quality-gates.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,YAAY,EAAiC,MAAM,YAAY,CAAC;AAiBzE;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CA+C/D;AAiRD,MAAM,WAAW,cAAc;IAC7B,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;CACzB"}