首页 > 解决方案 > 如何自动化 ElectronJS 应用程序

问题描述

我们正在为我们的桌面工作开发一个用于特定网站自动化的 ElectronJS 应用程序,其中包括登录、表单填写、报告下载等常见任务。

我们已经尝试过 ElectronJS、Spectron、NightmareJS、Puppeteer 等的基本教程,它们都可以单独工作,但是在相互集成时可用的文档非常少(尽管开放的 github 问题)。

我们要实现以下目标:

我们不需要无头自动化,在幕后会发生一些神奇的事情。我们只需要当前页面上的基于菜单/按钮单击的操作/任务。

NightmareJSPuppeteer似乎都启动了自己的网页实例(因为它们是为测试独立应用程序而构建的),但我们需要的是现有BrowserWindows.

是实现这些目标puppeteernightmarejs正确工具吗?如果是,有任何文件吗?

或者,我们是否应该mouseclick在控制台中注入我们自己的原生 JS 事件(如 etc 事件)来执行操作?

标签: javascriptautomationelectronpuppeteernightmare

解决方案


您可以使用puppeteer-core. core默认情况下,该版本不下载 Chromium,如果您想控制 Electron 应用程序,则不需要它。

然后在测试中调用launch方法,在该方法中定义electron为可执行文件而不是 Chromium,如下面的代码片段所示:

const electron = require("electron");
const puppeteer = require("puppeteer-core");

const delay = ms =>
  new Promise(resolve => {
    setTimeout(() => {
      resolve();
    }, ms);
  });

(async () => {
  try {
    const app = await puppeteer.launch({
      executablePath: electron,
      args: ["."],
      headless: false,
    });
    const pages = await app.pages();
    const [page] = pages;

    await page.setViewport({ width: 1200, height: 700 });
    await delay(5000);
    const image = await page.screenshot();
    console.log(image);
    await page.close();
    await delay(2000);
    await app.close();
  } catch (error) {
    console.error(error);
  }
})();

电子 5.xy 及更高版本的更新(目前最高为 7.xy,我尚未在 8.xy beta 上对其进行测试),puppeteer.connect使用 where 代替launch方法:

// const assert = require("assert");
const electron = require("electron");
const kill = require("tree-kill");
const puppeteer = require("puppeteer-core");
const { spawn } = require("child_process");

let pid;

const run = async () => {
  const port = 9200; // Debugging port
  const startTime = Date.now();
  const timeout = 20000; // Timeout in miliseconds
  let app;

  // Start Electron with custom debugging port
  pid = spawn(electron, [".", `--remote-debugging-port=${port}`], {
    shell: true
  }).pid;

  // Wait for Puppeteer to connect
  while (!app) {
    try {
      app = await puppeteer.connect({
        browserURL: `http://localhost:${port}`,
        defaultViewport: { width: 1000, height: 600 } // Optional I think
      });
    } catch (error) {
      if (Date.now() > startTime + timeout) {
        throw error;
      }
    }
  }

  // Do something, e.g.:
  // const [page] = await app.pages();
  // await page.waitForSelector("#someid")// 
  // const text = await page.$eval("#someid", element => element.innerText);
  // assert(text === "Your expected text");
  // await page.close();
};

run()
  .then(() => {
    // Do something
  })
  .catch(error => {
    // Do something
    kill(pid, () => {
      process.exit(1);
    });
  });

获取pid和使用kill是可选的。对于在某些 CI 平台上运行脚本无关紧要,但对于本地环境,您必须在每次尝试失败后手动关闭电子应用程序。

简单的演示仓库: https ://github.com/peterdanis/electron-puppeteer-demo


推荐阅读