testdriverai 7.8.0-test.3 → 7.8.0-test.30
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/CHANGELOG.md +25 -0
- package/agent/index.js +6 -5
- package/agent/lib/commands.js +3 -2
- package/agent/lib/http.js +144 -0
- package/agent/lib/sandbox.js +117 -102
- package/agent/lib/sdk.js +4 -2
- package/agent/lib/system.js +25 -65
- package/ai/skills/testdriver-cache/SKILL.md +221 -0
- package/ai/skills/testdriver-captcha/SKILL.md +0 -1
- package/ai/skills/testdriver-errors/SKILL.md +246 -0
- package/ai/skills/testdriver-events/SKILL.md +356 -0
- package/ai/skills/testdriver-exec/SKILL.md +13 -24
- package/ai/skills/testdriver-mcp/SKILL.md +7 -0
- package/ai/skills/testdriver-provision/SKILL.md +331 -0
- package/ai/skills/testdriver-quickstart/SKILL.md +1 -1
- package/ai/skills/testdriver-redraw/SKILL.md +214 -0
- package/ai/skills/testdriver-running-tests/SKILL.md +1 -1
- package/ai/skills/testdriver-screenshots/SKILL.md +184 -0
- package/docs/changelog.mdx +155 -3
- package/docs/docs.json +44 -37
- package/docs/images/content/vscode/v7-chat.png +0 -0
- package/docs/images/content/vscode/v7-choose-agent.png +0 -0
- package/docs/images/content/vscode/v7-full.png +0 -0
- package/docs/images/content/vscode/v7-onboarding.png +0 -0
- package/docs/v7/cache.mdx +223 -0
- package/docs/v7/captcha.mdx +0 -1
- package/docs/v7/copilot/auto-healing.mdx +265 -0
- package/docs/v7/copilot/creating-tests.mdx +156 -0
- package/docs/v7/copilot/github.mdx +143 -0
- package/docs/v7/copilot/running-tests.mdx +149 -0
- package/docs/v7/copilot/setup.mdx +143 -0
- package/docs/v7/enterprise.mdx +3 -110
- package/docs/v7/errors.mdx +248 -0
- package/docs/v7/events.mdx +358 -0
- package/docs/v7/examples/exec-output.mdx +85 -0
- package/docs/v7/examples/exec-pwsh.mdx +83 -0
- package/docs/v7/examples/focus-window.mdx +62 -0
- package/docs/v7/{cloud.mdx → hosted.mdx} +43 -5
- package/docs/v7/mcp.mdx +9 -0
- package/docs/v7/provision.mdx +333 -0
- package/docs/v7/quickstart.mdx +30 -2
- package/docs/v7/redraw.mdx +216 -0
- package/docs/v7/running-tests.mdx +1 -1
- package/docs/v7/screenshots.mdx +186 -0
- package/docs/v7/self-hosted.mdx +127 -44
- package/interfaces/logger.js +0 -12
- package/interfaces/vitest-plugin.mjs +3 -0
- package/lib/core/Dashcam.js +13 -16
- package/lib/environments.json +18 -0
- package/lib/resolve-channel.js +4 -3
- package/{examples → manual}/drag-and-drop.test.mjs +1 -1
- package/package.json +3 -3
- package/sdk.js +3 -3
- package/vitest.config.mjs +20 -32
- /package/{examples → manual}/flake-diffthreshold-001.test.mjs +0 -0
- /package/{examples → manual}/flake-diffthreshold-01.test.mjs +0 -0
- /package/{examples → manual}/flake-diffthreshold-05.test.mjs +0 -0
- /package/{examples → manual}/flake-noredraw-cache.test.mjs +0 -0
- /package/{examples → manual}/flake-noredraw-nocache.test.mjs +0 -0
- /package/{examples → manual}/flake-redraw-cache.test.mjs +0 -0
- /package/{examples → manual}/flake-redraw-nocache.test.mjs +0 -0
- /package/{examples → manual}/flake-rocket-match.test.mjs +0 -0
- /package/{examples → manual}/flake-shared.mjs +0 -0
- /package/{examples → manual}/no-provision.test.mjs +0 -0
- /package/{examples → manual}/scroll-until-text.test.mjs +0 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testdriver:events
|
|
3
|
+
description: Listen to SDK lifecycle events with wildcard support
|
|
4
|
+
---
|
|
5
|
+
<!-- Generated from events.mdx. DO NOT EDIT. -->
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
TestDriver uses [EventEmitter2](https://github.com/EventEmitter2/EventEmitter2) for its event system. Events use a colon-delimited namespace pattern and support wildcard listeners.
|
|
10
|
+
|
|
11
|
+
Access the emitter through `testdriver.emitter`:
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
testdriver.emitter.on('command:start', (data) => {
|
|
15
|
+
console.log(`Running: ${data.command}`);
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Configuration
|
|
20
|
+
|
|
21
|
+
The internal emitter is created with:
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
new EventEmitter2({
|
|
25
|
+
wildcard: true,
|
|
26
|
+
delimiter: ':',
|
|
27
|
+
maxListeners: 20,
|
|
28
|
+
verboseMemoryLeak: false,
|
|
29
|
+
ignoreErrors: false,
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Wildcard Listeners
|
|
34
|
+
|
|
35
|
+
Use `*` to match a single level or `**` to match multiple levels:
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
// Match all log events
|
|
39
|
+
testdriver.emitter.on('log:*', (message) => {
|
|
40
|
+
console.log(message);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Match all events in any namespace
|
|
44
|
+
testdriver.emitter.on('**', (...args) => {
|
|
45
|
+
console.log('Event:', this.event, args);
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Event Reference
|
|
50
|
+
|
|
51
|
+
### Command Events
|
|
52
|
+
|
|
53
|
+
Emitted during the execution of SDK commands (`click`, `type`, `find`, etc.).
|
|
54
|
+
|
|
55
|
+
| Event | Payload |
|
|
56
|
+
|---|---|
|
|
57
|
+
| `command:start` | `{ command, depth, data, timestamp, sourcePosition }` |
|
|
58
|
+
| `command:success` | `{ command, depth, data, duration, response, timestamp, sourcePosition }` |
|
|
59
|
+
| `command:error` | `{ command, depth, data, error, duration, timestamp, sourcePosition }` |
|
|
60
|
+
| `command:status` | `{ command, status: "executing", data, depth, timestamp }` |
|
|
61
|
+
| `command:progress` | `{ command, status: "completed", timing, data, depth, timestamp }` |
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
testdriver.emitter.on('command:start', ({ command, data }) => {
|
|
65
|
+
console.log(`Starting ${command}`, data);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
testdriver.emitter.on('command:error', ({ command, error, duration }) => {
|
|
69
|
+
console.error(`${command} failed after ${duration}ms: ${error}`);
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Step Events
|
|
74
|
+
|
|
75
|
+
Emitted for each AI reasoning step within a command.
|
|
76
|
+
|
|
77
|
+
| Event | Payload |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `step:start` | `{ stepIndex, prompt, commandCount, timestamp, sourcePosition }` |
|
|
80
|
+
| `step:success` | `{ stepIndex, prompt, commandCount, duration, timestamp, sourcePosition }` |
|
|
81
|
+
| `step:error` | `{ stepIndex, prompt, error, duration?, timestamp, sourcePosition? }` |
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
testdriver.emitter.on('step:start', ({ stepIndex, prompt }) => {
|
|
85
|
+
console.log(`Step ${stepIndex}: ${prompt}`);
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Test Events
|
|
90
|
+
|
|
91
|
+
Emitted when a test file execution starts.
|
|
92
|
+
|
|
93
|
+
| Event | Payload |
|
|
94
|
+
|---|---|
|
|
95
|
+
| `test:start` | `{ filePath, timestamp }` |
|
|
96
|
+
| `test:success` | *Emitted on test completion* |
|
|
97
|
+
| `test:error` | *Emitted on test failure* |
|
|
98
|
+
|
|
99
|
+
### Log Events
|
|
100
|
+
|
|
101
|
+
Emitted for all log output from the SDK.
|
|
102
|
+
|
|
103
|
+
| Event | Payload |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `log:log` | `(message: string)` — general log message |
|
|
106
|
+
| `log:warn` | `(message: string)` — warning message |
|
|
107
|
+
| `log:debug` | `(message: string)` — debug output (only when `VERBOSE`/`DEBUG`/`TD_DEBUG` env set) |
|
|
108
|
+
| `log:info` | `(message: string)` — informational message |
|
|
109
|
+
| `log:error` | `(message: string)` — error message |
|
|
110
|
+
| `log:narration` | `(message: string, overwrite?: boolean)` — in-place status line |
|
|
111
|
+
| `log:markdown` | `(markdown: string)` — full static markdown content |
|
|
112
|
+
| `log:markdown:start` | `(streamId: string)` — begin streaming markdown |
|
|
113
|
+
| `log:markdown:chunk` | `(streamId: string, chunk: string)` — incremental chunk |
|
|
114
|
+
| `log:markdown:end` | `(streamId: string)` — end streaming markdown |
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
// Capture all logs
|
|
118
|
+
testdriver.emitter.on('log:*', function (message) {
|
|
119
|
+
console.log(`[${this.event}]`, message);
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Screen Capture Events
|
|
124
|
+
|
|
125
|
+
Emitted during screenshot capture.
|
|
126
|
+
|
|
127
|
+
| Event | Payload |
|
|
128
|
+
|---|---|
|
|
129
|
+
| `screen-capture:start` | `{ scale, silent, display }` |
|
|
130
|
+
| `screen-capture:end` | `{ scale, silent, display }` |
|
|
131
|
+
| `screen-capture:error` | `{ error, scale, silent, display }` |
|
|
132
|
+
|
|
133
|
+
### Sandbox Events
|
|
134
|
+
|
|
135
|
+
Emitted for sandbox WebSocket lifecycle and communication.
|
|
136
|
+
|
|
137
|
+
| Event | Payload |
|
|
138
|
+
|---|---|
|
|
139
|
+
| `sandbox:connected` | *No payload* — WebSocket connection established |
|
|
140
|
+
| `sandbox:authenticated` | `{ traceId }` — authentication successful |
|
|
141
|
+
| `sandbox:error` | `(err: Error \| string)` — connection or sandbox error |
|
|
142
|
+
| `sandbox:sent` | `(message: object)` — WebSocket message sent |
|
|
143
|
+
| `sandbox:received` | *No payload* — successful message reply received |
|
|
144
|
+
| `sandbox:progress` | `{ step, message }` — sandbox setup progress |
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
testdriver.emitter.on('sandbox:connected', () => {
|
|
148
|
+
console.log('Connected to sandbox');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
testdriver.emitter.on('sandbox:progress', ({ step, message }) => {
|
|
152
|
+
console.log(`Sandbox: [${step}] ${message}`);
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Redraw Events
|
|
157
|
+
|
|
158
|
+
Emitted during screen stability detection. See [Redraw](/v7/redraw) for more details.
|
|
159
|
+
|
|
160
|
+
| Event | Payload |
|
|
161
|
+
|---|---|
|
|
162
|
+
| `redraw:status` | `{ redraw: { enabled, settled, hasChangedFromInitial, consecutiveFramesStable, diffFromInitial, diffFromLast, text }, network: { enabled, settled, rxBytes, txBytes, text }, timeout: { isTimeout, elapsed, max, text } }` |
|
|
163
|
+
| `redraw:complete` | `{ screenSettled, hasChangedFromInitial, consecutiveFramesStable, networkSettled, isTimeout, timeElapsed }` |
|
|
164
|
+
|
|
165
|
+
```javascript
|
|
166
|
+
testdriver.emitter.on('redraw:complete', (result) => {
|
|
167
|
+
if (result.isTimeout) {
|
|
168
|
+
console.warn('Redraw timed out after', result.timeElapsed, 'ms');
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### File Events
|
|
174
|
+
|
|
175
|
+
Emitted during file load/save operations in the agent.
|
|
176
|
+
|
|
177
|
+
| Event | Payload |
|
|
178
|
+
|---|---|
|
|
179
|
+
| `file:start` | `{ operation: "load" \| "save" \| "run", filePath, timestamp }` |
|
|
180
|
+
| `file:stop` | `{ operation, filePath, duration, success, sourceMap?, reason?, timestamp }` |
|
|
181
|
+
| `file:load` | `{ filePath, size, timestamp }` |
|
|
182
|
+
| `file:save` | `{ filePath, size, timestamp }` |
|
|
183
|
+
| `file:diff` | `{ filePath, diff: { patches, sourceMaps, summary: { additions, deletions, modifications } }, timestamp }` |
|
|
184
|
+
| `file:error` | `{ operation, filePath, error, duration?, timestamp }` |
|
|
185
|
+
|
|
186
|
+
### Error Events
|
|
187
|
+
|
|
188
|
+
Emitted for errors at various severity levels.
|
|
189
|
+
|
|
190
|
+
| Event | Payload |
|
|
191
|
+
|---|---|
|
|
192
|
+
| `error:fatal` | `(error: string \| Error)` — terminates the process |
|
|
193
|
+
| `error:general` | `(message: string)` — non-fatal error |
|
|
194
|
+
| `error:sandbox` | `(err: Error \| string)` — sandbox/WebSocket error |
|
|
195
|
+
|
|
196
|
+
```javascript
|
|
197
|
+
testdriver.emitter.on('error:*', function (err) {
|
|
198
|
+
console.error(`[${this.event}]`, err);
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### SDK Events
|
|
203
|
+
|
|
204
|
+
Emitted for API request lifecycle.
|
|
205
|
+
|
|
206
|
+
| Event | Payload |
|
|
207
|
+
|---|---|
|
|
208
|
+
| `sdk:request` | `{ path }` — outgoing API request |
|
|
209
|
+
| `sdk:response` | `{ path }` — API response received |
|
|
210
|
+
| `sdk:retry` | `{ path, attempt, error, delayMs }` — request retry |
|
|
211
|
+
|
|
212
|
+
### Other Events
|
|
213
|
+
|
|
214
|
+
| Event | Payload |
|
|
215
|
+
|---|---|
|
|
216
|
+
| `exit` | `(exitCode: number)` — `0` for success, `1` for failure |
|
|
217
|
+
| `status` | `(message: string)` — general status updates |
|
|
218
|
+
| `mouse-click` | `{ x, y, button, click, double }` — mouse click performed |
|
|
219
|
+
| `terminal:stdout` | Terminal stdout output |
|
|
220
|
+
| `terminal:stderr` | Terminal stderr output |
|
|
221
|
+
|
|
222
|
+
## Practical Examples
|
|
223
|
+
|
|
224
|
+
### Custom Test Reporter
|
|
225
|
+
|
|
226
|
+
```javascript
|
|
227
|
+
const results = [];
|
|
228
|
+
|
|
229
|
+
testdriver.emitter.on('command:success', ({ command, duration }) => {
|
|
230
|
+
results.push({ command, duration, status: 'pass' });
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
testdriver.emitter.on('command:error', ({ command, duration, error }) => {
|
|
234
|
+
results.push({ command, duration, status: 'fail', error });
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// After test completes
|
|
238
|
+
afterAll(() => {
|
|
239
|
+
console.table(results);
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Progress Monitoring
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
testdriver.emitter.on('step:start', ({ stepIndex, prompt }) => {
|
|
247
|
+
process.stdout.write(`\r Step ${stepIndex}: ${prompt}`);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
testdriver.emitter.on('command:progress', ({ command, timing }) => {
|
|
251
|
+
process.stdout.write(`\r ${command} completed in ${timing}ms`);
|
|
252
|
+
});
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Debug Logging
|
|
256
|
+
|
|
257
|
+
```javascript
|
|
258
|
+
// Log every event (verbose)
|
|
259
|
+
testdriver.emitter.on('**', function (...args) {
|
|
260
|
+
console.debug(`[EVENT] ${this.event}`, ...args);
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Types
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
interface CommandStartEvent {
|
|
268
|
+
command: string;
|
|
269
|
+
depth: number;
|
|
270
|
+
data: Record<string, any>;
|
|
271
|
+
timestamp: number;
|
|
272
|
+
sourcePosition: SourcePosition;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
interface CommandSuccessEvent {
|
|
276
|
+
command: string;
|
|
277
|
+
depth: number;
|
|
278
|
+
data: Record<string, any>;
|
|
279
|
+
duration: number;
|
|
280
|
+
response: any;
|
|
281
|
+
timestamp: number;
|
|
282
|
+
sourcePosition: SourcePosition;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
interface CommandErrorEvent {
|
|
286
|
+
command: string;
|
|
287
|
+
depth: number;
|
|
288
|
+
data: Record<string, any>;
|
|
289
|
+
error: string;
|
|
290
|
+
duration: number;
|
|
291
|
+
timestamp: number;
|
|
292
|
+
sourcePosition: SourcePosition;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
interface StepStartEvent {
|
|
296
|
+
stepIndex: number;
|
|
297
|
+
prompt: string;
|
|
298
|
+
commandCount: number;
|
|
299
|
+
timestamp: number;
|
|
300
|
+
sourcePosition: SourcePosition;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
interface StepSuccessEvent {
|
|
304
|
+
stepIndex: number;
|
|
305
|
+
prompt: string;
|
|
306
|
+
commandCount: number;
|
|
307
|
+
duration: number;
|
|
308
|
+
timestamp: number;
|
|
309
|
+
sourcePosition: SourcePosition;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
interface RedrawStatusEvent {
|
|
313
|
+
redraw: {
|
|
314
|
+
enabled: boolean;
|
|
315
|
+
settled: boolean;
|
|
316
|
+
hasChangedFromInitial: boolean;
|
|
317
|
+
consecutiveFramesStable: number;
|
|
318
|
+
diffFromInitial: number;
|
|
319
|
+
diffFromLast: number;
|
|
320
|
+
text: string;
|
|
321
|
+
};
|
|
322
|
+
network: {
|
|
323
|
+
enabled: boolean;
|
|
324
|
+
settled: boolean;
|
|
325
|
+
rxBytes: number;
|
|
326
|
+
txBytes: number;
|
|
327
|
+
text: string;
|
|
328
|
+
};
|
|
329
|
+
timeout: {
|
|
330
|
+
isTimeout: boolean;
|
|
331
|
+
elapsed: number;
|
|
332
|
+
max: number;
|
|
333
|
+
text: string;
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
interface RedrawCompleteEvent {
|
|
338
|
+
screenSettled: boolean;
|
|
339
|
+
hasChangedFromInitial: boolean;
|
|
340
|
+
consecutiveFramesStable: number;
|
|
341
|
+
networkSettled: boolean;
|
|
342
|
+
isTimeout: boolean;
|
|
343
|
+
timeElapsed: number;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
interface SandboxProgressEvent {
|
|
347
|
+
step: string;
|
|
348
|
+
message: string;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
interface SourcePosition {
|
|
352
|
+
file: string;
|
|
353
|
+
line: number;
|
|
354
|
+
column: number;
|
|
355
|
+
}
|
|
356
|
+
```
|
|
@@ -198,7 +198,7 @@ await testdriver.exec('pwsh', '.\\setup.ps1', 60000, true);
|
|
|
198
198
|
|
|
199
199
|
```javascript
|
|
200
200
|
// Quick operations: 5000ms
|
|
201
|
-
await testdriver.exec('
|
|
201
|
+
await testdriver.exec('sh', 'ls -la', 5000);
|
|
202
202
|
|
|
203
203
|
// Installations: 30000-60000ms
|
|
204
204
|
await testdriver.exec('pwsh', 'npm install -g package', 30000);
|
|
@@ -271,27 +271,20 @@ describe('Code Execution', () => {
|
|
|
271
271
|
await testdriver.disconnect();
|
|
272
272
|
});
|
|
273
273
|
|
|
274
|
-
it('should execute
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const title = await testdriver.exec('js', 'document.title', 5000);
|
|
279
|
-
console.log('Page title:', title);
|
|
280
|
-
|
|
281
|
-
// Manipulate DOM
|
|
282
|
-
await testdriver.exec('js', `
|
|
283
|
-
document.querySelector('#username').value = 'testuser';
|
|
284
|
-
`, 5000);
|
|
274
|
+
it('should execute shell commands on Linux', async () => {
|
|
275
|
+
// List directory
|
|
276
|
+
const files = await testdriver.exec('sh', 'ls -la', 5000);
|
|
277
|
+
console.log('Files:', files);
|
|
285
278
|
|
|
286
|
-
//
|
|
287
|
-
|
|
288
|
-
document.querySelector('#username').value
|
|
289
|
-
`, 5000);
|
|
279
|
+
// Create a file
|
|
280
|
+
await testdriver.exec('sh', 'echo "Hello World" > test.txt', 5000);
|
|
290
281
|
|
|
291
|
-
|
|
282
|
+
// Read the file
|
|
283
|
+
const content = await testdriver.exec('sh', 'cat test.txt', 5000);
|
|
284
|
+
expect(content).toContain('Hello World');
|
|
292
285
|
});
|
|
293
286
|
|
|
294
|
-
it('should install and use tools', async () => {
|
|
287
|
+
it('should install and use tools on Windows', async () => {
|
|
295
288
|
// Install tool
|
|
296
289
|
await testdriver.exec('pwsh', 'npm install -g http-server', 30000, true);
|
|
297
290
|
|
|
@@ -313,10 +306,6 @@ describe('Code Execution', () => {
|
|
|
313
306
|
`, 5000);
|
|
314
307
|
|
|
315
308
|
await testdriver.focusApplication('Google Chrome');
|
|
316
|
-
|
|
317
|
-
// Verify page loaded
|
|
318
|
-
const content = await testdriver.exec('js', 'document.body.textContent', 5000);
|
|
319
|
-
expect(content).toContain('Test Page');
|
|
320
309
|
});
|
|
321
310
|
});
|
|
322
311
|
```
|
|
@@ -324,5 +313,5 @@ describe('Code Execution', () => {
|
|
|
324
313
|
## Related Methods
|
|
325
314
|
|
|
326
315
|
- [`focusApplication()`](/v7/focus-application) - Focus apps before exec
|
|
327
|
-
- [`find()`](/v7/find) - Locate elements
|
|
328
|
-
- [`type()`](/v7/type) - Type text
|
|
316
|
+
- [`find()`](/v7/find) - Locate elements visually
|
|
317
|
+
- [`type()`](/v7/type) - Type text into inputs
|