@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,304 @@
1
+ /**
2
+ * Quality gates evaluation using AST-based analysis
3
+ */
4
+ import { parse } from '@typescript-eslint/typescript-estree';
5
+ /**
6
+ * Evaluate quality gates on test code
7
+ */
8
+ export function evaluateQualityGates(code) {
9
+ const issues = [];
10
+ let ast;
11
+ try {
12
+ ast = parse(code, {
13
+ loc: true,
14
+ range: true,
15
+ jsx: true,
16
+ ecmaVersion: 2020,
17
+ sourceType: 'module'
18
+ });
19
+ }
20
+ catch (error) {
21
+ issues.push({
22
+ type: 'structure',
23
+ severity: 'error',
24
+ message: 'Failed to parse code - syntax error',
25
+ suggestion: 'Check for valid TypeScript/JavaScript syntax'
26
+ });
27
+ return {
28
+ overall: 0,
29
+ criteria: { structure: 0, queries: 0, matchers: 0, noFragility: 0 },
30
+ issues,
31
+ passed: false
32
+ };
33
+ }
34
+ // Evaluate each criterion
35
+ const structure = evaluateStructure(ast, issues);
36
+ const queries = evaluateQueries(code, ast, issues);
37
+ const matchers = evaluateMatchers(ast, issues);
38
+ const noFragility = evaluateNoFragility(code, ast, issues);
39
+ // Calculate weighted overall score
40
+ const overall = Math.round(structure * 0.25 +
41
+ queries * 0.25 +
42
+ matchers * 0.30 +
43
+ noFragility * 0.20);
44
+ return {
45
+ overall,
46
+ criteria: { structure, queries, matchers, noFragility },
47
+ issues,
48
+ passed: overall >= 50 // Minimum threshold to pass
49
+ };
50
+ }
51
+ /**
52
+ * Evaluate test structure (describe/it blocks)
53
+ */
54
+ function evaluateStructure(ast, issues) {
55
+ let hasDescribe = false;
56
+ let hasTest = false;
57
+ function traverse(node) {
58
+ if (!node)
59
+ return;
60
+ if (node.type === 'CallExpression' && node.callee) {
61
+ const calleeName = getCalleeName(node.callee);
62
+ if (calleeName === 'describe')
63
+ hasDescribe = true;
64
+ if (calleeName === 'it' || calleeName === 'test')
65
+ hasTest = true;
66
+ }
67
+ // Recursively traverse children
68
+ if (Array.isArray(node.body)) {
69
+ node.body.forEach(traverse);
70
+ }
71
+ else if (node.body && typeof node.body === 'object') {
72
+ traverse(node.body);
73
+ }
74
+ // Also traverse function expression and arrow function bodies
75
+ if (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') {
76
+ if (node.body) {
77
+ if (Array.isArray(node.body)) {
78
+ node.body.forEach(traverse);
79
+ }
80
+ else if (typeof node.body === 'object') {
81
+ traverse(node.body);
82
+ }
83
+ }
84
+ }
85
+ if (node.arguments) {
86
+ node.arguments.forEach(arg => traverse(arg));
87
+ }
88
+ // Traverse expression for chaining like expect(x).toBe()
89
+ if (node.expression) {
90
+ traverse(node.expression);
91
+ }
92
+ }
93
+ traverse(ast);
94
+ if (!hasDescribe) {
95
+ issues.push({
96
+ type: 'structure',
97
+ severity: 'error',
98
+ message: 'Missing describe block',
99
+ suggestion: 'Wrap tests in describe() to organize test cases'
100
+ });
101
+ }
102
+ if (!hasTest) {
103
+ issues.push({
104
+ type: 'structure',
105
+ severity: 'error',
106
+ message: 'Missing test case (it/test)',
107
+ suggestion: 'Add it() or test() blocks for test cases'
108
+ });
109
+ }
110
+ // Score: 50 for having describe, +50 for having test block
111
+ return (hasDescribe ? 50 : 0) + (hasTest ? 50 : 0);
112
+ }
113
+ /**
114
+ * Evaluate query robustness
115
+ */
116
+ function evaluateQueries(code, ast, issues) {
117
+ const robustQueries = ['getByRole', 'getByLabelText', 'getByText', 'findByRole', 'findByLabelText', 'queryByRole', 'getByPlaceholderText'];
118
+ const fragileQueries = ['querySelector', 'getByTestId', 'queryByTestId'];
119
+ let robustCount = 0;
120
+ let fragileCount = 0;
121
+ // Check for query methods in code
122
+ robustQueries.forEach(q => {
123
+ if (code.includes(q))
124
+ robustCount++;
125
+ });
126
+ fragileQueries.forEach(q => {
127
+ if (code.includes(q))
128
+ fragileCount++;
129
+ });
130
+ if (fragileCount > 0 && robustCount === 0) {
131
+ issues.push({
132
+ type: 'queries',
133
+ severity: 'warning',
134
+ message: 'Using fragile queries (getByTestId, querySelector)',
135
+ suggestion: 'Prefer getByRole, getByLabelText, getByText for accessibility'
136
+ });
137
+ }
138
+ if (robustCount > 0) {
139
+ return Math.min(100, 50 + (robustCount * 10));
140
+ }
141
+ return fragileCount > 0 ? 30 : 50;
142
+ }
143
+ /**
144
+ * Evaluate assertion matchers
145
+ */
146
+ function evaluateMatchers(ast, issues) {
147
+ let expectCount = 0;
148
+ let matcherCount = 0;
149
+ function traverse(node) {
150
+ if (!node)
151
+ return;
152
+ // Check for expect() calls - look for CallExpression where callee starts with 'expect'
153
+ if (node.type === 'CallExpression' && node.callee) {
154
+ const calleeSource = getCalleeSource(node.callee);
155
+ if (calleeSource && calleeSource.startsWith('expect')) {
156
+ expectCount++;
157
+ // Check if has arguments
158
+ if (node.arguments && node.arguments.length > 0) {
159
+ matcherCount++;
160
+ }
161
+ }
162
+ }
163
+ // Check for common matchers in chained calls like expect(x).toBe(y)
164
+ const matcherNames = ['toBe', 'toEqual', 'toContain', 'toHaveLength', 'toBeTruthy', 'toBeFalsy', 'toBeInTheDocument', 'toBeVisible', 'toHaveTextContent'];
165
+ if (node.type === 'MemberExpression' && node.property) {
166
+ const prop = node.property;
167
+ const propName = typeof prop.name === 'string' ? prop.name : '';
168
+ if (matcherNames.includes(propName)) {
169
+ matcherCount++;
170
+ }
171
+ }
172
+ // Recursively traverse all node types
173
+ if (Array.isArray(node.body)) {
174
+ node.body.forEach(traverse);
175
+ }
176
+ else if (node.body && typeof node.body === 'object') {
177
+ traverse(node.body);
178
+ }
179
+ // Handle function expressions and arrow functions
180
+ if (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') {
181
+ if (node.body) {
182
+ if (Array.isArray(node.body)) {
183
+ node.body.forEach(traverse);
184
+ }
185
+ else if (typeof node.body === 'object') {
186
+ traverse(node.body);
187
+ }
188
+ }
189
+ }
190
+ if (node.arguments) {
191
+ node.arguments.forEach(arg => traverse(arg));
192
+ }
193
+ if (node.expression) {
194
+ traverse(node.expression);
195
+ }
196
+ // Handle object properties
197
+ if (node.properties) {
198
+ node.properties.forEach((prop) => traverse(prop));
199
+ }
200
+ }
201
+ traverse(ast);
202
+ if (expectCount === 0) {
203
+ issues.push({
204
+ type: 'matchers',
205
+ severity: 'error',
206
+ message: 'No expect statements found',
207
+ suggestion: 'Add assertions using expect() with matchers like toBe(), toEqual()'
208
+ });
209
+ return 0;
210
+ }
211
+ if (matcherCount < expectCount) {
212
+ return Math.min(100, 50 + (matcherCount * 15));
213
+ }
214
+ return Math.min(100, 50 + (expectCount * 10));
215
+ }
216
+ /**
217
+ * Evaluate fragility - avoid CSS selectors and test IDs as primary queries
218
+ */
219
+ function evaluateNoFragility(code, ast, issues) {
220
+ // Check for CSS selectors - but avoid false positives from method calls
221
+ // More careful patterns that exclude method chains like getByRole, queryByText
222
+ const cssSelectors = [
223
+ /(?:^|[^.\w])#[a-zA-Z][\w-]*/, // ID selectors (#button) - not preceded by word char
224
+ /\[[\w-]+=["'][^"']*["']\]/, // attribute selectors [data-testid="x"]
225
+ /document\.querySelector/,
226
+ /document\.getElementBy/
227
+ ];
228
+ // Also check for standalone class selectors that are not part of method chains
229
+ const classSelectorRegex = /(?<![a-zA-Z])\.[a-zA-Z][\w-]*(?![a-zA-Z(])/g;
230
+ let cssSelectorCount = 0;
231
+ cssSelectors.forEach(regex => {
232
+ const matches = code.match(regex);
233
+ if (matches)
234
+ cssSelectorCount += matches.length;
235
+ });
236
+ // Check for class selectors separately
237
+ const classMatches = code.match(classSelectorRegex);
238
+ if (classMatches)
239
+ cssSelectorCount += classMatches.length;
240
+ // Check for test IDs (data-testid)
241
+ const testIdRegex = /data-testid=["']([^"']+)["']/g;
242
+ const testIdMatches = code.match(testIdRegex);
243
+ const testIdCount = testIdMatches ? testIdMatches.length : 0;
244
+ if (cssSelectorCount > 0) {
245
+ issues.push({
246
+ type: 'fragility',
247
+ severity: 'warning',
248
+ message: `Found ${cssSelectorCount} CSS selector(s) - fragile to style changes`,
249
+ suggestion: 'Use semantic queries like getByRole for better resilience'
250
+ });
251
+ }
252
+ if (testIdCount > 0) {
253
+ issues.push({
254
+ type: 'fragility',
255
+ severity: 'info',
256
+ message: `Found ${testIdCount} test ID(s) - acceptable but not ideal`,
257
+ suggestion: 'Prefer semantic queries when possible'
258
+ });
259
+ }
260
+ // Score based on absence of fragile patterns
261
+ if (cssSelectorCount === 0 && testIdCount === 0)
262
+ return 100;
263
+ if (cssSelectorCount === 0)
264
+ return 80;
265
+ if (testIdCount === 0)
266
+ return 70;
267
+ return 50;
268
+ }
269
+ /**
270
+ * Get the full source of a callee including chained calls (e.g., "expect", "expect().toBe")
271
+ */
272
+ function getCalleeSource(callee) {
273
+ if (callee.type === 'Identifier') {
274
+ return callee.name || '';
275
+ }
276
+ if (callee.type === 'MemberExpression' && callee.object) {
277
+ // For chained calls like expect().toBe(), get the object part first
278
+ const objectSource = getCalleeSource(callee.object);
279
+ const prop = callee.property;
280
+ const propName = typeof prop.name === 'string' ? prop.name : '';
281
+ return objectSource ? `${objectSource}.${propName}` : propName;
282
+ }
283
+ if (callee.type === 'CallExpression' && callee.callee) {
284
+ return getCalleeSource(callee.callee);
285
+ }
286
+ return '';
287
+ }
288
+ /**
289
+ * Get the name of a callee (handles nested calls like expect().toBe)
290
+ */
291
+ function getCalleeName(callee) {
292
+ if (callee.type === 'Identifier') {
293
+ return callee.name || '';
294
+ }
295
+ if (callee.type === 'MemberExpression' && callee.property) {
296
+ const prop = callee.property;
297
+ return typeof prop.name === 'string' ? prop.name : '';
298
+ }
299
+ if (callee.type === 'CallExpression' && callee.callee) {
300
+ return getCalleeName(callee.callee);
301
+ }
302
+ return '';
303
+ }
304
+ //# sourceMappingURL=quality-gates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality-gates.js","sourceRoot":"","sources":["../../src/scorer/quality-gates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Quality scoring types for test evaluation
3
+ */
4
+ export interface QualityCriteria {
5
+ structure: number;
6
+ queries: number;
7
+ matchers: number;
8
+ noFragility: number;
9
+ }
10
+ export interface QualityIssue {
11
+ type: 'structure' | 'queries' | 'matchers' | 'fragility';
12
+ severity: 'error' | 'warning' | 'info';
13
+ message: string;
14
+ suggestion?: string;
15
+ }
16
+ export interface QualityScore {
17
+ overall: number;
18
+ criteria: QualityCriteria;
19
+ issues: QualityIssue[];
20
+ passed: boolean;
21
+ }
22
+ export interface ScoringResult {
23
+ score: QualityScore;
24
+ code: string;
25
+ timestamp: number;
26
+ }
27
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/scorer/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;IACzD,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,eAAe,CAAC;IAC1B,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Quality scoring types for test evaluation
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/scorer/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Code templates for RTL test structure.
3
+ * Functions return string fragments for composing test files.
4
+ */
5
+ import type { NormalizedAction } from '../types/recording.js';
6
+ export declare function importBlock(hasUserEvents: boolean, importStyle?: 'esm' | 'cjs'): string;
7
+ export interface StepTemplateOptions {
8
+ action: NormalizedAction;
9
+ query: string;
10
+ value?: string;
11
+ matcher?: string;
12
+ }
13
+ export declare function stepTemplate(opts: StepTemplateOptions): string;
14
+ export declare function describeBlock(name: string, bodyLines: string[], hasUserEvents: boolean): string;
15
+ export interface ItBlockTemplate {
16
+ name: string;
17
+ stepLines: string[];
18
+ hasUserEvents: boolean;
19
+ }
20
+ export declare function describeBlockMultiIt(name: string, itBlocks: ItBlockTemplate[]): string;
21
+ //# sourceMappingURL=test-template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-template.d.ts","sourceRoot":"","sources":["../../src/templates/test-template.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAE7D,wBAAgB,WAAW,CAAC,aAAa,EAAE,OAAO,EAAE,WAAW,GAAE,KAAK,GAAG,KAAa,GAAG,MAAM,CAoB9F;AAcD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,gBAAgB,CAAA;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,CAiC9D;AAED,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EAAE,EACnB,aAAa,EAAE,OAAO,GACrB,MAAM,CAYR;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,aAAa,EAAE,OAAO,CAAA;CACvB;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,eAAe,EAAE,GAC1B,MAAM,CAiBR"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Code templates for RTL test structure.
3
+ * Functions return string fragments for composing test files.
4
+ */
5
+ export function importBlock(hasUserEvents, importStyle = 'esm') {
6
+ if (importStyle === 'cjs') {
7
+ const lines = [
8
+ "const { render, screen } = require('@testing-library/react')",
9
+ "require('@testing-library/jest-dom')",
10
+ ];
11
+ if (hasUserEvents) {
12
+ lines.push("const userEvent = require('@testing-library/user-event')");
13
+ }
14
+ return lines.join('\n');
15
+ }
16
+ // ESM (default)
17
+ const lines = [
18
+ "import { render, screen } from '@testing-library/react'",
19
+ "import '@testing-library/jest-dom'",
20
+ ];
21
+ if (hasUserEvents) {
22
+ lines.push("import userEvent from '@testing-library/user-event'");
23
+ }
24
+ return lines.join('\n');
25
+ }
26
+ function escapeSingleQuote(s) {
27
+ return s.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
28
+ }
29
+ function indentLines(text, spaces) {
30
+ const pad = ' '.repeat(spaces);
31
+ return text
32
+ .split('\n')
33
+ .map((line) => (line.trim() ? pad + line : ''))
34
+ .join('\n');
35
+ }
36
+ export function stepTemplate(opts) {
37
+ const { action, query, value = '' } = opts;
38
+ const escapedValue = escapeSingleQuote(value);
39
+ switch (action) {
40
+ case 'click':
41
+ return `await user.click(${query})`;
42
+ case 'fill':
43
+ return [
44
+ `await user.clear(${query})`,
45
+ `await user.type(${query}, '${escapedValue}')`,
46
+ ].join('\n');
47
+ case 'select':
48
+ return `await user.selectOptions(${query}, '${escapedValue}')`;
49
+ case 'scroll':
50
+ return `${query}.scrollIntoView()`;
51
+ case 'assert':
52
+ return `expect(${query})${opts.matcher ?? '.toBeInTheDocument()'}`;
53
+ case 'navigate':
54
+ return `// navigate: ${value || query}`;
55
+ case 'keyDown':
56
+ return `await user.keyboard('${escapedValue}')`;
57
+ case 'unknown':
58
+ default:
59
+ return `// TODO: unsupported step — original selector: ${query}`;
60
+ }
61
+ }
62
+ export function describeBlock(name, bodyLines, hasUserEvents) {
63
+ const body = bodyLines.join('\n');
64
+ const indented = indentLines(body, 4);
65
+ const setupLine = hasUserEvents ? ` const user = userEvent.setup()\n` : '';
66
+ return [
67
+ `describe('${escapeSingleQuote(name)}', () => {`,
68
+ ` it('should complete the recorded flow', async () => {`,
69
+ `${setupLine}`,
70
+ indented,
71
+ ` })`,
72
+ `})`,
73
+ ].join('\n');
74
+ }
75
+ export function describeBlockMultiIt(name, itBlocks) {
76
+ const escapedName = escapeSingleQuote(name);
77
+ const blocks = itBlocks.map((block) => {
78
+ const setup = block.hasUserEvents
79
+ ? ` const user = userEvent.setup()\n`
80
+ : '';
81
+ const indented = indentLines(block.stepLines.join('\n'), 4);
82
+ return [
83
+ ` it('${escapeSingleQuote(block.name)}', async () => {`,
84
+ ` render(<App />)`,
85
+ setup,
86
+ indented,
87
+ ` })`,
88
+ ].join('\n');
89
+ });
90
+ return [`describe('${escapedName}', () => {`, ...blocks, `})`].join('\n');
91
+ }
92
+ //# sourceMappingURL=test-template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-template.js","sourceRoot":"","sources":["../../src/templates/test-template.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * TypeScript types for project conventions detection (Phase 3).
3
+ */
4
+ export type ImportStyle = 'esm' | 'cjs';
5
+ export type MockPattern = 'vi.mock' | 'jest.mock' | 'none';
6
+ export type MockRecommendationKind = 'inline' | 'extract';
7
+ export type MutationLifecycleStage = 'loading' | 'success' | 'error';
8
+ export type MockInstabilityKind = 'recreated-factory' | 'per-test-churn';
9
+ export interface ConventionFile {
10
+ path: string;
11
+ importStyle: ImportStyle;
12
+ hasDescribeBlock: boolean;
13
+ mockPattern: MockPattern;
14
+ hasHelperWithExpect: boolean;
15
+ }
16
+ export interface ConventionsSchema {
17
+ scannedAt: string;
18
+ projectRoot: string;
19
+ importStyle: ImportStyle;
20
+ mockPattern: MockPattern;
21
+ testFiles: ConventionFile[];
22
+ folderPattern: 'colocated' | '__tests__' | 'mixed' | 'unknown';
23
+ fileExtension: 'ts' | 'tsx' | 'js' | 'jsx' | 'mixed';
24
+ }
25
+ export interface MockTargetUsage {
26
+ target: string;
27
+ files: string[];
28
+ count: number;
29
+ }
30
+ export interface MockRecommendation {
31
+ target: string;
32
+ kind: MockRecommendationKind;
33
+ reason: string;
34
+ files: string[];
35
+ count: number;
36
+ }
37
+ export interface MutationLifecyclePattern {
38
+ file: string;
39
+ stages: MutationLifecycleStage[];
40
+ evidence: string[];
41
+ }
42
+ export interface MockInstabilityWarning {
43
+ file: string;
44
+ kind: MockInstabilityKind;
45
+ reason: string;
46
+ evidence: string[];
47
+ }
48
+ export declare const DEFAULT_CONVENTIONS: ConventionsSchema;
49
+ //# sourceMappingURL=conventions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conventions.d.ts","sourceRoot":"","sources":["../../src/types/conventions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,KAAK,CAAA;AACvC,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,MAAM,CAAA;AAC1D,MAAM,MAAM,sBAAsB,GAAG,QAAQ,GAAG,SAAS,CAAA;AACzD,MAAM,MAAM,sBAAsB,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAA;AACpE,MAAM,MAAM,mBAAmB,GAAG,mBAAmB,GAAG,gBAAgB,CAAA;AAExE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,WAAW,CAAA;IACxB,gBAAgB,EAAE,OAAO,CAAA;IACzB,WAAW,EAAE,WAAW,CAAA;IACxB,mBAAmB,EAAE,OAAO,CAAA;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,WAAW,CAAA;IACxB,WAAW,EAAE,WAAW,CAAA;IACxB,SAAS,EAAE,cAAc,EAAE,CAAA;IAC3B,aAAa,EAAE,WAAW,GAAG,WAAW,GAAG,OAAO,GAAG,SAAS,CAAA;IAC9D,aAAa,EAAE,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,OAAO,CAAA;CACrD;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,sBAAsB,CAAA;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,sBAAsB,EAAE,CAAA;IAChC,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,mBAAmB,CAAA;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED,eAAO,MAAM,mBAAmB,EAAE,iBAQjC,CAAA"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * TypeScript types for project conventions detection (Phase 3).
3
+ */
4
+ export const DEFAULT_CONVENTIONS = {
5
+ scannedAt: '',
6
+ projectRoot: '',
7
+ importStyle: 'esm',
8
+ mockPattern: 'none',
9
+ testFiles: [],
10
+ folderPattern: 'unknown',
11
+ fileExtension: 'ts',
12
+ };
13
+ //# sourceMappingURL=conventions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conventions.js","sourceRoot":"","sources":["../../src/types/conventions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAqDH,MAAM,CAAC,MAAM,mBAAmB,GAAsB;IACpD,SAAS,EAAE,EAAE;IACb,WAAW,EAAE,EAAE;IACf,WAAW,EAAE,KAAK;IAClB,WAAW,EAAE,MAAM;IACnB,SAAS,EAAE,EAAE;IACb,aAAa,EAAE,SAAS;IACxB,aAAa,EAAE,IAAI;CACpB,CAAA"}