tauri-test-cli 0.7.1 → 0.8.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.
Files changed (2) hide show
  1. package/dist/cli.js +235 -158
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -120717,6 +120717,7 @@ async function disconnect() {
120717
120717
 
120718
120718
  // src/commands/screenshot.ts
120719
120719
  import { writeFile } from "fs/promises";
120720
+ import { execFileSync } from "child_process";
120720
120721
 
120721
120722
  // src/driver.ts
120722
120723
  import { spawn as spawn2, execSync as execSync2 } from "child_process";
@@ -120910,6 +120911,11 @@ async function waitForInteractive(selector, timeout = 5000) {
120910
120911
  // src/commands/utils.ts
120911
120912
  var xvfbDisplay = null;
120912
120913
  function getXvfbDisplay() {
120914
+ const envVal = process.env.TAURI_TEST_XVFB_DISPLAY;
120915
+ if (envVal !== undefined) {
120916
+ const n = Number(envVal);
120917
+ return Number.isFinite(n) ? n : null;
120918
+ }
120913
120919
  return xvfbDisplay;
120914
120920
  }
120915
120921
 
@@ -120925,24 +120931,34 @@ async function screenshot(options = {}) {
120925
120931
  const { width, height } = await browser3.getWindowSize();
120926
120932
  let data2;
120927
120933
  let method;
120928
- try {
120929
- data2 = await withTimeout(captureWithHtml2Canvas(browser3), timeout, "html2canvas timed out");
120930
- method = "html2canvas";
120931
- } catch (err) {
120932
- console.error(`html2canvas failed: ${err}, trying canvas fallback...`);
120934
+ const xvfbDisplay2 = getXvfbDisplay();
120935
+ if (xvfbDisplay2 !== null) {
120933
120936
  try {
120934
- data2 = await withTimeout(captureWithCanvas(browser3), timeout, "Canvas screenshot timed out");
120935
- method = "canvas";
120936
- } catch (canvasErr) {
120937
- if (getXvfbDisplay() !== null) {
120938
- throw new Error(`All screenshot methods failed in Xvfb: html2canvas: ${err}, canvas: ${canvasErr}`);
120939
- }
120940
- console.error(`Canvas failed: ${canvasErr}, trying native...`);
120937
+ data2 = captureWithX11(xvfbDisplay2);
120938
+ method = "x11";
120939
+ } catch (err) {
120940
+ console.error(`X11 capture failed: ${err}, falling back to JS-based methods...`);
120941
+ }
120942
+ }
120943
+ if (!data2 && xvfbDisplay2 === null) {
120944
+ try {
120945
+ data2 = await withTimeout(browser3.takeScreenshot(), timeout, `Native screenshot timed out after ${timeout}ms`);
120946
+ method = "native";
120947
+ } catch (err) {
120948
+ console.error(`Native screenshot failed: ${err}, trying html2canvas...`);
120949
+ }
120950
+ }
120951
+ if (!data2) {
120952
+ try {
120953
+ data2 = await withTimeout(captureWithHtml2Canvas(browser3), timeout, "html2canvas timed out");
120954
+ method = "html2canvas";
120955
+ } catch (err) {
120956
+ console.error(`html2canvas failed: ${err}, trying canvas fallback...`);
120941
120957
  try {
120942
- data2 = await withTimeout(browser3.takeScreenshot(), timeout, `Native screenshot timed out after ${timeout}ms`);
120943
- method = "native";
120944
- } catch (nativeErr) {
120945
- throw new Error(`All screenshot methods failed: html2canvas: ${err}, canvas: ${canvasErr}, native: ${nativeErr}`);
120958
+ data2 = await withTimeout(captureWithCanvas(browser3), timeout, "Canvas screenshot timed out");
120959
+ method = "canvas";
120960
+ } catch (canvasErr) {
120961
+ throw new Error(`All screenshot methods failed: ${xvfbDisplay2 !== null ? "x11 failed, " : ""}html2canvas: ${err}, canvas: ${canvasErr}`);
120946
120962
  }
120947
120963
  }
120948
120964
  }
@@ -120988,22 +121004,28 @@ async function captureWithHtml2Canvas(browser3) {
120988
121004
  throw new Error("Failed to load html2canvas from CDN");
120989
121005
  }
120990
121006
  await new Promise((r) => setTimeout(r, 50));
120991
- const base64 = await browser3.executeAsync((done) => {
120992
- const h2c = window.html2canvas;
120993
- if (!h2c) {
120994
- done("");
120995
- return;
120996
- }
120997
- h2c(document.body, {
120998
- useCORS: true,
120999
- allowTaint: true,
121000
- logging: false,
121001
- backgroundColor: "#ffffff"
121002
- }).then((canvas) => {
121003
- const dataUrl = canvas.toDataURL("image/png");
121004
- done(dataUrl.replace(/^data:image\/png;base64,/, ""));
121005
- }).catch(() => done(""));
121006
- setTimeout(() => done(""), 4000);
121007
+ const base64 = await browser3.execute(() => {
121008
+ return new Promise((resolve) => {
121009
+ const h2c = window.html2canvas;
121010
+ if (!h2c) {
121011
+ resolve("");
121012
+ return;
121013
+ }
121014
+ h2c(document.body, {
121015
+ useCORS: true,
121016
+ allowTaint: false,
121017
+ logging: false,
121018
+ backgroundColor: "#ffffff"
121019
+ }).then((canvas) => {
121020
+ try {
121021
+ const dataUrl = canvas.toDataURL("image/png");
121022
+ resolve(dataUrl.replace(/^data:image\/png;base64,/, ""));
121023
+ } catch {
121024
+ resolve("");
121025
+ }
121026
+ }).catch(() => resolve(""));
121027
+ setTimeout(() => resolve(""), 4000);
121028
+ });
121007
121029
  });
121008
121030
  if (!base64) {
121009
121031
  throw new Error("html2canvas capture returned empty");
@@ -121011,60 +121033,78 @@ async function captureWithHtml2Canvas(browser3) {
121011
121033
  return base64;
121012
121034
  }
121013
121035
  async function captureWithCanvas(browser3) {
121014
- const base64 = await browser3.executeAsync((done) => {
121015
- try {
121016
- const w2 = window.innerWidth || 800;
121017
- const h = window.innerHeight || 600;
121018
- const canvas = document.createElement("canvas");
121019
- canvas.width = w2;
121020
- canvas.height = h;
121021
- const ctx = canvas.getContext("2d");
121022
- ctx.fillStyle = "#ffffff";
121023
- ctx.fillRect(0, 0, w2, h);
121024
- const serializer = new XMLSerializer;
121025
- const cloned = document.documentElement.cloneNode(true);
121026
- const html3 = serializer.serializeToString(cloned);
121027
- const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${w2}" height="${h}">
121028
- <foreignObject width="100%" height="100%">
121029
- ${html3}
121030
- </foreignObject>
121031
- </svg>`;
121032
- const blob = new Blob([svg], { type: "image/svg+xml;charset=utf-8" });
121033
- const url2 = URL.createObjectURL(blob);
121034
- const img = new Image;
121035
- img.onload = () => {
121036
- ctx.drawImage(img, 0, 0);
121037
- URL.revokeObjectURL(url2);
121038
- const dataUrl = canvas.toDataURL("image/png");
121039
- done(dataUrl.replace(/^data:image\/png;base64,/, ""));
121040
- };
121041
- img.onerror = () => {
121042
- URL.revokeObjectURL(url2);
121043
- ctx.fillStyle = "#000000";
121044
- ctx.font = "16px monospace";
121045
- const text3 = document.body.innerText || "";
121046
- const lines = text3.split(`
121036
+ const base64 = await browser3.execute(() => {
121037
+ return new Promise((resolve) => {
121038
+ try {
121039
+ const w2 = window.innerWidth || 800;
121040
+ const h = window.innerHeight || 600;
121041
+ const canvas = document.createElement("canvas");
121042
+ canvas.width = w2;
121043
+ canvas.height = h;
121044
+ const ctx = canvas.getContext("2d");
121045
+ ctx.fillStyle = "#ffffff";
121046
+ ctx.fillRect(0, 0, w2, h);
121047
+ const serializer = new XMLSerializer;
121048
+ const cloned = document.documentElement.cloneNode(true);
121049
+ const html3 = serializer.serializeToString(cloned);
121050
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${w2}" height="${h}">
121051
+ <foreignObject width="100%" height="100%">
121052
+ ${html3}
121053
+ </foreignObject>
121054
+ </svg>`;
121055
+ const blob = new Blob([svg], { type: "image/svg+xml;charset=utf-8" });
121056
+ const url2 = URL.createObjectURL(blob);
121057
+ const img = new Image;
121058
+ const renderText2 = () => {
121059
+ ctx.fillStyle = "#000000";
121060
+ ctx.font = "16px monospace";
121061
+ const text3 = document.body.innerText || "";
121062
+ const lines = text3.split(`
121047
121063
  `);
121048
- for (let i = 0;i < lines.length && i < 40; i++) {
121049
- ctx.fillText(lines[i], 10, 20 + i * 20);
121050
- }
121051
- const dataUrl = canvas.toDataURL("image/png");
121052
- done(dataUrl.replace(/^data:image\/png;base64,/, ""));
121053
- };
121054
- img.src = url2;
121055
- setTimeout(() => {
121056
- const dataUrl = canvas.toDataURL("image/png");
121057
- done(dataUrl.replace(/^data:image\/png;base64,/, ""));
121058
- }, 4000);
121059
- } catch (e) {
121060
- done("");
121061
- }
121064
+ for (let i = 0;i < lines.length && i < 40; i++) {
121065
+ ctx.fillText(lines[i], 10, 20 + i * 20);
121066
+ }
121067
+ const dataUrl = canvas.toDataURL("image/png");
121068
+ resolve(dataUrl.replace(/^data:image\/png;base64,/, ""));
121069
+ };
121070
+ img.onload = () => {
121071
+ try {
121072
+ ctx.drawImage(img, 0, 0);
121073
+ URL.revokeObjectURL(url2);
121074
+ const dataUrl = canvas.toDataURL("image/png");
121075
+ resolve(dataUrl.replace(/^data:image\/png;base64,/, ""));
121076
+ } catch {
121077
+ URL.revokeObjectURL(url2);
121078
+ renderText2();
121079
+ }
121080
+ };
121081
+ img.onerror = () => {
121082
+ URL.revokeObjectURL(url2);
121083
+ renderText2();
121084
+ };
121085
+ img.src = url2;
121086
+ setTimeout(() => {
121087
+ try {
121088
+ const dataUrl = canvas.toDataURL("image/png");
121089
+ resolve(dataUrl.replace(/^data:image\/png;base64,/, ""));
121090
+ } catch {
121091
+ renderText2();
121092
+ }
121093
+ }, 4000);
121094
+ } catch (e) {
121095
+ resolve("");
121096
+ }
121097
+ });
121062
121098
  });
121063
121099
  if (!base64) {
121064
121100
  throw new Error("Canvas screenshot capture returned empty");
121065
121101
  }
121066
121102
  return base64;
121067
121103
  }
121104
+ function captureWithX11(display) {
121105
+ const result = execFileSync("import", ["-display", `:${display}`, "-window", "root", "png:-"], { maxBuffer: 50 * 1024 * 1024, timeout: 1e4 });
121106
+ return result.toString("base64");
121107
+ }
121068
121108
 
121069
121109
  // src/commands/snapshot.ts
121070
121110
  import { writeFile as writeFile2 } from "fs/promises";
@@ -121342,6 +121382,7 @@ import { readFileSync } from "fs";
121342
121382
 
121343
121383
  // src/commands/screenshot.ts
121344
121384
  import { writeFile as writeFile3 } from "fs/promises";
121385
+ import { execFileSync as execFileSync2 } from "child_process";
121345
121386
  var HTML2CANVAS_CDN2 = "https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js";
121346
121387
  async function screenshot2(options = {}) {
121347
121388
  const browser3 = requireBrowser();
@@ -121353,24 +121394,34 @@ async function screenshot2(options = {}) {
121353
121394
  const { width, height } = await browser3.getWindowSize();
121354
121395
  let data2;
121355
121396
  let method;
121356
- try {
121357
- data2 = await withTimeout2(captureWithHtml2Canvas2(browser3), timeout, "html2canvas timed out");
121358
- method = "html2canvas";
121359
- } catch (err) {
121360
- console.error(`html2canvas failed: ${err}, trying canvas fallback...`);
121397
+ const xvfbDisplay2 = getXvfbDisplay();
121398
+ if (xvfbDisplay2 !== null) {
121361
121399
  try {
121362
- data2 = await withTimeout2(captureWithCanvas2(browser3), timeout, "Canvas screenshot timed out");
121363
- method = "canvas";
121364
- } catch (canvasErr) {
121365
- if (getXvfbDisplay() !== null) {
121366
- throw new Error(`All screenshot methods failed in Xvfb: html2canvas: ${err}, canvas: ${canvasErr}`);
121367
- }
121368
- console.error(`Canvas failed: ${canvasErr}, trying native...`);
121400
+ data2 = captureWithX112(xvfbDisplay2);
121401
+ method = "x11";
121402
+ } catch (err) {
121403
+ console.error(`X11 capture failed: ${err}, falling back to JS-based methods...`);
121404
+ }
121405
+ }
121406
+ if (!data2 && xvfbDisplay2 === null) {
121407
+ try {
121408
+ data2 = await withTimeout2(browser3.takeScreenshot(), timeout, `Native screenshot timed out after ${timeout}ms`);
121409
+ method = "native";
121410
+ } catch (err) {
121411
+ console.error(`Native screenshot failed: ${err}, trying html2canvas...`);
121412
+ }
121413
+ }
121414
+ if (!data2) {
121415
+ try {
121416
+ data2 = await withTimeout2(captureWithHtml2Canvas2(browser3), timeout, "html2canvas timed out");
121417
+ method = "html2canvas";
121418
+ } catch (err) {
121419
+ console.error(`html2canvas failed: ${err}, trying canvas fallback...`);
121369
121420
  try {
121370
- data2 = await withTimeout2(browser3.takeScreenshot(), timeout, `Native screenshot timed out after ${timeout}ms`);
121371
- method = "native";
121372
- } catch (nativeErr) {
121373
- throw new Error(`All screenshot methods failed: html2canvas: ${err}, canvas: ${canvasErr}, native: ${nativeErr}`);
121421
+ data2 = await withTimeout2(captureWithCanvas2(browser3), timeout, "Canvas screenshot timed out");
121422
+ method = "canvas";
121423
+ } catch (canvasErr) {
121424
+ throw new Error(`All screenshot methods failed: ${xvfbDisplay2 !== null ? "x11 failed, " : ""}html2canvas: ${err}, canvas: ${canvasErr}`);
121374
121425
  }
121375
121426
  }
121376
121427
  }
@@ -121416,22 +121467,28 @@ async function captureWithHtml2Canvas2(browser3) {
121416
121467
  throw new Error("Failed to load html2canvas from CDN");
121417
121468
  }
121418
121469
  await new Promise((r) => setTimeout(r, 50));
121419
- const base64 = await browser3.executeAsync((done) => {
121420
- const h2c = window.html2canvas;
121421
- if (!h2c) {
121422
- done("");
121423
- return;
121424
- }
121425
- h2c(document.body, {
121426
- useCORS: true,
121427
- allowTaint: true,
121428
- logging: false,
121429
- backgroundColor: "#ffffff"
121430
- }).then((canvas) => {
121431
- const dataUrl = canvas.toDataURL("image/png");
121432
- done(dataUrl.replace(/^data:image\/png;base64,/, ""));
121433
- }).catch(() => done(""));
121434
- setTimeout(() => done(""), 4000);
121470
+ const base64 = await browser3.execute(() => {
121471
+ return new Promise((resolve) => {
121472
+ const h2c = window.html2canvas;
121473
+ if (!h2c) {
121474
+ resolve("");
121475
+ return;
121476
+ }
121477
+ h2c(document.body, {
121478
+ useCORS: true,
121479
+ allowTaint: false,
121480
+ logging: false,
121481
+ backgroundColor: "#ffffff"
121482
+ }).then((canvas) => {
121483
+ try {
121484
+ const dataUrl = canvas.toDataURL("image/png");
121485
+ resolve(dataUrl.replace(/^data:image\/png;base64,/, ""));
121486
+ } catch {
121487
+ resolve("");
121488
+ }
121489
+ }).catch(() => resolve(""));
121490
+ setTimeout(() => resolve(""), 4000);
121491
+ });
121435
121492
  });
121436
121493
  if (!base64) {
121437
121494
  throw new Error("html2canvas capture returned empty");
@@ -121439,60 +121496,78 @@ async function captureWithHtml2Canvas2(browser3) {
121439
121496
  return base64;
121440
121497
  }
121441
121498
  async function captureWithCanvas2(browser3) {
121442
- const base64 = await browser3.executeAsync((done) => {
121443
- try {
121444
- const w2 = window.innerWidth || 800;
121445
- const h = window.innerHeight || 600;
121446
- const canvas = document.createElement("canvas");
121447
- canvas.width = w2;
121448
- canvas.height = h;
121449
- const ctx = canvas.getContext("2d");
121450
- ctx.fillStyle = "#ffffff";
121451
- ctx.fillRect(0, 0, w2, h);
121452
- const serializer = new XMLSerializer;
121453
- const cloned = document.documentElement.cloneNode(true);
121454
- const html3 = serializer.serializeToString(cloned);
121455
- const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${w2}" height="${h}">
121456
- <foreignObject width="100%" height="100%">
121457
- ${html3}
121458
- </foreignObject>
121459
- </svg>`;
121460
- const blob = new Blob([svg], { type: "image/svg+xml;charset=utf-8" });
121461
- const url2 = URL.createObjectURL(blob);
121462
- const img = new Image;
121463
- img.onload = () => {
121464
- ctx.drawImage(img, 0, 0);
121465
- URL.revokeObjectURL(url2);
121466
- const dataUrl = canvas.toDataURL("image/png");
121467
- done(dataUrl.replace(/^data:image\/png;base64,/, ""));
121468
- };
121469
- img.onerror = () => {
121470
- URL.revokeObjectURL(url2);
121471
- ctx.fillStyle = "#000000";
121472
- ctx.font = "16px monospace";
121473
- const text3 = document.body.innerText || "";
121474
- const lines = text3.split(`
121499
+ const base64 = await browser3.execute(() => {
121500
+ return new Promise((resolve) => {
121501
+ try {
121502
+ const w2 = window.innerWidth || 800;
121503
+ const h = window.innerHeight || 600;
121504
+ const canvas = document.createElement("canvas");
121505
+ canvas.width = w2;
121506
+ canvas.height = h;
121507
+ const ctx = canvas.getContext("2d");
121508
+ ctx.fillStyle = "#ffffff";
121509
+ ctx.fillRect(0, 0, w2, h);
121510
+ const serializer = new XMLSerializer;
121511
+ const cloned = document.documentElement.cloneNode(true);
121512
+ const html3 = serializer.serializeToString(cloned);
121513
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${w2}" height="${h}">
121514
+ <foreignObject width="100%" height="100%">
121515
+ ${html3}
121516
+ </foreignObject>
121517
+ </svg>`;
121518
+ const blob = new Blob([svg], { type: "image/svg+xml;charset=utf-8" });
121519
+ const url2 = URL.createObjectURL(blob);
121520
+ const img = new Image;
121521
+ const renderText2 = () => {
121522
+ ctx.fillStyle = "#000000";
121523
+ ctx.font = "16px monospace";
121524
+ const text3 = document.body.innerText || "";
121525
+ const lines = text3.split(`
121475
121526
  `);
121476
- for (let i = 0;i < lines.length && i < 40; i++) {
121477
- ctx.fillText(lines[i], 10, 20 + i * 20);
121478
- }
121479
- const dataUrl = canvas.toDataURL("image/png");
121480
- done(dataUrl.replace(/^data:image\/png;base64,/, ""));
121481
- };
121482
- img.src = url2;
121483
- setTimeout(() => {
121484
- const dataUrl = canvas.toDataURL("image/png");
121485
- done(dataUrl.replace(/^data:image\/png;base64,/, ""));
121486
- }, 4000);
121487
- } catch (e) {
121488
- done("");
121489
- }
121527
+ for (let i = 0;i < lines.length && i < 40; i++) {
121528
+ ctx.fillText(lines[i], 10, 20 + i * 20);
121529
+ }
121530
+ const dataUrl = canvas.toDataURL("image/png");
121531
+ resolve(dataUrl.replace(/^data:image\/png;base64,/, ""));
121532
+ };
121533
+ img.onload = () => {
121534
+ try {
121535
+ ctx.drawImage(img, 0, 0);
121536
+ URL.revokeObjectURL(url2);
121537
+ const dataUrl = canvas.toDataURL("image/png");
121538
+ resolve(dataUrl.replace(/^data:image\/png;base64,/, ""));
121539
+ } catch {
121540
+ URL.revokeObjectURL(url2);
121541
+ renderText2();
121542
+ }
121543
+ };
121544
+ img.onerror = () => {
121545
+ URL.revokeObjectURL(url2);
121546
+ renderText2();
121547
+ };
121548
+ img.src = url2;
121549
+ setTimeout(() => {
121550
+ try {
121551
+ const dataUrl = canvas.toDataURL("image/png");
121552
+ resolve(dataUrl.replace(/^data:image\/png;base64,/, ""));
121553
+ } catch {
121554
+ renderText2();
121555
+ }
121556
+ }, 4000);
121557
+ } catch (e) {
121558
+ resolve("");
121559
+ }
121560
+ });
121490
121561
  });
121491
121562
  if (!base64) {
121492
121563
  throw new Error("Canvas screenshot capture returned empty");
121493
121564
  }
121494
121565
  return base64;
121495
121566
  }
121567
+ function captureWithX112(display) {
121568
+ const result = execFileSync2("import", ["-display", `:${display}`, "-window", "root", "png:-"], { maxBuffer: 50 * 1024 * 1024, timeout: 1e4 });
121569
+ return result.toString("base64");
121570
+ }
121496
121571
 
121497
121572
  // src/commands/snapshot.ts
121498
121573
  import { writeFile as writeFile4 } from "fs/promises";
@@ -122294,6 +122369,7 @@ async function startXvfb() {
122294
122369
  }
122295
122370
  console.error(`Xvfb ready on display ${displayStr}`);
122296
122371
  xvfbDisplay2 = display;
122372
+ process.env.TAURI_TEST_XVFB_DISPLAY = String(display);
122297
122373
  process.env.DISPLAY = displayStr;
122298
122374
  delete process.env.WAYLAND_DISPLAY;
122299
122375
  process.env.GDK_BACKEND = "x11";
@@ -122305,6 +122381,7 @@ function stopXvfb() {
122305
122381
  xvfbProcess.kill("SIGTERM");
122306
122382
  xvfbProcess = null;
122307
122383
  xvfbDisplay2 = null;
122384
+ delete process.env.TAURI_TEST_XVFB_DISPLAY;
122308
122385
  }
122309
122386
  }
122310
122387
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tauri-test-cli",
3
- "version": "0.7.1",
3
+ "version": "0.8.0",
4
4
  "description": "CLI for testing Tauri applications with screenshot capture, DOM inspection, and user interaction simulation",
5
5
  "type": "module",
6
6
  "bin": {