testdriverai 7.1.3 → 7.1.4

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.
@@ -0,0 +1,145 @@
1
+ name: Test Init Command
2
+
3
+ on:
4
+ push:
5
+ branches: [ main, develop ]
6
+ pull_request:
7
+ branches: [ main, develop ]
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ test-init:
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - name: Checkout CLI repository
16
+ uses: actions/checkout@v4
17
+
18
+ - name: Setup Node.js
19
+ uses: actions/setup-node@v4
20
+ with:
21
+ node-version: '20'
22
+ cache: 'npm'
23
+
24
+ - name: Install CLI dependencies
25
+ run: npm ci
26
+
27
+ - name: Create test directory
28
+ run: |
29
+ mkdir -p /tmp/test-init-project
30
+ cd /tmp/test-init-project
31
+
32
+ - name: Run init command (skip prompts)
33
+ working-directory: /tmp/test-init-project
34
+ run: |
35
+ # Create .env with API key first to skip the prompt
36
+ echo "TD_API_KEY=${{ secrets.TD_API_KEY }}" > .env
37
+
38
+ # Run init command using the CLI from the repo
39
+ node ${{ github.workspace }}/bin/testdriverai.js init
40
+ env:
41
+ TD_API_KEY: ${{ secrets.TD_API_KEY }}
42
+
43
+ - name: Verify project structure
44
+ working-directory: /tmp/test-init-project
45
+ run: |
46
+ echo "Checking generated files..."
47
+
48
+ # Check for package.json
49
+ if [ ! -f "package.json" ]; then
50
+ echo "❌ package.json not found"
51
+ exit 1
52
+ fi
53
+ echo "✓ package.json exists"
54
+
55
+ # Check for vitest config
56
+ if [ ! -f "vitest.config.js" ]; then
57
+ echo "❌ vitest.config.js not found"
58
+ exit 1
59
+ fi
60
+ echo "✓ vitest.config.js exists"
61
+
62
+ # Check for test file
63
+ if [ ! -f "tests/example.test.js" ]; then
64
+ echo "❌ tests/example.test.js not found"
65
+ exit 1
66
+ fi
67
+ echo "✓ tests/example.test.js exists"
68
+
69
+ # Check for .env file
70
+ if [ ! -f ".env" ]; then
71
+ echo "❌ .env not found"
72
+ exit 1
73
+ fi
74
+ echo "✓ .env exists"
75
+
76
+ # Check for .gitignore
77
+ if [ ! -f ".gitignore" ]; then
78
+ echo "❌ .gitignore not found"
79
+ exit 1
80
+ fi
81
+ echo "✓ .gitignore exists"
82
+
83
+ # Check for GitHub workflow
84
+ if [ ! -f ".github/workflows/testdriver.yml" ]; then
85
+ echo "❌ .github/workflows/testdriver.yml not found"
86
+ exit 1
87
+ fi
88
+ echo "✓ .github/workflows/testdriver.yml exists"
89
+
90
+ - name: Verify vitest config contents
91
+ working-directory: /tmp/test-init-project
92
+ run: |
93
+ echo "Checking vitest.config.js contents..."
94
+
95
+ # Check for TestDriver reporter
96
+ if ! grep -q "TestDriver()" vitest.config.js; then
97
+ echo "❌ TestDriver reporter not found in vitest.config.js"
98
+ cat vitest.config.js
99
+ exit 1
100
+ fi
101
+ echo "✓ TestDriver reporter is configured"
102
+
103
+ # Check for setupFiles
104
+ if ! grep -q "setupFiles.*testdriverai/vitest/setup" vitest.config.js; then
105
+ echo "❌ setupFiles not configured correctly"
106
+ cat vitest.config.js
107
+ exit 1
108
+ fi
109
+ echo "✓ setupFiles is configured"
110
+
111
+ - name: Verify test file contents
112
+ working-directory: /tmp/test-init-project
113
+ run: |
114
+ echo "Checking test file contents..."
115
+
116
+ # Check for .provision usage
117
+ if ! grep -q "\.provision\.chrome" tests/example.test.js; then
118
+ echo "❌ Test does not use .provision.chrome"
119
+ cat tests/example.test.js
120
+ exit 1
121
+ fi
122
+ echo "✓ Test uses .provision.chrome"
123
+
124
+ # Check for TestDriver import
125
+ if ! grep -q "from 'testdriverai/vitest/hooks'" tests/example.test.js; then
126
+ echo "❌ Test does not import from testdriverai/vitest/hooks"
127
+ cat tests/example.test.js
128
+ exit 1
129
+ fi
130
+ echo "✓ Test imports TestDriver from vitest/hooks"
131
+
132
+ - name: Run the generated test
133
+ working-directory: /tmp/test-init-project
134
+ run: npm test
135
+ env:
136
+ TD_API_KEY: ${{ secrets.TD_API_KEY }}
137
+
138
+ - name: Upload test results
139
+ if: always()
140
+ uses: actions/upload-artifact@v4
141
+ with:
142
+ name: test-init-results
143
+ path: /tmp/test-init-project/test-results/
144
+ retention-days: 7
145
+ if-no-files-found: warn
@@ -178,9 +178,9 @@ commands:
178
178
  emitter.emit(events.log.log, generator.jsonToManual(object));
