testdriverai 4.2.15 → 4.2.16

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,27 @@
1
+
2
+ name: Test Interp
3
+
4
+ on:
5
+ push:
6
+ branches: ["main"]
7
+ pull_request:
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ run:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: testdriverai/action@main
15
+ with:
16
+ os: windows
17
+ branch: main
18
+ key: ${{secrets.TESTDRIVER_API_KEY}}
19
+ prompt: |
20
+ 1. /run test.yml
21
+ prerun: |
22
+ Start-Process "C:/Program Files/Google/Chrome/Application/chrome.exe" -ArgumentList "--start-maximized", "${{ env.WEBSITE_URL }}"
23
+
24
+ env:
25
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26
+ WEBSITE_URL: "https://kzmgtp9k2gtuuw2iquk2.lite.vusercontent.net/"
27
+ TD_PASSWORD: "passW0rd!"
package/agent.js CHANGED
@@ -205,7 +205,6 @@ if (!commandHistory.length) {
205
205
  }
206
206
 
207
207
  const exit = async (failed = true, shouldSave = false) => {
208
-
209
208
  if (shouldSave) {
210
209
  await save();
211
210
  }
@@ -241,7 +240,7 @@ const haveAIResolveError = async (error, markdown, depth = 0, undo = true) => {
241
240
 
242
241
  logger.error(eMessage);
243
242
 
244
- logger.debug("%j", error);
243
+ logger.debug("%j", error);
245
244
  logger.debug("%s", error.stack);
246
245
 
247
246
  log.prettyMarkdown(eMessage);
@@ -377,7 +376,6 @@ let csv = [["command,time"]];
377
376
 
378
377
  const executeCommands = async (commands, depth, pushToHistory = false) => {
379
378
  if (commands?.length) {
380
-
381
379
  for (const command of commands) {
382
380
  if (pushToHistory) {
383
381
  executionHistory[executionHistory.length - 1]?.commands.push(command);
@@ -454,7 +452,6 @@ const aiExecute = async (message, validateAndLoop = false) => {
454
452
  };
455
453
 
456
454
  const loadYML = async (file) => {
457
-
458
455
  let yml;
459
456
 
460
457
  //wrap this in try/catch so if the file doesn't exist output an error message to the user
@@ -469,7 +466,9 @@ const loadYML = async (file) => {
469
466
  await exit(true);
470
467
  }
471
468
 
472
- let interpolationVars = JSON.parse(process.env["TD_INTERPOLATION_VARS"] || '{}');
469
+ let interpolationVars = JSON.parse(
470
+ process.env["TD_INTERPOLATION_VARS"] || "{}",
471
+ );
473
472
 
474
473
  // Inject environment variables into any ${VAR} strings
475
474
  yml = parser.interpolate(yml, process.env);
@@ -477,7 +476,6 @@ const loadYML = async (file) => {
477
476
  // Inject any vars from the TD_INTERPOLATION_VARS variable (typically from the action)
478
477
  yml = parser.interpolate(yml, interpolationVars);
479
478
 
480
-
481
479
  let ymlObj = null;
482
480
  try {
483
481
  ymlObj = await yaml.load(yml);
@@ -490,8 +488,7 @@ const loadYML = async (file) => {
490
488
  }
491
489
 
492
490
  return ymlObj;
493
-
494
- }
491
+ };
495
492
 
496
493
  const assert = async (expect) => {
497
494
  analytics.track("assert");
@@ -564,7 +561,7 @@ const humanInput = async (currentTask, validateAndLoop = false) => {
564
561
  await save({ silent: true });
565
562
  };
566
563
 
567
- const generate = async (type, count) => {
564
+ const generate = async (type, count, baseYaml, skipYaml = false) => {
568
565
  logger.debug("generate called, %s", type);
569
566
 
570
567
  speak("thinking...");
@@ -573,6 +570,10 @@ const generate = async (type, count) => {
573
570
  logger.info(chalk.dim("thinking..."), true);
574
571
  logger.info("");
575
572
 
573
+ if (baseYaml && !skipYaml) {
574
+ await run(baseYaml, false, false);
575
+ }
576
+
576
577
  let image = await system.captureScreenBase64();
577
578
  const mdStream = log.createMarkdownStreamLogger();
578
579
  let message = await sdk.req(
@@ -613,6 +614,9 @@ const generate = async (type, count) => {
613
614
 
614
615
  let list = testPrompt.listsOrdered[0];
615
616
 
617
+ if (baseYaml && fs.existsSync(baseYaml)) {
618
+ list.unshift(`/run ${baseYaml} --embed`);
619
+ }
616
620
  let contents = list
617
621
  .map((item, index) => `${index + 1}. ${item}`)
618
622
  .join("\n");
@@ -682,7 +686,6 @@ const actOnMarkdown = async (content, depth, pushToHistory = false) => {
682
686
  };
683
687
 
684
688
  const newSession = async () => {
685
-
686
689
  // should be start of new session
687
690
  const sessionRes = await sdk.req("session/start", {
688
691
  systemInformationOsInfo: await system.getSystemInformationOsInfo(),
@@ -691,13 +694,11 @@ const newSession = async () => {
691
694
  });
692
695
 
693
696
  session.set(sessionRes.data.id);
694
-
695
697
  };
696
698
 
697
699
  // simple function to backfill the chat history with a prompt and
698
700
  // then call `promptUser()` to get the user input
699
701
  const firstPrompt = async () => {
700
-
701
702
  await newSession();
702
703
 
703
704
  // readline is what allows us to get user input
@@ -734,7 +735,10 @@ const firstPrompt = async () => {
734
735
 
735
736
  logger.info(""); // adds a nice break between submissions
736
737
 
737
- let commands = input.split(" ");
738
+ let commands = input
739
+ .split(" ")
740
+ .map((l) => l.trim())
741
+ .filter((l) => l.length);
738
742
 
739
743
  // if last character is a question mark, we assume the user is asking a question
740
744
  if (input.indexOf("/summarize") == 0) {
@@ -750,9 +754,41 @@ const firstPrompt = async () => {
750
754
  } else if (input.indexOf("/manual") == 0) {
751
755
  await manualInput(commands.slice(1).join(" "));
752
756
  } else if (input.indexOf("/run") == 0) {
753
- await run(commands[1], commands[2] == "true", commands[3] == "true");
757
+ const file = commands[1];
758
+ const flags = commands.slice(2);
759
+ let shouldSave = flags.includes("--save") ? true : false;
760
+ let shouldExit = flags.includes("--exit") ? true : false;
761
+ let shouldEmbed = flags.includes("--embed") ? true : false;
762
+
763
+ if (shouldEmbed && (shouldSave || shouldExit)) {
764
+ await dieOnFatal({
765
+ message:
766
+ "Cannot embed AND save or exit. Please either use --embed or use any combination of --save and --exit.",
767
+ });
768
+ }
769
+
770
+ if (shouldEmbed) {
771
+ const relativePath = path.relative(
772
+ process.cwd(),
773
+ path.resolve(process.cwd(), file),
774
+ );
775
+
776
+ executionHistory.push({
777
+ prompt: `/run ${relativePath}`,
778
+ commands: [
779
+ {
780
+ command: "run",
781
+ file: relativePath,
782
+ },
783
+ ],
784
+ });
785
+ await embed(file, 0);
786
+ } else {
787
+ await run(file, shouldSave, shouldExit);
788
+ }
754
789
  } else if (input.indexOf("/generate") == 0) {
755
- await generate(commands[1], commands[2]);
790
+ const skipYaml = commands[4] === "--skip-yaml";
791
+ await generate(commands[1], commands[2], commands[3], skipYaml);
756
792
  } else {
757
793
  await humanInput(input, true);
758
794
  }
@@ -884,7 +920,6 @@ let summarize = async (error = null) => {
884
920
 
885
921
  // this function is responsible for saving the regression test script to a file
886
922
  let save = async ({ filepath = thisFile, silent = false } = {}) => {
887
-
888
923
  analytics.track("save", { silent });
889
924
 
890
925
  if (!silent) {
@@ -925,7 +960,6 @@ ${regression}
925
960
  // it parses the markdown file and executes the codeblocks exactly as if they were
926
961
  // generated by the AI in a single prompt
927
962
  let run = async (file, shouldSave = false, shouldExit = true) => {
928
-
929
963
  await newSession();
930
964
 
931
965
  setTerminalWindowTransparency(true);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "4.2.15",
3
+ "version": "4.2.16",
4
4
  "description": "Next generation autonomous AI agent for end-to-end testing of web & desktop",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -38,7 +38,7 @@
38
38
  "odiff-bin": "^3.1.2",
39
39
  "prompts": "^2.4.2",
40
40
  "remark-parse": "^11.0.0",
41
- "testdriverai-robotjs": "^0.6.0",
41
+ "robotjs": "npm:@hurdlegroup/robotjs",
42
42
  "sanitize-filename": "^1.6.3",
43
43
  "say": "^0.16.0",
44
44
  "screenshot-desktop": "^1.15.0",
@@ -51,7 +51,8 @@
51
51
  },
52
52
  "overrides": {
53
53
  "glob": "^11.0.1",
54
- "rimraf": "^5.0.10"
54
+ "rimraf": "^5.0.10",
55
+ "robotjs": "npm:@hurdlegroup/robotjs"
55
56
  },
56
57
  "devDependencies": {
57
58
  "@eslint/js": "^9.10.0",
package/test.yml ADDED
@@ -0,0 +1,18 @@
1
+ version: 4.1.40
2
+ steps:
3
+ - prompt: Enter Password n stuff
4
+ commands:
5
+ - command: focus-application
6
+ name: Google Chrome
7
+ - command: hover-text
8
+ text: Username
9
+ description: username field
10
+ action: click
11
+ - command: type
12
+ text: ${TD_PASSWORD}
13
+ - command: hover-text
14
+ text: Password
15
+ description: Password field
16
+ action: click
17
+ - command: type
18
+ text: ${TD_PASSWORD}