Как автоматизировать приложение ElectronJS

Мы стремимся разработать приложение ElectronJS для автоматизации конкретного веб-сайта на нашей настольной работе, которая включает в себя общие задачи, такие как вход в систему, заполнение форм, загрузка отчетов и т. д.

Мы попробовали базовое руководство по ElectronJS, Spectron, NightmareJS, Puppeteer и т. д., и все они отлично работают по отдельности, но очень мало документации (хотя открыты проблемы с github) доступно по интеграции друг друга.

Мы хотим добиться следующего:

  • Состояние входа (session) не должно удаляться при закрытии приложения ElectronJS и должно быть доступно при перезапуске приложения.
  • Несколько кнопок меню, которые инициируют некоторые задачи автоматизации, такие как загрузка, заполнение форм и т. д., в существующих browserWindow

Нам не нужна безголовая автоматизация, когда за кулисами происходит какое-то волшебство. Нам нужны действия/задачи, основанные на меню/кнопке, только на текущей странице.

NightmareJS, Puppeteer и т. д., кажется, запускают свои собственные экземпляры веб-страниц (поскольку они были созданы для тестирования автономных приложений), но нам нужна автоматизация существующих BrowserWindows.

Является ли puppeteer или nightmarejs подходящим инструментом для таких целей? Если да, какие документы?

Или же мы должны вводить наши собственные события JS, такие как события mouseclick и т. д., в консоль для выполнения действия?


person D Joe    schedule 14.08.2018    source источник


Ответы (5)


Вы можете использовать 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.x.y и выше (на данный момент до 7.x.y, на бета-версии 8.x.y еще не тестировал), где вместо метода launch используется puppeteer.connect:

// 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

person PeterDanis    schedule 22.01.2019
comment
Привет, Питер, значит ли это, что я могу написать сценарий взаимодействия с пользователем внутри приложения Electron? Откуда он знает, как запустить Electron и поместить нужный скрипт в приложение Electron? Тогда флаги CLI Electron похожи на флаги Chromium CLI? - person trusktr; 27.02.2019
comment
Привет Джо. Точно! Вы можете управлять страницей, живущей внутри Electron (в процессе рендеринга). Он управляет приложением Electron так же, как и Chromium — через протокол DevTools. Что касается запуска правильного исполняемого файла - в приведенном выше примере я передаю путь Electron вместо Chromium в методе запуска. Я еще не пробовал использовать его для e2e-тестирования окончательного приложения, но, вероятно, оно должно работать таким же образом. - person PeterDanis; 27.02.2019
comment
Я получаю эту ошибку: The "file" argument must be of type string. Received type object в puppeteer-core/lib/Launcher.js:126:40 - person Justin; 29.03.2019
comment
@PeterDanis: я безуспешно тестировал ваше решение. Ваше предложение последовательно... Но у вас получилось, или вы можете предоставить репозиторий, где мы можем использовать ваше рабочее решение? - person Alain; 07.04.2019
comment
@ Ален, извините за поздний ответ. Пожалуйста, проверьте простое демо-репозиторий: github.com/peterdanis/electron-puppeteer-demo - person PeterDanis; 23.04.2019
comment
@PeterDanis: ваш репозиторий git работает при добавлении задержки между .launch() (с оболочкой) и .connect(), в противном случае страница не всегда устанавливается. Я хочу добавить плюс к этому ответу, однако ваш репозиторий git и этот ответ не совпадают! Наконец, с репозиторием git я смог создать скриншот страницы. Я не уверен, что протокол DevsTool полностью поддерживается электронами. - person Alain; 21.05.2019

Сценарий автоматизации на Java с использованием Selenium и ChromeDriver

package setUp;

import helper.Constants;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.DesiredCapabilities;


public class Test {

       public static void main(String[] args) {

             System.setProperty(Constants.WebDriverType, Constants.WebDriverPath + Constants.WindowsDriver);

             ChromeOptions opt = new ChromeOptions();

             DesiredCapabilities capabilities = new DesiredCapabilities();

             capabilities.setCapability("chromeOptions", opt);
             capabilities.setBrowserName("chrome");
             capabilities.setVersion("73.0.3683.121");

             ChromeOptions options = new ChromeOptions();
             options.merge(capabilities);
             options.setBinary("C:\\\\Program Files\\\\Audio\\\\Audio-Configuration\\\\Audio-Configuration.exe");
             options.setCapability("chromeOptions", options);
             ChromeDriver driver = new ChromeDriver(options);

             try {
                    Thread.sleep(5000);
                    WebElement webElement = driver.findElement(By.xpath(
                                 "/html/body/app-root/mat-drawer-container/mat-drawer/div/app-bottom-side-nav/div/app-settings-nav/div/div/a/div"));                        
                    webElement.click();
             } catch (Exception e) {
                    System.out.println("Exception trace");
                    System.out.println(e);
             }
       }
}

Сценарий автоматизации на JavaScript с использованием Spectron (построен на основе ChromeDriver и WebDriverIO).

const Application = require("spectron").Application;

const path =
  "C:/Program Files/Audio/Audio-Configuration/Audio-Configuration.exe";
const myApp = new Application({
  path: path,
  chromeDriverArgs: ["--disable-extensions"],
  env: {
    SPECTRON: true,
    ELECTRON_ENABLE_LOGGING: true,
    ELECTRON_ENABLE_STACK_DUMPING: true
  }
});

const windowClick = async app => {
  await app.start();
  try {
    // Identifying by class name
    await app.client.click(".ic-setting");

    // Identifying by Id
    // await app.client.click("#left-btn");
  } catch (error) {
    // Log any failures
    console.error("Test failed", error.message);
  }
  // Stop the application
     await app.stop();
};

windowClick(myApp);
person Sabunkar Tejas Sahailesh    schedule 06.01.2020

Spectron лучше всего подходит для приложений электронного построения.

У вас будет доступ ко всем электронным API. Мы можем запускать и останавливать ваше приложение только с помощью Spectron.

Мы можем запускать как упакованное приложение, так и без упаковки.

https://electronjs.org/spectron

person Bharath Kumar S    schedule 24.08.2018

Вы можете использовать Spectron, но если вы хотите посмотреть документацию, Spectron использует webdriverio с хорошей документацией.

Я рекомендую вам использовать Spectron, потому что я пытался автоматизировать свои тесты с помощью java-selenium, но в некоторых случаях это не удается. Если вы хотите использовать селен, напишите ниже код, чтобы установить возможности для настройки электронного приложения на chromedriver.

 ChromeOptions options = new ChromeOptions();
    options.setBinary(binaryPath);
    options.addArguments("--app=" + argPath);
    options.setCapability("chromeOptions", options);
    driver = new ChromeDriver(options);   

Надеюсь, это поможет вам.

person slckayhn    schedule 28.09.2018

Если интеграция с электронным кошмаром является очень хорошей библиотекой для достижения этой цели, даже если она будет готова к распространению с ней, вот следующая полезная документация для того же resource1 и

person Prakalp varshney    schedule 31.08.2020