@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.
- package/README.md +250 -0
- package/dist/analyzer/mocks/detector.d.ts +59 -0
- package/dist/analyzer/mocks/detector.d.ts.map +1 -0
- package/dist/analyzer/mocks/detector.js +264 -0
- package/dist/analyzer/mocks/detector.js.map +1 -0
- package/dist/analyzer/mocks/target-analyzer.d.ts +92 -0
- package/dist/analyzer/mocks/target-analyzer.d.ts.map +1 -0
- package/dist/analyzer/mocks/target-analyzer.js +305 -0
- package/dist/analyzer/mocks/target-analyzer.js.map +1 -0
- package/dist/analyzer/visual/element-analyzer.d.ts +44 -0
- package/dist/analyzer/visual/element-analyzer.d.ts.map +1 -0
- package/dist/analyzer/visual/element-analyzer.js +176 -0
- package/dist/analyzer/visual/element-analyzer.js.map +1 -0
- package/dist/analyzer/visual/inspector.d.ts +49 -0
- package/dist/analyzer/visual/inspector.d.ts.map +1 -0
- package/dist/analyzer/visual/inspector.js +109 -0
- package/dist/analyzer/visual/inspector.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +13 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +417 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/core/generator.d.ts +32 -0
- package/dist/core/generator.d.ts.map +1 -0
- package/dist/core/generator.js +173 -0
- package/dist/core/generator.js.map +1 -0
- package/dist/core/js-parser.d.ts +48 -0
- package/dist/core/js-parser.d.ts.map +1 -0
- package/dist/core/js-parser.js +244 -0
- package/dist/core/js-parser.js.map +1 -0
- package/dist/core/mock-intelligence.d.ts +14 -0
- package/dist/core/mock-intelligence.d.ts.map +1 -0
- package/dist/core/mock-intelligence.js +140 -0
- package/dist/core/mock-intelligence.js.map +1 -0
- package/dist/core/orchestrator.d.ts +49 -0
- package/dist/core/orchestrator.d.ts.map +1 -0
- package/dist/core/orchestrator.js +315 -0
- package/dist/core/orchestrator.js.map +1 -0
- package/dist/core/parser.d.ts +9 -0
- package/dist/core/parser.d.ts.map +1 -0
- package/dist/core/parser.js +120 -0
- package/dist/core/parser.js.map +1 -0
- package/dist/core/recording-intelligence.d.ts +15 -0
- package/dist/core/recording-intelligence.d.ts.map +1 -0
- package/dist/core/recording-intelligence.js +178 -0
- package/dist/core/recording-intelligence.js.map +1 -0
- package/dist/core/resolver.d.ts +58 -0
- package/dist/core/resolver.d.ts.map +1 -0
- package/dist/core/resolver.js +291 -0
- package/dist/core/resolver.js.map +1 -0
- package/dist/core/scanner.d.ts +51 -0
- package/dist/core/scanner.d.ts.map +1 -0
- package/dist/core/scanner.js +310 -0
- package/dist/core/scanner.js.map +1 -0
- package/dist/core/scorer.d.ts +8 -0
- package/dist/core/scorer.d.ts.map +1 -0
- package/dist/core/scorer.js +76 -0
- package/dist/core/scorer.js.map +1 -0
- package/dist/core/validator.d.ts +134 -0
- package/dist/core/validator.d.ts.map +1 -0
- package/dist/core/validator.js +44 -0
- package/dist/core/validator.js.map +1 -0
- package/dist/core/verifier.d.ts +10 -0
- package/dist/core/verifier.d.ts.map +1 -0
- package/dist/core/verifier.js +30 -0
- package/dist/core/verifier.js.map +1 -0
- package/dist/core/writer.d.ts +15 -0
- package/dist/core/writer.d.ts.map +1 -0
- package/dist/core/writer.js +43 -0
- package/dist/core/writer.js.map +1 -0
- package/dist/generator/mocks/builder.d.ts +47 -0
- package/dist/generator/mocks/builder.d.ts.map +1 -0
- package/dist/generator/mocks/builder.js +335 -0
- package/dist/generator/mocks/builder.js.map +1 -0
- package/dist/generator/transforms/dialog-transform.d.ts +35 -0
- package/dist/generator/transforms/dialog-transform.d.ts.map +1 -0
- package/dist/generator/transforms/dialog-transform.js +293 -0
- package/dist/generator/transforms/dialog-transform.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/learner/analyzer.d.ts +13 -0
- package/dist/learner/analyzer.d.ts.map +1 -0
- package/dist/learner/analyzer.js +484 -0
- package/dist/learner/analyzer.js.map +1 -0
- package/dist/learner/index.d.ts +66 -0
- package/dist/learner/index.d.ts.map +1 -0
- package/dist/learner/index.js +247 -0
- package/dist/learner/index.js.map +1 -0
- package/dist/learner/storage.d.ts +68 -0
- package/dist/learner/storage.d.ts.map +1 -0
- package/dist/learner/storage.js +201 -0
- package/dist/learner/storage.js.map +1 -0
- package/dist/learner/types.d.ts +41 -0
- package/dist/learner/types.d.ts.map +1 -0
- package/dist/learner/types.js +31 -0
- package/dist/learner/types.js.map +1 -0
- package/dist/parser/recorder-parser.d.ts +40 -0
- package/dist/parser/recorder-parser.d.ts.map +1 -0
- package/dist/parser/recorder-parser.js +139 -0
- package/dist/parser/recorder-parser.js.map +1 -0
- package/dist/parser/steps/deduplicator.d.ts +19 -0
- package/dist/parser/steps/deduplicator.d.ts.map +1 -0
- package/dist/parser/steps/deduplicator.js +75 -0
- package/dist/parser/steps/deduplicator.js.map +1 -0
- package/dist/parser/steps/dialog-detector.d.ts +38 -0
- package/dist/parser/steps/dialog-detector.d.ts.map +1 -0
- package/dist/parser/steps/dialog-detector.js +290 -0
- package/dist/parser/steps/dialog-detector.js.map +1 -0
- package/dist/parser/steps/noise-filter.d.ts +21 -0
- package/dist/parser/steps/noise-filter.d.ts.map +1 -0
- package/dist/parser/steps/noise-filter.js +138 -0
- package/dist/parser/steps/noise-filter.js.map +1 -0
- package/dist/scorer/index.d.ts +43 -0
- package/dist/scorer/index.d.ts.map +1 -0
- package/dist/scorer/index.js +82 -0
- package/dist/scorer/index.js.map +1 -0
- package/dist/scorer/post-verify.d.ts +17 -0
- package/dist/scorer/post-verify.d.ts.map +1 -0
- package/dist/scorer/post-verify.js +163 -0
- package/dist/scorer/post-verify.js.map +1 -0
- package/dist/scorer/pre-audit.d.ts +32 -0
- package/dist/scorer/pre-audit.d.ts.map +1 -0
- package/dist/scorer/pre-audit.js +99 -0
- package/dist/scorer/pre-audit.js.map +1 -0
- package/dist/scorer/quality-gates.d.ts +17 -0
- package/dist/scorer/quality-gates.d.ts.map +1 -0
- package/dist/scorer/quality-gates.js +304 -0
- package/dist/scorer/quality-gates.js.map +1 -0
- package/dist/scorer/types.d.ts +27 -0
- package/dist/scorer/types.d.ts.map +1 -0
- package/dist/scorer/types.js +5 -0
- package/dist/scorer/types.js.map +1 -0
- package/dist/templates/test-template.d.ts +21 -0
- package/dist/templates/test-template.d.ts.map +1 -0
- package/dist/templates/test-template.js +92 -0
- package/dist/templates/test-template.js.map +1 -0
- package/dist/types/conventions.d.ts +49 -0
- package/dist/types/conventions.d.ts.map +1 -0
- package/dist/types/conventions.js +13 -0
- package/dist/types/conventions.js.map +1 -0
- package/dist/types/recording.d.ts +143 -0
- package/dist/types/recording.d.ts.map +1 -0
- package/dist/types/recording.js +5 -0
- package/dist/types/recording.js.map +1 -0
- package/dist/types/score.d.ts +18 -0
- package/dist/types/score.d.ts.map +1 -0
- package/dist/types/score.js +2 -0
- package/dist/types/score.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
function hasPointerMetadata(step) {
|
|
2
|
+
return [step.x, step.y, step.offsetX, step.offsetY].some((value) => typeof value === 'number');
|
|
3
|
+
}
|
|
4
|
+
function isDoubleClickVariant(step) {
|
|
5
|
+
return /doubleclick|dblclick|tripleclick/i.test(step.originalType);
|
|
6
|
+
}
|
|
7
|
+
function isMovementType(step) {
|
|
8
|
+
return /hover|mousemove|pointermove|movemouse/i.test(step.originalType);
|
|
9
|
+
}
|
|
10
|
+
function isCursorWanderStep(step) {
|
|
11
|
+
if (isMovementType(step)) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
if (step.action === 'unknown' && (hasPointerMetadata(step) || !step.target)) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
return step.action === 'scroll' && !step.target && !step.value;
|
|
18
|
+
}
|
|
19
|
+
function normalizedTarget(target) {
|
|
20
|
+
const trimmed = target?.trim();
|
|
21
|
+
return trimmed ? trimmed : undefined;
|
|
22
|
+
}
|
|
23
|
+
function isSameClickTarget(current, candidate) {
|
|
24
|
+
return (current.action === 'click' &&
|
|
25
|
+
candidate.action === 'click' &&
|
|
26
|
+
normalizedTarget(current.target) !== undefined &&
|
|
27
|
+
normalizedTarget(current.target) === normalizedTarget(candidate.target));
|
|
28
|
+
}
|
|
29
|
+
function pickRepresentativeClick(cluster) {
|
|
30
|
+
return cluster.find((step) => !isDoubleClickVariant(step)) ?? cluster[0];
|
|
31
|
+
}
|
|
32
|
+
function deriveIntentLabel(steps) {
|
|
33
|
+
const navigateStep = steps.find((step) => step.action === 'navigate');
|
|
34
|
+
if (navigateStep) {
|
|
35
|
+
return navigateStep.target ? `navigate to ${navigateStep.target}` : 'navigation flow';
|
|
36
|
+
}
|
|
37
|
+
const submitStep = steps.find((step) => step.action === 'click' &&
|
|
38
|
+
/save|submit|confirm|continue|done|create|update/i.test(step.target ?? ''));
|
|
39
|
+
if (submitStep?.target) {
|
|
40
|
+
return `submit ${submitStep.target}`;
|
|
41
|
+
}
|
|
42
|
+
const fillStep = steps.find((step) => step.action === 'fill' || step.action === 'select');
|
|
43
|
+
if (fillStep?.target) {
|
|
44
|
+
return `edit ${fillStep.target}`;
|
|
45
|
+
}
|
|
46
|
+
const clickStep = steps.find((step) => step.action === 'click');
|
|
47
|
+
if (clickStep?.target && steps.some((step) => step.action === 'assert')) {
|
|
48
|
+
return `confirm ${clickStep.target}`;
|
|
49
|
+
}
|
|
50
|
+
if (clickStep?.target) {
|
|
51
|
+
return `interact with ${clickStep.target}`;
|
|
52
|
+
}
|
|
53
|
+
return 'recorded flow';
|
|
54
|
+
}
|
|
55
|
+
function isDialogLikeText(value) {
|
|
56
|
+
return /dialog|modal|drawer|sheet|popover/i.test(value ?? '');
|
|
57
|
+
}
|
|
58
|
+
function findGroupSelector(group) {
|
|
59
|
+
return group.steps.find((step) => step.action !== 'navigate' && step.target)?.target;
|
|
60
|
+
}
|
|
61
|
+
export function inferIntentGroups(steps) {
|
|
62
|
+
if (steps.length === 0) {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
const groups = [];
|
|
66
|
+
let currentGroup = [];
|
|
67
|
+
const flushGroup = () => {
|
|
68
|
+
if (currentGroup.length === 0) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
groups.push({
|
|
72
|
+
name: deriveIntentLabel(currentGroup),
|
|
73
|
+
steps: [...currentGroup],
|
|
74
|
+
});
|
|
75
|
+
currentGroup = [];
|
|
76
|
+
};
|
|
77
|
+
for (const step of steps) {
|
|
78
|
+
if (step.action === 'navigate') {
|
|
79
|
+
flushGroup();
|
|
80
|
+
currentGroup = [step];
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (currentGroup.length === 1 && currentGroup[0]?.action === 'navigate') {
|
|
84
|
+
flushGroup();
|
|
85
|
+
}
|
|
86
|
+
currentGroup.push(step);
|
|
87
|
+
if (step.action === 'assert') {
|
|
88
|
+
flushGroup();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
flushGroup();
|
|
92
|
+
return groups;
|
|
93
|
+
}
|
|
94
|
+
export function findVisualCaptureCandidates(analyzedRecording) {
|
|
95
|
+
return analyzedRecording.intentGroups.flatMap((group) => {
|
|
96
|
+
const joinedTargets = group.steps
|
|
97
|
+
.map((step) => step.target ?? '')
|
|
98
|
+
.join(' ');
|
|
99
|
+
const hasDialogState = isDialogLikeText(group.name) ||
|
|
100
|
+
isDialogLikeText(joinedTargets) ||
|
|
101
|
+
group.steps.some((step) => step.action === 'assert' &&
|
|
102
|
+
/open|confirm|add|dialog|modal/i.test(step.target ?? ''));
|
|
103
|
+
if (!hasDialogState) {
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
return [
|
|
107
|
+
{
|
|
108
|
+
groupName: group.name,
|
|
109
|
+
reason: 'dialog-state',
|
|
110
|
+
selector: findGroupSelector(group),
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
export function filterNoiseSteps(steps) {
|
|
116
|
+
let removedRedundantClicks = 0;
|
|
117
|
+
let removedDoubleClickNoise = 0;
|
|
118
|
+
let removedCursorWander = 0;
|
|
119
|
+
const filtered = [];
|
|
120
|
+
for (let index = 0; index < steps.length; index += 1) {
|
|
121
|
+
const step = steps[index];
|
|
122
|
+
if (isCursorWanderStep(step)) {
|
|
123
|
+
removedCursorWander += 1;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (step.action !== 'click' || !normalizedTarget(step.target)) {
|
|
127
|
+
filtered.push(step);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const cluster = [step];
|
|
131
|
+
for (let nextIndex = index + 1; nextIndex < steps.length; nextIndex += 1) {
|
|
132
|
+
const candidate = steps[nextIndex];
|
|
133
|
+
if (isCursorWanderStep(candidate)) {
|
|
134
|
+
removedCursorWander += 1;
|
|
135
|
+
index = nextIndex;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (!isSameClickTarget(step, candidate)) {
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
cluster.push(candidate);
|
|
142
|
+
index = nextIndex;
|
|
143
|
+
}
|
|
144
|
+
const extraClicks = cluster.length - 1;
|
|
145
|
+
if (extraClicks > 0) {
|
|
146
|
+
const removedDoubleClicks = cluster
|
|
147
|
+
.slice(1)
|
|
148
|
+
.filter((candidate) => isDoubleClickVariant(candidate)).length;
|
|
149
|
+
removedDoubleClickNoise += removedDoubleClicks;
|
|
150
|
+
removedRedundantClicks += extraClicks - removedDoubleClicks;
|
|
151
|
+
}
|
|
152
|
+
filtered.push(pickRepresentativeClick(cluster));
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
steps: filtered,
|
|
156
|
+
diagnostics: {
|
|
157
|
+
removedCursorWander,
|
|
158
|
+
removedDoubleClickNoise,
|
|
159
|
+
removedRedundantClicks,
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
export function analyzeRecording(recording) {
|
|
164
|
+
const filtered = filterNoiseSteps(recording.steps);
|
|
165
|
+
const intentGroups = inferIntentGroups(filtered.steps);
|
|
166
|
+
return {
|
|
167
|
+
...recording,
|
|
168
|
+
steps: filtered.steps,
|
|
169
|
+
diagnostics: {
|
|
170
|
+
...filtered.diagnostics,
|
|
171
|
+
rawStepCount: recording.rawStepCount,
|
|
172
|
+
filteredStepCount: filtered.steps.length,
|
|
173
|
+
intentGroupCount: intentGroups.length,
|
|
174
|
+
},
|
|
175
|
+
intentGroups,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=recording-intelligence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recording-intelligence.js","sourceRoot":"","sources":["../../src/core/recording-intelligence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Page } from 'playwright';
|
|
2
|
+
import type { DialogState, ElementInfo, QueryResult, VisualState } from '../types/recording.js';
|
|
3
|
+
export declare function extractDialogState(page: Page): Promise<DialogState | null>;
|
|
4
|
+
export interface CaptureVisualStateOptions {
|
|
5
|
+
reason: string;
|
|
6
|
+
screenshotDir?: string;
|
|
7
|
+
selector?: string;
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Captures a structured visual-state artifact for a page and optional selector.
|
|
12
|
+
*/
|
|
13
|
+
export declare function captureVisualState(url: string, options: CaptureVisualStateOptions): Promise<VisualState | null>;
|
|
14
|
+
/**
|
|
15
|
+
* Builds the highest-priority RTL query for an element based on its accessibility properties.
|
|
16
|
+
* Priority: getByRole > getByLabelText > getByText > getByPlaceholderText > getByTestId
|
|
17
|
+
*
|
|
18
|
+
* @param info - Element information from DOM inspection
|
|
19
|
+
* @param selector - Original CSS selector
|
|
20
|
+
* @returns QueryResult with query string, quality rating, and method name
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildQuery(info: ElementInfo, selector: string): QueryResult;
|
|
23
|
+
/**
|
|
24
|
+
* Selects the most appropriate RTL matcher based on element type and action.
|
|
25
|
+
*
|
|
26
|
+
* @param info - Element information from DOM inspection
|
|
27
|
+
* @param action - The action being performed (fill, assert, etc.)
|
|
28
|
+
* @returns Matcher string (e.g., '.toHaveValue()', '.toBeChecked()')
|
|
29
|
+
*/
|
|
30
|
+
export declare function selectMatcher(info: ElementInfo, action: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Inspects a single element on a page using Playwright.
|
|
33
|
+
* Launches headless Chromium, navigates to URL, evaluates element.
|
|
34
|
+
*
|
|
35
|
+
* @param url - URL to navigate to
|
|
36
|
+
* @param cssSelector - CSS selector to locate element
|
|
37
|
+
* @param timeoutMs - Timeout for navigation (default 5000ms)
|
|
38
|
+
* @returns ElementInfo or null if element not found/error occurs
|
|
39
|
+
*/
|
|
40
|
+
export declare function inspectElement(url: string, cssSelector: string, timeoutMs?: number): Promise<ElementInfo | null>;
|
|
41
|
+
/**
|
|
42
|
+
* Inspects multiple elements on a page using a single Playwright browser instance.
|
|
43
|
+
* More efficient than calling inspectElement multiple times.
|
|
44
|
+
*
|
|
45
|
+
* @param url - URL to navigate to
|
|
46
|
+
* @param selectors - Array of CSS selectors to locate elements
|
|
47
|
+
* @param timeoutMs - Timeout for navigation (default 5000ms)
|
|
48
|
+
* @returns Map of selector to ElementInfo (or null if not found)
|
|
49
|
+
*/
|
|
50
|
+
export declare function inspectElements(url: string, selectors: string[], timeoutMs?: number): Promise<Map<string, ElementInfo | null>>;
|
|
51
|
+
/**
|
|
52
|
+
* Emits a warning for fragile queries (getByTestId fallback).
|
|
53
|
+
* Should be called when buildQuery returns method: 'getByTestId'.
|
|
54
|
+
*
|
|
55
|
+
* @param selector - The CSS selector that required fallback to testId
|
|
56
|
+
*/
|
|
57
|
+
export declare function emitQry03Warning(selector: string): void;
|
|
58
|
+
//# sourceMappingURL=resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/core/resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,IAAI,EAAE,MAAM,YAAY,CAAA;AAEpD,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,WAAW,EAEX,WAAW,EACZ,MAAM,uBAAuB,CAAA;AA4D9B,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CA8BhF;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CA6C7B;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,WAAW,CA+C3E;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAuBvE;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,SAAS,SAAO,GACf,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAyB7B;AAED;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EAAE,EACnB,SAAS,SAAO,GACf,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC,CAAC,CAsC1C;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAMvD"}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import { chromium } from 'playwright';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
/**
|
|
4
|
+
* Maps HTML tag names to implied ARIA roles.
|
|
5
|
+
* Used by buildQuery to determine accessible query method.
|
|
6
|
+
*/
|
|
7
|
+
const ROLE_MAP = {
|
|
8
|
+
button: 'button',
|
|
9
|
+
a: 'link',
|
|
10
|
+
input: 'textbox',
|
|
11
|
+
select: 'combobox',
|
|
12
|
+
textarea: 'textbox',
|
|
13
|
+
h1: 'heading',
|
|
14
|
+
h2: 'heading',
|
|
15
|
+
h3: 'heading',
|
|
16
|
+
h4: 'heading',
|
|
17
|
+
h5: 'heading',
|
|
18
|
+
h6: 'heading',
|
|
19
|
+
img: 'img',
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Escapes single quotes in strings for use in generated query code.
|
|
23
|
+
*/
|
|
24
|
+
function escapeSingleQuote(str) {
|
|
25
|
+
return str.replace(/'/g, "\\'");
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Sanitizes a CSS selector to be used as a testId.
|
|
29
|
+
* Replaces non-alphanumeric characters with hyphens and trims leading/trailing hyphens.
|
|
30
|
+
*/
|
|
31
|
+
function sanitizeSelectorForTestId(selector) {
|
|
32
|
+
return selector.replace(/[^a-zA-Z0-9-]/g, '-').replace(/^-+|-+$/g, '');
|
|
33
|
+
}
|
|
34
|
+
async function readElementInfo(page, selector) {
|
|
35
|
+
const locator = page.locator(selector).first();
|
|
36
|
+
const elementInfo = await locator.evaluate((el) => {
|
|
37
|
+
const htmlEl = el;
|
|
38
|
+
return {
|
|
39
|
+
tagName: el.tagName.toLowerCase(),
|
|
40
|
+
role: el.getAttribute('role') ?? null,
|
|
41
|
+
ariaLabel: el.getAttribute('aria-label') ?? null,
|
|
42
|
+
ariaLabelledBy: el.getAttribute('aria-labelledby') ?? null,
|
|
43
|
+
innerText: htmlEl.innerText ?? '',
|
|
44
|
+
value: htmlEl.value ?? undefined,
|
|
45
|
+
type: htmlEl.type ?? undefined,
|
|
46
|
+
placeholder: htmlEl.placeholder ?? null,
|
|
47
|
+
isPresent: true,
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
return elementInfo;
|
|
51
|
+
}
|
|
52
|
+
function sanitizeCaptureSegment(value) {
|
|
53
|
+
return value.replace(/[^a-zA-Z0-9-_]+/g, '-').replace(/^-+|-+$/g, '') || 'capture';
|
|
54
|
+
}
|
|
55
|
+
export async function extractDialogState(page) {
|
|
56
|
+
try {
|
|
57
|
+
const state = await page.evaluate(() => {
|
|
58
|
+
const dialog = document.querySelector('[role="dialog"], [role="alertdialog"]');
|
|
59
|
+
if (!dialog) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
const titleNode = dialog.querySelector('h1, h2, h3, [aria-labelledby]');
|
|
63
|
+
const descriptionNode = dialog.querySelector('[aria-describedby], p');
|
|
64
|
+
const actionNodes = Array.from(dialog.querySelectorAll('button, [role="button"]'));
|
|
65
|
+
return {
|
|
66
|
+
role: dialog.getAttribute('role') ?? null,
|
|
67
|
+
title: titleNode?.textContent?.trim() ?? null,
|
|
68
|
+
description: descriptionNode?.textContent?.trim() ?? null,
|
|
69
|
+
actions: actionNodes
|
|
70
|
+
.map((node) => node.innerText?.trim())
|
|
71
|
+
.filter((text) => Boolean(text)),
|
|
72
|
+
isOpen: true,
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
return state;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Captures a structured visual-state artifact for a page and optional selector.
|
|
83
|
+
*/
|
|
84
|
+
export async function captureVisualState(url, options) {
|
|
85
|
+
const { reason, screenshotDir, selector, timeoutMs = 5000 } = options;
|
|
86
|
+
let browser = null;
|
|
87
|
+
try {
|
|
88
|
+
browser = await chromium.launch({ headless: true });
|
|
89
|
+
const page = await browser.newPage();
|
|
90
|
+
await page.goto(url, {
|
|
91
|
+
timeout: timeoutMs,
|
|
92
|
+
waitUntil: 'domcontentloaded',
|
|
93
|
+
});
|
|
94
|
+
const pageTitle = await page.title();
|
|
95
|
+
const dialog = await extractDialogState(page);
|
|
96
|
+
const element = selector ? await readElementInfo(page, selector) : null;
|
|
97
|
+
let screenshotPath;
|
|
98
|
+
if (screenshotDir) {
|
|
99
|
+
screenshotPath = `${screenshotDir}/${sanitizeCaptureSegment(pageTitle || reason)}.png`;
|
|
100
|
+
await page.screenshot({ path: screenshotPath, fullPage: true });
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
capturedAt: new Date().toISOString(),
|
|
104
|
+
dialog,
|
|
105
|
+
element,
|
|
106
|
+
pageTitle,
|
|
107
|
+
reason,
|
|
108
|
+
screenshotPath,
|
|
109
|
+
selector,
|
|
110
|
+
url,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
console.warn(pc.yellow('[taro]') +
|
|
115
|
+
pc.dim(' VIS-01:') +
|
|
116
|
+
` Failed to capture visual state for ${url}: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
if (browser) {
|
|
121
|
+
await browser.close();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Builds the highest-priority RTL query for an element based on its accessibility properties.
|
|
127
|
+
* Priority: getByRole > getByLabelText > getByText > getByPlaceholderText > getByTestId
|
|
128
|
+
*
|
|
129
|
+
* @param info - Element information from DOM inspection
|
|
130
|
+
* @param selector - Original CSS selector
|
|
131
|
+
* @returns QueryResult with query string, quality rating, and method name
|
|
132
|
+
*/
|
|
133
|
+
export function buildQuery(info, selector) {
|
|
134
|
+
const impliedRole = info.role ?? ROLE_MAP[info.tagName];
|
|
135
|
+
const accessibleName = info.ariaLabel ?? info.innerText;
|
|
136
|
+
// Priority 1: getByRole when both role and accessible name exist
|
|
137
|
+
if (impliedRole && accessibleName) {
|
|
138
|
+
return {
|
|
139
|
+
method: 'getByRole',
|
|
140
|
+
quality: 'excellent',
|
|
141
|
+
query: `screen.getByRole('${impliedRole}', { name: '${escapeSingleQuote(accessibleName)}' })`,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
// Priority 2: getByLabelText when ariaLabel exists (no role match)
|
|
145
|
+
if (info.ariaLabel) {
|
|
146
|
+
return {
|
|
147
|
+
method: 'getByLabelText',
|
|
148
|
+
quality: 'excellent',
|
|
149
|
+
query: `screen.getByLabelText('${escapeSingleQuote(info.ariaLabel)}')`,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
// Priority 3: getByText when innerText exists
|
|
153
|
+
if (info.innerText) {
|
|
154
|
+
return {
|
|
155
|
+
method: 'getByText',
|
|
156
|
+
quality: 'good',
|
|
157
|
+
query: `screen.getByText('${escapeSingleQuote(info.innerText)}')`,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
// Priority 4: getByPlaceholderText when placeholder exists
|
|
161
|
+
if (info.placeholder) {
|
|
162
|
+
return {
|
|
163
|
+
method: 'getByPlaceholderText',
|
|
164
|
+
quality: 'acceptable',
|
|
165
|
+
query: `screen.getByPlaceholderText('${escapeSingleQuote(info.placeholder)}')`,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
// Priority 5: Fallback to getByTestId (fragile)
|
|
169
|
+
const sanitized = sanitizeSelectorForTestId(selector);
|
|
170
|
+
return {
|
|
171
|
+
method: 'getByTestId',
|
|
172
|
+
quality: 'fragile',
|
|
173
|
+
query: `screen.getByTestId('${sanitized}')`,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Selects the most appropriate RTL matcher based on element type and action.
|
|
178
|
+
*
|
|
179
|
+
* @param info - Element information from DOM inspection
|
|
180
|
+
* @param action - The action being performed (fill, assert, etc.)
|
|
181
|
+
* @returns Matcher string (e.g., '.toHaveValue()', '.toBeChecked()')
|
|
182
|
+
*/
|
|
183
|
+
export function selectMatcher(info, action) {
|
|
184
|
+
// checkbox → toBeChecked
|
|
185
|
+
if (info.type === 'checkbox') {
|
|
186
|
+
return '.toBeChecked()';
|
|
187
|
+
}
|
|
188
|
+
// fill with value → toHaveValue
|
|
189
|
+
if (info.value !== undefined && action === 'fill') {
|
|
190
|
+
return `.toHaveValue('${escapeSingleQuote(info.value)}')`;
|
|
191
|
+
}
|
|
192
|
+
// assert with innerText → toHaveTextContent
|
|
193
|
+
if (action === 'assert' && info.innerText) {
|
|
194
|
+
return `.toHaveTextContent('${escapeSingleQuote(info.innerText)}')`;
|
|
195
|
+
}
|
|
196
|
+
// dialog → toBeVisible
|
|
197
|
+
if (action === 'assert' && info.role === 'dialog') {
|
|
198
|
+
return '.toBeVisible()';
|
|
199
|
+
}
|
|
200
|
+
// Default → toBeInTheDocument
|
|
201
|
+
return '.toBeInTheDocument()';
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Inspects a single element on a page using Playwright.
|
|
205
|
+
* Launches headless Chromium, navigates to URL, evaluates element.
|
|
206
|
+
*
|
|
207
|
+
* @param url - URL to navigate to
|
|
208
|
+
* @param cssSelector - CSS selector to locate element
|
|
209
|
+
* @param timeoutMs - Timeout for navigation (default 5000ms)
|
|
210
|
+
* @returns ElementInfo or null if element not found/error occurs
|
|
211
|
+
*/
|
|
212
|
+
export async function inspectElement(url, cssSelector, timeoutMs = 5000) {
|
|
213
|
+
let browser = null;
|
|
214
|
+
try {
|
|
215
|
+
browser = await chromium.launch({ headless: true });
|
|
216
|
+
const page = await browser.newPage();
|
|
217
|
+
await page.goto(url, {
|
|
218
|
+
timeout: timeoutMs,
|
|
219
|
+
waitUntil: 'domcontentloaded',
|
|
220
|
+
});
|
|
221
|
+
return await readElementInfo(page, cssSelector);
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
console.warn(pc.yellow('[taro]') +
|
|
225
|
+
pc.dim(' QRY-02:') +
|
|
226
|
+
` Failed to inspect element ${cssSelector} on ${url}: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
finally {
|
|
230
|
+
if (browser) {
|
|
231
|
+
await browser.close();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Inspects multiple elements on a page using a single Playwright browser instance.
|
|
237
|
+
* More efficient than calling inspectElement multiple times.
|
|
238
|
+
*
|
|
239
|
+
* @param url - URL to navigate to
|
|
240
|
+
* @param selectors - Array of CSS selectors to locate elements
|
|
241
|
+
* @param timeoutMs - Timeout for navigation (default 5000ms)
|
|
242
|
+
* @returns Map of selector to ElementInfo (or null if not found)
|
|
243
|
+
*/
|
|
244
|
+
export async function inspectElements(url, selectors, timeoutMs = 5000) {
|
|
245
|
+
const result = new Map();
|
|
246
|
+
let browser = null;
|
|
247
|
+
try {
|
|
248
|
+
browser = await chromium.launch({ headless: true });
|
|
249
|
+
const page = await browser.newPage();
|
|
250
|
+
await page.goto(url, {
|
|
251
|
+
timeout: timeoutMs,
|
|
252
|
+
waitUntil: 'domcontentloaded',
|
|
253
|
+
});
|
|
254
|
+
for (const selector of selectors) {
|
|
255
|
+
try {
|
|
256
|
+
result.set(selector, await readElementInfo(page, selector));
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
// On individual selector failure, set to null and continue
|
|
260
|
+
result.set(selector, null);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
// On browser/page error, set all selectors to null
|
|
266
|
+
console.warn(pc.yellow('[taro]') +
|
|
267
|
+
pc.dim(' QRY-02:') +
|
|
268
|
+
` Failed to inspect elements on ${url}: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
269
|
+
for (const selector of selectors) {
|
|
270
|
+
result.set(selector, null);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
finally {
|
|
274
|
+
if (browser) {
|
|
275
|
+
await browser.close();
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return result;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Emits a warning for fragile queries (getByTestId fallback).
|
|
282
|
+
* Should be called when buildQuery returns method: 'getByTestId'.
|
|
283
|
+
*
|
|
284
|
+
* @param selector - The CSS selector that required fallback to testId
|
|
285
|
+
*/
|
|
286
|
+
export function emitQry03Warning(selector) {
|
|
287
|
+
console.warn(pc.yellow('[taro]') +
|
|
288
|
+
pc.dim(' QRY-03:') +
|
|
289
|
+
` No accessible query for ${pc.bold(selector)} — consider adding aria-label or data-testid to this element`);
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../src/core/resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codebase convention scanner
|
|
3
|
+
* Scans project for test file conventions and persists to .taro/conventions.json
|
|
4
|
+
*/
|
|
5
|
+
import type { ConventionsSchema, ConventionFile } from '../types/conventions.js';
|
|
6
|
+
/**
|
|
7
|
+
* Recursively find all test files in a directory
|
|
8
|
+
* @param root - Root directory to scan
|
|
9
|
+
* @returns Array of absolute paths to test files
|
|
10
|
+
*/
|
|
11
|
+
export declare function findTestFiles(root: string): Promise<string[]>;
|
|
12
|
+
export interface TestFileContent {
|
|
13
|
+
path: string;
|
|
14
|
+
content: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Load discovered test files with content for downstream analyzers.
|
|
18
|
+
*/
|
|
19
|
+
export declare function readTestFiles(root: string): Promise<TestFileContent[]>;
|
|
20
|
+
/**
|
|
21
|
+
* Derive conventions from analyzed files
|
|
22
|
+
* @param files - Array of analyzed ConventionFile objects
|
|
23
|
+
* @param projectRoot - Root directory of the project
|
|
24
|
+
* @returns ConventionsSchema with derived conventions
|
|
25
|
+
*/
|
|
26
|
+
export declare function deriveConventions(files: ConventionFile[], projectRoot: string): ConventionsSchema;
|
|
27
|
+
/**
|
|
28
|
+
* Read conventions from .taro/conventions.json
|
|
29
|
+
* @param projectRoot - Root directory of the project
|
|
30
|
+
* @returns ConventionsSchema or null if not found
|
|
31
|
+
*/
|
|
32
|
+
export declare function readConventions(projectRoot: string): Promise<ConventionsSchema | null>;
|
|
33
|
+
/**
|
|
34
|
+
* Scan project for test conventions
|
|
35
|
+
* @param projectRoot - Root directory of the project
|
|
36
|
+
* @returns ConventionsSchema with detected conventions
|
|
37
|
+
*/
|
|
38
|
+
export declare function scanConventions(projectRoot: string): Promise<ConventionsSchema>;
|
|
39
|
+
/**
|
|
40
|
+
* Persist conventions to .taro/conventions.json
|
|
41
|
+
*/
|
|
42
|
+
export declare function persistConventions(projectRoot: string, conventions: ConventionsSchema): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Merge new file conventions into the persisted conventions store.
|
|
45
|
+
*/
|
|
46
|
+
export declare function mergeConventions(projectRoot: string, newPatterns: ConventionFile): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Analyze a single test file without rescanning the whole project.
|
|
49
|
+
*/
|
|
50
|
+
export declare function analyzeSingleTestFile(projectRoot: string, filePath: string): Promise<ConventionFile>;
|
|
51
|
+
//# sourceMappingURL=scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/core/scanner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAA4B,MAAM,yBAAyB,CAAA;AAc1G;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA2BnE;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAc5E;AAoED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,cAAc,EAAE,EACvB,WAAW,EAAE,MAAM,GAClB,iBAAiB,CAuCnB;AAgED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAWnC;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC,CAgD5B;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,iBAAiB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAaf;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,cAAc,GAC1B,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,cAAc,CAAC,CAMzB"}
|