179
179
  response = await commands["focus-application"](object.name);
180
180
  break;
181
- case "remember": {
181
+ case "extract": {
182
182
  emitter.emit(events.log.log, generator.jsonToManual(object));
183
- let value = await commands["remember"](object.description);
183
+ let value = await commands["extract"](object.description);
184
184
  emitter.emit(events.log.log, value);
185
185
  outputsInstance.set(object.output, value);
186
186
  break;
@@ -1276,11 +1276,11 @@ const createCommands = (
1276
1276
  return "The application was focused.";
1277
1277
  },
1278
1278
  /**
1279
- * Extract and remember information from the screen using AI
1279
+ * Extract information from the screen using AI
1280
1280
  * @param {Object|string} options - Options object or description (for backward compatibility)
1281
- * @param {string} options.description - What to remember
1281
+ * @param {string} options.description - What to extract
1282
1282
  */
1283
- "remember": async (...args) => {
1283
+ "extract": async (...args) => {
1284
1284
  const rememberStartTime = Date.now();
1285
1285
  let description;
1286
1286
 
@@ -207,16 +207,16 @@ await testdriver.focusApplication('Google Chrome');
207
207
  ```
208
208
  </CodeGroup>
209
209
 
210
- ### Remember
210
+ ### Extract
211
211
 
212
212
  <CodeGroup>
213
213
  ```yaml YAML
214
- - command: remember
214
+ - command: extract
215
215
  description: the order number
216
216
  ```
217
217
 
218
218
  ```javascript SDK
219
- const orderNumber = await testdriver.remember('the order number');
219
+ const orderNumber = await testdriver.extract('the order number');
220
220
  ```
221
221
  </CodeGroup>
222
222
 
@@ -202,4 +202,4 @@ describe('E-commerce Flow with AI', () => {
202
202
 
203
203
  - [`find()`](/v7/api/find) - Locate specific elements
204
204
  - [`assert()`](/v7/api/assert) - Make assertions
205
- - [`remember()`](/v7/api/remember) - Extract information
205
+ - [`extract()`](/v7/api/extract) - Extract information
@@ -280,6 +280,6 @@ describe('Assertions', () => {
280
280
 
281
281
  ## Related Methods
282
282
 
283
- - [`remember()`](/v7/api/remember) - Extract information for detailed assertions
283
+ - [`extract()`](/v7/api/extract) - Extract information for detailed assertions
284
284
  - [`find()`](/v7/api/find) - Locate elements to verify
285
285
  - [`ai()`](/v7/api/ai) - Complex AI-driven tasks
@@ -77,12 +77,12 @@ await waitForAssertion(testdriver, 'results are displayed', 10000);
77
77
 
78
78
  ## Extracting Information
79
79
 
80
- ### remember()
80
+ ### extract()
81
81
 
82
- Extract and remember information from the screen using AI.
82
+ Extract information from the screen using AI.
83
83
 
84
84
  ```javascript
85
- await testdriver.remember(description)
85
+ await testdriver.extract(description)
86
86
  ```
87
87
 
88
88
  **Parameters:**
@@ -94,17 +94,17 @@ await testdriver.remember(description)
94
94
 
95
95
  ```javascript
96
96
  // Extract text from screen
97
- const password = await testdriver.remember('the password displayed on screen');
98
- const total = await testdriver.remember('the order total amount');
99
- const errorMessage = await testdriver.remember('the error message text');
97
+ const password = await testdriver.extract('the password displayed on screen');
98
+ const total = await testdriver.extract('the order total amount');
99
+ const errorMessage = await testdriver.extract('the error message text');
100
100
 
101
101
  // Extract structured data
102
- const email = await testdriver.remember('the email address in the confirmation');
103
- const orderId = await testdriver.remember('the order ID number');
104
- const phoneNumber = await testdriver.remember('the phone number');
102
+ const email = await testdriver.extract('the email address in the confirmation');
103
+ const orderId = await testdriver.extract('the order ID number');
104
+ const phoneNumber = await testdriver.extract('the phone number');
105
105
 
106
106
  // Use extracted data
107
- const password = await testdriver.remember('the password for standard_user');
107
+ const password = await testdriver.extract('the password for standard_user');
108
108
  const passwordField = await testdriver.find('password input');
109
109
  await passwordField.click();
110
110
  await testdriver.type(password);
@@ -114,8 +114,8 @@ await testdriver.type(password);
114
114
 
115
115
  **Dynamic Content:**
116
116
  ```javascript
117
- // Remember generated values
118
- const confirmationCode = await testdriver.remember('the 6-digit confirmation code');
117
+ // Extract generated values
118
+ const confirmationCode = await testdriver.extract('the 6-digit confirmation code');
119
119
  console.log('Code:', confirmationCode);
120
120
 
121
121
  // Use it later in the test
@@ -125,7 +125,7 @@ await testdriver.type(confirmationCode);
125
125
  **Verification:**
126
126
  ```javascript
127
127
  // Extract and verify
128
- const displayedTotal = await testdriver.remember('the cart total');
128
+ const displayedTotal = await testdriver.extract('the cart total');
129
129
  const expectedTotal = '$99.99';
130
130
 
131
131
  expect(displayedTotal).toBe(expectedTotal);
@@ -134,7 +134,7 @@ expect(displayedTotal).toBe(expectedTotal);
134
134
  **Conditional Logic:**
135
135
  ```javascript
136
136
  // Extract state and make decisions
137
- const status = await testdriver.remember('the order status');
137
+ const status = await testdriver.extract('the order status');
138
138
 
139
139
  if (status.includes('Pending')) {
140
140
  // Wait for processing
@@ -75,7 +75,7 @@ v7/
75
75
  - Basic assertions
76
76
  - Negative assertions (invert parameter)
77
77
  - Async assertions
78
- - `remember()` - Extract information from screen
78
+ - `extract()` - Extract information from screen
79
79
  - Testing patterns:
80
80
  - Polling assertions
81
81
  - Multi-step validation
@@ -143,7 +143,10 @@ class InitCommand extends BaseCommand {
143
143
  },
144
144
  keywords: ["testdriver", "testing", "e2e"],
145
145
  author: "",
146
- license: "ISC"
146
+ license: "ISC",
147
+ engines: {
148
+ node: ">=20.19.0"
149
+ }
147
150
  };
148
151
 
149
152
  fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n");
@@ -159,6 +162,7 @@ class InitCommand extends BaseCommand {
159
162
  async createVitestExample() {
160
163
  const testDir = path.join(process.cwd(), "tests");
161
164
  const testFile = path.join(testDir, "example.test.js");
165
+ const loginSnippetFile = path.join(testDir, "login.js");
162
166
  const configFile = path.join(process.cwd(), "vitest.config.js");
163
167
 
164
168
  // Create test directory if it doesn't exist
@@ -167,23 +171,73 @@ class InitCommand extends BaseCommand {
167
171
  console.log(chalk.gray(` Created directory: ${testDir}`));
168
172
  }
169
173
 
170
- // Create example Vitest test
174
+ // Create login snippet file
175
+ const loginSnippetContent = `/**
176
+ * Login snippet - reusable login function
177
+ *
178
+ * This demonstrates how to create reusable test snippets that can be
179
+ * imported and used across multiple test files.
180
+ */
181
+ export async function login(testdriver) {
182
+
183
+ // The password is displayed on screen, have TestDriver extract it
184
+ const password = await testdriver.extract('the password');
185
+
186
+ // Find the username field
187
+ const usernameField = await testdriver.find(
188
+ 'Username, label above the username input field on the login form'
189
+ );
190
+ await usernameField.click();
191
+
192
+ // Type username
193
+ await testdriver.type('standard_user');
194
+
195
+ // Enter password form earlier
196
+ // Marked as secret so it's not logged or stored
197
+ await testdriver.pressKeys(['tab']);
198
+ await testdriver.type(password, { secret: true });
199
+
200
+ // Submit the form
201
+ await testdriver.find('submit button on the login form').click();
202
+ }
203
+ `;
204
+
205
+ fs.writeFileSync(loginSnippetFile, loginSnippetContent);
206
+ console.log(chalk.green(` Created login snippet: ${loginSnippetFile}`));
207
+
208
+ // Create example Vitest test that uses the login snippet
171
209
  const vitestContent = `import { test, expect } from 'vitest';
172
- import { chrome } from 'testdriverai/presets';
210
+ import { TestDriver } from 'testdriverai/vitest/hooks';
211
+ import { login } from './login.js';
212
+
213
+ test('should login and add item to cart', async (context) => {
214
+
215
+ // Create TestDriver instance - automatically connects to sandbox
216
+ const testdriver = TestDriver(context);
217
+
218
+ // Launch chrome and navigate to demo app
219
+ await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
220
+
221
+ // Use the login snippet to handle authentication
222
+ // This demonstrates how to reuse test logic across multiple tests
223
+ await login(testdriver);
173
224
 
174
- test('should navigate to example.com and find elements', async (context) => {
175
- // The chrome preset handles connection, browser launch, and cleanup automatically
176
- const { testdriver } = await chrome(context, {
177
- url: 'https://example.com'
178
- // apiKey automatically read from process.env.TD_API_KEY via .env file
179
- });
225
+ // Add item to cart
226
+ const addToCartButton = await testdriver.find(
227
+ 'add to cart button under TestDriver Hat'
228
+ );
229
+ await addToCartButton.click();
180
230
 
181
- // Find and verify elements
182
- const heading = await testdriver.find('heading that says Example Domain');
183
- expect(heading.found()).toBe(true);
231
+ // Open cart
232
+ const cartButton = await testdriver.find(
233
+ 'cart button in the top right corner'
234
+ );
235
+ await cartButton.click();
184
236
 
185
- const link = await testdriver.find('More information link');
186
- expect(link.found()).toBe(true);
237
+ // Verify item in cart
238
+ const result = await testdriver.assert('TestDriver Hat is in the cart');
239
+ expect(result).toBeTruthy();
240
+
187
241
  });
188
242
  `;
189
243
 
@@ -194,16 +248,20 @@ test('should navigate to example.com and find elements', async (context) => {
194
248
  if (!fs.existsSync(configFile)) {
195
249
  const configContent = `import { defineConfig } from 'vitest/config';
196
250
  import TestDriver from 'testdriverai/vitest';
197
- import dotenv from 'dotenv';
251
+ import { config } from 'dotenv';
198
252
 
199
253
  // Load environment variables from .env file
200
- dotenv.config();
254
+ config();
201
255
 
202
256
  export default defineConfig({
203
- plugins: [TestDriver()],
204
257
  test: {
205
258
  testTimeout: 300000,
206
259
  hookTimeout: 300000,
260
+ reporters: [
261
+ 'default',
262
+ TestDriver(),
263
+ ],
264
+ setupFiles: ['testdriverai/vitest/setup'],
207
265
  },
208
266
  });
209
267
  `;
@@ -0,0 +1,223 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Test Init Command
5
+ *
6
+ * This script tests the `testdriverai init` command by:
7
+ * 1. Creating a temporary test project
8
+ * 2. Running the init command
9
+ * 3. Verifying all files were created correctly
10
+ * 4. Running the generated test
11
+ * 5. Cleaning up
12
+ *
13
+ * Usage:
14
+ * node manual/test-init-command.js
15
+ *
16
+ * Requirements:
17
+ * - TD_API_KEY environment variable must be set
18
+ */
19
+
20
+ const fs = require('fs');
21
+ const path = require('path');
22
+ const { execSync } = require('child_process');
23
+ const os = require('os');
24
+
25
+ // Colors for terminal output
26
+ const colors = {
27
+ reset: '\x1b[0m',
28
+ green: '\x1b[32m',
29
+ red: '\x1b[31m',
30
+ cyan: '\x1b[36m',
31
+ yellow: '\x1b[33m',
32
+ gray: '\x1b[90m',
33
+ };
34
+
35
+ function log(message, color = 'reset') {
36
+ console.log(`${colors[color]}${message}${colors.reset}`);
37
+ }
38
+
39
+ function success(message) {
40
+ log(`✓ ${message}`, 'green');
41
+ }
42
+
43
+ function error(message) {
44
+ log(`✗ ${message}`, 'red');
45
+ }
46
+
47
+ function info(message) {
48
+ log(message, 'cyan');
49
+ }
50
+
51
+ function step(message) {
52
+ log(`\n${message}`, 'cyan');
53
+ }
54
+
55
+ // Main test function
56
+ async function testInitCommand() {
57
+ // Check for API key
58
+ if (!process.env.TD_API_KEY) {
59
+ error('TD_API_KEY environment variable is required');
60
+ process.exit(1);
61
+ }
62
+
63
+ const testDir = path.join(os.tmpdir(), `test-init-${Date.now()}`);
64
+ const cliPath = path.join(__dirname, '..');
65
+
66
+ try {
67
+ step('📦 Creating test directory...');
68
+ fs.mkdirSync(testDir, { recursive: true });
69
+ success(`Created: ${testDir}`);
70
+
71
+ step('🔧 Setting up .env file...');
72
+ const envContent = `TD_API_KEY=${process.env.TD_API_KEY}\n`;
73
+ fs.writeFileSync(path.join(testDir, '.env'), envContent);
74
+ success('Created .env with API key');
75
+
76
+ step('🚀 Running init command...');
77
+ try {
78
+ execSync(`node ${path.join(cliPath, 'bin/testdriverai.js')} init`, {
79
+ cwd: testDir,
80
+ stdio: 'inherit',
81
+ env: { ...process.env, TD_API_KEY: process.env.TD_API_KEY }
82
+ });
83
+ success('Init command completed');
84
+ } catch (err) {
85
+ error('Init command failed');
86
+ throw err;
87
+ }
88
+
89
+ step('🔍 Verifying project structure...');
90
+
91
+ const expectedFiles = [
92
+ 'package.json',
93
+ 'vitest.config.js',
94
+ 'tests/example.test.js',
95
+ 'tests/login.js',
96
+ '.env',
97
+ '.gitignore',
98
+ '.github/workflows/testdriver.yml'
99
+ ];
100
+
101
+ for (const file of expectedFiles) {
102
+ const filePath = path.join(testDir, file);
103
+ if (!fs.existsSync(filePath)) {
104
+ error(`Missing file: ${file}`);
105
+ throw new Error(`Expected file not found: ${file}`);
106
+ }
107
+ success(`Found: ${file}`);
108
+ }
109
+
110
+ step('📝 Verifying vitest.config.js contents...');
111
+ const vitestConfig = fs.readFileSync(path.join(testDir, 'vitest.config.js'), 'utf8');
112
+
113
+ if (!vitestConfig.includes('TestDriver()')) {
114
+ error('TestDriver reporter not found in vitest.config.js');
115
+ console.log(vitestConfig);
116
+ throw new Error('TestDriver reporter not configured');
117
+ }
118
+ success('TestDriver reporter is configured');
119
+
120
+ if (!vitestConfig.includes('setupFiles') || !vitestConfig.includes('testdriverai/vitest/setup')) {
121
+ error('setupFiles not configured correctly');
122
+ console.log(vitestConfig);
123
+ throw new Error('setupFiles not configured');
124
+ }
125
+ success('setupFiles is configured correctly');
126
+
127
+ if (!vitestConfig.includes('reporters')) {
128
+ error('reporters array not found');
129
+ console.log(vitestConfig);
130
+ throw new Error('reporters not configured');
131
+ }
132
+ success('reporters array includes TestDriver');
133
+
134
+ step('📝 Verifying example test contents...');
135
+ const testFile = fs.readFileSync(path.join(testDir, 'tests/example.test.js'), 'utf8');
136
+
137
+ if (!testFile.includes('.provision.chrome')) {
138
+ error('Test does not use .provision.chrome');
139
+ console.log(testFile);
140
+ throw new Error('Test does not use .provision pattern');
141
+ }
142
+ success('Test uses .provision.chrome');
143
+
144
+ if (!testFile.includes("from 'testdriverai/vitest/hooks'")) {
145
+ error('Test does not import from testdriverai/vitest/hooks');
146
+ console.log(testFile);
147
+ throw new Error('Test does not import TestDriver from vitest/hooks');
148
+ }
149
+ success('Test imports TestDriver from vitest/hooks');
150
+
151
+ if (!testFile.includes("from './login.js'")) {
152
+ error('Test does not import login from ./login.js');
153
+ console.log(testFile);
154
+ throw new Error('Test does not import login snippet');
155
+ }
156
+ success('Test imports login snippet');
157
+
158
+ step('📝 Verifying login snippet contents...');
159
+ const loginFile = fs.readFileSync(path.join(testDir, 'tests/login.js'), 'utf8');
160
+
161
+ if (!loginFile.includes('.extract(')) {
162
+ error('Login snippet does not use .extract()');
163
+ console.log(loginFile);
164
+ throw new Error('Login snippet does not demonstrate .extract()');
165
+ }
166
+ success('Login snippet demonstrates .extract()');
167
+
168
+ if (!loginFile.includes('secret: true')) {
169
+ error('Login snippet does not use secret option');
170
+ console.log(loginFile);
171
+ throw new Error('Login snippet does not demonstrate secret typing');
172
+ }
173
+ success('Login snippet demonstrates secret typing');
174
+
175
+ step('🧪 Running generated test...');
176
+ try {
177
+ execSync('npm test', {
178
+ cwd: testDir,
179
+ stdio: 'inherit',
180
+ env: { ...process.env, TD_API_KEY: process.env.TD_API_KEY }
181
+ });
182
+ success('Test execution completed successfully');
183
+ } catch (err) {
184
+ error('Test execution failed');
185
+ throw err;
186
+ }
187
+
188
+ step('✅ All checks passed!');
189
+ log('\nTest summary:', 'green');
190
+ log(' • Init command executed successfully', 'green');
191
+ log(' • All expected files created', 'green');
192
+ log(' • Configuration files are correct', 'green');
193
+ log(' • Example test has proper patterns', 'green');
194
+ log(' • Generated test runs successfully', 'green');
195
+
196
+ } catch (err) {
197
+ step('❌ Test failed!');
198
+ error(err.message);
199
+ if (err.stack) {
200
+ log(err.stack, 'gray');
201
+ }
202
+ process.exit(1);
203
+ } finally {
204
+ // Optional: Clean up test directory
205
+ // Commented out so you can inspect the generated files
206
+ // step('🧹 Cleaning up...');
207
+ // if (fs.existsSync(testDir)) {
208
+ // fs.rmSync(testDir, { recursive: true, force: true });
209
+ // success('Cleaned up test directory');
210
+ // }
211
+
212
+ info(`\nTest project preserved at: ${testDir}`);
213
+ info('To clean up manually, run:');
214
+ log(` rm -rf ${testDir}`, 'gray');
215
+ }
216
+ }
217
+
218
+ // Run the test
219
+ testInitCommand().catch(err => {
220
+ error('Unexpected error:');
221
+ console.error(err);
222
+ process.exit(1);
223
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "7.1.3",
3
+ "version": "7.1.4",
4
4
  "description": "Next generation autonomous AI agent for end-to-end testing of web & desktop",
5
5
  "main": "sdk.js",
6
6
  "exports": {
@@ -85,7 +85,7 @@
85
85
  },
86
86
  "devDependencies": {
87
87
  "@eslint/js": "^9.10.0",
88
- "@vitest/ui": "^4.0.8",
88
+ "@vitest/ui": "^4.0.15",
89
89
  "chai": "^5.1.2",
90
90
  "esbuild": "0.20.2",
91
91
  "esbuild-plugin-fileloc": "^0.0.6",
package/schema.json CHANGED
@@ -618,7 +618,7 @@
618
618
  }
619
619
  }
620
620
  },
621
- "remember": {
621
+ "extract": {
622
622
  "type": "object",
623
623
  "required": [
624
624
  "description",
@@ -628,7 +628,7 @@
628
628
  "properties": {
629
629
  "command": {
630
630
  "type": "string",
631
- "const": "remember"
631
+ "const": "extract"
632
632
  },
633
633
  "description": {
634
634
  "type": "string"
@@ -783,7 +783,7 @@
783
783
  "scroll-until-text",
784
784
  "scroll-until-image",
785
785
  "focus-application",
786
- "remember",
786
+ "extract",
787
787
  "assert",
788
788
  "exec",
789
789
  "if",
@@ -971,12 +971,12 @@
971
971
  "if": {
972
972
  "properties": {
973
973
  "command": {
974
- "const": "remember"
974
+ "const": "extract"
975
975
  }
976
976
  }
977
977
  },
978
978
  "then": {
979
- "$ref": "#/$defs/commandsAvailable/remember"
979
+ "$ref": "#/$defs/commandsAvailable/extract"
980
980
  }
981
981
  },
982
982
  {
@@ -130,7 +130,7 @@ class SDKLogFormatter {
130
130
  // Validation
131
131
  assert: chalk.green("✅"),
132
132
  verify: chalk.green("🔍"),
133
- remember: chalk.blue("🧠"),
133
+ extract: chalk.blue("🧠"),
134
134
 
135
135
  // System
136
136
  connect: chalk.green("🔌"),
package/sdk.d.ts CHANGED
@@ -433,9 +433,9 @@ export interface FocusApplicationOptions {
433
433
  name: string;
434
434
  }
435
435
 
436
- /** Options for remember command */
437
- export interface RememberOptions {
438
- /** What to remember */
436
+ /** Options for extract command */
437
+ export interface ExtractOptions {
438
+ /** What to extract */
439
439
  description: string;
440
440
  }
441
441
 
@@ -919,15 +919,15 @@ export default class TestDriverSDK {
919
919
  assert(assertion: string, options?: object): Promise<boolean>;
920
920
 
921
921
  /**
922
- * Extract and remember information from the screen using AI
922
+ * Extract information from the screen using AI
923
923
  * @param options - Options object with description
924
924
  */
925
- remember(options: RememberOptions): Promise<string>;
925
+ extract(options: { description: string }): Promise<string>;
926
926
  /**
927
- * Extract and remember information from the screen using AI (positional arguments - legacy)
928
- * @param description - What to remember
927
+ * Extract information from the screen using AI (positional arguments - legacy)
928
+ * @param description - What to extract
929
929
  */
930
- remember(description: string): Promise<string>;
930
+ extract(description: string): Promise<string>;
931
931
 
932
932
  // Code Execution
933
933
 
package/sdk.js CHANGED
@@ -2101,15 +2101,15 @@ class TestDriverSDK {
2101
2101
  */
2102
2102
  doc: "Focus an application by name",
2103
2103
  },
2104
- remember: {
2105
- name: "remember",
2104
+ extract: {
2105
+ name: "extract",
2106
2106
  /**
2107
- * Extract and remember information from the screen using AI
2107
+ * Extract information from the screen using AI
2108
2108
  * @param {Object|string} options - Options object or description (legacy positional)
2109
- * @param {string} options.description - What to remember
2109
+ * @param {string} options.description - What to extract
2110
2110
  * @returns {Promise<string>}
2111
2111
  */
2112
- doc: "Extract and remember information from the screen",
2112
+ doc: "Extract information from the screen",
2113
2113
  },
2114
2114
  assert: {
2115
2115
  name: "assert",
@@ -17,21 +17,18 @@ describe("Hover Text With Description Test", () => {
17
17
  await performLogin(testdriver);
18
18
 
19
19
  // Click on "Add to Cart" under TestDriver Hat
20
- await testdriver.focusApplication("Google Chrome");
21
20
  const addToCartButton = await testdriver.find(
22
21
  "Add to Cart, add to cart button under TestDriver Hat",
23
22
  );
24
23
  await addToCartButton.click();
25
24
 
26
25
  // Click on the cart
27
- await testdriver.focusApplication("Google Chrome");
28
26
  const cartButton = await testdriver.find(
29
27
  "Cart, cart button in the top right corner",
30
28
  );
31
29
  await cartButton.click();
32
30
 
33
31
  // Assert the TestDriver Hat is in the cart
34
- await testdriver.focusApplication("Google Chrome");
35
32
  const result = await testdriver.assert("TestDriver Hat is in the cart");
36
33
  expect(result).toBeTruthy();
37
34
  });