tauri-test-cli 0.5.2 → 0.6.1

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/dist/cli.js CHANGED
@@ -102311,8 +102311,11 @@ var init_esm11 = __esm(() => {
102311
102311
  };
102312
102312
  });
102313
102313
 
102314
+ // src/cli.ts
102315
+ import { resolve } from "path";
102316
+
102314
102317
  // src/driver.ts
102315
- import { spawn } from "child_process";
102318
+ import { spawn, execSync } from "child_process";
102316
102319
 
102317
102320
  // node_modules/webdriverio/build/node.js
102318
102321
  var import_jszip = __toESM(require_lib3(), 1);
@@ -120571,17 +120574,78 @@ import { homedir } from "os";
120571
120574
  import { join } from "path";
120572
120575
  var driverProcess = null;
120573
120576
  var browser = null;
120577
+ var exitHandlerRegistered = false;
120574
120578
  var DRIVER_PORT = 4444;
120575
120579
  var DRIVER_HOST = "127.0.0.1";
120580
+ function getDescendantPids(pid) {
120581
+ try {
120582
+ const children2 = execSync(`pgrep -P ${pid} 2>/dev/null`, { encoding: "utf8" }).trim().split(`
120583
+ `).filter(Boolean).map(Number);
120584
+ const descendants = [];
120585
+ for (const child of children2) {
120586
+ descendants.push(child, ...getDescendantPids(child));
120587
+ }
120588
+ return descendants;
120589
+ } catch {
120590
+ return [];
120591
+ }
120592
+ }
120593
+ function killProcessTree(pid, signal = "SIGKILL") {
120594
+ const descendants = getDescendantPids(pid);
120595
+ for (const child of descendants.reverse()) {
120596
+ try {
120597
+ process.kill(child, signal);
120598
+ } catch {}
120599
+ }
120600
+ try {
120601
+ process.kill(pid, signal);
120602
+ } catch {}
120603
+ }
120604
+ function forceKillDriver() {
120605
+ if (driverProcess?.pid) {
120606
+ killProcessTree(driverProcess.pid);
120607
+ driverProcess = null;
120608
+ }
120609
+ }
120610
+ function killStaleDriver() {
120611
+ let killed = false;
120612
+ for (const port of [DRIVER_PORT, DRIVER_PORT + 1]) {
120613
+ try {
120614
+ const pids = execSync(`lsof -ti:${port} 2>/dev/null`, { encoding: "utf8" }).trim();
120615
+ if (pids) {
120616
+ for (const pidStr of pids.split(`
120617
+ `)) {
120618
+ const pid = parseInt(pidStr);
120619
+ if (pid) {
120620
+ killProcessTree(pid);
120621
+ killed = true;
120622
+ }
120623
+ }
120624
+ }
120625
+ } catch {}
120626
+ }
120627
+ if (killed) {
120628
+ execSync("sleep 0.5");
120629
+ }
120630
+ }
120576
120631
  async function startDriver() {
120577
120632
  if (driverProcess) {
120578
120633
  return;
120579
120634
  }
120635
+ killStaleDriver();
120580
120636
  const tauriDriverPath = join(homedir(), ".cargo", "bin", "tauri-driver");
120581
120637
  return new Promise((resolve, reject) => {
120582
- driverProcess = spawn(tauriDriverPath, [], {
120583
- stdio: ["ignore", "pipe", "pipe"]
120638
+ driverProcess = spawn("setsid", [
120639
+ "sh",
120640
+ "-c",
120641
+ `"${tauriDriverPath}" & PID=$!; trap "kill 0 2>/dev/null" EXIT; read; exit`
120642
+ ], {
120643
+ stdio: ["pipe", "pipe", "pipe"]
120584
120644
  });
120645
+ if (!exitHandlerRegistered) {
120646
+ exitHandlerRegistered = true;
120647
+ process.on("exit", forceKillDriver);
120648
+ }
120585
120649
  driverProcess.on("error", (err) => {
120586
120650
  reject(new Error(`Failed to start tauri-driver: ${err.message}`));
120587
120651
  });
@@ -120602,8 +120666,8 @@ async function startDriver() {
120602
120666
  });
120603
120667
  }
120604
120668
  function stopDriver() {
120605
- if (driverProcess) {
120606
- driverProcess.kill();
120669
+ if (driverProcess?.pid) {
120670
+ killProcessTree(driverProcess.pid);
120607
120671
  driverProcess = null;
120608
120672
  }
120609
120673
  }
@@ -120653,22 +120717,83 @@ async function disconnect() {
120653
120717
  import { writeFile } from "fs/promises";
120654
120718
 
120655
120719
  // src/driver.ts
120656
- import { spawn as spawn2 } from "child_process";
120720
+ import { spawn as spawn2, execSync as execSync2 } from "child_process";
120657
120721
  import { homedir as homedir2 } from "os";
120658
120722
  import { join as join2 } from "path";
120659
120723
  var driverProcess2 = null;
120660
120724
  var browser2 = null;
120725
+ var exitHandlerRegistered2 = false;
120661
120726
  var DRIVER_PORT2 = 4444;
120662
120727
  var DRIVER_HOST2 = "127.0.0.1";
120728
+ function getDescendantPids2(pid) {
120729
+ try {
120730
+ const children2 = execSync2(`pgrep -P ${pid} 2>/dev/null`, { encoding: "utf8" }).trim().split(`
120731
+ `).filter(Boolean).map(Number);
120732
+ const descendants = [];
120733
+ for (const child of children2) {
120734
+ descendants.push(child, ...getDescendantPids2(child));
120735
+ }
120736
+ return descendants;
120737
+ } catch {
120738
+ return [];
120739
+ }
120740
+ }
120741
+ function killProcessTree2(pid, signal = "SIGKILL") {
120742
+ const descendants = getDescendantPids2(pid);
120743
+ for (const child of descendants.reverse()) {
120744
+ try {
120745
+ process.kill(child, signal);
120746
+ } catch {}
120747
+ }
120748
+ try {
120749
+ process.kill(pid, signal);
120750
+ } catch {}
120751
+ }
120752
+ function forceKillDriver2() {
120753
+ if (driverProcess2?.pid) {
120754
+ killProcessTree2(driverProcess2.pid);
120755
+ driverProcess2 = null;
120756
+ }
120757
+ }
120758
+ function killStaleDriver2() {
120759
+ let killed = false;
120760
+ for (const port of [DRIVER_PORT2, DRIVER_PORT2 + 1]) {
120761
+ try {
120762
+ const pids = execSync2(`lsof -ti:${port} 2>/dev/null`, { encoding: "utf8" }).trim();
120763
+ if (pids) {
120764
+ for (const pidStr of pids.split(`
120765
+ `)) {
120766
+ const pid = parseInt(pidStr);
120767
+ if (pid) {
120768
+ killProcessTree2(pid);
120769
+ killed = true;
120770
+ }
120771
+ }
120772
+ }
120773
+ } catch {}
120774
+ }
120775
+ if (killed) {
120776
+ execSync2("sleep 0.5");
120777
+ }
120778
+ }
120663
120779
  async function startDriver2() {
120664
120780
  if (driverProcess2) {
120665
120781
  return;
120666
120782
  }
120783
+ killStaleDriver2();
120667
120784
  const tauriDriverPath = join2(homedir2(), ".cargo", "bin", "tauri-driver");
120668
120785
  return new Promise((resolve, reject) => {
120669
- driverProcess2 = spawn2(tauriDriverPath, [], {
120670
- stdio: ["ignore", "pipe", "pipe"]
120786
+ driverProcess2 = spawn2("setsid", [
120787
+ "sh",
120788
+ "-c",
120789
+ `"${tauriDriverPath}" & PID=$!; trap "kill 0 2>/dev/null" EXIT; read; exit`
120790
+ ], {
120791
+ stdio: ["pipe", "pipe", "pipe"]
120671
120792
  });
120793
+ if (!exitHandlerRegistered2) {
120794
+ exitHandlerRegistered2 = true;
120795
+ process.on("exit", forceKillDriver2);
120796
+ }
120672
120797
  driverProcess2.on("error", (err) => {
120673
120798
  reject(new Error(`Failed to start tauri-driver: ${err.message}`));
120674
120799
  });
@@ -120688,12 +120813,6 @@ async function startDriver2() {
120688
120813
  setTimeout(() => resolve(), 1000);
120689
120814
  });
120690
120815
  }
120691
- function stopDriver2() {
120692
- if (driverProcess2) {
120693
- driverProcess2.kill();
120694
- driverProcess2 = null;
120695
- }
120696
- }
120697
120816
  async function waitForPageLoad2(browser3, timeout = 1e4) {
120698
120817
  const start = Date.now();
120699
120818
  while (Date.now() - start < timeout) {
@@ -120731,13 +120850,6 @@ async function connect2(options) {
120731
120850
  function getBrowser() {
120732
120851
  return browser2;
120733
120852
  }
120734
- async function disconnect2() {
120735
- if (browser2) {
120736
- await browser2.deleteSession();
120737
- browser2 = null;
120738
- }
120739
- stopDriver2();
120740
- }
120741
120853
  function requireBrowser() {
120742
120854
  if (!browser2) {
120743
120855
  throw new Error("Not connected. Run 'tauri-test-cli connect' first.");
@@ -121158,6 +121270,7 @@ async function evaluate(script) {
121158
121270
 
121159
121271
  // src/server.ts
121160
121272
  import { createServer } from "http";
121273
+ import { readFileSync } from "fs";
121161
121274
 
121162
121275
  // src/commands/screenshot.ts
121163
121276
  import { writeFile as writeFile3 } from "fs/promises";
@@ -121675,12 +121788,10 @@ async function shutdown() {
121675
121788
  return;
121676
121789
  isShuttingDown = true;
121677
121790
  console.error("Shutting down...");
121791
+ forceKillDriver2();
121678
121792
  if (serverInstance) {
121679
121793
  serverInstance.close();
121680
121794
  }
121681
- try {
121682
- await disconnect2();
121683
- } catch {}
121684
121795
  process.exit(0);
121685
121796
  }
121686
121797
  async function injectKeepAlive() {
@@ -121714,6 +121825,36 @@ async function startServer(options) {
121714
121825
  const { port, appPath, waitTimeout, autoWait } = options;
121715
121826
  process.on("SIGINT", shutdown);
121716
121827
  process.on("SIGTERM", shutdown);
121828
+ const getAncestorPids = () => {
121829
+ const pids = [];
121830
+ let pid = process.pid;
121831
+ while (pid > 1) {
121832
+ try {
121833
+ const stat = readFileSync(`/proc/${pid}/stat`, "utf8");
121834
+ const ppid = parseInt(stat.split(") ")[1].split(" ")[1]);
121835
+ if (ppid <= 1)
121836
+ break;
121837
+ pids.push(ppid);
121838
+ pid = ppid;
121839
+ } catch {
121840
+ break;
121841
+ }
121842
+ }
121843
+ return pids;
121844
+ };
121845
+ const ancestorPids = getAncestorPids();
121846
+ if (ancestorPids.length > 0) {
121847
+ setInterval(() => {
121848
+ for (const pid of ancestorPids) {
121849
+ try {
121850
+ process.kill(pid, 0);
121851
+ } catch {
121852
+ shutdown();
121853
+ return;
121854
+ }
121855
+ }
121856
+ }, 500);
121857
+ }
121717
121858
  console.error(`Launching app and waiting for load (timeout: ${waitTimeout}ms)...`);
121718
121859
  await connect2({ appPath, waitTimeout });
121719
121860
  console.error("App loaded successfully.");
@@ -121740,7 +121881,7 @@ async function startServer(options) {
121740
121881
  }
121741
121882
 
121742
121883
  // src/checks.ts
121743
- import { execSync } from "child_process";
121884
+ import { execSync as execSync3 } from "child_process";
121744
121885
  import os4 from "os";
121745
121886
  var reset = "\x1B[0m";
121746
121887
  var bold = "\x1B[1m";
@@ -121751,7 +121892,7 @@ var dim = "\x1B[2m";
121751
121892
  function commandExists(cmd) {
121752
121893
  try {
121753
121894
  const checkCmd = os4.platform() === "win32" ? `where ${cmd} 2>nul` : `which ${cmd} 2>/dev/null`;
121754
- execSync(checkCmd, { stdio: "ignore" });
121895
+ execSync3(checkCmd, { stdio: "ignore" });
121755
121896
  return true;
121756
121897
  } catch {
121757
121898
  return false;
@@ -121759,7 +121900,7 @@ function commandExists(cmd) {
121759
121900
  }
121760
121901
  function pkgConfigExists(pkg) {
121761
121902
  try {
121762
- execSync(`pkg-config --modversion ${pkg}`, { stdio: "ignore" });
121903
+ execSync3(`pkg-config --modversion ${pkg}`, { stdio: "ignore" });
121763
121904
  return true;
121764
121905
  } catch {
121765
121906
  return false;
@@ -121848,7 +121989,7 @@ function printDependencyStatus() {
121848
121989
  }
121849
121990
 
121850
121991
  // src/commands/utils.ts
121851
- import { execSync as execSync2, spawn as spawn3 } from "child_process";
121992
+ import { execSync as execSync4, spawn as spawn3 } from "child_process";
121852
121993
  import os5 from "os";
121853
121994
  var reset2 = "\x1B[0m";
121854
121995
  var bold2 = "\x1B[1m";
@@ -121862,7 +122003,7 @@ async function setup() {
121862
122003
  console.log();
121863
122004
  try {
121864
122005
  try {
121865
- execSync2("cargo --version", { stdio: "ignore" });
122006
+ execSync4("cargo --version", { stdio: "ignore" });
121866
122007
  } catch {
121867
122008
  return {
121868
122009
  success: false,
@@ -121925,7 +122066,7 @@ async function cleanup() {
121925
122066
  if (platform === "win32") {
121926
122067
  for (const pattern of processPatterns) {
121927
122068
  try {
121928
- execSync2(`taskkill /F /IM ${pattern}.exe 2>nul`, { stdio: "ignore" });
122069
+ execSync4(`taskkill /F /IM ${pattern}.exe 2>nul`, { stdio: "ignore" });
121929
122070
  killed.push(pattern);
121930
122071
  console.log(` ${green2}✓${reset2} Killed ${pattern}`);
121931
122072
  } catch {
@@ -121935,7 +122076,7 @@ async function cleanup() {
121935
122076
  } else {
121936
122077
  for (const pattern of processPatterns) {
121937
122078
  try {
121938
- execSync2(`pkill -f "${pattern}"`, { stdio: "ignore" });
122079
+ execSync4(`pkill -f "${pattern}"`, { stdio: "ignore" });
121939
122080
  killed.push(pattern);
121940
122081
  console.log(` ${green2}✓${reset2} Killed ${pattern}`);
121941
122082
  } catch {
@@ -121956,7 +122097,7 @@ function checkXvfb() {
121956
122097
  return false;
121957
122098
  }
121958
122099
  try {
121959
- execSync2("which Xvfb", { stdio: "ignore" });
122100
+ execSync4("which Xvfb", { stdio: "ignore" });
121960
122101
  return true;
121961
122102
  } catch {
121962
122103
  return false;
@@ -121967,7 +122108,7 @@ function findAvailableDisplay() {
121967
122108
  const lockFile = `/tmp/.X${display}-lock`;
121968
122109
  const socketFile = `/tmp/.X11-unix/X${display}`;
121969
122110
  try {
121970
- execSync2(`test -e ${lockFile} || test -e ${socketFile}`, { stdio: "ignore" });
122111
+ execSync4(`test -e ${lockFile} || test -e ${socketFile}`, { stdio: "ignore" });
121971
122112
  } catch {
121972
122113
  return display;
121973
122114
  }
@@ -121980,7 +122121,7 @@ async function waitForDisplay(display, timeoutMs = 1e4) {
121980
122121
  const pollInterval = 100;
121981
122122
  while (Date.now() - startTime < timeoutMs) {
121982
122123
  try {
121983
- execSync2(`DISPLAY=${displayStr} xdpyinfo`, { stdio: "ignore", timeout: 1000 });
122124
+ execSync4(`DISPLAY=${displayStr} xdpyinfo`, { stdio: "ignore", timeout: 1000 });
121984
122125
  return true;
121985
122126
  } catch {
121986
122127
  await new Promise((resolve) => setTimeout(resolve, pollInterval));
@@ -122270,7 +122411,7 @@ async function executeCommand2(cmd, globalAutoWait) {
122270
122411
  }
122271
122412
  return await evaluate(cmd.script);
122272
122413
  case "sleep":
122273
- await new Promise((resolve) => setTimeout(resolve, cmd.ms ?? 1000));
122414
+ await new Promise((resolve2) => setTimeout(resolve2, cmd.ms ?? 1000));
122274
122415
  return { slept: cmd.ms ?? 1000 };
122275
122416
  default:
122276
122417
  throw new Error(`Unknown command: ${cmd.cmd}`);
@@ -122342,7 +122483,7 @@ async function main() {
122342
122483
  process.exit(1);
122343
122484
  }
122344
122485
  }
122345
- const appPath = options.app;
122486
+ const appPath = options.app ? resolve(options.app) : undefined;
122346
122487
  const jsonOutput = !!options.json;
122347
122488
  const port = options.port ? parseInt(options.port) : 9222;
122348
122489
  const clientModeCommands = ["screenshot", "snapshot", "click", "type", "wait", "eval"];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tauri-test-cli",
3
- "version": "0.5.2",
3
+ "version": "0.6.1",
4
4
  "description": "CLI for testing Tauri applications with screenshot capture, DOM inspection, and user interaction simulation",
5
5
  "type": "module",
6
6
  "bin": {
@@ -81,29 +81,34 @@ MINOR_VERSION="${major}.$((minor + 1)).0"
81
81
  MAJOR_VERSION="$((major + 1)).0.0"
82
82
 
83
83
  echo -e "${CYAN}Select version bump type:${NC}"
84
- echo " 1) patch (${CURRENT_VERSION} -> ${PATCH_VERSION})"
85
- echo " 2) minor (${CURRENT_VERSION} -> ${MINOR_VERSION})"
86
- echo " 3) major (${CURRENT_VERSION} -> ${MAJOR_VERSION})"
87
- echo " 4) cancel"
84
+ echo " 1) none (keep ${CURRENT_VERSION})"
85
+ echo " 2) patch (${CURRENT_VERSION} -> ${PATCH_VERSION})"
86
+ echo " 3) minor (${CURRENT_VERSION} -> ${MINOR_VERSION})"
87
+ echo " 4) major (${CURRENT_VERSION} -> ${MAJOR_VERSION})"
88
+ echo " 5) cancel"
88
89
  echo ""
89
90
 
90
- read -p "Enter choice [1-4]: " -n 1 -r CHOICE
91
+ read -p "Enter choice [1-5]: " -n 1 -r CHOICE
91
92
  echo ""
92
93
 
93
94
  case $CHOICE in
94
95
  1)
96
+ BUMP_TYPE=""
97
+ NEW_VERSION="$CURRENT_VERSION"
98
+ ;;
99
+ 2)
95
100
  BUMP_TYPE="patch"
96
101
  NEW_VERSION="$PATCH_VERSION"
97
102
  ;;
98
- 2)
103
+ 3)
99
104
  BUMP_TYPE="minor"
100
105
  NEW_VERSION="$MINOR_VERSION"
101
106
  ;;
102
- 3)
107
+ 4)
103
108
  BUMP_TYPE="major"
104
109
  NEW_VERSION="$MAJOR_VERSION"
105
110
  ;;
106
- 4|*)
111
+ 5|*)
107
112
  echo -e "${YELLOW}Publish cancelled.${NC}"
108
113
  exit 0
109
114
  ;;
@@ -115,33 +120,39 @@ echo ""
115
120
  # STEP 3: Bump version
116
121
  # ============================================================================
117
122
 
118
- echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
119
- echo -e "${GREEN}▶ Step 3: Bumping version to ${NEW_VERSION}...${NC}"
120
- echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
121
- echo ""
123
+ if [[ -n "$BUMP_TYPE" ]]; then
124
+ echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
125
+ echo -e "${GREEN}▶ Step 3: Bumping version to ${NEW_VERSION}...${NC}"
126
+ echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
127
+ echo ""
122
128
 
123
- ./scripts/bump-version.sh "$BUMP_TYPE"
129
+ ./scripts/bump-version.sh "$BUMP_TYPE"
124
130
 
125
- # ============================================================================
126
- # STEP 4: Commit, tag, and push to GitHub
127
- # ============================================================================
131
+ # ============================================================================
132
+ # STEP 4: Commit, tag, and push to GitHub
133
+ # ============================================================================
128
134
 
129
- echo ""
130
- echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
131
- echo -e "${GREEN}▶ Step 4: Pushing to GitHub...${NC}"
132
- echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
133
- echo ""
135
+ echo ""
136
+ echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
137
+ echo -e "${GREEN}▶ Step 4: Pushing to GitHub...${NC}"
138
+ echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
139
+ echo ""
134
140
 
135
- echo -e "${BLUE}Committing changes...${NC}"
136
- git add pixi.toml package.json .claude-plugin/plugin.json
137
- git commit -m "Bump version to $NEW_VERSION"
141
+ echo -e "${BLUE}Committing changes...${NC}"
142
+ git add pixi.toml package.json .claude-plugin/plugin.json
143
+ git commit -m "Bump version to $NEW_VERSION"
138
144
 
139
- echo -e "${BLUE}Creating git tag v${NEW_VERSION}...${NC}"
140
- git tag "v${NEW_VERSION}"
145
+ echo -e "${BLUE}Creating git tag v${NEW_VERSION}...${NC}"
146
+ git tag "v${NEW_VERSION}"
141
147
 
142
- echo -e "${BLUE}Pushing to remote...${NC}"
143
- git push
144
- git push --tags
148
+ echo -e "${BLUE}Pushing to remote...${NC}"
149
+ git push
150
+ git push --tags
151
+ else
152
+ echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
153
+ echo -e "${GREEN}▶ Skipping version bump, keeping ${CURRENT_VERSION}${NC}"
154
+ echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
155
+ fi
145
156
 
146
157
  echo -e "${GREEN}✓ Pushed to GitHub${NC}"
147
158