playwright-mimic 0.1.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 (42) hide show
  1. package/README.md +446 -0
  2. package/dist/index.d.ts +13 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +14 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/mimic.d.ts +26 -0
  7. package/dist/mimic.d.ts.map +1 -0
  8. package/dist/mimic.js +71 -0
  9. package/dist/mimic.js.map +1 -0
  10. package/dist/mimicry/actionType.d.ts +6 -0
  11. package/dist/mimicry/actionType.d.ts.map +1 -0
  12. package/dist/mimicry/actionType.js +32 -0
  13. package/dist/mimicry/actionType.js.map +1 -0
  14. package/dist/mimicry/click.d.ts +20 -0
  15. package/dist/mimicry/click.d.ts.map +1 -0
  16. package/dist/mimicry/click.js +152 -0
  17. package/dist/mimicry/click.js.map +1 -0
  18. package/dist/mimicry/forms.d.ts +31 -0
  19. package/dist/mimicry/forms.d.ts.map +1 -0
  20. package/dist/mimicry/forms.js +154 -0
  21. package/dist/mimicry/forms.js.map +1 -0
  22. package/dist/mimicry/navigation.d.ts +6 -0
  23. package/dist/mimicry/navigation.d.ts.map +1 -0
  24. package/dist/mimicry/navigation.js +52 -0
  25. package/dist/mimicry/navigation.js.map +1 -0
  26. package/dist/mimicry/schema/action.d.ts +312 -0
  27. package/dist/mimicry/schema/action.d.ts.map +1 -0
  28. package/dist/mimicry/schema/action.js +194 -0
  29. package/dist/mimicry/schema/action.js.map +1 -0
  30. package/dist/mimicry/selector.d.ts +118 -0
  31. package/dist/mimicry/selector.d.ts.map +1 -0
  32. package/dist/mimicry/selector.js +682 -0
  33. package/dist/mimicry/selector.js.map +1 -0
  34. package/dist/mimicry.d.ts +24 -0
  35. package/dist/mimicry.d.ts.map +1 -0
  36. package/dist/mimicry.js +71 -0
  37. package/dist/mimicry.js.map +1 -0
  38. package/dist/utils/token-counter.d.ts +63 -0
  39. package/dist/utils/token-counter.d.ts.map +1 -0
  40. package/dist/utils/token-counter.js +171 -0
  41. package/dist/utils/token-counter.js.map +1 -0
  42. package/package.json +43 -0
