playwright-mimic 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +633 -446
- package/dist/agentic/agent.d.ts +106 -0
- package/dist/agentic/agent.d.ts.map +1 -0
- package/dist/agentic/agent.js +528 -0
- package/dist/agentic/agent.js.map +1 -0
- package/dist/agentic/index.d.ts +13 -0
- package/dist/agentic/index.d.ts.map +1 -0
- package/dist/agentic/index.js +12 -0
- package/dist/agentic/index.js.map +1 -0
- package/dist/agentic/planner.d.ts +41 -0
- package/dist/agentic/planner.d.ts.map +1 -0
- package/dist/agentic/planner.js +136 -0
- package/dist/agentic/planner.js.map +1 -0
- package/dist/agentic/react.d.ts +35 -0
- package/dist/agentic/react.d.ts.map +1 -0
- package/dist/agentic/react.js +170 -0
- package/dist/agentic/react.js.map +1 -0
- package/dist/agentic/recovery.d.ts +55 -0
- package/dist/agentic/recovery.d.ts.map +1 -0
- package/dist/agentic/recovery.js +200 -0
- package/dist/agentic/recovery.js.map +1 -0
- package/dist/agentic/reflection.d.ts +40 -0
- package/dist/agentic/reflection.d.ts.map +1 -0
- package/dist/agentic/reflection.js +142 -0
- package/dist/agentic/reflection.js.map +1 -0
- package/dist/agentic/types.d.ts +177 -0
- package/dist/agentic/types.d.ts.map +1 -0
- package/dist/agentic/types.js +8 -0
- package/dist/agentic/types.js.map +1 -0
- package/dist/agentic/wait.d.ts +50 -0
- package/dist/agentic/wait.d.ts.map +1 -0
- package/dist/agentic/wait.js +140 -0
- package/dist/agentic/wait.js.map +1 -0
- package/dist/agentic-mimic.d.ts +56 -0
- package/dist/agentic-mimic.d.ts.map +1 -0
- package/dist/agentic-mimic.js +98 -0
- package/dist/agentic-mimic.js.map +1 -0
- package/dist/index.d.ts +11 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -9
- package/dist/index.js.map +1 -1
- package/dist/mimic/actionType.d.ts +7 -0
- package/dist/mimic/actionType.d.ts.map +1 -0
- package/dist/mimic/actionType.js +44 -0
- package/dist/mimic/actionType.js.map +1 -0
- package/dist/mimic/annotations.d.ts +20 -0
- package/dist/mimic/annotations.d.ts.map +1 -0
- package/dist/mimic/annotations.js +30 -0
- package/dist/mimic/annotations.js.map +1 -0
- package/dist/mimic/cli.d.ts +15 -0
- package/dist/mimic/cli.d.ts.map +1 -0
- package/dist/mimic/cli.js +17 -0
- package/dist/mimic/cli.js.map +1 -0
- package/dist/mimic/click.d.ts +39 -0
- package/dist/mimic/click.d.ts.map +1 -0
- package/dist/mimic/click.js +233 -0
- package/dist/mimic/click.js.map +1 -0
- package/dist/mimic/forms.d.ts +47 -0
- package/dist/mimic/forms.d.ts.map +1 -0
- package/dist/mimic/forms.js +264 -0
- package/dist/mimic/forms.js.map +1 -0
- package/dist/mimic/navigation.d.ts +19 -0
- package/dist/mimic/navigation.d.ts.map +1 -0
- package/dist/mimic/navigation.js +117 -0
- package/dist/mimic/navigation.js.map +1 -0
- package/dist/mimic/replay.d.ts +21 -0
- package/dist/mimic/replay.d.ts.map +1 -0
- package/dist/mimic/replay.js +133 -0
- package/dist/mimic/replay.js.map +1 -0
- package/dist/mimic/schema/action.d.ts +315 -0
- package/dist/mimic/schema/action.d.ts.map +1 -0
- package/dist/mimic/schema/action.js +204 -0
- package/dist/mimic/schema/action.js.map +1 -0
- package/dist/mimic/selector.d.ts +139 -0
- package/dist/mimic/selector.d.ts.map +1 -0
- package/dist/mimic/selector.js +1103 -0
- package/dist/mimic/selector.js.map +1 -0
- package/dist/mimic/selectorDescriptor.d.ts +13 -0
- package/dist/mimic/selectorDescriptor.d.ts.map +1 -0
- package/dist/mimic/selectorDescriptor.js +9 -0
- package/dist/mimic/selectorDescriptor.js.map +1 -0
- package/dist/mimic/selectorSerialization.d.ts +30 -0
- package/dist/mimic/selectorSerialization.d.ts.map +1 -0
- package/dist/mimic/selectorSerialization.js +170 -0
- package/dist/mimic/selectorSerialization.js.map +1 -0
- package/dist/mimic/selectorTypes.d.ts +200 -0
- package/dist/mimic/selectorTypes.d.ts.map +1 -0
- package/dist/mimic/selectorTypes.js +2 -0
- package/dist/mimic/selectorTypes.js.map +1 -0
- package/dist/mimic/selectorUtils.d.ts +26 -0
- package/dist/mimic/selectorUtils.d.ts.map +1 -0
- package/dist/mimic/selectorUtils.js +144 -0
- package/dist/mimic/selectorUtils.js.map +1 -0
- package/dist/mimic/storage.d.ts +75 -0
- package/dist/mimic/storage.d.ts.map +1 -0
- package/dist/mimic/storage.js +197 -0
- package/dist/mimic/storage.js.map +1 -0
- package/dist/mimic/types.d.ts +63 -0
- package/dist/mimic/types.d.ts.map +1 -0
- package/dist/mimic/types.js +7 -0
- package/dist/mimic/types.js.map +1 -0
- package/dist/mimic.d.ts +28 -4
- package/dist/mimic.d.ts.map +1 -1
- package/dist/mimic.js +374 -32
- package/dist/mimic.js.map +1 -1
- package/dist/mimicry.d.ts +4 -4
- package/dist/mimicry.d.ts.map +1 -1
- package/dist/mimicry.js +22 -13
- package/dist/mimicry.js.map +1 -1
- package/package.json +5 -2
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reconstruct a Playwright Locator from a stored SelectorDescriptor
|
|
3
|
+
*
|
|
4
|
+
* This function recursively builds a locator from a selector descriptor,
|
|
5
|
+
* handling nested selectors by chaining locator method calls.
|
|
6
|
+
*
|
|
7
|
+
* @param page - Playwright Page object (or parent Locator for nested selectors)
|
|
8
|
+
* @param descriptor - SelectorDescriptor (can be from JSON)
|
|
9
|
+
* @returns Playwright Locator reconstructed from the descriptor
|
|
10
|
+
*/
|
|
11
|
+
export function getFromSelector(page, descriptor) {
|
|
12
|
+
let baseLocator;
|
|
13
|
+
// Build base locator based on selector type
|
|
14
|
+
// Both Page and Locator have the same locator methods, so we can call them directly
|
|
15
|
+
switch (descriptor.type) {
|
|
16
|
+
case 'testid':
|
|
17
|
+
baseLocator = page.getByTestId(descriptor.value);
|
|
18
|
+
break;
|
|
19
|
+
case 'role':
|
|
20
|
+
if (descriptor.name !== undefined) {
|
|
21
|
+
// Handle regex patterns
|
|
22
|
+
const nameValue = descriptor.name instanceof RegExp
|
|
23
|
+
? descriptor.name
|
|
24
|
+
: descriptor.name;
|
|
25
|
+
const roleOptions = descriptor.name instanceof RegExp
|
|
26
|
+
? { name: nameValue }
|
|
27
|
+
: { name: nameValue, exact: descriptor.exact ?? false };
|
|
28
|
+
baseLocator = page.getByRole(descriptor.role, roleOptions);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
baseLocator = page.getByRole(descriptor.role);
|
|
32
|
+
}
|
|
33
|
+
break;
|
|
34
|
+
case 'label':
|
|
35
|
+
{
|
|
36
|
+
const labelOptions = descriptor.value instanceof RegExp
|
|
37
|
+
? {}
|
|
38
|
+
: { exact: descriptor.exact ?? false };
|
|
39
|
+
baseLocator = page.getByLabel(descriptor.value, labelOptions);
|
|
40
|
+
}
|
|
41
|
+
break;
|
|
42
|
+
case 'placeholder':
|
|
43
|
+
{
|
|
44
|
+
const placeholderOptions = descriptor.value instanceof RegExp
|
|
45
|
+
? {}
|
|
46
|
+
: { exact: descriptor.exact ?? false };
|
|
47
|
+
baseLocator = page.getByPlaceholder(descriptor.value, placeholderOptions);
|
|
48
|
+
}
|
|
49
|
+
break;
|
|
50
|
+
case 'alt':
|
|
51
|
+
{
|
|
52
|
+
const altOptions = descriptor.value instanceof RegExp
|
|
53
|
+
? {}
|
|
54
|
+
: { exact: descriptor.exact ?? false };
|
|
55
|
+
baseLocator = page.getByAltText(descriptor.value, altOptions);
|
|
56
|
+
}
|
|
57
|
+
break;
|
|
58
|
+
case 'title':
|
|
59
|
+
{
|
|
60
|
+
const titleOptions = descriptor.value instanceof RegExp
|
|
61
|
+
? {}
|
|
62
|
+
: { exact: descriptor.exact ?? false };
|
|
63
|
+
baseLocator = page.getByTitle(descriptor.value, titleOptions);
|
|
64
|
+
}
|
|
65
|
+
break;
|
|
66
|
+
case 'text':
|
|
67
|
+
{
|
|
68
|
+
const textOptions = descriptor.value instanceof RegExp
|
|
69
|
+
? {}
|
|
70
|
+
: { exact: descriptor.exact ?? false };
|
|
71
|
+
baseLocator = page.getByText(descriptor.value, textOptions);
|
|
72
|
+
}
|
|
73
|
+
break;
|
|
74
|
+
case 'css':
|
|
75
|
+
baseLocator = page.locator(descriptor.selector);
|
|
76
|
+
break;
|
|
77
|
+
default:
|
|
78
|
+
// TypeScript exhaustiveness check - if we reach here, a case is missing
|
|
79
|
+
const _exhaustive = descriptor;
|
|
80
|
+
void _exhaustive; // Suppress unused variable warning
|
|
81
|
+
throw new Error(`Unknown selector type: ${descriptor.type}`);
|
|
82
|
+
}
|
|
83
|
+
// If there's a nested child selector, recursively build it from the base locator
|
|
84
|
+
if (descriptor.child) {
|
|
85
|
+
return getFromSelector(baseLocator, descriptor.child);
|
|
86
|
+
}
|
|
87
|
+
return baseLocator;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Verify that a selector uniquely identifies the target element
|
|
91
|
+
*
|
|
92
|
+
* This function checks if a locator built from a SelectorDescriptor matches
|
|
93
|
+
* exactly one element, and optionally verifies it matches the original target element.
|
|
94
|
+
*
|
|
95
|
+
* @param page - Playwright Page object
|
|
96
|
+
* @param descriptor - SelectorDescriptor to verify
|
|
97
|
+
* @param targetElementHandle - Optional element handle to verify the match is correct
|
|
98
|
+
* @returns Promise resolving to true if selector is unique (and matches target if provided)
|
|
99
|
+
*/
|
|
100
|
+
export async function verifySelectorUniqueness(page, descriptor, targetElementHandle) {
|
|
101
|
+
try {
|
|
102
|
+
const locator = getFromSelector(page, descriptor);
|
|
103
|
+
const count = await locator.count();
|
|
104
|
+
// Must match exactly one element
|
|
105
|
+
if (count !== 1) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
// If target element provided, verify it's the same element
|
|
109
|
+
if (targetElementHandle) {
|
|
110
|
+
const matchedElement = await locator.elementHandle();
|
|
111
|
+
if (!matchedElement) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
// Compare elements by checking if they have the same properties
|
|
115
|
+
// We'll compare by getting a unique identifier from both elements
|
|
116
|
+
const targetId = await page.evaluate((el) => {
|
|
117
|
+
// Create a unique identifier: tag + id + text + position
|
|
118
|
+
const rect = el.getBoundingClientRect();
|
|
119
|
+
return JSON.stringify({
|
|
120
|
+
tag: el.tagName,
|
|
121
|
+
id: el.id,
|
|
122
|
+
text: (el.textContent || '').substring(0, 50),
|
|
123
|
+
position: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },
|
|
124
|
+
});
|
|
125
|
+
}, targetElementHandle);
|
|
126
|
+
const matchedId = await page.evaluate((el) => {
|
|
127
|
+
const rect = el.getBoundingClientRect();
|
|
128
|
+
return JSON.stringify({
|
|
129
|
+
tag: el.tagName,
|
|
130
|
+
id: el.id,
|
|
131
|
+
text: (el.textContent || '').substring(0, 50),
|
|
132
|
+
position: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },
|
|
133
|
+
});
|
|
134
|
+
}, matchedElement);
|
|
135
|
+
return targetId === matchedId;
|
|
136
|
+
}
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
// If selector is invalid or throws, it's not unique
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=selectorUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectorUtils.js","sourceRoot":"","sources":["../../src/mimic/selectorUtils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snapshot Storage Module
|
|
3
|
+
*
|
|
4
|
+
* Handles reading, writing, and managing test execution snapshots.
|
|
5
|
+
* Snapshots store successful test executions as JSON files for fast replay.
|
|
6
|
+
*/
|
|
7
|
+
import type { Snapshot } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Generate a hash from test text to create a unique identifier
|
|
10
|
+
*
|
|
11
|
+
* @param testText - The test text (mimic template string)
|
|
12
|
+
* @returns SHA-256 hash of the test text (first 16 characters for readability)
|
|
13
|
+
*/
|
|
14
|
+
export declare function hashTestText(testText: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Get the snapshot directory path for a test file
|
|
17
|
+
*
|
|
18
|
+
* @param testFilePath - Directory path of the test file
|
|
19
|
+
* @returns Path to the .mimic-snapshots directory
|
|
20
|
+
*/
|
|
21
|
+
export declare function getSnapshotDir(testFilePath: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Get the snapshot file path for a specific test
|
|
24
|
+
*
|
|
25
|
+
* @param testFilePath - Directory path of the test file
|
|
26
|
+
* @param testHash - Hash identifier for the test
|
|
27
|
+
* @returns Full path to the snapshot JSON file
|
|
28
|
+
*/
|
|
29
|
+
export declare function getSnapshotPath(testFilePath: string, testHash: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Read a snapshot from disk
|
|
32
|
+
*
|
|
33
|
+
* @param testFilePath - Directory path of the test file
|
|
34
|
+
* @param testHash - Hash identifier for the test
|
|
35
|
+
* @returns Snapshot object if found, null otherwise
|
|
36
|
+
*/
|
|
37
|
+
export declare function getSnapshot(testFilePath: string, testHash: string): Promise<Snapshot | null>;
|
|
38
|
+
/**
|
|
39
|
+
* Save a snapshot to disk
|
|
40
|
+
*
|
|
41
|
+
* @param testFilePath - Directory path of the test file
|
|
42
|
+
* @param snapshot - Snapshot object to save
|
|
43
|
+
* @returns Promise that resolves when snapshot is saved
|
|
44
|
+
*/
|
|
45
|
+
export declare function saveSnapshot(testFilePath: string, snapshot: Snapshot): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Record a test failure timestamp
|
|
48
|
+
*
|
|
49
|
+
* Updates the snapshot's lastFailedAt timestamp if the snapshot exists.
|
|
50
|
+
*
|
|
51
|
+
* @param testFilePath - Directory path of the test file
|
|
52
|
+
* @param testHash - Hash identifier for the test
|
|
53
|
+
* @param failedStepIndex - Index of the step that failed (optional)
|
|
54
|
+
* @param failedStepText - Text of the step that failed (optional)
|
|
55
|
+
* @param error - Error message (optional)
|
|
56
|
+
* @returns Promise that resolves when failure is recorded
|
|
57
|
+
*/
|
|
58
|
+
export declare function recordFailure(testFilePath: string, testHash: string, failedStepIndex?: number, failedStepText?: string, error?: string): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Determine if a snapshot should be used for replay
|
|
61
|
+
*
|
|
62
|
+
* A snapshot should be used if:
|
|
63
|
+
* - It exists
|
|
64
|
+
* - lastPassedAt is more recent than lastFailedAt (or lastFailedAt is null)
|
|
65
|
+
*
|
|
66
|
+
* Note: Even in troubleshoot mode, we use snapshots if they've passed.
|
|
67
|
+
* Regeneration only happens if replay fails.
|
|
68
|
+
*
|
|
69
|
+
* @param testFilePath - Directory path of the test file
|
|
70
|
+
* @param testHash - Hash identifier for the test
|
|
71
|
+
* @param troubleshootMode - Whether troubleshoot mode is enabled (unused, kept for compatibility)
|
|
72
|
+
* @returns true if snapshot should be used, false otherwise
|
|
73
|
+
*/
|
|
74
|
+
export declare function shouldUseSnapshot(testFilePath: string, testHash: string, _troubleshootMode?: boolean, expectedStepCount?: number): Promise<boolean>;
|
|
75
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/mimic/storage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIrD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG9E;AAoBD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAoB1B;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CACjC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,eAAe,CAAC,EAAE,MAAM,EACxB,cAAc,CAAC,EAAE,MAAM,EACvB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAiCf;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,iBAAiB,CACrC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,iBAAiB,GAAE,OAAe,EAClC,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,OAAO,CAAC,CAwClB"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snapshot Storage Module
|
|
3
|
+
*
|
|
4
|
+
* Handles reading, writing, and managing test execution snapshots.
|
|
5
|
+
* Snapshots store successful test executions as JSON files for fast replay.
|
|
6
|
+
*/
|
|
7
|
+
import { createHash } from 'crypto';
|
|
8
|
+
import fs from 'node:fs/promises';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
/**
|
|
11
|
+
* Generate a hash from test text to create a unique identifier
|
|
12
|
+
*
|
|
13
|
+
* @param testText - The test text (mimic template string)
|
|
14
|
+
* @returns SHA-256 hash of the test text (first 16 characters for readability)
|
|
15
|
+
*/
|
|
16
|
+
export function hashTestText(testText) {
|
|
17
|
+
const hash = createHash('sha256');
|
|
18
|
+
hash.update(testText.trim());
|
|
19
|
+
return hash.digest('hex').substring(0, 16);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get the snapshot directory path for a test file
|
|
23
|
+
*
|
|
24
|
+
* @param testFilePath - Directory path of the test file
|
|
25
|
+
* @returns Path to the .mimic-snapshots directory
|
|
26
|
+
*/
|
|
27
|
+
export function getSnapshotDir(testFilePath) {
|
|
28
|
+
return join(testFilePath, '.mimic-snapshots');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get the snapshot file path for a specific test
|
|
32
|
+
*
|
|
33
|
+
* @param testFilePath - Directory path of the test file
|
|
34
|
+
* @param testHash - Hash identifier for the test
|
|
35
|
+
* @returns Full path to the snapshot JSON file
|
|
36
|
+
*/
|
|
37
|
+
export function getSnapshotPath(testFilePath, testHash) {
|
|
38
|
+
const snapshotDir = getSnapshotDir(testFilePath);
|
|
39
|
+
return join(snapshotDir, `${testHash}.json`);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Ensure the snapshot directory exists
|
|
43
|
+
*
|
|
44
|
+
* @param testFilePath - Directory path of the test file
|
|
45
|
+
* @returns Promise that resolves when directory is created or already exists
|
|
46
|
+
*/
|
|
47
|
+
async function ensureSnapshotDir(testFilePath) {
|
|
48
|
+
const snapshotDir = getSnapshotDir(testFilePath);
|
|
49
|
+
try {
|
|
50
|
+
await fs.mkdir(snapshotDir, { recursive: true });
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
// Directory might already exist, which is fine
|
|
54
|
+
if (error instanceof Error && !error.message.includes('EEXIST')) {
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Read a snapshot from disk
|
|
61
|
+
*
|
|
62
|
+
* @param testFilePath - Directory path of the test file
|
|
63
|
+
* @param testHash - Hash identifier for the test
|
|
64
|
+
* @returns Snapshot object if found, null otherwise
|
|
65
|
+
*/
|
|
66
|
+
export async function getSnapshot(testFilePath, testHash) {
|
|
67
|
+
if (!testFilePath) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const snapshotPath = getSnapshotPath(testFilePath, testHash);
|
|
71
|
+
try {
|
|
72
|
+
const content = await fs.readFile(snapshotPath, 'utf-8');
|
|
73
|
+
const snapshot = JSON.parse(content);
|
|
74
|
+
return snapshot;
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
// File doesn't exist or is invalid - return null
|
|
78
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
// For other errors (parse errors, etc.), log and return null
|
|
82
|
+
console.warn(`Failed to read snapshot at ${snapshotPath}:`, error);
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Save a snapshot to disk
|
|
88
|
+
*
|
|
89
|
+
* @param testFilePath - Directory path of the test file
|
|
90
|
+
* @param snapshot - Snapshot object to save
|
|
91
|
+
* @returns Promise that resolves when snapshot is saved
|
|
92
|
+
*/
|
|
93
|
+
export async function saveSnapshot(testFilePath, snapshot) {
|
|
94
|
+
if (!testFilePath) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
await ensureSnapshotDir(testFilePath);
|
|
98
|
+
const snapshotPath = getSnapshotPath(testFilePath, snapshot.testHash);
|
|
99
|
+
// Update timestamps
|
|
100
|
+
const now = new Date().toISOString();
|
|
101
|
+
snapshot.lastPassedAt = now;
|
|
102
|
+
if (!snapshot.createdAt) {
|
|
103
|
+
snapshot.createdAt = now;
|
|
104
|
+
}
|
|
105
|
+
await fs.writeFile(snapshotPath, JSON.stringify(snapshot, null, 2), 'utf-8');
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Record a test failure timestamp
|
|
109
|
+
*
|
|
110
|
+
* Updates the snapshot's lastFailedAt timestamp if the snapshot exists.
|
|
111
|
+
*
|
|
112
|
+
* @param testFilePath - Directory path of the test file
|
|
113
|
+
* @param testHash - Hash identifier for the test
|
|
114
|
+
* @param failedStepIndex - Index of the step that failed (optional)
|
|
115
|
+
* @param failedStepText - Text of the step that failed (optional)
|
|
116
|
+
* @param error - Error message (optional)
|
|
117
|
+
* @returns Promise that resolves when failure is recorded
|
|
118
|
+
*/
|
|
119
|
+
export async function recordFailure(testFilePath, testHash, failedStepIndex, failedStepText, error) {
|
|
120
|
+
if (!testFilePath) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const snapshot = await getSnapshot(testFilePath, testHash);
|
|
124
|
+
if (!snapshot) {
|
|
125
|
+
// Create a minimal snapshot just for failure tracking
|
|
126
|
+
const failureSnapshot = {
|
|
127
|
+
testHash,
|
|
128
|
+
testText: '',
|
|
129
|
+
createdAt: new Date().toISOString(),
|
|
130
|
+
lastPassedAt: null,
|
|
131
|
+
lastFailedAt: new Date().toISOString(),
|
|
132
|
+
steps: [],
|
|
133
|
+
};
|
|
134
|
+
await saveSnapshot(testFilePath, failureSnapshot);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// Update existing snapshot with failure info
|
|
138
|
+
snapshot.lastFailedAt = new Date().toISOString();
|
|
139
|
+
// Store failure details if provided
|
|
140
|
+
if (failedStepIndex !== undefined || failedStepText || error) {
|
|
141
|
+
snapshot.failureDetails = {
|
|
142
|
+
failedStepIndex,
|
|
143
|
+
failedStepText,
|
|
144
|
+
error,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
await saveSnapshot(testFilePath, snapshot);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Determine if a snapshot should be used for replay
|
|
151
|
+
*
|
|
152
|
+
* A snapshot should be used if:
|
|
153
|
+
* - It exists
|
|
154
|
+
* - lastPassedAt is more recent than lastFailedAt (or lastFailedAt is null)
|
|
155
|
+
*
|
|
156
|
+
* Note: Even in troubleshoot mode, we use snapshots if they've passed.
|
|
157
|
+
* Regeneration only happens if replay fails.
|
|
158
|
+
*
|
|
159
|
+
* @param testFilePath - Directory path of the test file
|
|
160
|
+
* @param testHash - Hash identifier for the test
|
|
161
|
+
* @param troubleshootMode - Whether troubleshoot mode is enabled (unused, kept for compatibility)
|
|
162
|
+
* @returns true if snapshot should be used, false otherwise
|
|
163
|
+
*/
|
|
164
|
+
export async function shouldUseSnapshot(testFilePath, testHash, _troubleshootMode = false, expectedStepCount) {
|
|
165
|
+
// Use snapshots even in troubleshoot mode if they've passed
|
|
166
|
+
// Regeneration will happen only if replay fails
|
|
167
|
+
if (!testFilePath) {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
const snapshot = await getSnapshot(testFilePath, testHash);
|
|
171
|
+
if (!snapshot) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
// Validate that snapshot has at least as many steps as expected input lines
|
|
175
|
+
if (expectedStepCount !== undefined) {
|
|
176
|
+
// Count unique steps in snapshot (by stepIndex)
|
|
177
|
+
const uniqueStepIndices = new Set(snapshot.steps.map((step) => step.stepIndex));
|
|
178
|
+
const snapshotStepCount = uniqueStepIndices.size;
|
|
179
|
+
if (snapshotStepCount < expectedStepCount) {
|
|
180
|
+
// Snapshot is incomplete - don't use it
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// If never passed, don't use snapshot
|
|
185
|
+
if (!snapshot.lastPassedAt) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
// If never failed, use snapshot
|
|
189
|
+
if (!snapshot.lastFailedAt) {
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
// Compare timestamps: use snapshot if pass is more recent than failure
|
|
193
|
+
const passTime = new Date(snapshot.lastPassedAt).getTime();
|
|
194
|
+
const failTime = new Date(snapshot.lastFailedAt).getTime();
|
|
195
|
+
return passTime > failTime;
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/mimic/storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snapshot-related Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Types for storing and replaying test execution snapshots.
|
|
5
|
+
*/
|
|
6
|
+
import type { NavigationAction } from './schema/action.js';
|
|
7
|
+
import type { ClickActionResult } from './schema/action.js';
|
|
8
|
+
import type { FormActionResult } from './forms.js';
|
|
9
|
+
import type { TargetInfo } from './selector.js';
|
|
10
|
+
/**
|
|
11
|
+
* A single step in a test execution snapshot
|
|
12
|
+
*/
|
|
13
|
+
export interface SnapshotStep {
|
|
14
|
+
/** Index of the step in the test (0-based) */
|
|
15
|
+
stepIndex: number;
|
|
16
|
+
/** Original step text (Gherkin step) */
|
|
17
|
+
stepText: string;
|
|
18
|
+
/** Type of action (navigation, click, form update) */
|
|
19
|
+
actionKind: 'navigation' | 'click' | 'form update';
|
|
20
|
+
/** Full action details (varies by actionKind) */
|
|
21
|
+
actionDetails: NavigationAction | ClickActionResult | FormActionResult;
|
|
22
|
+
/** Target element information (for click and form actions) */
|
|
23
|
+
targetElement?: TargetInfo & {
|
|
24
|
+
selector?: string;
|
|
25
|
+
};
|
|
26
|
+
/** Timestamp when this step was executed */
|
|
27
|
+
executedAt: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Complete snapshot of a test execution
|
|
31
|
+
*/
|
|
32
|
+
export interface Snapshot {
|
|
33
|
+
/** Hash identifier for this test */
|
|
34
|
+
testHash: string;
|
|
35
|
+
/** Original test text (mimic template string) */
|
|
36
|
+
testText: string;
|
|
37
|
+
/** When this snapshot was first created */
|
|
38
|
+
createdAt: string;
|
|
39
|
+
/** When the test last passed (ISO timestamp) */
|
|
40
|
+
lastPassedAt: string | null;
|
|
41
|
+
/** When the test last failed (ISO timestamp, null if never failed) */
|
|
42
|
+
lastFailedAt: string | null;
|
|
43
|
+
/** Array of executed steps */
|
|
44
|
+
steps: SnapshotStep[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Result of executing a single step (for snapshot creation)
|
|
48
|
+
*/
|
|
49
|
+
export interface StepExecutionResult {
|
|
50
|
+
/** Index of the step in the test (0-based) */
|
|
51
|
+
stepIndex: number;
|
|
52
|
+
/** Original step text (Gherkin step) */
|
|
53
|
+
stepText: string;
|
|
54
|
+
/** Type of action (navigation, click, form update) */
|
|
55
|
+
actionKind: 'navigation' | 'click' | 'form update';
|
|
56
|
+
/** Full action details (varies by actionKind) */
|
|
57
|
+
actionDetails: NavigationAction | ClickActionResult | FormActionResult;
|
|
58
|
+
/** Target element information (for click and form actions) */
|
|
59
|
+
targetElement?: TargetInfo & {
|
|
60
|
+
selector?: string;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/mimic/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,UAAU,EAAE,YAAY,GAAG,OAAO,GAAG,aAAa,CAAC;IACnD,iDAAiD;IACjD,aAAa,EAAE,gBAAgB,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;IACvE,8DAA8D;IAC9D,aAAa,CAAC,EAAE,UAAU,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,sEAAsE;IACtE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,8BAA8B;IAC9B,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,UAAU,EAAE,YAAY,GAAG,OAAO,GAAG,aAAa,CAAC;IACnD,iDAAiD;IACjD,aAAa,EAAE,gBAAgB,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;IACvE,8DAA8D;IAC9D,aAAa,CAAC,EAAE,UAAU,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACpD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/mimic/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
package/dist/mimic.d.ts
CHANGED
|
@@ -4,23 +4,47 @@
|
|
|
4
4
|
import { Page, TestInfo } from '@playwright/test';
|
|
5
5
|
import type { LanguageModel } from 'ai';
|
|
6
6
|
export type Mimic = (steps: TemplateStringsArray, ...args: unknown[]) => Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Test context that tracks previous state and actions for better decision-making
|
|
9
|
+
*/
|
|
10
|
+
export interface TestContext {
|
|
11
|
+
/** Previous steps that have been executed */
|
|
12
|
+
previousSteps: Array<{
|
|
13
|
+
stepIndex: number;
|
|
14
|
+
stepText: string;
|
|
15
|
+
actionKind: string;
|
|
16
|
+
url?: string;
|
|
17
|
+
pageTitle?: string;
|
|
18
|
+
}>;
|
|
19
|
+
/** Current page state */
|
|
20
|
+
currentState: {
|
|
21
|
+
url: string;
|
|
22
|
+
pageTitle: string;
|
|
23
|
+
};
|
|
24
|
+
/** Total number of steps in the test */
|
|
25
|
+
totalSteps: number;
|
|
26
|
+
/** Current step index */
|
|
27
|
+
currentStepIndex: number;
|
|
28
|
+
}
|
|
7
29
|
/**
|
|
8
30
|
* Minimal flow function that takes a Playwright page and input string
|
|
9
31
|
*
|
|
10
32
|
* @param page - Playwright Page object
|
|
11
33
|
* @param input - Input string to process
|
|
34
|
+
* @param testFilePath - Directory path of the test file (for snapshot storage)
|
|
35
|
+
* @param troubleshootMode - Whether troubleshoot mode is enabled
|
|
12
36
|
* @returns Flow execution result with validated context
|
|
13
37
|
*/
|
|
14
|
-
export declare function mimic(input: string, { page, brains, testInfo }: {
|
|
38
|
+
export declare function mimic(input: string, { page, brains, testInfo, testFilePath, troubleshootMode }: {
|
|
15
39
|
page: Page;
|
|
16
40
|
brains: LanguageModel;
|
|
17
|
-
|
|
18
|
-
|
|
41
|
+
testInfo: TestInfo | undefined;
|
|
42
|
+
testFilePath?: string;
|
|
43
|
+
troubleshootMode?: boolean;
|
|
19
44
|
}): Promise<void>;
|
|
20
45
|
export declare const createMimic: (config: {
|
|
21
46
|
page: Page;
|
|
22
47
|
brains: LanguageModel;
|
|
23
|
-
eyes: LanguageModel;
|
|
24
48
|
testInfo?: TestInfo;
|
|
25
49
|
}) => (prompt: TemplateStringsArray, ...args: unknown[]) => Promise<void>;
|
|
26
50
|
//# sourceMappingURL=mimic.d.ts.map
|
package/dist/mimic.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mimic.d.ts","sourceRoot":"","sources":["../src/mimic.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAQ,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"mimic.d.ts","sourceRoot":"","sources":["../src/mimic.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAQ,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAiBxC,MAAM,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,oBAAoB,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEvF;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,6CAA6C;IAC7C,aAAa,EAAE,KAAK,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;IACH,yBAAyB;IACzB,YAAY,EAAE;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAoHD;;;;;;;;GAQG;AACH,wBAAsB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,gBAAgB,EAAE,EAAE;IACrG,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,iBAsUA;AAeD,eAAO,MAAM,WAAW,GAAI,QAAQ;IAClC,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,MASe,QAAQ,oBAAoB,EAAE,GAAG,MAAM,OAAO,EAAE,kBAU/D,CAAA"}
|