testdriverai 6.0.16-canary.e337e67.0 → 6.0.16-canary.f0eefe0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/agent/events.js CHANGED
@@ -33,7 +33,6 @@ const events = {
33
33
  vm: {
34
34
  show: "vm:show",
35
35
  },
36
- narration: "narration",
37
36
  status: "status",
38
37
  log: {
39
38
  markdown: {
@@ -45,6 +44,7 @@ const events = {
45
44
  log: "log:log",
46
45
  warn: "log:warn",
47
46
  debug: "log:debug",
47
+ narration: "log:narration",
48
48
  },
49
49
  command: {
50
50
  start: "command:start",
package/agent/index.js CHANGED
@@ -158,7 +158,7 @@ class TestDriverAgent extends EventEmitter2 {
158
158
  // single function to handle all program exits
159
159
  // allows us to save the current state, run lifecycle hooks, and track analytics
160
160
  async exit(failed = true, shouldSave = false, shouldRunPostrun = false) {
161
- this.emitter.emit(events.log.log, theme.dim("exiting..."), true);
161
+ this.emitter.emit(events.log.narration, theme.dim("exiting..."), true);
162
162
 
163
163
  // Clean up redraw interval
164
164
  if (this.redraw && this.redraw.cleanup) {
@@ -192,7 +192,7 @@ class TestDriverAgent extends EventEmitter2 {
192
192
 
193
193
  // fatal errors always exit the program
194
194
  // this ensure we log the error, summarize it, and exit cleanly
195
- async dieOnFatal(error) {
195
+ async dieOnFatal(error, skipPostrun = false) {
196
196
  // Show error with source context if available
197
197
  const errorContext = this.sourceMapper.getErrorWithSourceContext(error);
198
198
  if (errorContext) {
@@ -204,9 +204,13 @@ class TestDriverAgent extends EventEmitter2 {
204
204
  );
205
205
  }
206
206
 
207
- await this.summarize(error.message);
208
- // Always run postrun lifecycle script, even for fatal errors
209
- return await this.exit(true, false, true);
207
+ if (skipPostrun) {
208
+ this.exit(true);
209
+ } else {
210
+ await this.summarize(error.message);
211
+ // Always run postrun lifecycle script, even for fatal errors
212
+ return await this.exit(true, false, true);
213
+ }
210
214
  }
211
215
 
212
216
  // creates a new "thread" in which the AI is given an error
@@ -286,7 +290,7 @@ class TestDriverAgent extends EventEmitter2 {
286
290
  image = null;
287
291
  }
288
292
 
289
- this.emitter.emit(events.log.log, theme.dim("thinking..."), true);
293
+ this.emitter.emit(events.log.narration, theme.dim("thinking..."), true);
290
294
 
291
295
  const streamId = `error-${Date.now()}`;
292
296
  this.emitter.emit(events.log.markdown.start, streamId);
@@ -328,14 +332,14 @@ class TestDriverAgent extends EventEmitter2 {
328
332
 
329
333
  if (this.checkCount >= this.checkLimit) {
330
334
  this.emitter.emit(
331
- events.log.log,
335
+ events.log.narration,
332
336
  theme.red("Exploratory loop detected. Exiting."),
333
337
  );
334
338
  await this.summarize("Check loop detected.");
335
339
  return await this.exit(true);
336
340
  }
337
341
 
338
- this.emitter.emit(events.log.log, theme.dim("checking..."));
342
+ this.emitter.emit(events.log.narration, theme.dim("checking..."));
339
343
 
340
344
  // check asks the ai if the task is complete
341
345
  let thisScreenshot = await this.system.captureScreenBase64(1, false, true);
@@ -579,8 +583,6 @@ class TestDriverAgent extends EventEmitter2 {
579
583
  "check thinks more needs to be done",
580
584
  );
581
585
 
582
- this.emitter.emit(events.log.log, theme.dim("not done yet!"));
583
-
584
586
  return await this.aiExecute(response, validateAndLoop);
585
587
  } else {
586
588
  this.emitter.emit(events.log.debug, "seems complete, returning");
@@ -715,7 +717,7 @@ class TestDriverAgent extends EventEmitter2 {
715
717
  }
716
718
  }
717
719
 
718
- this.emitter.emit(events.log.log, theme.dim("thinking..."), true);
720
+ this.emitter.emit(events.log.narration, theme.dim("thinking..."), true);
719
721
 
720
722
  let response = `\`\`\`yaml
721
723
  commands:
@@ -743,7 +745,7 @@ commands:
743
745
 
744
746
  this.tasks.push(currentTask);
745
747
 
746
- this.emitter.emit(events.log.log, theme.dim("thinking..."), true);
748
+ this.emitter.emit(events.log.narration, theme.dim("thinking..."), true);
747
749
 
748
750
  this.lastScreenshot = await this.system.captureScreenBase64();
749
751
 
@@ -785,7 +787,7 @@ commands:
785
787
  async generate(type, count, baseYaml, skipYaml = false) {
786
788
  this.emitter.emit(events.log.debug, "generate called, %s", type);
787
789
 
788
- this.emitter.emit(events.log.log, theme.dim("thinking..."), true);
790
+ this.emitter.emit(events.log.narration, theme.dim("thinking..."), true);
789
791
 
790
792
  if (baseYaml && !skipYaml) {
791
793
  await this.runLifecycle("prerun");
@@ -862,7 +864,7 @@ commands:
862
864
 
863
865
  // this is the functinoality for "undo"
864
866
  async popFromHistory(fullStep) {
865
- this.emitter.emit(events.log.log, theme.dim("undoing..."), true);
867
+ this.emitter.emit(events.log.narration, theme.dim("undoing..."), true);
866
868
 
867
869
  if (this.executionHistory.length) {
868
870
  if (fullStep) {
@@ -942,12 +944,16 @@ ${yml}
942
944
  async summarize(error = null) {
943
945
  this.analytics.track("summarize");
944
946
 
945
- this.emitter.emit(events.log.log, theme.dim("reviewing test..."), true);
947
+ this.emitter.emit(
948
+ events.log.narration,
949
+ theme.dim("reviewing test..."),
950
+ true,
951
+ );
946
952
 
947
953
  // let text = prompts.summarize(tasks, error);
948
954
  let image = await this.system.captureScreenBase64();
949
955
 
950
- this.emitter.emit(events.log.log, theme.dim("summarizing..."), true);
956
+ this.emitter.emit(events.log.narration, theme.dim("summarizing..."), true);
951
957
 
952
958
  const streamId = `summarize-${Date.now()}`;
953
959
  this.emitter.emit(events.log.markdown.start, streamId);
@@ -1120,7 +1126,7 @@ ${regression}
1120
1126
  timestamp: fileStartTime,
1121
1127
  });
1122
1128
 
1123
- this.emitter.emit(events.log.log, theme.cyan(`running ${file}...`));
1129
+ this.emitter.emit(events.log.narration, theme.cyan(`running ${file}...`));
1124
1130
 
1125
1131
  let ymlObj = await this.loadYML(file);
1126
1132
 
@@ -1512,8 +1518,8 @@ ${regression}
1512
1518
  if (this.sandboxId && !this.config.CI && !createNew) {
1513
1519
  // Attempt to connect to known instance
1514
1520
  this.emitter.emit(
1515
- events.log.log,
1516
- theme.dim(`- connecting to sandbox ${this.sandboxId}...`),
1521
+ events.log.narration,
1522
+ theme.dim(`connecting to sandbox ${this.sandboxId}...`),
1517
1523
  );
1518
1524
 
1519
1525
  try {
@@ -1535,17 +1541,20 @@ ${regression}
1535
1541
  }
1536
1542
  }
1537
1543
 
1538
- this.emitter.emit(events.log.log, theme.dim(`- creating new sandbox...`));
1544
+ this.emitter.emit(
1545
+ events.log.narration,
1546
+ theme.dim(`creating new sandbox...`),
1547
+ );
1539
1548
  this.emitter.emit(
1540
1549
  events.log.log,
1541
- theme.dim(` (this can take between 10 - 240 seconds)`),
1550
+ theme.dim(`this can take between 10 - 240 seconds`),
1542
1551
  );
1543
1552
  // We don't have resiliency/retries baked in, so let's at least give it 1 attempt
1544
1553
  // to see if that fixes the issue.
1545
1554
  let newSandbox = await this.createNewSandbox().catch(() => {
1546
1555
  this.emitter.emit(
1547
- events.log.log,
1548
- theme.dim(` (double-checking sandbox availability)`),
1556
+ events.log.narration,
1557
+ theme.dim(`double-checking sandbox availability`),
1549
1558
  );
1550
1559
 
1551
1560
  return this.createNewSandbox();
@@ -1572,7 +1581,7 @@ ${regression}
1572
1581
  if (!debuggerStarted) {
1573
1582
  debuggerStarted = true; // Prevent multiple starts, especially when running test in parallel
1574
1583
  this.emitter.emit(
1575
- events.log.log,
1584
+ events.log.narration,
1576
1585
  theme.green(`Starting debugger server...`),
1577
1586
  );
1578
1587
  debuggerProcess = await createDebuggerProcess(
@@ -1584,9 +1593,12 @@ ${regression}
1584
1593
  this.emitter.emit(events.log.log, `This is beta software!`);
1585
1594
  this.emitter.emit(
1586
1595
  events.log.log,
1587
- theme.yellow(`Join our Forums for help`),
1596
+ theme.yellow(`Join our Discord for help`),
1597
+ );
1598
+ this.emitter.emit(
1599
+ events.log.log,
1600
+ `https://discord.com/invite/cWDFW8DzPm`,
1588
1601
  );
1589
- this.emitter.emit(events.log.log, `https://forums.testdriver.ai`);
1590
1602
 
1591
1603
  // make testdriver directory if it doesn't exist
1592
1604
  let testdriverFolder = path.join(this.workingDir);
@@ -1690,16 +1702,33 @@ ${regression}
1690
1702
 
1691
1703
  async connectToSandboxService() {
1692
1704
  this.emitter.emit(
1693
- events.log.log,
1694
- theme.gray(`- establishing connection...`),
1705
+ events.log.narration,
1706
+ theme.dim(`establishing connection...`),
1695
1707
  );
1696
- await this.sandbox.boot(this.config.TD_API_ROOT);
1697
- this.emitter.emit(events.log.log, theme.gray(`- authenticating...`));
1698
- await this.sandbox.auth(this.config.TD_API_KEY);
1708
+ let ableToBoot = await this.sandbox.boot(this.config.TD_API_ROOT);
1709
+
1710
+ if (!ableToBoot) {
1711
+ return await this.dieOnFatal(
1712
+ `Unable to connect to TestDriver sandbox service at ${this.config.TD_API_ROOT}.
1713
+ Please check your network connection, TD_API_KEY, or the service status.`,
1714
+ true,
1715
+ );
1716
+ }
1717
+
1718
+ this.emitter.emit(events.log.narration, theme.dim(`authenticating...`));
1719
+ let ableToAuth = await this.sandbox.auth(this.config.TD_API_KEY);
1720
+
1721
+ if (!ableToAuth) {
1722
+ return await this.dieOnFatal(
1723
+ `Unable to authorize with TestDriver sandbox service at ${this.config.TD_API_ROOT}.
1724
+ Please check your network connection, TD_API_KEY, or the service status.`,
1725
+ true,
1726
+ );
1727
+ }
1699
1728
  }
1700
1729
 
1701
1730
  async connectToSandboxDirect(sandboxId, persist = false) {
1702
- this.emitter.emit(events.log.log, theme.gray(`- connecting...`));
1731
+ this.emitter.emit(events.log.narration, theme.dim(`connecting...`));
1703
1732
  let instance = await this.sandbox.connect(sandboxId, persist);
1704
1733
  return instance;
1705
1734
  }
@@ -80,20 +80,20 @@ commands:
80
80
  // this will actually interpret the command and execute it
81
81
  switch (object.command) {
82
82
  case "type":
83
- emitter.emit(events.narration, `typing ${object.text}`);
83
+ emitter.emit(events.log.narration, `typing ${object.text}`);
84
84
  emitter.emit(events.log.log, generator.jsonToManual(object));
85
85
  response = await commands.type(object.text, object.delay);
86
86
  break;
87
87
  case "press-keys":
88
88
  emitter.emit(
89
- events.narration,
89
+ events.log.narration,
90
90
  `pressing keys ${object.keys.join(",")}`,
91
91
  );
92
92
  emitter.emit(events.log.log, generator.jsonToManual(object));
93
93
  response = await commands["press-keys"](object.keys);
94
94
  break;
95
95
  case "scroll":
96
- emitter.emit(events.narration, `scrolling ${object.direction}`);
96
+ emitter.emit(events.log.narration, `scrolling ${object.direction}`);
97
97
  emitter.emit(events.log.log, generator.jsonToManual(object));
98
98
  response = await commands.scroll(
99
99
  object.direction,
@@ -102,17 +102,20 @@ commands:
102
102
  );
103
103
  break;
104
104
  case "wait":
105
- emitter.emit(events.narration, `waiting ${object.timeout} seconds`);
105
+ emitter.emit(
106
+ events.log.narration,
107
+ `waiting ${object.timeout} seconds`,
108
+ );
106
109
  emitter.emit(events.log.log, generator.jsonToManual(object));
107
110
  response = await commands.wait(object.timeout);
108
111
  break;
109
112
  case "click":
110
- emitter.emit(events.narration, `${object.action}`);
113
+ emitter.emit(events.log.narration, `${object.action}`);
111
114
  emitter.emit(events.log.log, generator.jsonToManual(object));
112
115
  response = await commands["click"](object.x, object.y, object.action);
113
116
  break;
114
117
  case "hover":
115
- emitter.emit(events.narration, `moving mouse`);
118
+ emitter.emit(events.log.narration, `moving mouse`);
116
119
  emitter.emit(events.log.log, generator.jsonToManual(object));
117
120
  response = await commands["hover"](object.x, object.y);
118
121
  break;
@@ -121,7 +124,10 @@ commands:
121
124
  response = await commands["drag"](object.x, object.y);
122
125
  break;
123
126
  case "hover-text":
124
- emitter.emit(events.narration, `searching for ${object.description}`);
127
+ emitter.emit(
128
+ events.log.narration,
129
+ `searching for ${object.description}`,
130
+ );
125
131
  emitter.emit(events.log.log, generator.jsonToManual(object));
126
132
  response = await commands["hover-text"](
127
133
  object.text,
@@ -132,7 +138,7 @@ commands:
132
138
  break;
133
139
  case "hover-image":
134
140
  emitter.emit(
135
- events.narration,
141
+ events.log.narration,
136
142
  `searching for image of ${object.description}`,
137
143
  );
138
144
  emitter.emit(events.log.log, generator.jsonToManual(object));
@@ -144,13 +150,16 @@ commands:
144
150
  case "match-image":
145
151
  emitter.emit(events.log.log, generator.jsonToManual(object));
146
152
  emitter.emit(
147
- events.narration,
153
+ events.log.narration,
148
154
  `${object.action} image ${object.path}`,
149
155
  );
150
156
  response = await commands["match-image"](object.path, object.action);
151
157
  break;
152
158
  case "wait-for-image":
153
- emitter.emit(events.narration, `waiting for ${object.description}`);
159
+ emitter.emit(
160
+ events.log.narration,
161
+ `waiting for ${object.description}`,
162
+ );
154
163
  emitter.emit(events.log.log, generator.jsonToManual(object));
155
164
  response = await commands["wait-for-image"](
156
165
  object.description,
@@ -158,7 +167,7 @@ commands:
158
167
  );
159
168
  break;
160
169
  case "wait-for-text":
161
- emitter.emit(events.narration, `waiting for ${object.text}`);
170
+ emitter.emit(events.log.narration, `waiting for ${object.text}`);
162
171
  emitter.emit(events.log.log, generator.jsonToManual(object));
163
172
  copy.text = "*****";
164
173
  response = await commands["wait-for-text"](
@@ -168,7 +177,7 @@ commands:
168
177
  );
169
178
  break;
170
179
  case "scroll-until-text":
171
- emitter.emit(events.narration, `scrolling until ${object.text}`);
180
+ emitter.emit(events.log.narration, `scrolling until ${object.text}`);
172
181
  emitter.emit(events.log.log, generator.jsonToManual(object));
173
182
  copy.text = "*****";
174
183
  response = await commands["scroll-until-text"](
@@ -181,7 +190,7 @@ commands:
181
190
  break;
182
191
  case "scroll-until-image": {
183
192
  const needle = object.description || object.path;
184
- emitter.emit(events.narration, `scrolling until ${needle}`);
193
+ emitter.emit(events.log.narration, `scrolling until ${needle}`);
185
194
  emitter.emit(events.log.log, generator.jsonToManual(object));
186
195
  response = await commands["scroll-until-image"](
187
196
  object.description,
@@ -193,7 +202,7 @@ commands:
193
202
  break;
194
203
  }
195
204
  case "focus-application":
196
- emitter.emit(events.narration, `focusing ${object.name}`);
205
+ emitter.emit(events.log.narration, `focusing ${object.name}`);
197
206
  emitter.emit(events.log.log, generator.jsonToManual(object));
198
207
  response = await commands["focus-application"](object.name);
199
208
  break;
@@ -205,12 +214,12 @@ commands:
205
214
  break;
206
215
  }
207
216
  case "assert":
208
- emitter.emit(events.narration, `asserting ${object.expect}`);
217
+ emitter.emit(events.log.narration, `asserting ${object.expect}`);
209
218
  emitter.emit(events.log.log, generator.jsonToManual(object));
210
219
  response = await commands.assert(object.expect, object.async);
211
220
  break;
212
221
  case "exec":
213
- emitter.emit(events.narration, `exec`);
222
+ emitter.emit(events.log.narration, `exec`);
214
223
  emitter.emit(
215
224
  events.log.log,
216
225
  generator.jsonToManual({
@@ -190,7 +190,7 @@ const createCommands = (
190
190
  }
191
191
  };
192
192
 
193
- emitter.emit(events.log.log, `thinking...`);
193
+ emitter.emit(events.log.narration, `thinking...`);
194
194
 
195
195
  if (async) {
196
196
  await sdk
@@ -276,7 +276,7 @@ const createCommands = (
276
276
  }
277
277
 
278
278
  emitter.emit(
279
- "log:debug",
279
+ events.log.narration,
280
280
  theme.dim(`${action} ${button} clicking at ${x}, ${y}...`),
281
281
  true,
282
282
  );
@@ -347,7 +347,7 @@ const createCommands = (
347
347
 
348
348
  description = description ? description.toString() : null;
349
349
 
350
- emitter.emit(events.log.log, theme.dim("thinking..."), true);
350
+ emitter.emit(events.log.narration, theme.dim("thinking..."), true);
351
351
 
352
352
  let response = await sdk.req(
353
353
  "hover/text",
@@ -375,7 +375,7 @@ const createCommands = (
375
375
  // uses our api to find all images on screen
376
376
  "hover-image": async (description, action = "click") => {
377
377
  // take a screenshot
378
- emitter.emit(events.log.log, theme.dim("thinking..."), true);
378
+ emitter.emit(events.log.narration, theme.dim("thinking..."), true);
379
379
 
380
380
  let response = await sdk.req(
381
381
  "hover/image",
@@ -446,7 +446,7 @@ const createCommands = (
446
446
  },
447
447
  "wait-for-image": async (description, timeout = 10000) => {
448
448
  emitter.emit(
449
- events.log.log,
449
+ events.log.narration,
450
450
  theme.dim(
451
451
  `waiting for an image matching description "${description}"...`,
452
452
  ),
@@ -467,7 +467,7 @@ const createCommands = (
467
467
  durationPassed = new Date().getTime() - startTime;
468
468
  if (!passed) {
469
469
  emitter.emit(
470
- events.log.log,
470
+ events.log.narration,
471
471
  theme.dim(
472
472
  `${niceSeconds(durationPassed)} seconds have passed without finding an image matching the description "${description}"`,
473
473
  ),
@@ -479,7 +479,7 @@ const createCommands = (
479
479
 
480
480
  if (passed) {
481
481
  emitter.emit(
482
- events.log.log,
482
+ events.log.narration,
483
483
  theme.dim(
484
484
  `An image matching the description "${description}" found!`,
485
485
  ),
@@ -496,7 +496,7 @@ const createCommands = (
496
496
  await redraw.start();
497
497
 
498
498
  emitter.emit(
499
- events.log.log,
499
+ events.log.narration,
500
500
  theme.dim(`waiting for text: "${text}"...`),
501
501
  true,
502
502
  );
@@ -525,7 +525,7 @@ const createCommands = (
525
525
  durationPassed = new Date().getTime() - startTime;
526
526
  if (!passed) {
527
527
  emitter.emit(
528
- events.log.log,
528
+ events.log.narration,
529
529
  theme.dim(
530
530
  `${niceSeconds(durationPassed)} seconds have passed without finding "${text}"`,
531
531
  ),
@@ -536,7 +536,7 @@ const createCommands = (
536
536
  }
537
537
 
538
538
  if (passed) {
539
- emitter.emit(events.log.log, theme.dim(`"${text}" found!`), true);
539
+ emitter.emit(events.log.narration, theme.dim(`"${text}" found!`), true);
540
540
  return;
541
541
  } else {
542
542
  throw new MatchError(
@@ -554,7 +554,7 @@ const createCommands = (
554
554
  await redraw.start();
555
555
 
556
556
  emitter.emit(
557
- events.log.log,
557
+ events.log.narration,
558
558
  theme.dim(`scrolling for text: "${text}"...`),
559
559
  true,
560
560
  );
@@ -598,7 +598,7 @@ const createCommands = (
598
598
  passed = response.data;
599
599
  if (!passed) {
600
600
  emitter.emit(
601
- events.log.log,
601
+ events.log.narration,
602
602
  theme.dim(
603
603
  `scrolling ${direction} ${incrementDistance}px. ${scrollDistance + incrementDistance}/${maxDistance}px scrolled...`,
604
604
  ),
@@ -610,7 +610,7 @@ const createCommands = (
610
610
  }
611
611
 
612
612
  if (passed) {
613
- emitter.emit(events.log.log, theme.dim(`"${text}" found!`), true);
613
+ emitter.emit(events.log.narration, theme.dim(`"${text}" found!`), true);
614
614
  return;
615
615
  } else {
616
616
  throw new MatchError(
@@ -638,7 +638,7 @@ const createCommands = (
638
638
  }
639
639
 
640
640
  emitter.emit(
641
- events.log.log,
641
+ events.log.narration,
642
642
  theme.dim(`scrolling for an image matching "${needle}"...`),
643
643
  true,
644
644
  );
@@ -665,7 +665,7 @@ const createCommands = (
665
665
 
666
666
  if (!passed) {
667
667
  emitter.emit(
668
- events.log.log,
668
+ events.log.narration,
669
669
  theme.dim(`scrolling ${direction} ${incrementDistance} pixels...`),
670
670
  true,
671
671
  );
@@ -675,7 +675,11 @@ const createCommands = (
675
675
  }
676
676
 
677
677
  if (passed) {
678
- emitter.emit(events.log.log, theme.dim(`"${needle}" found!`), true);
678
+ emitter.emit(
679
+ events.log.narration,
680
+ theme.dim(`"${needle}" found!`),
681
+ true,
682
+ );
679
683
  return;
680
684
  } else {
681
685
  throw new CommandError(
@@ -705,7 +709,7 @@ const createCommands = (
705
709
  return await assert(assertion, true, async);
706
710
  },
707
711
  exec: async (language, code, timeout, silent = false) => {
708
- emitter.emit(events.log.log, theme.dim(`calling exec...`), true);
712
+ emitter.emit(events.log.narration, theme.dim(`calling exec...`), true);
709
713
 
710
714
  emitter.emit(events.log.log, code);
711
715
 
@@ -738,10 +742,10 @@ const createCommands = (
738
742
  return result.out?.stdout?.trim();
739
743
  }
740
744
  } else if (language == "js") {
741
- emitter.emit(events.log.log, theme.dim(`running js...`), true);
745
+ emitter.emit(events.log.narration, theme.dim(`running js...`), true);
742
746
 
743
747
  emitter.emit(
744
- events.log.log,
748
+ events.log.narration,
745
749
  theme.dim(`running value of \`${plat}\` in local JS vm...`),
746
750
  true,
747
751
  );
@@ -84,10 +84,6 @@ const createSandbox = (emitter, analytics) => {
84
84
  this.socket.on("close", () => {
85
85
  clearInterval(this.heartbeat);
86
86
  // Emit a clear error event for API key issues
87
- emitter.emit(events.error.fatal, {
88
- message: "Socket closed. Check your API KEY (TD_API_KEY)",
89
- code: "API_KEY_MISSING_OR_INVALID",
90
- });
91
87
  reject();
92
88
  this.apiSocketConnected = false;
93
89
  });
package/docs/docs.json CHANGED
@@ -220,8 +220,8 @@
220
220
  "href": "https://github.com/testdriverai/testdriverai"
221
221
  },
222
222
  {
223
- "label": "Forums",
224
- "href": "https://forums.testdriver.ai"
223
+ "label": "Discord",
224
+ "href": "https://discord.com/invite/cWDFW8DzPm"
225
225
  },
226
226
  {
227
227
  "label": "Report an Issue",
@@ -13,6 +13,7 @@ When executing the `hover-image` and `hover-text` command, TestDriver may use th
13
13
 
14
14
  TestDriver may not accurately locate matches in certain cases. This can lead to unexpected behavior when using the `hover-image` or `hover-text` command. For example, if you specify a description that's too generic or similar to other images on the screen, TestDriver may not be able to identify the correct image to interact with. To improve accuracy, use specific and unique descriptions for images and text.
15
15
  When executing the `hover-image` and `hover-text` commands, TestDriver uses the provided description to identify the target image or text. If the description is too generic or matches multiple elements on the screen, TestDriver may not be able to determine which one to interact with, leading to unexpected behavior. To improve accuracy, always use specific and unique descriptions for both images and text.
16
+
16
17
  ### Avoid using `hover-text` for single characters (ex: `1`, `>`, `|`)
17
18
 
18
19
  To improve accuracy of our model, we do not include single characters or symbols in the matching data. This means that `hover-text` may not work as expected for these cases. If you need to interact with single characters or symbols, consider using the `match-image` command with a screenshot of the target element instead.
@@ -29,14 +30,14 @@ Assertions use the current state of the page to determine if the step passes or
29
30
 
30
31
  ## Reporting issues
31
32
 
32
- If you encounter any issues while using TestDriver, please report them to us. You can do this by creating a new issue in the [Feedback Forum](https://forums.testdriver.ai/c/feedback/10). We appreciate your feedback and will work to resolve any problems as quickly as possible.
33
+ If you encounter any issues while using TestDriver, please report them to us. You can do this by creating a new issue in the [discord](https://discord.com/invite/cWDFW8DzPm). We appreciate your feedback and will work to resolve any problems as quickly as possible.
33
34
 
34
35
  <Card
35
36
  title="Report an Issue"
36
37
  icon="arrow-turn-down-right"
37
38
  iconType="duotone"
38
39
  horizontal
39
- href="https://forums.testdriver.ai/c/feedback/10"
40
+ href="https://discord.com/invite/cWDFW8DzPm"
40
41
  >
41
42
  We'd love to hear from you!
42
43
  </Card>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "6.0.16-canary.e337e67.0",
3
+ "version": "6.0.16-canary.f0eefe0.0",
4
4
  "description": "Next generation autonomous AI agent for end-to-end testing of web & desktop",
5
5
  "main": "index.js",
6
6
  "bin": {
package/curl.sh DELETED
@@ -1,13 +0,0 @@
1
- curl -X POST "https://forums.testdriver.ai/users" \
2
- -H "Content-Type: application/json" \
3
- -H "Api-Key: YOUR_ADMIN_API_KEY" \
4
- -H "Api-Username: admin" \
5
- -d '{
6
- "name": "Jane Doe",
7
- "email": "jane.doe@example.com",
8
- "username": "janedoe",
9
- "active": false,
10
- "approved": true,
11
- "email_verified": false,
12
- "staged": false
13
- }'
package/debug-ast.js DELETED
@@ -1,38 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const yamlAst = require("@stoplight/yaml-ast-parser");
4
- const yaml = require("js-yaml");
5
- const fs = require("fs");
6
-
7
- function debugAST() {
8
- const testFile =
9
- "/Users/ianjennings/Development/testdriverai/test-source-mapping.yaml";
10
- const yamlContent = fs.readFileSync(testFile, "utf-8");
11
-
12
- console.log("YAML Content:");
13
- console.log(yamlContent);
14
- console.log("\n" + "=".repeat(50) + "\n");
15
-
16
- const ast = yamlAst.load(yamlContent);
17
-
18
- console.log("AST Structure:");
19
- console.log(
20
- JSON.stringify(
21
- ast,
22
- (key, value) => {
23
- if (key === "parent") return "[parent]"; // Avoid circular reference
24
- return value;
25
- },
26
- 2,
27
- ),
28
- );
29
-
30
- console.log("\n" + "=".repeat(50) + "\n");
31
-
32
- // Test with js-yaml for comparison
33
- const yamlObj = yaml.load(yamlContent);
34
- console.log("js-yaml result:");
35
- console.log(JSON.stringify(yamlObj, null, 2));
36
- }
37
-
38
- debugAST();