package/README.md ADDED
@@ -0,0 +1,446 @@
1
+ # Playwright Mimic
2
+
3
+ **Playwright Mimic** is an AI-powered browser testing framework that takes natural language instructions and reasons through them to operate the browser and run tests. It's designed to work seamlessly with Playwright, allowing you to write tests in plain English (Gherkin-style) that are automatically executed by AI.
4
+
5
+ ## Features
6
+
7
+ - 🤖 **AI-Powered**: Uses language models to understand and execute natural language test instructions
8
+ - 🎯 **Smart Element Selection**: Automatically finds and interacts with elements based on semantic understanding
9
+ - 📝 **Gherkin-Style Syntax**: Write tests in natural language, one instruction per line
10
+ - 🔄 **Multiple Action Types**: Supports navigation, clicks, form updates, and more
11
+ - 🎭 **Playwright Integration**: Built on top of Playwright for reliable browser automation
12
+ - 📊 **Token Tracking**: Built-in token usage tracking for AI model calls
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install playwright-mimic
18
+ # or
19
+ pnpm install playwright-mimic
20
+ # or
21
+ yarn add playwright-mimic
22
+ ```
23
+
24
+ ## Prerequisites
25
+
26
+ - Node.js 18+
27
+ - Playwright installed in your project
28
+ - An AI model provider (OpenAI, Ollama, or compatible provider from the `ai` SDK)
29
+
30
+ ## Quick Start
31
+
32
+ ### 1. Install Dependencies
33
+
34
+ ```bash
35
+ npm install @playwright/test playwright-mimic @ai-sdk/openai ai
36
+ # or for Ollama
37
+ npm install @playwright/test playwright-mimic ollama-ai-provider-v2 ai
38
+ ```
39
+
40
+ ### 2. Set Up Environment Variables
41
+
42
+ Create a `.env` file in your project root:
43
+
44
+ ```env
45
+ OPENAI_API_KEY=your_openai_api_key_here
46
+ # or for Ollama (if using local models)
47
+ OLLAMA_BASE_URL=http://localhost:11434
48
+ ```
49
+
50
+ ### 3. Configure Playwright Fixtures
51
+
52
+ Create a test utilities file (e.g., `test-utils.ts`):
53
+
54
+ ```typescript
55
+ import "dotenv/config";
56
+ import { test as base } from '@playwright/test';
57
+ import { createMimicry, type Mimicry } from 'playwright-mimic';
58
+ import { openai } from '@ai-sdk/openai';
59
+ // or for Ollama: import { ollama } from 'ollama-ai-provider-v2';
60
+
61
+ // Configure your AI model
62
+ const brains = openai('gpt-4o-mini');
63
+ // or for Ollama: const brains = ollama('llama3.2') as LanguageModel;
64
+
65
+ export * from '@playwright/test';
66
+
67
+ // Extend Playwright's test with mimicry fixture
68
+ export const test = base.extend<{
69
+ mimicry: Mimicry
70
+ }>({
71
+ mimicry: async ({ page }, use, testInfo) => {
72
+ const mimicry = createMimicry({
73
+ page,
74
+ brains,
75
+ eyes: brains, // Can use a different model for visual analysis
76
+ testInfo,
77
+ });
78
+ await use(mimicry);
79
+ }
80
+ });
81
+ ```
82
+
83
+ ### 4. Write Your First Test
84
+
85
+ Create a test file (e.g., `example.spec.ts`):
86
+
87
+ ```typescript
88
+ import { test, expect } from './test-utils';
89
+
90
+ test('navigate and interact with Playwright docs', async ({ page, mimicry }) => {
91
+ await mimicry`
92
+ navigate to https://playwright.dev/
93
+ click on "get started"
94
+ and click on "trace viewer"
95
+ `;
96
+
97
+ expect(page.url()).toBe('https://playwright.dev/docs/trace-viewer-intro');
98
+
99
+ await mimicry`go back`;
100
+
101
+ expect(page.url()).toBe('https://playwright.dev/docs/intro');
102
+ });
103
+ ```
104
+
105
+ ### 5. Run Your Tests
106
+
107
+ ```bash
108
+ npx playwright test
109
+ ```
110
+
111
+ ## Usage
112
+
113
+ ### Basic Syntax
114
+
115
+ Mimicry uses a simple line-by-line syntax where each line represents a test step:
116
+
117
+ ```typescript
118
+ await mimicry`
119
+ navigate to https://example.com
120
+ click on "Sign In"
121
+ type "username" into the email field
122
+ type "password123" into the password field
123
+ click on the submit button
124
+ `;
125
+ ```
126
+
127
+ ### Supported Actions
128
+
129
+ #### Navigation
130
+
131
+ ```typescript
132
+ await mimicry`
133
+ navigate to https://example.com
134
+ go back
135
+ go forward
136
+ refresh the page
137
+ close the page
138
+ `;
139
+ ```
140
+
141
+ #### Clicking Elements
142
+
143
+ Mimicry can find elements by:
144
+ - Visible text: `click on "Sign In"`
145
+ - Button labels: `click on the submit button`
146
+ - Link text: `click on "About Us"`
147
+ - Semantic descriptions: `click on the login button in the header`
148
+
149
+ ```typescript
150
+ await mimicry`
151
+ click on "Get Started"
152
+ click on the search icon
153
+ click on the menu button
154
+ `;
155
+ ```
156
+
157
+ #### Form Interactions
158
+
159
+ ```typescript
160
+ await mimicry`
161
+ type "john@example.com" into the email field
162
+ fill the password field with "secret123"
163
+ select "United States" from the country dropdown
164
+ check the terms and conditions checkbox
165
+ uncheck the newsletter checkbox
166
+ `;
167
+ ```
168
+
169
+ ### Using Variables
170
+
171
+ You can use template literals to inject variables:
172
+
173
+ ```typescript
174
+ const username = 'testuser';
175
+ const password = 'testpass';
176
+
177
+ await mimicry`
178
+ type "${username}" into the username field
179
+ type "${password}" into the password field
180
+ click on "Login"
181
+ `;
182
+ ```
183
+
184
+ ### Combining with Playwright Assertions
185
+
186
+ Mimicry works seamlessly with Playwright's built-in assertions:
187
+
188
+ ```typescript
189
+ test('complete user registration', async ({ page, mimicry }) => {
190
+ await mimicry`
191
+ navigate to https://example.com/register
192
+ type "John Doe" into the name field
193
+ type "john@example.com" into the email field
194
+ type "SecurePass123!" into the password field
195
+ click on "Create Account"
196
+ `;
197
+
198
+ // Use Playwright assertions
199
+ await expect(page.locator('text=Welcome')).toBeVisible();
200
+ expect(page.url()).toContain('/dashboard');
201
+ });
202
+ ```
203
+
204
+ ### Advanced: Direct API Usage
205
+
206
+ If you need more control, you can use the `mimicry` function directly:
207
+
208
+ ```typescript
209
+ import { mimicry } from 'playwright-mimic';
210
+ import { openai } from '@ai-sdk/openai';
211
+ import { test } from '@playwright/test';
212
+
213
+ test('custom usage', async ({ page, testInfo }) => {
214
+ const brains = openai('gpt-4o-mini');
215
+
216
+ await mimicry(
217
+ 'navigate to https://example.com\nclick on "Get Started"',
218
+ {
219
+ page,
220
+ brains,
221
+ eyes: brains,
222
+ testInfo,
223
+ }
224
+ );
225
+ });
226
+ ```
227
+
228
+ ## API Reference
229
+
230
+ ### `createMimicry(config)`
231
+
232
+ Creates a mimicry function that can be used as a template literal tag.
233
+
234
+ **Parameters:**
235
+ - `config.page` (required): Playwright `Page` object
236
+ - `config.brains` (required): Language model for reasoning (from `ai` SDK)
237
+ - `config.eyes` (required): Language model for visual analysis (can be same as brains)
238
+ - `config.testInfo` (optional): Playwright `TestInfo` object for test tracking
239
+
240
+ **Returns:** A function that accepts template literals
241
+
242
+ ### `mimicry(input, config)`
243
+
244
+ Direct function call version.
245
+
246
+ **Parameters:**
247
+ - `input` (string): Newline-separated test steps
248
+ - `config`: Same as `createMimicry`
249
+
250
+ ### Exported Utilities
251
+
252
+ You can also import individual utilities for custom implementations:
253
+
254
+ ```typescript
255
+ import {
256
+ getBaseAction,
257
+ getClickAction,
258
+ executeClickAction,
259
+ getNavigationAction,
260
+ executeNavigationAction,
261
+ getFormAction,
262
+ executeFormAction,
263
+ captureTargets,
264
+ buildSelectorForTarget,
265
+ } from 'playwright-mimic';
266
+ ```
267
+
268
+ ## Configuration
269
+
270
+ ### AI Model Selection
271
+
272
+ **OpenAI:**
273
+ ```typescript
274
+ import { openai } from '@ai-sdk/openai';
275
+ const brains = openai('gpt-4o-mini'); // or 'gpt-4', 'gpt-4-turbo', etc.
276
+ ```
277
+
278
+ **Ollama (Local Models):**
279
+ ```typescript
280
+ import { ollama } from 'ollama-ai-provider-v2';
281
+ const brains = ollama('llama3.2') as LanguageModel;
282
+ ```
283
+
284
+ **Different Models for Different Tasks:**
285
+ ```typescript
286
+ const brains = openai('gpt-4o-mini'); // For reasoning
287
+ const eyes = openai('gpt-4-vision-preview'); // For visual analysis (if needed)
288
+ ```
289
+
290
+ ### Playwright Configuration
291
+
292
+ Ensure your `playwright.config.ts` is set up correctly:
293
+
294
+ ```typescript
295
+ import { defineConfig } from '@playwright/test';
296
+
297
+ export default defineConfig({
298
+ testDir: './tests', // or wherever your tests are
299
+ use: {
300
+ trace: 'on-first-retry',
301
+ },
302
+ // ... other config
303
+ });
304
+ ```
305
+
306
+ ## Best Practices
307
+
308
+ ### 1. Use Descriptive Steps
309
+
310
+ Be specific in your instructions:
311
+
312
+ ```typescript
313
+ // ✅ Good
314
+ await mimicry`
315
+ click on the "Sign In" button in the header
316
+ type "admin@example.com" into the email input field
317
+ `;
318
+
319
+ // ❌ Less clear
320
+ await mimicry`
321
+ click button
322
+ type email
323
+ `;
324
+ ```
325
+
326
+ ### 2. Combine with Assertions
327
+
328
+ Always verify the results:
329
+
330
+ ```typescript
331
+ await mimicry`
332
+ navigate to /dashboard
333
+ click on "Create Project"
334
+ type "My Project" into the project name field
335
+ click on "Save"
336
+ `;
337
+
338
+ await expect(page.locator('text=My Project')).toBeVisible();
339
+ ```
340
+
341
+ ### 3. Use Test Steps for Debugging
342
+
343
+ Mimicry automatically creates Playwright test steps, making it easy to debug:
344
+
345
+ ```typescript
346
+ // Each line becomes a test step in Playwright's trace viewer
347
+ await mimicry`
348
+ navigate to https://example.com
349
+ click on "Products"
350
+ click on "View Details"
351
+ `;
352
+ ```
353
+
354
+ ### 4. Handle Dynamic Content
355
+
356
+ For dynamic content, combine mimicry with Playwright waits:
357
+
358
+ ```typescript
359
+ await mimicry`click on "Load More"`;
360
+ await page.waitForSelector('text=New Content');
361
+ await mimicry`click on "New Content"`;
362
+ ```
363
+
364
+ ### 5. Token Usage
365
+
366
+ Mimicry tracks token usage automatically. Monitor your AI provider's usage to optimize costs:
367
+
368
+ - Use smaller models (like `gpt-4o-mini`) for faster, cheaper tests
369
+ - Use larger models only when needed for complex reasoning
370
+
371
+ ## Troubleshooting
372
+
373
+ ### Element Not Found
374
+
375
+ If mimicry can't find an element, try:
376
+ 1. Be more specific: `click on "Submit" button` instead of `click on "Submit"`
377
+ 2. Use unique identifiers: `click on the login button with id "submit-btn"`
378
+ 3. Check if the element is visible: Add a wait before the action
379
+
380
+ ### Slow Execution
381
+
382
+ AI model calls take time. To speed up:
383
+ 1. Use faster models (e.g., `gpt-4o-mini` instead of `gpt-4`)
384
+ 2. Batch related actions when possible
385
+ 3. Use Playwright's native selectors for simple, stable elements
386
+
387
+ ### API Key Issues
388
+
389
+ Ensure your `.env` file is loaded:
390
+ ```typescript
391
+ import "dotenv/config"; // At the top of your test-utils.ts
392
+ ```
393
+
394
+ ## Examples
395
+
396
+ ### E-commerce Checkout Flow
397
+
398
+ ```typescript
399
+ test('complete checkout process', async ({ page, mimicry }) => {
400
+ await mimicry`
401
+ navigate to https://store.example.com
402
+ click on "Add to Cart" for "Product Name"
403
+ click on the shopping cart icon
404
+ click on "Proceed to Checkout"
405
+ type "john@example.com" into the email field
406
+ type "123 Main St" into the address field
407
+ type "New York" into the city field
408
+ select "United States" from the country dropdown
409
+ type "10001" into the zip code field
410
+ click on "Continue to Payment"
411
+ type "4242 4242 4242 4242" into the card number field
412
+ type "12/25" into the expiration field
413
+ type "123" into the CVV field
414
+ click on "Place Order"
415
+ `;
416
+
417
+ await expect(page.locator('text=Order Confirmed')).toBeVisible();
418
+ });
419
+ ```
420
+
421
+ ### Form Validation Testing
422
+
423
+ ```typescript
424
+ test('validate required fields', async ({ page, mimicry }) => {
425
+ await mimicry`
426
+ navigate to https://example.com/contact
427
+ click on "Submit" without filling fields
428
+ `;
429
+
430
+ await expect(page.locator('text=Email is required')).toBeVisible();
431
+ await expect(page.locator('text=Name is required')).toBeVisible();
432
+ });
433
+ ```
434
+
435
+ ## Contributing
436
+
437
+ Contributions are welcome! Please feel free to submit a Pull Request.
438
+
439
+ ## License
440
+
441
+ ISC
442
+
443
+ ## Support
444
+
445
+ For issues, questions, or contributions, please open an issue on the GitHub repository.
446
+
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Mimicry - AI-powered browser testing framework
3
+ *
4
+ * Main entry point exporting all public APIs
5
+ */
6
+ export { mimicry, createMimicry, type Mimicry } from './mimicry.js';
7
+ export { getBaseAction } from './mimicry/actionType.js';
8
+ export { getClickAction, executeClickAction } from './mimicry/click.js';
9
+ export { getNavigationAction, executeNavigationAction } from './mimicry/navigation.js';
10
+ export { getFormAction, executeFormAction, type FormActionResult } from './mimicry/forms.js';
11
+ export { captureTargets, buildSelectorForTarget, type TargetInfo, type CaptureTargetsOptions } from './mimicry/selector.js';
12
+ export type { NavigationAction, ClickActionResult, Point, } from './mimicry/schema/action.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AAGpE,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,KAAK,UAAU,EAAE,KAAK,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAG5H,YAAY,EACV,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,GACN,MAAM,4BAA4B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Mimicry - AI-powered browser testing framework
3
+ *
4
+ * Main entry point exporting all public APIs
5
+ */
6
+ // Main mimicry functionality
7
+ export { mimicry, createMimicry } from './mimicry.js';
8
+ // Mimicry action types and utilities
9
+ export { getBaseAction } from './mimicry/actionType.js';
10
+ export { getClickAction, executeClickAction } from './mimicry/click.js';
11
+ export { getNavigationAction, executeNavigationAction } from './mimicry/navigation.js';
12
+ export { getFormAction, executeFormAction } from './mimicry/forms.js';
13
+ export { captureTargets, buildSelectorForTarget } from './mimicry/selector.js';
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,6BAA6B;AAC7B,OAAO,EAAE,OAAO,EAAE,aAAa,EAAgB,MAAM,cAAc,CAAC;AAEpE,qCAAqC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAyB,MAAM,oBAAoB,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAA+C,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Minimal flow example function
3
+ */
4
+ import { Page, TestInfo } from '@playwright/test';
5
+ import type { LanguageModel } from 'ai';
6
+ export type Mimic = (steps: TemplateStringsArray, ...args: unknown[]) => Promise<void>;
7
+ /**
8
+ * Minimal flow function that takes a Playwright page and input string
9
+ *
10
+ * @param page - Playwright Page object
11
+ * @param input - Input string to process
12
+ * @returns Flow execution result with validated context
13
+ */
14
+ export declare function mimic(input: string, { page, brains, testInfo }: {
15
+ page: Page;
16
+ brains: LanguageModel;
17
+ eyes: LanguageModel;
18
+ testInfo?: TestInfo;
19
+ }): Promise<void>;
20
+ export declare const createMimic: (config: {
21
+ page: Page;
22
+ brains: LanguageModel;
23
+ eyes: LanguageModel;
24
+ testInfo?: TestInfo;
25
+ }) => (prompt: TemplateStringsArray, ...args: unknown[]) => Promise<void>;
26
+ //# sourceMappingURL=mimic.d.ts.map
@@ -0,0 +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;AAQxC,MAAM,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,oBAAoB,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAGvF;;;;;;GAMG;AACH,wBAAsB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE;IACrE,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,aAAa,CAAC;IACpB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,iBAwCA;AAeD,eAAO,MAAM,WAAW,GAAI,QAAQ;IAClC,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,aAAa,CAAC;IACpB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,MACe,QAAQ,oBAAoB,EAAE,GAAG,MAAM,OAAO,EAAE,kBAI/D,CAAA"}
package/dist/mimic.js ADDED
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Minimal flow example function
3
+ */
4
+ import { test } from '@playwright/test';
5
+ import { getBaseAction } from './mimicry/actionType.js';
6
+ import { getNavigationAction, executeNavigationAction } from './mimicry/navigation.js';
7
+ import { buildSelectorForTarget, captureTargets } from './mimicry/selector.js';
8
+ import { executeClickAction, getClickAction } from './mimicry/click.js';
9
+ import { startTestCase } from './utils/token-counter.js';
10
+ /**
11
+ * Minimal flow function that takes a Playwright page and input string
12
+ *
13
+ * @param page - Playwright Page object
14
+ * @param input - Input string to process
15
+ * @returns Flow execution result with validated context
16
+ */
17
+ export async function mimic(input, { page, brains, testInfo }) {
18
+ if (testInfo?.title)
19
+ await startTestCase(testInfo.title);
20
+ const steps = input.split('\n')
21
+ // lets clean up things
22
+ .map(step => step.trim())
23
+ // and remove empty steps
24
+ .filter(step => step.length > 0);
25
+ // now lets process each step
26
+ for (const step of steps) {
27
+ await test.step(step, async () => {
28
+ const baseAction = await getBaseAction(page, brains, step);
29
+ switch (baseAction.kind) {
30
+ case 'navigation':
31
+ console.log(`Navigating to ${step}`);
32
+ const navigationAction = await getNavigationAction(page, brains, step);
33
+ await executeNavigationAction(page, navigationAction);
34
+ break;
35
+ case 'click':
36
+ console.log(`Clicking on ${step}`);
37
+ const targetElements = await captureTargets(page, { interactableOnly: true });
38
+ const clickActionResult = await getClickAction(page, brains, step, targetElements);
39
+ // TODO: better way to work out if the top priority candidate is a clickable element
40
+ const clickable = await buildSelectorForTarget(page, clickActionResult.candidates.find(Boolean));
41
+ await executeClickAction(clickable, clickActionResult);
42
+ break;
43
+ case 'form update':
44
+ const formElements = await captureTargets(page, { interactableOnly: true });
45
+ console.log(`Form element count: ${formElements.length}`);
46
+ break;
47
+ default:
48
+ throw new Error(`Unknown base action type: ${baseAction.kind}`);
49
+ }
50
+ });
51
+ }
52
+ }
53
+ function trimTemplate(strings, ...values) {
54
+ // Combine the template string with interpolated values
55
+ let result = strings.reduce((acc, str, i) => {
56
+ return acc + str + (values[i] ?? '');
57
+ }, '');
58
+ // Split into lines, trim each, filter out empty lines, and join back
59
+ return result
60
+ .split('\n')
61
+ .map(line => line.trim())
62
+ .filter(line => line.length > 0)
63
+ .join('\n');
64
+ }
65
+ export const createMimic = (config) => {
66
+ return async (prompt, ...args) => {
67
+ const lines = trimTemplate(prompt, ...args);
68
+ return await mimic(lines, config);
69
+ };
70
+ };
71
+ //# sourceMappingURL=mimic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mimic.js","sourceRoot":"","sources":["../src/mimic.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { type LanguageModel } from 'ai';
2
+ import { z } from 'zod';
3
+ import { Page } from '@playwright/test';
4
+ import { zGeneralActionPlan } from './schema/action.js';
5
+ export declare const getBaseAction: (_page: Page, brain: LanguageModel, action: string) => Promise<z.infer<typeof zGeneralActionPlan>>;
6
+ //# sourceMappingURL=actionType.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actionType.d.ts","sourceRoot":"","sources":["../../src/mimicry/actionType.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAwB,MAAM,IAAI,CAAA;AAC7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAEvC,OAAO,EACL,kBAAkB,EACnB,MAAM,oBAAoB,CAAA;AAK3B,eAAO,MAAM,aAAa,GACxB,OAAO,IAAI,EACX,OAAO,aAAa,EACpB,QAAQ,MAAM,KACb,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CA4B5C,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { generateText, Output } from 'ai';
2
+ import { zGeneralActionPlan, } from './schema/action.js';
3
+ import { countTokens } from '../utils/token-counter.js';
4
+ export const getBaseAction = async (_page, brain, action) => {
5
+ const res = await generateText({
6
+ model: brain,
7
+ prompt: `You are an expert in interpreting Gherkin steps and classifying them into base user action types for automated testing using Playwright.
8
+
9
+ For each Gherkin step, output the following:
10
+
11
+ Decision: One of the following categories:
12
+ Form update: Modifying input fields, selecting options, checking boxes, etc.
13
+ Navigation: Moving between pages or URLs, or using "back"/"forward".
14
+ Assertion: Verifying an element's presence, state, or content.
15
+ Click: Clicking on buttons, links, or other interactive elements.
16
+ Hover: Hovering over elements to trigger UI events or tooltips.
17
+ Unknown: Step is too ambiguous to confidently classify.
18
+
19
+ Explanation: Describe the reasoning behind the classification based on the literal intent of the Gherkin step. Do not infer outcomes — classify strictly based on what the step says is being done.
20
+ Format:
21
+ Classification: <one of the 6 categories>
22
+ Reason: <brief explanation of how you arrived at the classification>
23
+
24
+ Input Gherkin step:: ${action}
25
+
26
+ `,
27
+ output: Output.object({ schema: zGeneralActionPlan, name: 'generalActionPlan' }),
28
+ });
29
+ await countTokens(res);
30
+ return res.output;
31
+ };
32
+ //# sourceMappingURL=actionType.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actionType.js","sourceRoot":"","sources":["../../src/mimicry/actionType.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,YAAY,EAAE,MAAM,EAAE,MAAM,IAAI,CAAA;AAI7D,OAAO,EACL,kBAAkB,GACnB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAIxD,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAChC,KAAW,EACX,KAAoB,EACpB,MAAc,EAC+B,EAAE;IAC/C,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC;QAC7B,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE;;;;;;;;;;;;;;;;;uBAiBW,MAAM;;KAExB;QACD,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC;KACjF,CAAC,CAAC;IACH,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;IAEvB,OAAO,GAAG,CAAC,MAAM,CAAC;AACpB,CAAC,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { type LanguageModel } from 'ai';
2
+ import { Locator, Page } from '@playwright/test';
3
+ import { type ClickActionResult } from './schema/action.js';
4
+ import type { TargetInfo } from './selector.js';
5
+ /**
6
+ * Get click action by matching Gherkin step against captured target elements
7
+ *
8
+ * This function uses AI to analyze a Gherkin step and match it against
9
+ * all available target elements on the page. It returns the top 5 most
10
+ * likely candidates along with the appropriate click type.
11
+ *
12
+ * @param page - Playwright Page object (currently unused but kept for consistency)
13
+ * @param brain - LanguageModel instance for AI analysis
14
+ * @param gherkinStep - The Gherkin step to match (e.g., "I click on the Submit button")
15
+ * @param targetElements - Array of captured target elements from the page
16
+ * @returns Promise resolving to ClickActionResult with top candidates and click type
17
+ */
18
+ export declare const getClickAction: (_page: Page, brain: LanguageModel, gherkinStep: string, targetElements: TargetInfo[]) => Promise<ClickActionResult>;
19
+ export declare const executeClickAction: (element: Locator | null, clickActionResult: ClickActionResult) => Promise<void>;
20
+ //# sourceMappingURL=click.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"click.d.ts","sourceRoot":"","sources":["../../src/mimicry/click.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAwB,MAAM,IAAI,CAAA;AAC7D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAEhD,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAG/C;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,cAAc,GACzB,OAAO,IAAI,EACX,OAAO,aAAa,EACpB,aAAa,MAAM,EACnB,gBAAgB,UAAU,EAAE,KAC3B,OAAO,CAAC,iBAAiB,CA+H3B,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,SAAS,OAAO,GAAG,IAAI,EACvB,mBAAmB,iBAAiB,KACnC,OAAO,CAAC,IAAI,CAed,CAAC"}